From acbb090b2400f627a801074c4e3e006c7501bb26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 15 Aug 2012 14:15:41 +0200 Subject: [PATCH 0001/1634] prep: Include devices for ppc64 as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows running qemu-system-ppc64 -M prep for consistency. Reported-by: Markus Armbruster Signed-off-by: Andreas Färber Acked-by: Hervé Poussineau --- default-configs/ppc64-softmmu.mak | 3 +++ 1 file changed, 3 insertions(+) diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index e4265b4978..a1d2d4f136 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -12,9 +12,12 @@ CONFIG_I8254=y CONFIG_PCKBD=y CONFIG_FDC=y CONFIG_DMA=y +CONFIG_I82374=y CONFIG_OPENPIC=y CONFIG_PREP_PCI=y +CONFIG_I82378=y CONFIG_MACIO=y +CONFIG_PCSPK=y CONFIG_CUDA=y CONFIG_ADB=y CONFIG_MAC_NVRAM=y From 1ae41f447d1467172b0f8290ca1b83726ea9942a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 14 Apr 2012 22:48:35 +0200 Subject: [PATCH 0002/1634] prep: Add pc87312 Super I/O emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides floppy and IDE controllers as well as serial and parallel ports. However, dynamic configuration of devices is not yet supported. Signed-off-by: Hervé Poussineau [AF: QOM'ify, split out header, create CharDriverState if absent] Signed-off-by: Andreas Färber --- hw/Makefile.objs | 1 + hw/pc87312.c | 386 +++++++++++++++++++++++++++++++++++++++++++++++ hw/pc87312.h | 66 ++++++++ trace-events | 8 + 4 files changed, 461 insertions(+) create mode 100644 hw/pc87312.c create mode 100644 hw/pc87312.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 7f57ed58e2..aab0a469bb 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -39,6 +39,7 @@ hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o # PPC devices hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o hw-obj-$(CONFIG_I82378) += i82378.o +hw-obj-$(CONFIG_PC87312) += pc87312.o # Mac shared devices hw-obj-$(CONFIG_MACIO) += macio.o hw-obj-$(CONFIG_CUDA) += cuda.o diff --git a/hw/pc87312.c b/hw/pc87312.c new file mode 100644 index 0000000000..b5fa01681b --- /dev/null +++ b/hw/pc87312.c @@ -0,0 +1,386 @@ +/* + * QEMU National Semiconductor PC87312 (Super I/O) + * + * Copyright (c) 2010-2012 Herve Poussineau + * Copyright (c) 2011-2012 Andreas Färber + * + * 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 "pc87312.h" +#include "blockdev.h" +#include "sysemu.h" +#include "trace.h" + + +#define REG_FER 0 +#define REG_FAR 1 +#define REG_PTR 2 + +#define FER regs[REG_FER] +#define FAR regs[REG_FAR] +#define PTR regs[REG_PTR] + +#define FER_PARALLEL_EN 0x01 +#define FER_UART1_EN 0x02 +#define FER_UART2_EN 0x04 +#define FER_FDC_EN 0x08 +#define FER_FDC_4 0x10 +#define FER_FDC_ADDR 0x20 +#define FER_IDE_EN 0x40 +#define FER_IDE_ADDR 0x80 + +#define FAR_PARALLEL_ADDR 0x03 +#define FAR_UART1_ADDR 0x0C +#define FAR_UART2_ADDR 0x30 +#define FAR_UART_3_4 0xC0 + +#define PTR_POWER_DOWN 0x01 +#define PTR_CLOCK_DOWN 0x02 +#define PTR_PWDN 0x04 +#define PTR_IRQ_5_7 0x08 +#define PTR_UART1_TEST 0x10 +#define PTR_UART2_TEST 0x20 +#define PTR_LOCK_CONF 0x40 +#define PTR_EPP_MODE 0x80 + + +/* Parallel port */ + +static inline bool is_parallel_enabled(PC87312State *s) +{ + return s->FER & FER_PARALLEL_EN; +} + +static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 }; + +static inline uint32_t get_parallel_iobase(PC87312State *s) +{ + return parallel_base[s->FAR & FAR_PARALLEL_ADDR]; +} + +static const uint32_t parallel_irq[] = { 5, 7, 5, 0 }; + +static inline uint32_t get_parallel_irq(PC87312State *s) +{ + int idx; + idx = (s->FAR & FAR_PARALLEL_ADDR); + if (idx == 0) { + return (s->PTR & PTR_IRQ_5_7) ? 7 : 5; + } else { + return parallel_irq[idx]; + } +} + +static inline bool is_parallel_epp(PC87312State *s) +{ + return s->PTR & PTR_EPP_MODE; +} + + +/* UARTs */ + +static const uint32_t uart_base[2][4] = { + { 0x3e8, 0x338, 0x2e8, 0x220 }, + { 0x2e8, 0x238, 0x2e0, 0x228 } +}; + +static inline uint32_t get_uart_iobase(PC87312State *s, int i) +{ + int idx; + idx = (s->FAR >> (2 * i + 2)) & 0x3; + if (idx == 0) { + return 0x3f8; + } else if (idx == 1) { + return 0x2f8; + } else { + return uart_base[idx & 1][(s->FAR & FAR_UART_3_4) >> 6]; + } +} + +static inline uint32_t get_uart_irq(PC87312State *s, int i) +{ + int idx; + idx = (s->FAR >> (2 * i + 2)) & 0x3; + return (idx & 1) ? 3 : 4; +} + +static inline bool is_uart_enabled(PC87312State *s, int i) +{ + return s->FER & (FER_UART1_EN << i); +} + + +/* Floppy controller */ + +static inline bool is_fdc_enabled(PC87312State *s) +{ + return s->FER & FER_FDC_EN; +} + +static inline uint32_t get_fdc_iobase(PC87312State *s) +{ + return (s->FER & FER_FDC_ADDR) ? 0x370 : 0x3f0; +} + + +/* IDE controller */ + +static inline bool is_ide_enabled(PC87312State *s) +{ + return s->FER & FER_IDE_EN; +} + +static inline uint32_t get_ide_iobase(PC87312State *s) +{ + return (s->FER & FER_IDE_ADDR) ? 0x170 : 0x1f0; +} + + +static void reconfigure_devices(PC87312State *s) +{ + error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)", + s->FER, s->FAR, s->PTR); +} + +static void pc87312_soft_reset(PC87312State *s) +{ + static const uint8_t fer_init[] = { + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f, + 0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00, + }; + static const uint8_t far_init[] = { + 0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01, + 0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24, + 0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24, + 0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10, + }; + static const uint8_t ptr_init[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + }; + + s->read_id_step = 0; + s->selected_index = REG_FER; + + s->FER = fer_init[s->config & 0x1f]; + s->FAR = far_init[s->config & 0x1f]; + s->PTR = ptr_init[s->config & 0x1f]; +} + +static void pc87312_hard_reset(PC87312State *s) +{ + pc87312_soft_reset(s); +} + +static void pc87312_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PC87312State *s = opaque; + + trace_pc87312_io_write(addr, val); + + if ((addr & 1) == 0) { + /* Index register */ + s->read_id_step = 2; + s->selected_index = val; + } else { + /* Data register */ + if (s->selected_index < 3) { + s->regs[s->selected_index] = val; + reconfigure_devices(s); + } + } +} + +static uint32_t pc87312_ioport_read(void *opaque, uint32_t addr) +{ + PC87312State *s = opaque; + uint32_t val; + + if ((addr & 1) == 0) { + /* Index register */ + if (s->read_id_step++ == 0) { + val = 0x88; + } else if (s->read_id_step++ == 1) { + val = 0; + } else { + val = s->selected_index; + } + } else { + /* Data register */ + if (s->selected_index < 3) { + val = s->regs[s->selected_index]; + } else { + /* Invalid selected index */ + val = 0; + } + } + + trace_pc87312_io_read(addr, val); + return val; +} + +static int pc87312_post_load(void *opaque, int version_id) +{ + PC87312State *s = opaque; + + reconfigure_devices(s); + return 0; +} + +static void pc87312_reset(DeviceState *d) +{ + PC87312State *s = PC87312(d); + + pc87312_soft_reset(s); +} + +static int pc87312_init(ISADevice *dev) +{ + PC87312State *s; + DeviceState *d; + ISADevice *isa; + ISABus *bus; + CharDriverState *chr; + DriveInfo *drive; + char name[5]; + int i; + + s = PC87312(dev); + bus = isa_bus_from_device(dev); + pc87312_hard_reset(s); + + if (is_parallel_enabled(s)) { + chr = parallel_hds[0]; + if (chr == NULL) { + chr = qemu_chr_new("par0", "null", NULL); + } + isa = isa_create(bus, "isa-parallel"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "index", 0); + qdev_prop_set_uint32(d, "iobase", get_parallel_iobase(s)); + qdev_prop_set_uint32(d, "irq", get_parallel_irq(s)); + qdev_prop_set_chr(d, "chardev", chr); + qdev_init_nofail(d); + s->parallel.dev = isa; + trace_pc87312_info_parallel(get_parallel_iobase(s), + get_parallel_irq(s)); + } + + for (i = 0; i < 2; i++) { + if (is_uart_enabled(s, i)) { + chr = serial_hds[i]; + if (chr == NULL) { + snprintf(name, sizeof(name), "ser%d", i); + chr = qemu_chr_new(name, "null", NULL); + } + isa = isa_create(bus, "isa-serial"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "index", i); + qdev_prop_set_uint32(d, "iobase", get_uart_iobase(s, i)); + qdev_prop_set_uint32(d, "irq", get_uart_irq(s, i)); + qdev_prop_set_chr(d, "chardev", chr); + qdev_init_nofail(d); + s->uart[i].dev = isa; + trace_pc87312_info_serial(i, get_uart_iobase(s, i), + get_uart_irq(s, i)); + } + } + + if (is_fdc_enabled(s)) { + isa = isa_create(bus, "isa-fdc"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "iobase", get_fdc_iobase(s)); + qdev_prop_set_uint32(d, "irq", 6); + drive = drive_get(IF_FLOPPY, 0, 0); + if (drive != NULL) { + qdev_prop_set_drive_nofail(d, "driveA", drive->bdrv); + } + drive = drive_get(IF_FLOPPY, 0, 1); + if (drive != NULL) { + qdev_prop_set_drive_nofail(d, "driveB", drive->bdrv); + } + qdev_init_nofail(d); + s->fdc.dev = isa; + trace_pc87312_info_floppy(get_fdc_iobase(s)); + } + + if (is_ide_enabled(s)) { + isa = isa_create(bus, "isa-ide"); + d = DEVICE(isa); + qdev_prop_set_uint32(d, "iobase", get_ide_iobase(s)); + qdev_prop_set_uint32(d, "iobase2", get_ide_iobase(s) + 0x206); + qdev_prop_set_uint32(d, "irq", 14); + qdev_init_nofail(d); + s->ide.dev = isa; + trace_pc87312_info_ide(get_ide_iobase(s)); + } + + register_ioport_write(s->iobase, 2, 1, pc87312_ioport_write, s); + register_ioport_read(s->iobase, 2, 1, pc87312_ioport_read, s); + return 0; +} + +static const VMStateDescription vmstate_pc87312 = { + .name = "pc87312", + .version_id = 1, + .minimum_version_id = 1, + .post_load = pc87312_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(read_id_step, PC87312State), + VMSTATE_UINT8(selected_index, PC87312State), + VMSTATE_UINT8_ARRAY(regs, PC87312State, 3), + VMSTATE_END_OF_LIST() + } +}; + +static Property pc87312_properties[] = { + DEFINE_PROP_HEX32("iobase", PC87312State, iobase, 0x398), + DEFINE_PROP_UINT8("config", PC87312State, config, 1), + DEFINE_PROP_END_OF_LIST() +}; + +static void pc87312_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + + ic->init = pc87312_init; + dc->reset = pc87312_reset; + dc->vmsd = &vmstate_pc87312; + dc->props = pc87312_properties; +} + +static const TypeInfo pc87312_type_info = { + .name = TYPE_PC87312, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(PC87312State), + .class_init = pc87312_class_init, +}; + +static void pc87312_register_types(void) +{ + type_register_static(&pc87312_type_info); +} + +type_init(pc87312_register_types) diff --git a/hw/pc87312.h b/hw/pc87312.h new file mode 100644 index 0000000000..7ca7912ba7 --- /dev/null +++ b/hw/pc87312.h @@ -0,0 +1,66 @@ +/* + * QEMU National Semiconductor PC87312 (Super I/O) + * + * Copyright (c) 2010-2012 Herve Poussineau + * Copyright (c) 2011-2012 Andreas Färber + * + * 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. + */ +#ifndef QEMU_PC87312_H +#define QEMU_PC87312_H + +#include "isa.h" + + +#define TYPE_PC87312 "pc87312" +#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312) + +typedef struct PC87312State { + ISADevice dev; + + uint32_t iobase; + uint8_t config; /* initial configuration */ + + struct { + ISADevice *dev; + } parallel; + + struct { + ISADevice *dev; + } uart[2]; + + struct { + ISADevice *dev; + BlockDriverState *drive[2]; + uint32_t base; + } fdc; + + struct { + ISADevice *dev; + uint32_t base; + } ide; + + uint8_t read_id_step; + uint8_t selected_index; + + uint8_t regs[3]; +} PC87312State; + + +#endif diff --git a/trace-events b/trace-events index 6b12f83de0..b4ca0e9e52 100644 --- a/trace-events +++ b/trace-events @@ -694,6 +694,14 @@ mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x" mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64 "" mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)" +# hw/pc87312.c +pc87312_io_read(uint32_t addr, uint32_t val) "read addr=%x val=%x" +pc87312_io_write(uint32_t addr, uint32_t val) "write addr=%x val=%x" +pc87312_info_floppy(uint32_t base) "base 0x%x" +pc87312_info_ide(uint32_t base) "base 0x%x" +pc87312_info_parallel(uint32_t base, uint32_t irq) "base 0x%x, irq %u" +pc87312_info_serial(int n, uint32_t base, uint32_t irq) "id=%d, base 0x%x, irq %u" + # xen-all.c xen_ram_alloc(unsigned long ram_addr, unsigned long size) "requested: %#lx, size %#lx" xen_client_set_memory(uint64_t start_addr, unsigned long size, bool log_dirty) "%#"PRIx64" size %#lx, log_dirty %i" From 52a71bff6085398fbb8602718af228cd6339c02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 14 Apr 2012 22:48:36 +0200 Subject: [PATCH 0003/1634] prep: Use pc87312 device instead of collection of random ISA devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't however replace the built-in IDE controller, as the one in pc87312 is only single-channel and can use only IRQ 14. Therefore the pc87312's IDE function gets disabled via the config property. PReP emulation also gains a parallel port emulation this way. Signed-off-by: Hervé Poussineau [AF: Use TYPE_PC87312 constant, add to ppc64-softmmu and to MAINTAINERS] Signed-off-by: Andreas Färber --- MAINTAINERS | 1 + default-configs/ppc-softmmu.mak | 2 ++ default-configs/ppc64-softmmu.mak | 2 ++ hw/ppc_prep.c | 39 ++++++------------------------- 4 files changed, 12 insertions(+), 32 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 6d864c1ceb..950270f8a8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -373,6 +373,7 @@ L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc_prep.c F: hw/prep_pci.[hc] +F: hw/pc87312.[hc] SH4 Machines ------------ diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index d0fde7b93d..1f4a1cff61 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -8,6 +8,7 @@ CONFIG_M48T59=y CONFIG_VGA=y CONFIG_VGA_PCI=y CONFIG_SERIAL=y +CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCKBD=y CONFIG_FDC=y @@ -16,6 +17,7 @@ CONFIG_I82374=y CONFIG_OPENPIC=y CONFIG_PREP_PCI=y CONFIG_I82378=y +CONFIG_PC87312=y CONFIG_MACIO=y CONFIG_PCSPK=y CONFIG_CUDA=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index a1d2d4f136..5ff406caa5 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -8,6 +8,7 @@ CONFIG_M48T59=y CONFIG_VGA=y CONFIG_VGA_PCI=y CONFIG_SERIAL=y +CONFIG_PARALLEL=y CONFIG_I8254=y CONFIG_PCKBD=y CONFIG_FDC=y @@ -16,6 +17,7 @@ CONFIG_I82374=y CONFIG_OPENPIC=y CONFIG_PREP_PCI=y CONFIG_I82378=y +CONFIG_PC87312=y CONFIG_MACIO=y CONFIG_PCSPK=y CONFIG_CUDA=y diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index be2b26830d..59def908fd 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -36,6 +36,7 @@ #include "ide.h" #include "loader.h" #include "mc146818rtc.h" +#include "pc87312.h" #include "blockdev.h" #include "arch_init.h" #include "exec-memory.h" @@ -180,7 +181,6 @@ typedef struct sysctrl_t { M48t59State *nvram; uint8_t state; uint8_t syscontrol; - uint8_t fake_io[2]; int contiguous_map; int endian; } sysctrl_t; @@ -191,24 +191,6 @@ enum { static sysctrl_t *sysctrl; -static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) -{ - sysctrl_t *sysctrl = opaque; - - PPC_IO_DPRINTF("0x%08" PRIx32 " => 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, - val); - sysctrl->fake_io[addr - 0x0398] = val; -} - -static uint32_t PREP_io_read (void *opaque, uint32_t addr) -{ - sysctrl_t *sysctrl = opaque; - - PPC_IO_DPRINTF("0x%08" PRIx32 " <= 0x%02" PRIx32 "\n", addr - PPC_IO_BASE, - sysctrl->fake_io[addr - 0x0398]); - return sysctrl->fake_io[addr - 0x0398]; -} - static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) { sysctrl_t *sysctrl = opaque; @@ -475,10 +457,10 @@ static void ppc_prep_init (ram_addr_t ram_size, PCIBus *pci_bus; PCIDevice *pci; ISABus *isa_bus; + ISADevice *isa; qemu_irq *cpu_exit_irq; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DriveInfo *fd[MAX_FD]; sysctrl = g_malloc0(sizeof(sysctrl_t)); @@ -606,6 +588,11 @@ static void ppc_prep_init (ram_addr_t ram_size, sysbus_connect_irq(&pcihost->busdev, 3, qdev_get_gpio_in(&pci->qdev, 11)); isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&pci->qdev, "isa.0")); + /* Super I/O (parallel + serial ports) */ + isa = isa_create(isa_bus, TYPE_PC87312); + qdev_prop_set_uint8(&isa->qdev, "config", 13); /* fdc, ser0, ser1, par0 */ + qdev_init_nofail(&isa->qdev); + /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl, "ppc-io", 0x00800000); @@ -614,8 +601,6 @@ static void ppc_prep_init (ram_addr_t ram_size, /* init basic PC hardware */ pci_vga_init(pci_bus); - if (serial_hds[0]) - serial_isa_init(isa_bus, 0, serial_hds[0]); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; @@ -639,17 +624,7 @@ static void ppc_prep_init (ram_addr_t ram_size, } isa_create_simple(isa_bus, "i8042"); - // SB16_init(); - - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - } - fdctrl_init_isa(isa_bus, fd); - - /* Register fake IO ports for PREP */ sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET]; - register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); - register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl); /* System control ports */ register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl); register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl); From f28558d3d37ad3bc4e35e8ac93f7bf81a0d5622c Mon Sep 17 00:00:00 2001 From: Will Auld Date: Mon, 26 Nov 2012 21:32:18 -0800 Subject: [PATCH 0004/1634] target-i386: Enabling IA32_TSC_ADJUST for QEMU KVM guest VMs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPUID.7.0.EBX[1]=1 indicates IA32_TSC_ADJUST MSR 0x3b is supported Basic design is to emulate the MSR by allowing reads and writes to the hypervisor vcpu specific locations to store the value of the emulated MSRs. In this way the IA32_TSC_ADJUST value will be included in all reads to the TSC MSR whether through rdmsr or rdtsc. As this is a new MSR that the guest may access and modify its value needs to be migrated along with the other MRSs. The changes here are specifically for recognizing when IA32_TSC_ADJUST is enabled in CPUID and code added for migrating its value. Signed-off-by: Will Auld Reviewed-by: Andreas Färber Signed-off-by: Marcelo Tosatti --- target-i386/cpu.h | 2 ++ target-i386/kvm.c | 14 ++++++++++++++ target-i386/machine.c | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 386c4f6d98..477da33aa8 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -295,6 +295,7 @@ #define MSR_IA32_APICBASE_BSP (1<<8) #define MSR_IA32_APICBASE_ENABLE (1<<11) #define MSR_IA32_APICBASE_BASE (0xfffff<<12) +#define MSR_TSC_ADJUST 0x0000003b #define MSR_IA32_TSCDEADLINE 0x6e0 #define MSR_MTRRcap 0xfe @@ -774,6 +775,7 @@ typedef struct CPUX86State { uint64_t pv_eoi_en_msr; uint64_t tsc; + uint64_t tsc_adjust; uint64_t tsc_deadline; uint64_t mcg_status; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f669281e13..ae6ce1ff3c 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -62,6 +62,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { static bool has_msr_star; static bool has_msr_hsave_pa; +static bool has_msr_tsc_adjust; static bool has_msr_tsc_deadline; static bool has_msr_async_pf_en; static bool has_msr_pv_eoi_en; @@ -676,6 +677,10 @@ static int kvm_get_supported_msrs(KVMState *s) has_msr_hsave_pa = true; continue; } + if (kvm_msr_list->indices[i] == MSR_TSC_ADJUST) { + has_msr_tsc_adjust = true; + continue; + } if (kvm_msr_list->indices[i] == MSR_IA32_TSCDEADLINE) { has_msr_tsc_deadline = true; continue; @@ -1013,6 +1018,9 @@ static int kvm_put_msrs(CPUX86State *env, int level) if (has_msr_hsave_pa) { kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave); } + if (has_msr_tsc_adjust) { + kvm_msr_entry_set(&msrs[n++], MSR_TSC_ADJUST, env->tsc_adjust); + } if (has_msr_tsc_deadline) { kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSCDEADLINE, env->tsc_deadline); } @@ -1273,6 +1281,9 @@ static int kvm_get_msrs(CPUX86State *env) if (has_msr_hsave_pa) { msrs[n++].index = MSR_VM_HSAVE_PA; } + if (has_msr_tsc_adjust) { + msrs[n++].index = MSR_TSC_ADJUST; + } if (has_msr_tsc_deadline) { msrs[n++].index = MSR_IA32_TSCDEADLINE; } @@ -1350,6 +1361,9 @@ static int kvm_get_msrs(CPUX86State *env) case MSR_IA32_TSC: env->tsc = msrs[i].data; break; + case MSR_TSC_ADJUST: + env->tsc_adjust = msrs[i].data; + break; case MSR_IA32_TSCDEADLINE: env->tsc_deadline = msrs[i].data; break; diff --git a/target-i386/machine.c b/target-i386/machine.c index 477150887b..4229ddeac8 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -328,6 +328,24 @@ static const VMStateDescription vmstate_fpop_ip_dp = { } }; +static bool tsc_adjust_needed(void *opaque) +{ + CPUX86State *env = opaque; + + return env->tsc_adjust != 0; +} + +static const VMStateDescription vmstate_msr_tsc_adjust = { + .name = "cpu/msr_tsc_adjust", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(tsc_adjust, CPUX86State), + VMSTATE_END_OF_LIST() + } +}; + static bool tscdeadline_needed(void *opaque) { CPUX86State *env = opaque; @@ -477,6 +495,9 @@ static const VMStateDescription vmstate_cpu = { } , { .vmsd = &vmstate_fpop_ip_dp, .needed = fpop_ip_dp_needed, + }, { + .vmsd = &vmstate_msr_tsc_adjust, + .needed = tsc_adjust_needed, }, { .vmsd = &vmstate_msr_tscdeadline, .needed = tscdeadline_needed, From 5f5e335088925cedc5b912fd8bb4e1e933094d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 15 Oct 2012 17:52:00 +0200 Subject: [PATCH 0005/1634] target-alpha: Let cpu_alpha_init() return AlphaCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace cpu_init() macro with inline function for backwards compatibility. Signed-off-by: Andreas Färber Acked-by: Richard Henderson --- target-alpha/cpu.h | 13 +++++++++++-- target-alpha/translate.c | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 9939d61ca8..32e3777cdc 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -290,7 +290,6 @@ struct CPUAlphaState { int implver; }; -#define cpu_init cpu_alpha_init #define cpu_exec cpu_alpha_exec #define cpu_gen_code cpu_alpha_gen_code #define cpu_signal_handler cpu_alpha_signal_handler @@ -427,7 +426,17 @@ enum { IR_ZERO = 31, }; -CPUAlphaState * cpu_alpha_init (const char *cpu_model); +AlphaCPU *cpu_alpha_init(const char *cpu_model); + +static inline CPUAlphaState *cpu_init(const char *cpu_model) +{ + AlphaCPU *cpu = cpu_alpha_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + int cpu_alpha_exec(CPUAlphaState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 71fe1a1ab0..6f41ef7bfe 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -3517,7 +3517,7 @@ static const struct cpu_def_t cpu_defs[] = { | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), } }; -CPUAlphaState * cpu_alpha_init (const char *cpu_model) +AlphaCPU *cpu_alpha_init(const char *cpu_model) { AlphaCPU *cpu; CPUAlphaState *env; @@ -3546,7 +3546,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) env->cpu_model_str = cpu_model; qemu_init_vcpu(env); - return env; + return cpu; } void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, int pc_pos) From ad6011775a324d7c3e2a8bd824e03c5e576dda48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 16 Oct 2012 02:45:53 +0200 Subject: [PATCH 0006/1634] alpha: Pass AlphaCPU array to Typhoon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also store it in TyphoonCchip. Signed-off-by: Andreas Färber Acked-by: Richard Henderson --- hw/alpha_dp264.c | 18 +++++++++--------- hw/alpha_sys.h | 2 +- hw/alpha_typhoon.c | 29 ++++++++++++++++------------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 76d8ae8a84..af24d1eaf4 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -50,7 +50,7 @@ static void clipper_init(QEMUMachineInitArgs *args) const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; - CPUAlphaState *cpus[4]; + AlphaCPU *cpus[4]; PCIBus *pci_bus; ISABus *isa_bus; qemu_irq rtc_irq; @@ -62,12 +62,12 @@ static void clipper_init(QEMUMachineInitArgs *args) /* Create up to 4 cpus. */ memset(cpus, 0, sizeof(cpus)); for (i = 0; i < smp_cpus; ++i) { - cpus[i] = cpu_init(cpu_model ? cpu_model : "ev67"); + cpus[i] = cpu_alpha_init(cpu_model ? cpu_model : "ev67"); } - cpus[0]->trap_arg0 = ram_size; - cpus[0]->trap_arg1 = 0; - cpus[0]->trap_arg2 = smp_cpus; + cpus[0]->env.trap_arg0 = ram_size; + cpus[0]->env.trap_arg1 = 0; + cpus[0]->env.trap_arg2 = smp_cpus; /* Init the chipset. */ pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, @@ -119,9 +119,9 @@ static void clipper_init(QEMUMachineInitArgs *args) /* Start all cpus at the PALcode RESET entry point. */ for (i = 0; i < smp_cpus; ++i) { - cpus[i]->pal_mode = 1; - cpus[i]->pc = palcode_entry; - cpus[i]->palbr = palcode_entry; + cpus[i]->env.pal_mode = 1; + cpus[i]->env.pc = palcode_entry; + cpus[i]->env.palbr = palcode_entry; } /* Load a kernel. */ @@ -136,7 +136,7 @@ static void clipper_init(QEMUMachineInitArgs *args) exit(1); } - cpus[0]->trap_arg1 = kernel_entry; + cpus[0]->env.trap_arg1 = kernel_entry; param_offset = kernel_low - 0x6000; diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index 7604d09c80..69929ea815 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -11,7 +11,7 @@ #include "irq.h" -PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, CPUAlphaState *[4], +PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4], pci_map_irq_fn); /* alpha_pci.c. */ diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 9b16d96612..4cc810fb21 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -23,7 +23,7 @@ typedef struct TyphoonCchip { uint64_t drir; uint64_t dim[4]; uint32_t iic[4]; - CPUAlphaState *cpu[4]; + AlphaCPU *cpu[4]; } TyphoonCchip; typedef struct TyphoonWindow { @@ -58,10 +58,11 @@ typedef struct TyphoonState { } TyphoonState; /* Called when one of DRIR or DIM changes. */ -static void cpu_irq_change(CPUAlphaState *env, uint64_t req) +static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) { /* If there are any non-masked interrupts, tell the cpu. */ - if (env) { + if (cpu != NULL) { + CPUAlphaState *env = &cpu->env; if (req) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { @@ -353,8 +354,9 @@ static void cchip_write(void *opaque, hwaddr addr, if ((newval ^ oldval) & 0xff0) { int i; for (i = 0; i < 4; ++i) { - CPUAlphaState *env = s->cchip.cpu[i]; - if (env) { + AlphaCPU *cpu = s->cchip.cpu[i]; + if (cpu != NULL) { + CPUAlphaState *env = &cpu->env; /* IPI can be either cleared or set by the write. */ if (newval & (1 << (i + 8))) { cpu_interrupt(env, CPU_INTERRUPT_SMP); @@ -661,8 +663,8 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) /* Deliver the interrupt to each CPU, considering each CPU's IIC. */ for (i = 0; i < 4; ++i) { - CPUAlphaState *env = s->cchip.cpu[i]; - if (env) { + AlphaCPU *cpu = s->cchip.cpu[i]; + if (cpu != NULL) { uint32_t iic = s->cchip.iic[i]; /* ??? The verbage in Section 10.2.2.10 isn't 100% clear. @@ -681,7 +683,7 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (i + 4); /* And signal the interrupt. */ - cpu_interrupt(env, CPU_INTERRUPT_TIMER); + cpu_interrupt(&cpu->env, CPU_INTERRUPT_TIMER); } } } @@ -694,12 +696,12 @@ static void typhoon_alarm_timer(void *opaque) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (cpu + 4); - cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER); + cpu_interrupt(&s->cchip.cpu[cpu]->env, CPU_INTERRUPT_TIMER); } PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, qemu_irq *p_rtc_irq, - CPUAlphaState *cpus[4], pci_map_irq_fn sys_map_irq) + AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq) { const uint64_t MB = 1024 * 1024; const uint64_t GB = 1024 * MB; @@ -719,9 +721,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, /* Remember the CPUs so that we can deliver interrupts to them. */ for (i = 0; i < 4; i++) { - CPUAlphaState *env = cpus[i]; - s->cchip.cpu[i] = env; - if (env) { + AlphaCPU *cpu = cpus[i]; + s->cchip.cpu[i] = cpu; + if (cpu != NULL) { + CPUAlphaState *env = &cpu->env; env->alarm_timer = qemu_new_timer_ns(rtc_clock, typhoon_alarm_timer, (void *)((uintptr_t)s + i)); From c92458538f501eda585b4b774c50644aed391a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 31 Oct 2012 02:41:11 +0100 Subject: [PATCH 0007/1634] target-alpha: Avoid leaking the alarm timer over reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the timer from CPUAlphaState to AlphaCPU to avoid the pointer being zero'ed once we implement reset. Would cause a segfault in sys_helper.c:helper_set_alarm(). This also simplifies timer initialization in Typhoon. Signed-off-by: Andreas Färber Acked-by: Richard Henderson --- hw/alpha_typhoon.c | 3 +-- target-alpha/cpu-qom.h | 3 +++ target-alpha/cpu.h | 1 - target-alpha/sys_helper.c | 6 ++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 4cc810fb21..40b3a47c7e 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -724,8 +724,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, AlphaCPU *cpu = cpus[i]; s->cchip.cpu[i] = cpu; if (cpu != NULL) { - CPUAlphaState *env = &cpu->env; - env->alarm_timer = qemu_new_timer_ns(rtc_clock, + cpu->alarm_timer = qemu_new_timer_ns(rtc_clock, typhoon_alarm_timer, (void *)((uintptr_t)s + i)); } diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h index 6b4ca6d1d1..98585d5023 100644 --- a/target-alpha/cpu-qom.h +++ b/target-alpha/cpu-qom.h @@ -58,6 +58,9 @@ typedef struct AlphaCPU { /*< public >*/ CPUAlphaState env; + + /* This alarm doesn't exist in real hardware; we wish it did. */ + struct QEMUTimer *alarm_timer; } AlphaCPU; static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 32e3777cdc..e1d771562a 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -277,7 +277,6 @@ struct CPUAlphaState { #endif /* This alarm doesn't exist in real hardware; we wish it did. */ - struct QEMUTimer *alarm_timer; uint64_t alarm_expire; /* Those resources are used only in QEMU core */ diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c index 40ca49c883..d4f14efd86 100644 --- a/target-alpha/sys_helper.c +++ b/target-alpha/sys_helper.c @@ -77,11 +77,13 @@ uint64_t helper_get_time(void) void helper_set_alarm(CPUAlphaState *env, uint64_t expire) { + AlphaCPU *cpu = alpha_env_get_cpu(env); + if (expire) { env->alarm_expire = expire; - qemu_mod_timer(env->alarm_timer, expire); + qemu_mod_timer(cpu->alarm_timer, expire); } else { - qemu_del_timer(env->alarm_timer); + qemu_del_timer(cpu->alarm_timer); } } #endif /* CONFIG_USER_ONLY */ From 0c28246fcd5ea9ccb22aa93ef2e0af14463fec58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 15 Oct 2012 17:33:32 +0200 Subject: [PATCH 0008/1634] target-alpha: Turn CPU definitions into subclasses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make TYPE_ALPHA_CPU abstract and add types -alpha-cpu. Use type inheritence, and turn "2*" models into aliases. Move cpu_alpha_init() to cpu.c and split out CPU realization. Default to creating type "ev67-alpha-cpu" as before. Signed-off-by: Andreas Färber Acked-by: Richard Henderson --- target-alpha/cpu.c | 178 ++++++++++++++++++++++++++++++++++++++- target-alpha/cpu.h | 2 + target-alpha/translate.c | 58 +------------ 3 files changed, 180 insertions(+), 58 deletions(-) diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 11a19ebc87..a5a98d0fd5 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -21,8 +21,175 @@ #include "cpu.h" #include "qemu-common.h" +#include "error.h" +static void alpha_cpu_realize(Object *obj, Error **errp) +{ +#ifndef CONFIG_USER_ONLY + AlphaCPU *cpu = ALPHA_CPU(obj); + + qemu_init_vcpu(&cpu->env); +#endif +} + +/* Models */ + +#define TYPE(model) model "-" TYPE_ALPHA_CPU + +typedef struct AlphaCPUAlias { + const char *alias; + const char *typename; +} AlphaCPUAlias; + +static const AlphaCPUAlias alpha_cpu_aliases[] = { + { "21064", TYPE("ev4") }, + { "21164", TYPE("ev5") }, + { "21164a", TYPE("ev56") }, + { "21164pc", TYPE("pca56") }, + { "21264", TYPE("ev6") }, + { "21264a", TYPE("ev67") }, +}; + +static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc = NULL; + char *typename; + int i; + + if (cpu_model == NULL) { + return NULL; + } + + oc = object_class_by_name(cpu_model); + if (oc != NULL) { + return oc; + } + + for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) { + if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) { + oc = object_class_by_name(alpha_cpu_aliases[i].typename); + assert(oc != NULL); + return oc; + } + } + + typename = g_strdup_printf("%s-" TYPE_ALPHA_CPU, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + return oc; +} + +AlphaCPU *cpu_alpha_init(const char *cpu_model) +{ + AlphaCPU *cpu; + CPUAlphaState *env; + ObjectClass *cpu_class; + + cpu_class = alpha_cpu_class_by_name(cpu_model); + if (cpu_class == NULL) { + /* Default to ev67; no reason not to emulate insns by default. */ + cpu_class = object_class_by_name(TYPE("ev67")); + } + cpu = ALPHA_CPU(object_new(object_class_get_name(cpu_class))); + env = &cpu->env; + + env->cpu_model_str = cpu_model; + + alpha_cpu_realize(OBJECT(cpu), NULL); + return cpu; +} + +static void ev4_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->implver = IMPLVER_2106x; +} + +static const TypeInfo ev4_cpu_type_info = { + .name = TYPE("ev4"), + .parent = TYPE_ALPHA_CPU, + .instance_init = ev4_cpu_initfn, +}; + +static void ev5_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->implver = IMPLVER_21164; +} + +static const TypeInfo ev5_cpu_type_info = { + .name = TYPE("ev5"), + .parent = TYPE_ALPHA_CPU, + .instance_init = ev5_cpu_initfn, +}; + +static void ev56_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->amask |= AMASK_BWX; +} + +static const TypeInfo ev56_cpu_type_info = { + .name = TYPE("ev56"), + .parent = TYPE("ev5"), + .instance_init = ev56_cpu_initfn, +}; + +static void pca56_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->amask |= AMASK_MVI; +} + +static const TypeInfo pca56_cpu_type_info = { + .name = TYPE("pca56"), + .parent = TYPE("ev56"), + .instance_init = pca56_cpu_initfn, +}; + +static void ev6_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->implver = IMPLVER_21264; + env->amask = AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP; +} + +static const TypeInfo ev6_cpu_type_info = { + .name = TYPE("ev6"), + .parent = TYPE_ALPHA_CPU, + .instance_init = ev6_cpu_initfn, +}; + +static void ev67_cpu_initfn(Object *obj) +{ + AlphaCPU *cpu = ALPHA_CPU(obj); + CPUAlphaState *env = &cpu->env; + + env->amask |= AMASK_CIX | AMASK_PREFETCH; +} + +static const TypeInfo ev67_cpu_type_info = { + .name = TYPE("ev67"), + .parent = TYPE("ev6"), + .instance_init = ev67_cpu_initfn, +}; + +static const TypeInfo ev68_cpu_type_info = { + .name = TYPE("ev68"), + .parent = TYPE("ev67"), +}; + static void alpha_cpu_initfn(Object *obj) { AlphaCPU *cpu = ALPHA_CPU(obj); @@ -31,6 +198,8 @@ static void alpha_cpu_initfn(Object *obj) cpu_exec_init(env); tlb_flush(env, 1); + alpha_translate_init(); + #if defined(CONFIG_USER_ONLY) env->ps = PS_USER_MODE; cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD @@ -46,13 +215,20 @@ static const TypeInfo alpha_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(AlphaCPU), .instance_init = alpha_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(AlphaCPUClass), }; static void alpha_cpu_register_types(void) { type_register_static(&alpha_cpu_type_info); + type_register_static(&ev4_cpu_type_info); + type_register_static(&ev5_cpu_type_info); + type_register_static(&ev56_cpu_type_info); + type_register_static(&pca56_cpu_type_info); + type_register_static(&ev6_cpu_type_info); + type_register_static(&ev67_cpu_type_info); + type_register_static(&ev68_cpu_type_info); } type_init(alpha_cpu_register_types) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index e1d771562a..0d084586e1 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -425,6 +425,8 @@ enum { IR_ZERO = 31, }; +void alpha_translate_init(void); + AlphaCPU *cpu_alpha_init(const char *cpu_model); static inline CPUAlphaState *cpu_init(const char *cpu_model) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 6f41ef7bfe..dc0c97c571 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -90,7 +90,7 @@ static char cpu_reg_names[10*4+21*5 + 10*5+21*6]; #include "gen-icount.h" -static void alpha_translate_init(void) +void alpha_translate_init(void) { int i; char *p; @@ -3493,62 +3493,6 @@ void gen_intermediate_code_pc (CPUAlphaState *env, struct TranslationBlock *tb) gen_intermediate_code_internal(env, tb, 1); } -struct cpu_def_t { - const char *name; - int implver, amask; -}; - -static const struct cpu_def_t cpu_defs[] = { - { "ev4", IMPLVER_2106x, 0 }, - { "ev5", IMPLVER_21164, 0 }, - { "ev56", IMPLVER_21164, AMASK_BWX }, - { "pca56", IMPLVER_21164, AMASK_BWX | AMASK_MVI }, - { "ev6", IMPLVER_21264, AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP }, - { "ev67", IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX - | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), }, - { "ev68", IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX - | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), }, - { "21064", IMPLVER_2106x, 0 }, - { "21164", IMPLVER_21164, 0 }, - { "21164a", IMPLVER_21164, AMASK_BWX }, - { "21164pc", IMPLVER_21164, AMASK_BWX | AMASK_MVI }, - { "21264", IMPLVER_21264, AMASK_BWX | AMASK_FIX | AMASK_MVI | AMASK_TRAP }, - { "21264a", IMPLVER_21264, (AMASK_BWX | AMASK_FIX | AMASK_CIX - | AMASK_MVI | AMASK_TRAP | AMASK_PREFETCH), } -}; - -AlphaCPU *cpu_alpha_init(const char *cpu_model) -{ - AlphaCPU *cpu; - CPUAlphaState *env; - int implver, amask, i, max; - - cpu = ALPHA_CPU(object_new(TYPE_ALPHA_CPU)); - env = &cpu->env; - - alpha_translate_init(); - - /* Default to ev67; no reason not to emulate insns by default. */ - implver = IMPLVER_21264; - amask = (AMASK_BWX | AMASK_FIX | AMASK_CIX | AMASK_MVI - | AMASK_TRAP | AMASK_PREFETCH); - - max = ARRAY_SIZE(cpu_defs); - for (i = 0; i < max; i++) { - if (strcmp (cpu_model, cpu_defs[i].name) == 0) { - implver = cpu_defs[i].implver; - amask = cpu_defs[i].amask; - break; - } - } - env->implver = implver; - env->amask = amask; - env->cpu_model_str = cpu_model; - - qemu_init_vcpu(env); - return cpu; -} - void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, int pc_pos) { env->pc = tcg_ctx.gen_opc_pc[pc_pos]; From 494342b35b55b3b126821141e15c8a49df122ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 15 Oct 2012 17:44:21 +0200 Subject: [PATCH 0009/1634] target-alpha: Add support for -cpu ? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement alphabetical listing of CPU subclasses. Signed-off-by: Andreas Färber Acked-by: Richard Henderson --- target-alpha/cpu.c | 41 +++++++++++++++++++++++++++++++++++++++++ target-alpha/cpu.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index a5a98d0fd5..2deb3c1d7d 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -33,6 +33,47 @@ static void alpha_cpu_realize(Object *obj, Error **errp) #endif } +typedef struct AlphaCPUListState { + fprintf_function cpu_fprintf; + FILE *file; +} AlphaCPUListState; + +/* Sort alphabetically by type name. */ +static gint alpha_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *class_a = (ObjectClass *)a; + ObjectClass *class_b = (ObjectClass *)b; + const char *name_a, *name_b; + + name_a = object_class_get_name(class_a); + name_b = object_class_get_name(class_b); + return strcmp(name_a, name_b); +} + +static void alpha_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + AlphaCPUListState *s = user_data; + + (*s->cpu_fprintf)(s->file, " %s\n", + object_class_get_name(oc)); +} + +void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + AlphaCPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_ALPHA_CPU, false); + list = g_slist_sort(list, alpha_cpu_list_compare); + (*cpu_fprintf)(f, "Available CPUs:\n"); + g_slist_foreach(list, alpha_cpu_list_entry, &s); + g_slist_free(list); +} + /* Models */ #define TYPE(model) model "-" TYPE_ALPHA_CPU diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 0d084586e1..23f06c5a02 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -289,6 +289,7 @@ struct CPUAlphaState { int implver; }; +#define cpu_list alpha_cpu_list #define cpu_exec cpu_alpha_exec #define cpu_gen_code cpu_alpha_gen_code #define cpu_signal_handler cpu_alpha_signal_handler @@ -438,6 +439,7 @@ static inline CPUAlphaState *cpu_init(const char *cpu_model) return &cpu->env; } +void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf); int cpu_alpha_exec(CPUAlphaState *s); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero From 92a3136174f60ee45b113296cb2c2a5225b00369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 16 Dec 2012 02:17:02 +0100 Subject: [PATCH 0010/1634] cpu: Introduce CPUListState struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This generalizes {ARM,M68k,Alpha}CPUListState to avoid declaring it for each target. Place it in cpu-common.h to avoid circular dependencies. Signed-off-by: Andreas Färber Reviewed-by: Igor Mammedov Reviewed-by: Eduardo Habkost --- cpu-common.h | 12 ++++++++++++ target-alpha/cpu.c | 9 ++------- target-arm/helper.c | 9 ++------- target-m68k/helper.c | 9 ++------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/cpu-common.h b/cpu-common.h index d2fbafac9c..a62b6ea3f9 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -12,6 +12,18 @@ #include "bswap.h" #include "qemu-queue.h" +/** + * CPUListState: + * @cpu_fprintf: Print function. + * @file: File to print to using @cpu_fprint. + * + * State commonly used for iterating over CPU models. + */ +typedef struct CPUListState { + fprintf_function cpu_fprintf; + FILE *file; +} CPUListState; + #if !defined(CONFIG_USER_ONLY) enum device_endian { diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 2deb3c1d7d..59d8669ab0 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -33,11 +33,6 @@ static void alpha_cpu_realize(Object *obj, Error **errp) #endif } -typedef struct AlphaCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} AlphaCPUListState; - /* Sort alphabetically by type name. */ static gint alpha_cpu_list_compare(gconstpointer a, gconstpointer b) { @@ -53,7 +48,7 @@ static gint alpha_cpu_list_compare(gconstpointer a, gconstpointer b) static void alpha_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - AlphaCPUListState *s = user_data; + CPUListState *s = user_data; (*s->cpu_fprintf)(s->file, " %s\n", object_class_get_name(oc)); @@ -61,7 +56,7 @@ static void alpha_cpu_list_entry(gpointer data, gpointer user_data) void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf) { - AlphaCPUListState s = { + CPUListState s = { .file = f, .cpu_fprintf = cpu_fprintf, }; diff --git a/target-arm/helper.c b/target-arm/helper.c index ab8b734933..d2f2fb4820 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1291,11 +1291,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model) return cpu; } -typedef struct ARMCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} ARMCPUListState; - /* Sort alphabetically by type name, except for "any". */ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) { @@ -1317,7 +1312,7 @@ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) static void arm_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - ARMCPUListState *s = user_data; + CPUListState *s = user_data; (*s->cpu_fprintf)(s->file, " %s\n", object_class_get_name(oc)); @@ -1325,7 +1320,7 @@ static void arm_cpu_list_entry(gpointer data, gpointer user_data) void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf) { - ARMCPUListState s = { + CPUListState s = { .file = f, .cpu_fprintf = cpu_fprintf, }; diff --git a/target-m68k/helper.c b/target-m68k/helper.c index a5d0100473..875a71af21 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -25,11 +25,6 @@ #define SIGNBIT (1u << 31) -typedef struct M68kCPUListState { - fprintf_function cpu_fprintf; - FILE *file; -} M68kCPUListState; - /* Sort alphabetically, except for "any". */ static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) { @@ -51,7 +46,7 @@ static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) static void m68k_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *c = data; - M68kCPUListState *s = user_data; + CPUListState *s = user_data; (*s->cpu_fprintf)(s->file, "%s\n", object_class_get_name(c)); @@ -59,7 +54,7 @@ static void m68k_cpu_list_entry(gpointer data, gpointer user_data) void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) { - M68kCPUListState s = { + CPUListState s = { .file = f, .cpu_fprintf = cpu_fprintf, }; From 04a2d61e494532260214736ebb0f975822771643 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Dec 2012 14:49:10 -0200 Subject: [PATCH 0011/1634] qdev: Coding style fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing braces and break lines larger than 80 chars. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/qdev-properties.c | 53 +++++++++++++++++++++++++++++--------------- hw/qdev.c | 3 ++- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 81d901c6c4..67543fd76f 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -95,10 +95,11 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) { uint32_t *p = qdev_get_prop_ptr(dev, props); uint32_t mask = qdev_get_prop_mask(props); - if (val) + if (val) { *p |= mask; - else + } else { *p &= ~mask; + } } static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -420,11 +421,13 @@ static void release_string(Object *obj, const char *name, void *opaque) g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); } -static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) +static int print_string(DeviceState *dev, Property *prop, char *dest, + size_t len) { char **ptr = qdev_get_prop_ptr(dev, prop); - if (!*ptr) + if (!*ptr) { return snprintf(dest, len, ""); + } return snprintf(dest, len, "\"%s\"", *ptr); } @@ -483,10 +486,12 @@ static int parse_drive(DeviceState *dev, const char *str, void **ptr) BlockDriverState *bs; bs = bdrv_find(str); - if (bs == NULL) + if (bs == NULL) { return -ENOENT; - if (bdrv_attach_dev(bs, dev) < 0) + } + if (bdrv_attach_dev(bs, dev) < 0) { return -EEXIST; + } *ptr = bs; return 0; } @@ -749,16 +754,20 @@ static void set_mac(Object *obj, Visitor *v, void *opaque, } for (i = 0, pos = 0; i < 6; i++, pos += 3) { - if (!qemu_isxdigit(str[pos])) + if (!qemu_isxdigit(str[pos])) { goto inval; - if (!qemu_isxdigit(str[pos+1])) + } + if (!qemu_isxdigit(str[pos+1])) { goto inval; + } if (i == 5) { - if (str[pos+2] != '\0') + if (str[pos+2] != '\0') { goto inval; + } } else { - if (str[pos+2] != ':' && str[pos+2] != '-') + if (str[pos+2] != ':' && str[pos+2] != '-') { goto inval; + } } mac->a[i] = strtol(str+pos, &p, 16); } @@ -864,7 +873,8 @@ invalid: g_free(str); } -static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) +static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, + size_t len) { int32_t *ptr = qdev_get_prop_ptr(dev, prop); @@ -1038,11 +1048,13 @@ PropertyInfo qdev_prop_pci_host_devaddr = { static Property *qdev_prop_walk(Property *props, const char *name) { - if (!props) + if (!props) { return NULL; + } while (props->name) { - if (strcmp(props->name, name) == 0) + if (strcmp(props->name, name) == 0) { return props; + } props++; } return NULL; @@ -1158,7 +1170,8 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) assert_no_error(errp); } -int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) +int qdev_prop_set_drive(DeviceState *dev, const char *name, + BlockDriverState *value) { Error *errp = NULL; const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; @@ -1172,13 +1185,15 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va return 0; } -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value) +void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, + BlockDriverState *value) { if (qdev_prop_set_drive(dev, name, value) < 0) { exit(1); } } -void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) +void qdev_prop_set_chr(DeviceState *dev, const char *name, + CharDriverState *value) { Error *errp = NULL; assert(!value || value->label); @@ -1187,7 +1202,8 @@ void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *valu assert_no_error(errp); } -void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value) +void qdev_prop_set_netdev(DeviceState *dev, const char *name, + NetClientState *value) { Error *errp = NULL; assert(!value || value->name); @@ -1229,7 +1245,8 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) *ptr = value; } -static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); +static QTAILQ_HEAD(, GlobalProperty) global_props = + QTAILQ_HEAD_INITIALIZER(global_props); static void qdev_prop_register_global(GlobalProperty *prop) { diff --git a/hw/qdev.c b/hw/qdev.c index 599382cab2..0f8b87843a 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -315,8 +315,9 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) { qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); - if (nd->netdev) + if (nd->netdev) { qdev_prop_set_netdev(dev, "netdev", nd->netdev); + } if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && object_property_find(OBJECT(dev), "vectors", NULL)) { qdev_prop_set_uint32(dev, "vectors", nd->nvectors); From a404b61244ff555ace0a1360fc22275fbeda503e Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Dec 2012 14:49:11 -0200 Subject: [PATCH 0012/1634] qdev-properties.c: Separate core from the code used only by qemu-system-* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This separates the qdev properties code in two parts: - qdev-properties.c, that contains most of the qdev properties code; - qdev-properties-system.c for code specific for qemu-system-*, containing: - Property types: drive, chr, netdev, vlan, that depend on code that won't be included on *-user - qemu_add_globals(), that depends on qemu-config.o. This change should help on two things: - Allowing DeviceState to be used by *-user without pulling dependencies that are specific for qemu-system-*; - Writing qdev unit tests without pulling too many dependencies. The copyright/license of qdev-properties.c isn't explicitly stated at the file, so add a simple copyright/license header pointing to the commit ID of the original file. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/Makefile.objs | 1 + hw/qdev-properties-system.c | 357 ++++++++++++++++++++++++++++++++++++ hw/qdev-properties.c | 327 +-------------------------------- hw/qdev-properties.h | 1 + hw/qdev.c | 14 -- 5 files changed, 360 insertions(+), 340 deletions(-) create mode 100644 hw/qdev-properties-system.c diff --git a/hw/Makefile.objs b/hw/Makefile.objs index d581d8d6d6..96a8365349 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -185,6 +185,7 @@ common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += msmouse.o ps2.o common-obj-y += qdev.o qdev-properties.o qdev-monitor.o +common-obj-y += qdev-properties-system.o common-obj-$(CONFIG_BRLAPI) += baum.o # xen backend driver support diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c new file mode 100644 index 0000000000..86b4cf6e99 --- /dev/null +++ b/hw/qdev-properties-system.c @@ -0,0 +1,357 @@ +/* + * qdev property parsing and global properties + * (parts specific for qemu-system-*) + * + * This file is based on code from hw/qdev-properties.c from + * commit 074a86fccd185616469dfcdc0e157f438aebba18, + * Copyright (c) Gerd Hoffmann and other contributors. + * + * 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 "net.h" +#include "qdev.h" +#include "qerror.h" +#include "blockdev.h" +#include "hw/block-common.h" +#include "net/hub.h" +#include "qapi/qapi-visit-core.h" + +static void get_pointer(Object *obj, Visitor *v, Property *prop, + const char *(*print)(void *ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + void **ptr = qdev_get_prop_ptr(dev, prop); + char *p; + + p = (char *) (*ptr ? print(*ptr) : ""); + visit_type_str(v, &p, name, errp); +} + +static void set_pointer(Object *obj, Visitor *v, Property *prop, + int (*parse)(DeviceState *dev, const char *str, + void **ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Error *local_err = NULL; + void **ptr = qdev_get_prop_ptr(dev, prop); + char *str; + int ret; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (!*str) { + g_free(str); + *ptr = NULL; + return; + } + ret = parse(dev, str, ptr); + error_set_from_qdev_prop_error(errp, ret, dev, prop, str); + g_free(str); +} + +/* --- drive --- */ + +static int parse_drive(DeviceState *dev, const char *str, void **ptr) +{ + BlockDriverState *bs; + + bs = bdrv_find(str); + if (bs == NULL) { + return -ENOENT; + } + if (bdrv_attach_dev(bs, dev) < 0) { + return -EEXIST; + } + *ptr = bs; + return 0; +} + +static void release_drive(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + bdrv_detach_dev(*ptr, dev); + blockdev_auto_del(*ptr); + } +} + +static const char *print_drive(void *ptr) +{ + return bdrv_get_device_name(ptr); +} + +static void get_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_drive, name, errp); +} + +static void set_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_drive, name, errp); +} + +PropertyInfo qdev_prop_drive = { + .name = "drive", + .get = get_drive, + .set = set_drive, + .release = release_drive, +}; + +/* --- character device --- */ + +static int parse_chr(DeviceState *dev, const char *str, void **ptr) +{ + CharDriverState *chr = qemu_chr_find(str); + if (chr == NULL) { + return -ENOENT; + } + if (chr->avail_connections < 1) { + return -EEXIST; + } + *ptr = chr; + --chr->avail_connections; + return 0; +} + +static void release_chr(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); + } +} + + +static const char *print_chr(void *ptr) +{ + CharDriverState *chr = ptr; + + return chr->label ? chr->label : ""; +} + +static void get_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_chr, name, errp); +} + +static void set_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_chr, name, errp); +} + +PropertyInfo qdev_prop_chr = { + .name = "chr", + .get = get_chr, + .set = set_chr, + .release = release_chr, +}; + +/* --- netdev device --- */ + +static int parse_netdev(DeviceState *dev, const char *str, void **ptr) +{ + NetClientState *netdev = qemu_find_netdev(str); + + if (netdev == NULL) { + return -ENOENT; + } + if (netdev->peer) { + return -EEXIST; + } + *ptr = netdev; + return 0; +} + +static const char *print_netdev(void *ptr) +{ + NetClientState *netdev = ptr; + + return netdev->name ? netdev->name : ""; +} + +static void get_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_netdev, name, errp); +} + +static void set_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_netdev, name, errp); +} + +PropertyInfo qdev_prop_netdev = { + .name = "netdev", + .get = get_netdev, + .set = set_netdev, +}; + +/* --- vlan --- */ + +static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) +{ + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + int id; + if (!net_hub_id_for_client(*ptr, &id)) { + return snprintf(dest, len, "%d", id); + } + } + + return snprintf(dest, len, ""); +} + +static void get_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + int32_t id = -1; + + if (*ptr) { + int hub_id; + if (!net_hub_id_for_client(*ptr, &hub_id)) { + id = hub_id; + } + } + + visit_type_int32(v, &id, name, errp); +} + +static void set_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + int32_t id; + NetClientState *hubport; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_int32(v, &id, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (id == -1) { + *ptr = NULL; + return; + } + + hubport = net_hub_port_find(id); + if (!hubport) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + name, prop->info->name); + return; + } + *ptr = hubport; +} + +PropertyInfo qdev_prop_vlan = { + .name = "vlan", + .print = print_vlan, + .get = get_vlan, + .set = set_vlan, +}; + +int qdev_prop_set_drive(DeviceState *dev, const char *name, + BlockDriverState *value) +{ + Error *errp = NULL; + const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; + object_property_set_str(OBJECT(dev), bdrv_name, + name, &errp); + if (errp) { + qerror_report_err(errp); + error_free(errp); + return -1; + } + return 0; +} + +void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, + BlockDriverState *value) +{ + if (qdev_prop_set_drive(dev, name, value) < 0) { + exit(1); + } +} +void qdev_prop_set_chr(DeviceState *dev, const char *name, + CharDriverState *value) +{ + Error *errp = NULL; + assert(!value || value->label); + object_property_set_str(OBJECT(dev), + value ? value->label : "", name, &errp); + assert_no_error(errp); +} + +void qdev_prop_set_netdev(DeviceState *dev, const char *name, + NetClientState *value) +{ + Error *errp = NULL; + assert(!value || value->name); + object_property_set_str(OBJECT(dev), + value ? value->name : "", name, &errp); + assert_no_error(errp); +} + +void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) +{ + qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); + if (nd->netdev) { + qdev_prop_set_netdev(dev, "netdev", nd->netdev); + } + if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && + object_property_find(OBJECT(dev), "vectors", NULL)) { + qdev_prop_set_uint32(dev, "vectors", nd->nvectors); + } + nd->instantiated = 1; +} + +static int qdev_add_one_global(QemuOpts *opts, void *opaque) +{ + GlobalProperty *g; + + g = g_malloc0(sizeof(*g)); + g->driver = qemu_opt_get(opts, "driver"); + g->property = qemu_opt_get(opts, "property"); + g->value = qemu_opt_get(opts, "value"); + qdev_prop_register_global(g); + return 0; +} + +void qemu_add_globals(void) +{ + qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); +} diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 67543fd76f..bbab2a95af 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -13,49 +13,6 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) return ptr; } -static void get_pointer(Object *obj, Visitor *v, Property *prop, - const char *(*print)(void *ptr), - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - void **ptr = qdev_get_prop_ptr(dev, prop); - char *p; - - p = (char *) (*ptr ? print(*ptr) : ""); - visit_type_str(v, &p, name, errp); -} - -static void set_pointer(Object *obj, Visitor *v, Property *prop, - int (*parse)(DeviceState *dev, const char *str, - void **ptr), - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; - void **ptr = qdev_get_prop_ptr(dev, prop); - char *str; - int ret; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_str(v, &str, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (!*str) { - g_free(str); - *ptr = NULL; - return; - } - ret = parse(dev, str, ptr); - error_set_from_qdev_prop_error(errp, ret, dev, prop, str); - g_free(str); -} - static void get_enum(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { @@ -479,229 +436,6 @@ PropertyInfo qdev_prop_string = { .set = set_string, }; -/* --- drive --- */ - -static int parse_drive(DeviceState *dev, const char *str, void **ptr) -{ - BlockDriverState *bs; - - bs = bdrv_find(str); - if (bs == NULL) { - return -ENOENT; - } - if (bdrv_attach_dev(bs, dev) < 0) { - return -EEXIST; - } - *ptr = bs; - return 0; -} - -static void release_drive(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - bdrv_detach_dev(*ptr, dev); - blockdev_auto_del(*ptr); - } -} - -static const char *print_drive(void *ptr) -{ - return bdrv_get_device_name(ptr); -} - -static void get_drive(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_drive, name, errp); -} - -static void set_drive(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_drive, name, errp); -} - -PropertyInfo qdev_prop_drive = { - .name = "drive", - .get = get_drive, - .set = set_drive, - .release = release_drive, -}; - -/* --- character device --- */ - -static int parse_chr(DeviceState *dev, const char *str, void **ptr) -{ - CharDriverState *chr = qemu_chr_find(str); - if (chr == NULL) { - return -ENOENT; - } - if (chr->avail_connections < 1) { - return -EEXIST; - } - *ptr = chr; - --chr->avail_connections; - return 0; -} - -static void release_chr(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); - } -} - - -static const char *print_chr(void *ptr) -{ - CharDriverState *chr = ptr; - - return chr->label ? chr->label : ""; -} - -static void get_chr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_chr, name, errp); -} - -static void set_chr(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_chr, name, errp); -} - -PropertyInfo qdev_prop_chr = { - .name = "chr", - .get = get_chr, - .set = set_chr, - .release = release_chr, -}; - -/* --- netdev device --- */ - -static int parse_netdev(DeviceState *dev, const char *str, void **ptr) -{ - NetClientState *netdev = qemu_find_netdev(str); - - if (netdev == NULL) { - return -ENOENT; - } - if (netdev->peer) { - return -EEXIST; - } - *ptr = netdev; - return 0; -} - -static const char *print_netdev(void *ptr) -{ - NetClientState *netdev = ptr; - - return netdev->name ? netdev->name : ""; -} - -static void get_netdev(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - get_pointer(obj, v, opaque, print_netdev, name, errp); -} - -static void set_netdev(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - set_pointer(obj, v, opaque, parse_netdev, name, errp); -} - -PropertyInfo qdev_prop_netdev = { - .name = "netdev", - .get = get_netdev, - .set = set_netdev, -}; - -/* --- vlan --- */ - -static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { - int id; - if (!net_hub_id_for_client(*ptr, &id)) { - return snprintf(dest, len, "%d", id); - } - } - - return snprintf(dest, len, ""); -} - -static void get_vlan(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - int32_t id = -1; - - if (*ptr) { - int hub_id; - if (!net_hub_id_for_client(*ptr, &hub_id)) { - id = hub_id; - } - } - - visit_type_int32(v, &id, name, errp); -} - -static void set_vlan(Object *obj, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - int32_t id; - NetClientState *hubport; - - if (dev->state != DEV_STATE_CREATED) { - error_set(errp, QERR_PERMISSION_DENIED); - return; - } - - visit_type_int32(v, &id, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - if (id == -1) { - *ptr = NULL; - return; - } - - hubport = net_hub_port_find(id); - if (!hubport) { - error_set(errp, QERR_INVALID_PARAMETER_VALUE, - name, prop->info->name); - return; - } - *ptr = hubport; -} - -PropertyInfo qdev_prop_vlan = { - .name = "vlan", - .print = print_vlan, - .get = get_vlan, - .set = set_vlan, -}; - /* --- pointer --- */ /* Not a proper property, just for dirty hacks. TODO Remove it! */ @@ -1170,48 +904,6 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value) assert_no_error(errp); } -int qdev_prop_set_drive(DeviceState *dev, const char *name, - BlockDriverState *value) -{ - Error *errp = NULL; - const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; - object_property_set_str(OBJECT(dev), bdrv_name, - name, &errp); - if (errp) { - qerror_report_err(errp); - error_free(errp); - return -1; - } - return 0; -} - -void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, - BlockDriverState *value) -{ - if (qdev_prop_set_drive(dev, name, value) < 0) { - exit(1); - } -} -void qdev_prop_set_chr(DeviceState *dev, const char *name, - CharDriverState *value) -{ - Error *errp = NULL; - assert(!value || value->label); - object_property_set_str(OBJECT(dev), - value ? value->label : "", name, &errp); - assert_no_error(errp); -} - -void qdev_prop_set_netdev(DeviceState *dev, const char *name, - NetClientState *value) -{ - Error *errp = NULL; - assert(!value || value->name); - object_property_set_str(OBJECT(dev), - value ? value->name : "", name, &errp); - assert_no_error(errp); -} - void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) { Error *errp = NULL; @@ -1248,7 +940,7 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); -static void qdev_prop_register_global(GlobalProperty *prop) +void qdev_prop_register_global(GlobalProperty *prop) { QTAILQ_INSERT_TAIL(&global_props, prop, next); } @@ -1279,20 +971,3 @@ void qdev_prop_set_globals(DeviceState *dev) class = object_class_get_parent(class); } while (class); } - -static int qdev_add_one_global(QemuOpts *opts, void *opaque) -{ - GlobalProperty *g; - - g = g_malloc0(sizeof(*g)); - g->driver = qemu_opt_get(opts, "driver"); - g->property = qemu_opt_get(opts, "property"); - g->value = qemu_opt_get(opts, "value"); - qdev_prop_register_global(g); - return 0; -} - -void qemu_add_globals(void) -{ - qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0); -} diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h index 5b046abb28..ddcf774506 100644 --- a/hw/qdev-properties.h +++ b/hw/qdev-properties.h @@ -116,6 +116,7 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value); /* FIXME: Remove opaque pointer properties. */ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); +void qdev_prop_register_global(GlobalProperty *prop); void qdev_prop_register_global_list(GlobalProperty *props); void qdev_prop_set_globals(DeviceState *dev); void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, diff --git a/hw/qdev.c b/hw/qdev.c index 0f8b87843a..fa0af21b58 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -25,7 +25,6 @@ inherit from a particular bus (e.g. PCI or I2C) rather than this API directly. */ -#include "net.h" #include "qdev.h" #include "sysemu.h" #include "error.h" @@ -312,19 +311,6 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) dev->gpio_out[n] = pin; } -void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) -{ - qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); - if (nd->netdev) { - qdev_prop_set_netdev(dev, "netdev", nd->netdev); - } - if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && - object_property_find(OBJECT(dev), "vectors", NULL)) { - qdev_prop_set_uint32(dev, "vectors", nd->nvectors); - } - nd->instantiated = 1; -} - BusState *qdev_get_child_bus(DeviceState *dev, const char *name) { BusState *bus; From 8737c51c0444f832c4e97d7eb7540eae457e08e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 31 Oct 2012 05:29:00 +0100 Subject: [PATCH 0013/1634] cpu: Move kvm_fd into CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber --- cpu-defs.h | 1 - include/qemu/cpu.h | 5 +++++ kvm-all.c | 8 +++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 3669241faf..6373a808f9 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -207,7 +207,6 @@ typedef struct CPUWatchpoint { const char *cpu_model_str; \ struct KVMState *kvm_state; \ struct kvm_run *kvm_run; \ - int kvm_fd; \ int kvm_vcpu_dirty; #endif diff --git a/include/qemu/cpu.h b/include/qemu/cpu.h index 61b76982f1..6049a20a4d 100644 --- a/include/qemu/cpu.h +++ b/include/qemu/cpu.h @@ -57,6 +57,7 @@ typedef struct CPUClass { * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. + * @kvm_fd: vCPU file descriptor for KVM. * * State of one CPU core or thread. */ @@ -77,6 +78,10 @@ struct CPUState { bool stop; bool stopped; +#if !defined(CONFIG_USER_ONLY) + int kvm_fd; +#endif + /* TODO Move common fields from CPUArchState here. */ }; diff --git a/kvm-all.c b/kvm-all.c index 8e9a8d8fd2..8a00df72c3 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -216,6 +216,7 @@ static void kvm_reset_vcpu(void *opaque) int kvm_init_vcpu(CPUArchState *env) { + CPUState *cpu = ENV_GET_CPU(env); KVMState *s = kvm_state; long mmap_size; int ret; @@ -228,7 +229,7 @@ int kvm_init_vcpu(CPUArchState *env) goto err; } - env->kvm_fd = ret; + cpu->kvm_fd = ret; env->kvm_state = s; env->kvm_vcpu_dirty = 1; @@ -240,7 +241,7 @@ int kvm_init_vcpu(CPUArchState *env) } env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, - env->kvm_fd, 0); + cpu->kvm_fd, 0); if (env->kvm_run == MAP_FAILED) { ret = -errno; DPRINTF("mmap'ing vcpu state failed\n"); @@ -1652,6 +1653,7 @@ int kvm_vm_ioctl(KVMState *s, int type, ...) int kvm_vcpu_ioctl(CPUArchState *env, int type, ...) { + CPUState *cpu = ENV_GET_CPU(env); int ret; void *arg; va_list ap; @@ -1660,7 +1662,7 @@ int kvm_vcpu_ioctl(CPUArchState *env, int type, ...) arg = va_arg(ap, void *); va_end(ap); - ret = ioctl(env->kvm_fd, type, arg); + ret = ioctl(cpu->kvm_fd, type, arg); if (ret == -1) { ret = -errno; } From 20d695a9254c1b086a456d3b79a3c311236643ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 31 Oct 2012 06:57:49 +0100 Subject: [PATCH 0014/1634] kvm: Pass CPUState to kvm_arch_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move kvm_vcpu_dirty field into CPUState to simplify things and change its type to bool while at it. Signed-off-by: Andreas Färber --- cpu-defs.h | 3 +- include/qemu/cpu.h | 1 + kvm-all.c | 75 +++++++++++++++++++++++++++------------------- kvm.h | 26 ++++++++-------- target-i386/kvm.c | 59 +++++++++++++++++++++++------------- target-ppc/kvm.c | 36 ++++++++++++++-------- target-s390x/kvm.c | 38 +++++++++++++++-------- 7 files changed, 146 insertions(+), 92 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 6373a808f9..a382e35248 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -206,7 +206,6 @@ typedef struct CPUWatchpoint { \ const char *cpu_model_str; \ struct KVMState *kvm_state; \ - struct kvm_run *kvm_run; \ - int kvm_vcpu_dirty; + struct kvm_run *kvm_run; #endif diff --git a/include/qemu/cpu.h b/include/qemu/cpu.h index 6049a20a4d..b8f8dd1d13 100644 --- a/include/qemu/cpu.h +++ b/include/qemu/cpu.h @@ -80,6 +80,7 @@ struct CPUState { #if !defined(CONFIG_USER_ONLY) int kvm_fd; + bool kvm_vcpu_dirty; #endif /* TODO Move common fields from CPUArchState here. */ diff --git a/kvm-all.c b/kvm-all.c index 8a00df72c3..792cdf1d66 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -209,9 +209,9 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) static void kvm_reset_vcpu(void *opaque) { - CPUArchState *env = opaque; + CPUState *cpu = opaque; - kvm_arch_reset_vcpu(env); + kvm_arch_reset_vcpu(cpu); } int kvm_init_vcpu(CPUArchState *env) @@ -231,7 +231,7 @@ int kvm_init_vcpu(CPUArchState *env) cpu->kvm_fd = ret; env->kvm_state = s; - env->kvm_vcpu_dirty = 1; + cpu->kvm_vcpu_dirty = true; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { @@ -253,10 +253,10 @@ int kvm_init_vcpu(CPUArchState *env) (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE; } - ret = kvm_arch_init_vcpu(env); + ret = kvm_arch_init_vcpu(cpu); if (ret == 0) { - qemu_register_reset(kvm_reset_vcpu, env); - kvm_arch_reset_vcpu(env); + qemu_register_reset(kvm_reset_vcpu, cpu); + kvm_arch_reset_vcpu(cpu); } err: return ret; @@ -1438,6 +1438,8 @@ static void kvm_handle_io(uint16_t port, void *data, int direction, int size, static int kvm_handle_internal_error(CPUArchState *env, struct kvm_run *run) { + CPUState *cpu = ENV_GET_CPU(env); + fprintf(stderr, "KVM internal error."); if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) { int i; @@ -1452,7 +1454,7 @@ static int kvm_handle_internal_error(CPUArchState *env, struct kvm_run *run) } if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) { fprintf(stderr, "emulation failure\n"); - if (!kvm_arch_stop_on_emulation_error(env)) { + if (!kvm_arch_stop_on_emulation_error(cpu)) { cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); return EXCP_INTERRUPT; } @@ -1489,13 +1491,13 @@ void kvm_flush_coalesced_mmio_buffer(void) s->coalesced_flush_in_progress = false; } -static void do_kvm_cpu_synchronize_state(void *_env) +static void do_kvm_cpu_synchronize_state(void *arg) { - CPUArchState *env = _env; + CPUState *cpu = arg; - if (!env->kvm_vcpu_dirty) { - kvm_arch_get_registers(env); - env->kvm_vcpu_dirty = 1; + if (!cpu->kvm_vcpu_dirty) { + kvm_arch_get_registers(cpu); + cpu->kvm_vcpu_dirty = true; } } @@ -1503,42 +1505,47 @@ void kvm_cpu_synchronize_state(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); - if (!env->kvm_vcpu_dirty) { - run_on_cpu(cpu, do_kvm_cpu_synchronize_state, env); + if (!cpu->kvm_vcpu_dirty) { + run_on_cpu(cpu, do_kvm_cpu_synchronize_state, cpu); } } void kvm_cpu_synchronize_post_reset(CPUArchState *env) { - kvm_arch_put_registers(env, KVM_PUT_RESET_STATE); - env->kvm_vcpu_dirty = 0; + CPUState *cpu = ENV_GET_CPU(env); + + kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); + cpu->kvm_vcpu_dirty = false; } void kvm_cpu_synchronize_post_init(CPUArchState *env) { - kvm_arch_put_registers(env, KVM_PUT_FULL_STATE); - env->kvm_vcpu_dirty = 0; + CPUState *cpu = ENV_GET_CPU(env); + + kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); + cpu->kvm_vcpu_dirty = false; } int kvm_cpu_exec(CPUArchState *env) { + CPUState *cpu = ENV_GET_CPU(env); struct kvm_run *run = env->kvm_run; int ret, run_ret; DPRINTF("kvm_cpu_exec()\n"); - if (kvm_arch_process_async_events(env)) { + if (kvm_arch_process_async_events(cpu)) { env->exit_request = 0; return EXCP_HLT; } do { - if (env->kvm_vcpu_dirty) { - kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE); - env->kvm_vcpu_dirty = 0; + if (cpu->kvm_vcpu_dirty) { + kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE); + cpu->kvm_vcpu_dirty = false; } - kvm_arch_pre_run(env, run); + kvm_arch_pre_run(cpu, run); if (env->exit_request) { DPRINTF("interrupt exit requested\n"); /* @@ -1553,7 +1560,7 @@ int kvm_cpu_exec(CPUArchState *env) run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); qemu_mutex_lock_iothread(); - kvm_arch_post_run(env, run); + kvm_arch_post_run(cpu, run); if (run_ret < 0) { if (run_ret == -EINTR || run_ret == -EAGAIN) { @@ -1603,7 +1610,7 @@ int kvm_cpu_exec(CPUArchState *env) break; default: DPRINTF("kvm_arch_handle_exit\n"); - ret = kvm_arch_handle_exit(env, run); + ret = kvm_arch_handle_exit(cpu, run); break; } } while (ret == 0); @@ -1799,7 +1806,7 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) if (env->singlestep_enabled) { data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; } - kvm_arch_update_guest_debug(env, &data.dbg); + kvm_arch_update_guest_debug(cpu, &data.dbg); data.env = env; run_on_cpu(cpu, kvm_invoke_set_guest_debug, &data); @@ -1809,6 +1816,7 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, target_ulong len, int type) { + CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp; CPUArchState *env; int err; @@ -1827,7 +1835,7 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, bp->pc = addr; bp->use_count = 1; - err = kvm_arch_insert_sw_breakpoint(current_env, bp); + err = kvm_arch_insert_sw_breakpoint(current_cpu, bp); if (err) { g_free(bp); return err; @@ -1854,6 +1862,7 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, target_ulong len, int type) { + CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp; CPUArchState *env; int err; @@ -1869,7 +1878,7 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, return 0; } - err = kvm_arch_remove_sw_breakpoint(current_env, bp); + err = kvm_arch_remove_sw_breakpoint(current_cpu, bp); if (err) { return err; } @@ -1894,15 +1903,18 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, void kvm_remove_all_breakpoints(CPUArchState *current_env) { + CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp, *next; KVMState *s = current_env->kvm_state; CPUArchState *env; + CPUState *cpu; QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) { - if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) { + if (kvm_arch_remove_sw_breakpoint(current_cpu, bp) != 0) { /* Try harder to find a CPU that currently sees the breakpoint. */ for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) { + cpu = ENV_GET_CPU(env); + if (kvm_arch_remove_sw_breakpoint(cpu, bp) == 0) { break; } } @@ -2014,7 +2026,8 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr) { - return kvm_arch_on_sigbus_vcpu(env, code, addr); + CPUState *cpu = ENV_GET_CPU(env); + return kvm_arch_on_sigbus_vcpu(cpu, code, addr); } int kvm_on_sigbus(int code, void *addr) diff --git a/kvm.h b/kvm.h index 72d866a966..61f00b7456 100644 --- a/kvm.h +++ b/kvm.h @@ -158,14 +158,14 @@ int kvm_vcpu_ioctl(CPUArchState *env, int type, ...); extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; -void kvm_arch_pre_run(CPUArchState *env, struct kvm_run *run); -void kvm_arch_post_run(CPUArchState *env, struct kvm_run *run); +void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run); +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run); -int kvm_arch_handle_exit(CPUArchState *env, struct kvm_run *run); +int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run); -int kvm_arch_process_async_events(CPUArchState *env); +int kvm_arch_process_async_events(CPUState *cpu); -int kvm_arch_get_registers(CPUArchState *env); +int kvm_arch_get_registers(CPUState *cpu); /* state subset only touched by the VCPU itself during runtime */ #define KVM_PUT_RUNTIME_STATE 1 @@ -174,15 +174,15 @@ int kvm_arch_get_registers(CPUArchState *env); /* full state set, modified during initialization or on vmload */ #define KVM_PUT_FULL_STATE 3 -int kvm_arch_put_registers(CPUArchState *env, int level); +int kvm_arch_put_registers(CPUState *cpu, int level); int kvm_arch_init(KVMState *s); -int kvm_arch_init_vcpu(CPUArchState *env); +int kvm_arch_init_vcpu(CPUState *cpu); -void kvm_arch_reset_vcpu(CPUArchState *env); +void kvm_arch_reset_vcpu(CPUState *cpu); -int kvm_arch_on_sigbus_vcpu(CPUArchState *env, int code, void *addr); +int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); int kvm_arch_on_sigbus(int code, void *addr); void kvm_arch_init_irq_routing(KVMState *s); @@ -212,9 +212,9 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, int kvm_sw_breakpoints_active(CPUArchState *env); -int kvm_arch_insert_sw_breakpoint(CPUArchState *current_env, +int kvm_arch_insert_sw_breakpoint(CPUState *current_cpu, struct kvm_sw_breakpoint *bp); -int kvm_arch_remove_sw_breakpoint(CPUArchState *current_env, +int kvm_arch_remove_sw_breakpoint(CPUState *current_cpu, struct kvm_sw_breakpoint *bp); int kvm_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type); @@ -222,9 +222,9 @@ int kvm_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type); void kvm_arch_remove_all_hw_breakpoints(void); -void kvm_arch_update_guest_debug(CPUArchState *env, struct kvm_guest_debug *dbg); +void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg); -bool kvm_arch_stop_on_emulation_error(CPUArchState *env); +bool kvm_arch_stop_on_emulation_error(CPUState *cpu); int kvm_check_extension(KVMState *s, unsigned int extension); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f669281e13..80cacf3764 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -306,9 +306,10 @@ static void hardware_memory_error(void) exit(1); } -int kvm_arch_on_sigbus_vcpu(CPUX86State *env, int code, void *addr) +int kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(c); + CPUX86State *env = &cpu->env; ram_addr_t ram_addr; hwaddr paddr; @@ -406,12 +407,14 @@ static void cpu_update_state(void *opaque, int running, RunState state) } } -int kvm_arch_init_vcpu(CPUX86State *env) +int kvm_arch_init_vcpu(CPUState *cs) { struct { struct kvm_cpuid2 cpuid; struct kvm_cpuid_entry2 entries[100]; } QEMU_PACKED cpuid_data; + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; uint32_t limit, i, j, cpuid_i; uint32_t unused; struct kvm_cpuid_entry2 *c; @@ -623,9 +626,10 @@ int kvm_arch_init_vcpu(CPUX86State *env) return 0; } -void kvm_arch_reset_vcpu(CPUX86State *env) +void kvm_arch_reset_vcpu(CPUState *cs) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; env->exception_injected = -1; env->interrupt_injected = -1; @@ -1582,9 +1586,10 @@ static int kvm_get_debugregs(CPUX86State *env) return 0; } -int kvm_arch_put_registers(CPUX86State *env, int level) +int kvm_arch_put_registers(CPUState *cpu, int level) { - CPUState *cpu = ENV_GET_CPU(env); + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; int ret; assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); @@ -1640,12 +1645,13 @@ int kvm_arch_put_registers(CPUX86State *env, int level) return 0; } -int kvm_arch_get_registers(CPUX86State *env) +int kvm_arch_get_registers(CPUState *cs) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; int ret; - assert(cpu_is_stopped(CPU(cpu)) || qemu_cpu_is_self(CPU(cpu))); + assert(cpu_is_stopped(cs) || qemu_cpu_is_self(cs)); ret = kvm_getput_regs(env, 0); if (ret < 0) { @@ -1686,8 +1692,10 @@ int kvm_arch_get_registers(CPUX86State *env) return 0; } -void kvm_arch_pre_run(CPUX86State *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; int ret; /* Inject NMI */ @@ -1746,8 +1754,11 @@ void kvm_arch_pre_run(CPUX86State *env, struct kvm_run *run) } } -void kvm_arch_post_run(CPUX86State *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + if (run->if_flag) { env->eflags |= IF_MASK; } else { @@ -1757,9 +1768,10 @@ void kvm_arch_post_run(CPUX86State *env, struct kvm_run *run) cpu_set_apic_base(env->apic_state, run->apic_base); } -int kvm_arch_process_async_events(CPUX86State *env) +int kvm_arch_process_async_events(CPUState *cs) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; if (env->interrupt_request & CPU_INTERRUPT_MCE) { /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */ @@ -1839,8 +1851,9 @@ static int kvm_handle_tpr_access(CPUX86State *env) return 1; } -int kvm_arch_insert_sw_breakpoint(CPUX86State *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_insert_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp) { + CPUX86State *env = &X86_CPU(cpu)->env; static const uint8_t int3 = 0xcc; if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) || @@ -1850,8 +1863,9 @@ int kvm_arch_insert_sw_breakpoint(CPUX86State *env, struct kvm_sw_breakpoint *bp return 0; } -int kvm_arch_remove_sw_breakpoint(CPUX86State *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_remove_sw_breakpoint(CPUState *cpu, struct kvm_sw_breakpoint *bp) { + CPUX86State *env = &X86_CPU(cpu)->env; uint8_t int3; if (cpu_memory_rw_debug(env, bp->pc, &int3, 1, 0) || int3 != 0xcc || @@ -1994,8 +2008,9 @@ static int kvm_handle_debug(CPUX86State *env, return ret; } -void kvm_arch_update_guest_debug(CPUX86State *env, struct kvm_guest_debug *dbg) +void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) { + CPUX86State *env = &X86_CPU(cpu)->env; const uint8_t type_code[] = { [GDB_BREAKPOINT_HW] = 0x0, [GDB_WATCHPOINT_WRITE] = 0x1, @@ -2031,9 +2046,10 @@ static bool host_supports_vmx(void) #define VMX_INVALID_GUEST_STATE 0x80000021 -int kvm_arch_handle_exit(CPUX86State *env, struct kvm_run *run) +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { - X86CPU *cpu = x86_env_get_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; uint64_t code; int ret; @@ -2083,8 +2099,11 @@ int kvm_arch_handle_exit(CPUX86State *env, struct kvm_run *run) return ret; } -bool kvm_arch_stop_on_emulation_error(CPUX86State *env) +bool kvm_arch_stop_on_emulation_error(CPUState *cs) { + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + kvm_cpu_synchronize_state(env); return !(env->cr[0] & CR0_PE_MASK) || ((env->segs[R_CS].selector & 3) != 3); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 3f5df5772f..8a59b706da 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -375,9 +375,10 @@ static inline void kvm_fixup_page_sizes(CPUPPCState *env) #endif /* !defined (TARGET_PPC64) */ -int kvm_arch_init_vcpu(CPUPPCState *cenv) +int kvm_arch_init_vcpu(CPUState *cs) { - PowerPCCPU *cpu = ppc_env_get_cpu(cenv); + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *cenv = &cpu->env; int ret; /* Gather server mmu info from KVM and update the CPU state */ @@ -403,7 +404,7 @@ int kvm_arch_init_vcpu(CPUPPCState *cenv) return ret; } -void kvm_arch_reset_vcpu(CPUPPCState *env) +void kvm_arch_reset_vcpu(CPUState *cpu) { } @@ -432,8 +433,10 @@ static void kvm_sw_tlb_put(CPUPPCState *env) g_free(bitmap); } -int kvm_arch_put_registers(CPUPPCState *env, int level) +int kvm_arch_put_registers(CPUState *cs, int level) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; struct kvm_regs regs; int ret; int i; @@ -525,8 +528,10 @@ int kvm_arch_put_registers(CPUPPCState *env, int level) return ret; } -int kvm_arch_get_registers(CPUPPCState *env) +int kvm_arch_get_registers(CPUState *cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; struct kvm_regs regs; struct kvm_sregs sregs; uint32_t cr; @@ -727,8 +732,10 @@ int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) #define PPC_INPUT_INT PPC6xx_INPUT_INT #endif -void kvm_arch_pre_run(CPUPPCState *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; int r; unsigned irq; @@ -760,13 +767,14 @@ void kvm_arch_pre_run(CPUPPCState *env, struct kvm_run *run) * anyways, so we will get a chance to deliver the rest. */ } -void kvm_arch_post_run(CPUPPCState *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) { } -int kvm_arch_process_async_events(CPUPPCState *env) +int kvm_arch_process_async_events(CPUState *cs) { - return env->halted; + PowerPCCPU *cpu = POWERPC_CPU(cs); + return cpu->env.halted; } static int kvmppc_handle_halt(CPUPPCState *env) @@ -796,8 +804,10 @@ static int kvmppc_handle_dcr_write(CPUPPCState *env, uint32_t dcrn, uint32_t dat return 0; } -int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run) +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; int ret; switch (run->exit_reason) { @@ -817,7 +827,7 @@ int kvm_arch_handle_exit(CPUPPCState *env, struct kvm_run *run) #ifdef CONFIG_PSERIES case KVM_EXIT_PAPR_HCALL: dprintf("handle PAPR hypercall\n"); - run->papr_hcall.ret = spapr_hypercall(ppc_env_get_cpu(env), + run->papr_hcall.ret = spapr_hypercall(cpu, run->papr_hcall.nr, run->papr_hcall.args); ret = 0; @@ -1225,12 +1235,12 @@ int kvmppc_fixup_cpu(CPUPPCState *env) } -bool kvm_arch_stop_on_emulation_error(CPUPPCState *env) +bool kvm_arch_stop_on_emulation_error(CPUState *cpu) { return true; } -int kvm_arch_on_sigbus_vcpu(CPUPPCState *env, int code, void *addr) +int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { return 1; } diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 94de764264..d4e6ab2db8 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -72,8 +72,9 @@ int kvm_arch_init(KVMState *s) return 0; } -int kvm_arch_init_vcpu(CPUS390XState *env) +int kvm_arch_init_vcpu(CPUState *cpu) { + CPUS390XState *env = &S390_CPU(cpu)->env; int ret = 0; if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) { @@ -83,13 +84,15 @@ int kvm_arch_init_vcpu(CPUS390XState *env) return ret; } -void kvm_arch_reset_vcpu(CPUS390XState *env) +void kvm_arch_reset_vcpu(CPUState *cpu) { /* FIXME: add code to reset vcpu. */ } -int kvm_arch_put_registers(CPUS390XState *env, int level) +int kvm_arch_put_registers(CPUState *cs, int level) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; struct kvm_sregs sregs; struct kvm_regs regs; int ret; @@ -149,8 +152,10 @@ int kvm_arch_put_registers(CPUS390XState *env, int level) return 0; } -int kvm_arch_get_registers(CPUS390XState *env) +int kvm_arch_get_registers(CPUState *cs) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; struct kvm_sregs sregs; struct kvm_regs regs; int ret; @@ -239,8 +244,10 @@ void *kvm_arch_vmalloc(ram_addr_t size) } } -int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || @@ -250,8 +257,10 @@ int kvm_arch_insert_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint * return 0; } -int kvm_arch_remove_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint *bp) +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; uint8_t t[4]; static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; @@ -266,17 +275,18 @@ int kvm_arch_remove_sw_breakpoint(CPUS390XState *env, struct kvm_sw_breakpoint * return 0; } -void kvm_arch_pre_run(CPUS390XState *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) { } -void kvm_arch_post_run(CPUS390XState *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) { } -int kvm_arch_process_async_events(CPUS390XState *env) +int kvm_arch_process_async_events(CPUState *cs) { - return env->halted; + S390CPU *cpu = S390_CPU(cs); + return cpu->env.halted; } void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, @@ -565,8 +575,10 @@ static int handle_intercept(CPUS390XState *env) return r; } -int kvm_arch_handle_exit(CPUS390XState *env, struct kvm_run *run) +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; int ret = 0; switch (run->exit_reason) { @@ -587,12 +599,12 @@ int kvm_arch_handle_exit(CPUS390XState *env, struct kvm_run *run) return ret; } -bool kvm_arch_stop_on_emulation_error(CPUS390XState *env) +bool kvm_arch_stop_on_emulation_error(CPUState *cpu) { return true; } -int kvm_arch_on_sigbus_vcpu(CPUS390XState *env, int code, void *addr) +int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { return 1; } From 1bc22652d62f862a5def54f939e87fdb7a5593ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 31 Oct 2012 06:06:49 +0100 Subject: [PATCH 0015/1634] kvm: Pass CPUState to kvm_vcpu_ioctl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt helper functions to pass X86CPU / PowerPCCPU / S390CPU. Signed-off-by: Andreas Färber --- hw/kvm/apic.c | 10 +-- hw/kvm/clock.c | 2 +- hw/ppc.c | 2 +- hw/s390-virtio-bus.c | 12 +-- hw/spapr.c | 2 +- kvm-all.c | 14 ++-- kvm.h | 2 +- target-i386/kvm.c | 158 +++++++++++++++++++++---------------- target-ppc/kvm.c | 55 +++++++------ target-ppc/kvm_ppc.h | 8 +- target-s390x/cpu.h | 12 +-- target-s390x/interrupt.c | 3 +- target-s390x/kvm.c | 62 ++++++++------- target-s390x/misc_helper.c | 2 +- 14 files changed, 188 insertions(+), 156 deletions(-) diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c index 8b65d513db..c4d74ee1aa 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -104,7 +104,7 @@ static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable) .enabled = enable }; - kvm_vcpu_ioctl(&s->cpu->env, KVM_TPR_ACCESS_REPORTING, &ctl); + kvm_vcpu_ioctl(CPU(s->cpu), KVM_TPR_ACCESS_REPORTING, &ctl); } static void kvm_apic_vapic_base_update(APICCommonState *s) @@ -114,7 +114,7 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) }; int ret; - ret = kvm_vcpu_ioctl(&s->cpu->env, KVM_SET_VAPIC_ADDR, &vapid_addr); + ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_VAPIC_ADDR, &vapid_addr); if (ret < 0) { fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n", strerror(-ret)); @@ -125,15 +125,15 @@ static void kvm_apic_vapic_base_update(APICCommonState *s) static void do_inject_external_nmi(void *data) { APICCommonState *s = data; - CPUX86State *env = &s->cpu->env; + CPUState *cpu = CPU(s->cpu); uint32_t lvt; int ret; - cpu_synchronize_state(env); + cpu_synchronize_state(&s->cpu->env); lvt = s->lvt[APIC_LVT_LINT1]; if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) { - ret = kvm_vcpu_ioctl(env, KVM_NMI); + ret = kvm_vcpu_ioctl(cpu, KVM_NMI); if (ret < 0) { fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", strerror(-ret)); diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c index 824b978397..4cf62f696a 100644 --- a/hw/kvm/clock.c +++ b/hw/kvm/clock.c @@ -76,7 +76,7 @@ static void kvmclock_vm_state_change(void *opaque, int running, return; } for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) { - ret = kvm_vcpu_ioctl(penv, KVM_KVMCLOCK_CTRL, 0); + ret = kvm_vcpu_ioctl(ENV_GET_CPU(penv), KVM_KVMCLOCK_CTRL, 0); if (ret) { if (ret != -EINVAL) { fprintf(stderr, "%s: %s\n", __func__, strerror(-ret)); diff --git a/hw/ppc.c b/hw/ppc.c index 11fd199eaa..e99a93db96 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -65,7 +65,7 @@ void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) if (old_pending != env->pending_interrupts) { #ifdef CONFIG_KVM - kvmppc_set_interrupt(env, n_IRQ, level); + kvmppc_set_interrupt(ppc_env_get_cpu(env), n_IRQ, level); #endif } diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index e0ac2d1ec2..716028d3a2 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -111,10 +111,12 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size) return bus; } -static void s390_virtio_irq(CPUS390XState *env, int config_change, uint64_t token) +static void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { + CPUS390XState *env = &cpu->env; + if (kvm_enabled()) { - kvm_s390_virtio_irq(env, config_change, token); + kvm_s390_virtio_irq(cpu, config_change, token); } else { cpu_inject_ext(env, VIRTIO_EXT_CODE, config_change, token); } @@ -143,8 +145,7 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) s390_virtio_reset_idx(dev); if (dev->qdev.hotplugged) { S390CPU *cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &cpu->env; - s390_virtio_irq(env, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); + s390_virtio_irq(cpu, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); } return 0; @@ -369,9 +370,8 @@ static void virtio_s390_notify(void *opaque, uint16_t vector) VirtIOS390Device *dev = (VirtIOS390Device*)opaque; uint64_t token = s390_virtio_device_vq_token(dev, vector); S390CPU *cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &cpu->env; - s390_virtio_irq(env, 0, token); + s390_virtio_irq(cpu, 0, token); } static unsigned virtio_s390_get_features(void *opaque) diff --git a/hw/spapr.c b/hw/spapr.c index 504d0fca5e..341f0b91ca 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -797,7 +797,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Tell KVM that we're in PAPR mode */ if (kvm_enabled()) { - kvmppc_set_papr(env); + kvmppc_set_papr(cpu); } qemu_register_reset(spapr_cpu_reset, cpu); diff --git a/kvm-all.c b/kvm-all.c index 792cdf1d66..5f1d1fed2c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1557,7 +1557,7 @@ int kvm_cpu_exec(CPUArchState *env) } qemu_mutex_unlock_iothread(); - run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0); + run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0); qemu_mutex_lock_iothread(); kvm_arch_post_run(cpu, run); @@ -1658,9 +1658,8 @@ int kvm_vm_ioctl(KVMState *s, int type, ...) return ret; } -int kvm_vcpu_ioctl(CPUArchState *env, int type, ...) +int kvm_vcpu_ioctl(CPUState *cpu, int type, ...) { - CPUState *cpu = ENV_GET_CPU(env); int ret; void *arg; va_list ap; @@ -1791,9 +1790,9 @@ struct kvm_set_guest_debug_data { static void kvm_invoke_set_guest_debug(void *data) { struct kvm_set_guest_debug_data *dbg_data = data; - CPUArchState *env = dbg_data->env; + CPUState *cpu = ENV_GET_CPU(dbg_data->env); - dbg_data->err = kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); + dbg_data->err = kvm_vcpu_ioctl(cpu, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); } int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) @@ -1955,18 +1954,19 @@ void kvm_remove_all_breakpoints(CPUArchState *current_env) int kvm_set_signal_mask(CPUArchState *env, const sigset_t *sigset) { + CPUState *cpu = ENV_GET_CPU(env); struct kvm_signal_mask *sigmask; int r; if (!sigset) { - return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL); + return kvm_vcpu_ioctl(cpu, KVM_SET_SIGNAL_MASK, NULL); } sigmask = g_malloc(sizeof(*sigmask) + sizeof(*sigset)); sigmask->len = 8; memcpy(sigmask->sigset, sigset, sizeof(*sigset)); - r = kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, sigmask); + r = kvm_vcpu_ioctl(cpu, KVM_SET_SIGNAL_MASK, sigmask); g_free(sigmask); return r; diff --git a/kvm.h b/kvm.h index 61f00b7456..a2375ff469 100644 --- a/kvm.h +++ b/kvm.h @@ -152,7 +152,7 @@ int kvm_ioctl(KVMState *s, int type, ...); int kvm_vm_ioctl(KVMState *s, int type, ...); -int kvm_vcpu_ioctl(CPUArchState *env, int type, ...); +int kvm_vcpu_ioctl(CPUState *cpu, int type, ...); /* Arch specific hooks */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 80cacf3764..b2efa1e928 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -368,8 +368,10 @@ int kvm_arch_on_sigbus(int code, void *addr) return 0; } -static int kvm_inject_mce_oldstyle(CPUX86State *env) +static int kvm_inject_mce_oldstyle(X86CPU *cpu) { + CPUX86State *env = &cpu->env; + if (!kvm_has_vcpu_events() && env->exception_injected == EXCP12_MCHK) { unsigned int bank, bank_num = env->mcg_cap & 0xff; struct kvm_x86_mce mce; @@ -393,7 +395,7 @@ static int kvm_inject_mce_oldstyle(CPUX86State *env) mce.addr = env->mce_banks[bank * 4 + 2]; mce.misc = env->mce_banks[bank * 4 + 3]; - return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, &mce); + return kvm_vcpu_ioctl(CPU(cpu), KVM_X86_SET_MCE, &mce); } return 0; } @@ -593,7 +595,7 @@ int kvm_arch_init_vcpu(CPUState *cs) } mcg_cap &= MCE_CAP_DEF; mcg_cap |= banks; - ret = kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap); + ret = kvm_vcpu_ioctl(cs, KVM_X86_SETUP_MCE, &mcg_cap); if (ret < 0) { fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret)); return ret; @@ -605,14 +607,14 @@ int kvm_arch_init_vcpu(CPUState *cs) qemu_add_vm_change_state_handler(cpu_update_state, env); cpuid_data.cpuid.padding = 0; - r = kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data); + r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data); if (r) { return r; } r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL); if (r && env->tsc_khz) { - r = kvm_vcpu_ioctl(env, KVM_SET_TSC_KHZ, env->tsc_khz); + r = kvm_vcpu_ioctl(cs, KVM_SET_TSC_KHZ, env->tsc_khz); if (r < 0) { fprintf(stderr, "KVM_SET_TSC_KHZ failed\n"); return r; @@ -820,13 +822,14 @@ static void kvm_getput_reg(__u64 *kvm_reg, target_ulong *qemu_reg, int set) } } -static int kvm_getput_regs(CPUX86State *env, int set) +static int kvm_getput_regs(X86CPU *cpu, int set) { + CPUX86State *env = &cpu->env; struct kvm_regs regs; int ret = 0; if (!set) { - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_REGS, ®s); if (ret < 0) { return ret; } @@ -855,14 +858,15 @@ static int kvm_getput_regs(CPUX86State *env, int set) kvm_getput_reg(®s.rip, &env->eip, set); if (set) { - ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_REGS, ®s); } return ret; } -static int kvm_put_fpu(CPUX86State *env) +static int kvm_put_fpu(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_fpu fpu; int i; @@ -880,7 +884,7 @@ static int kvm_put_fpu(CPUX86State *env) memcpy(fpu.xmm, env->xmm_regs, sizeof env->xmm_regs); fpu.mxcsr = env->mxcsr; - return kvm_vcpu_ioctl(env, KVM_SET_FPU, &fpu); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_FPU, &fpu); } #define XSAVE_FCW_FSW 0 @@ -893,14 +897,15 @@ static int kvm_put_fpu(CPUX86State *env) #define XSAVE_XSTATE_BV 128 #define XSAVE_YMMH_SPACE 144 -static int kvm_put_xsave(CPUX86State *env) +static int kvm_put_xsave(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; uint16_t cwd, swd, twd; int i, r; if (!kvm_has_xsave()) { - return kvm_put_fpu(env); + return kvm_put_fpu(cpu); } memset(xsave, 0, sizeof(struct kvm_xsave)); @@ -923,12 +928,13 @@ static int kvm_put_xsave(CPUX86State *env) *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv; memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs, sizeof env->ymmh_regs); - r = kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave); + r = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XSAVE, xsave); return r; } -static int kvm_put_xcrs(CPUX86State *env) +static int kvm_put_xcrs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_xcrs xcrs; if (!kvm_has_xcrs()) { @@ -939,11 +945,12 @@ static int kvm_put_xcrs(CPUX86State *env) xcrs.flags = 0; xcrs.xcrs[0].xcr = 0; xcrs.xcrs[0].value = env->xcr0; - return kvm_vcpu_ioctl(env, KVM_SET_XCRS, &xcrs); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_XCRS, &xcrs); } -static int kvm_put_sregs(CPUX86State *env) +static int kvm_put_sregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_sregs sregs; memset(sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap)); @@ -988,7 +995,7 @@ static int kvm_put_sregs(CPUX86State *env) sregs.efer = env->efer; - return kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs); } static void kvm_msr_entry_set(struct kvm_msr_entry *entry, @@ -998,8 +1005,9 @@ static void kvm_msr_entry_set(struct kvm_msr_entry *entry, entry->data = value; } -static int kvm_put_msrs(CPUX86State *env, int level) +static int kvm_put_msrs(X86CPU *cpu, int level) { + CPUX86State *env = &cpu->env; struct { struct kvm_msrs info; struct kvm_msr_entry entries[100]; @@ -1080,17 +1088,18 @@ static int kvm_put_msrs(CPUX86State *env, int level) msr_data.info.nmsrs = n; - return kvm_vcpu_ioctl(env, KVM_SET_MSRS, &msr_data); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MSRS, &msr_data); } -static int kvm_get_fpu(CPUX86State *env) +static int kvm_get_fpu(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_fpu fpu; int i, ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_FPU, &fpu); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_FPU, &fpu); if (ret < 0) { return ret; } @@ -1111,17 +1120,18 @@ static int kvm_get_fpu(CPUX86State *env) return 0; } -static int kvm_get_xsave(CPUX86State *env) +static int kvm_get_xsave(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_xsave* xsave = env->kvm_xsave_buf; int ret, i; uint16_t cwd, swd, twd; if (!kvm_has_xsave()) { - return kvm_get_fpu(env); + return kvm_get_fpu(cpu); } - ret = kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_XSAVE, xsave); if (ret < 0) { return ret; } @@ -1149,8 +1159,9 @@ static int kvm_get_xsave(CPUX86State *env) return 0; } -static int kvm_get_xcrs(CPUX86State *env) +static int kvm_get_xcrs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; int i, ret; struct kvm_xcrs xcrs; @@ -1158,7 +1169,7 @@ static int kvm_get_xcrs(CPUX86State *env) return 0; } - ret = kvm_vcpu_ioctl(env, KVM_GET_XCRS, &xcrs); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_XCRS, &xcrs); if (ret < 0) { return ret; } @@ -1173,13 +1184,14 @@ static int kvm_get_xcrs(CPUX86State *env) return 0; } -static int kvm_get_sregs(CPUX86State *env) +static int kvm_get_sregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_sregs sregs; uint32_t hflags; int bit, i, ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -1257,8 +1269,9 @@ static int kvm_get_sregs(CPUX86State *env) return 0; } -static int kvm_get_msrs(CPUX86State *env) +static int kvm_get_msrs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct { struct kvm_msrs info; struct kvm_msr_entry entries[100]; @@ -1315,7 +1328,7 @@ static int kvm_get_msrs(CPUX86State *env) } msr_data.info.nmsrs = n; - ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data); if (ret < 0) { return ret; } @@ -1393,11 +1406,11 @@ static int kvm_get_msrs(CPUX86State *env) return 0; } -static int kvm_put_mp_state(CPUX86State *env) +static int kvm_put_mp_state(X86CPU *cpu) { - struct kvm_mp_state mp_state = { .mp_state = env->mp_state }; + struct kvm_mp_state mp_state = { .mp_state = cpu->env.mp_state }; - return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, &mp_state); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state); } static int kvm_get_mp_state(X86CPU *cpu) @@ -1406,7 +1419,7 @@ static int kvm_get_mp_state(X86CPU *cpu) struct kvm_mp_state mp_state; int ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_MP_STATE, &mp_state); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state); if (ret < 0) { return ret; } @@ -1417,14 +1430,15 @@ static int kvm_get_mp_state(X86CPU *cpu) return 0; } -static int kvm_get_apic(CPUX86State *env) +static int kvm_get_apic(X86CPU *cpu) { + CPUX86State *env = &cpu->env; DeviceState *apic = env->apic_state; struct kvm_lapic_state kapic; int ret; if (apic && kvm_irqchip_in_kernel()) { - ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_LAPIC, &kapic); if (ret < 0) { return ret; } @@ -1434,21 +1448,23 @@ static int kvm_get_apic(CPUX86State *env) return 0; } -static int kvm_put_apic(CPUX86State *env) +static int kvm_put_apic(X86CPU *cpu) { + CPUX86State *env = &cpu->env; DeviceState *apic = env->apic_state; struct kvm_lapic_state kapic; if (apic && kvm_irqchip_in_kernel()) { kvm_put_apic_state(apic, &kapic); - return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_LAPIC, &kapic); } return 0; } -static int kvm_put_vcpu_events(CPUX86State *env, int level) +static int kvm_put_vcpu_events(X86CPU *cpu, int level) { + CPUX86State *env = &cpu->env; struct kvm_vcpu_events events; if (!kvm_has_vcpu_events()) { @@ -1478,11 +1494,12 @@ static int kvm_put_vcpu_events(CPUX86State *env, int level) KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR; } - return kvm_vcpu_ioctl(env, KVM_SET_VCPU_EVENTS, &events); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events); } -static int kvm_get_vcpu_events(CPUX86State *env) +static int kvm_get_vcpu_events(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_vcpu_events events; int ret; @@ -1490,7 +1507,7 @@ static int kvm_get_vcpu_events(CPUX86State *env) return 0; } - ret = kvm_vcpu_ioctl(env, KVM_GET_VCPU_EVENTS, &events); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_VCPU_EVENTS, &events); if (ret < 0) { return ret; } @@ -1516,8 +1533,9 @@ static int kvm_get_vcpu_events(CPUX86State *env) return 0; } -static int kvm_guest_debug_workarounds(CPUX86State *env) +static int kvm_guest_debug_workarounds(X86CPU *cpu) { + CPUX86State *env = &cpu->env; int ret = 0; unsigned long reinject_trap = 0; @@ -1545,8 +1563,9 @@ static int kvm_guest_debug_workarounds(CPUX86State *env) return ret; } -static int kvm_put_debugregs(CPUX86State *env) +static int kvm_put_debugregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_debugregs dbgregs; int i; @@ -1561,11 +1580,12 @@ static int kvm_put_debugregs(CPUX86State *env) dbgregs.dr7 = env->dr[7]; dbgregs.flags = 0; - return kvm_vcpu_ioctl(env, KVM_SET_DEBUGREGS, &dbgregs); + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEBUGREGS, &dbgregs); } -static int kvm_get_debugregs(CPUX86State *env) +static int kvm_get_debugregs(X86CPU *cpu) { + CPUX86State *env = &cpu->env; struct kvm_debugregs dbgregs; int i, ret; @@ -1573,7 +1593,7 @@ static int kvm_get_debugregs(CPUX86State *env) return 0; } - ret = kvm_vcpu_ioctl(env, KVM_GET_DEBUGREGS, &dbgregs); + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEBUGREGS, &dbgregs); if (ret < 0) { return ret; } @@ -1589,56 +1609,55 @@ static int kvm_get_debugregs(CPUX86State *env) int kvm_arch_put_registers(CPUState *cpu, int level) { X86CPU *x86_cpu = X86_CPU(cpu); - CPUX86State *env = &x86_cpu->env; int ret; assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); - ret = kvm_getput_regs(env, 1); + ret = kvm_getput_regs(x86_cpu, 1); if (ret < 0) { return ret; } - ret = kvm_put_xsave(env); + ret = kvm_put_xsave(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_xcrs(env); + ret = kvm_put_xcrs(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_sregs(env); + ret = kvm_put_sregs(x86_cpu); if (ret < 0) { return ret; } /* must be before kvm_put_msrs */ - ret = kvm_inject_mce_oldstyle(env); + ret = kvm_inject_mce_oldstyle(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_msrs(env, level); + ret = kvm_put_msrs(x86_cpu, level); if (ret < 0) { return ret; } if (level >= KVM_PUT_RESET_STATE) { - ret = kvm_put_mp_state(env); + ret = kvm_put_mp_state(x86_cpu); if (ret < 0) { return ret; } - ret = kvm_put_apic(env); + ret = kvm_put_apic(x86_cpu); if (ret < 0) { return ret; } } - ret = kvm_put_vcpu_events(env, level); + ret = kvm_put_vcpu_events(x86_cpu, level); if (ret < 0) { return ret; } - ret = kvm_put_debugregs(env); + ret = kvm_put_debugregs(x86_cpu); if (ret < 0) { return ret; } /* must be last */ - ret = kvm_guest_debug_workarounds(env); + ret = kvm_guest_debug_workarounds(x86_cpu); if (ret < 0) { return ret; } @@ -1648,28 +1667,27 @@ int kvm_arch_put_registers(CPUState *cpu, int level) int kvm_arch_get_registers(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; int ret; assert(cpu_is_stopped(cs) || qemu_cpu_is_self(cs)); - ret = kvm_getput_regs(env, 0); + ret = kvm_getput_regs(cpu, 0); if (ret < 0) { return ret; } - ret = kvm_get_xsave(env); + ret = kvm_get_xsave(cpu); if (ret < 0) { return ret; } - ret = kvm_get_xcrs(env); + ret = kvm_get_xcrs(cpu); if (ret < 0) { return ret; } - ret = kvm_get_sregs(env); + ret = kvm_get_sregs(cpu); if (ret < 0) { return ret; } - ret = kvm_get_msrs(env); + ret = kvm_get_msrs(cpu); if (ret < 0) { return ret; } @@ -1677,15 +1695,15 @@ int kvm_arch_get_registers(CPUState *cs) if (ret < 0) { return ret; } - ret = kvm_get_apic(env); + ret = kvm_get_apic(cpu); if (ret < 0) { return ret; } - ret = kvm_get_vcpu_events(env); + ret = kvm_get_vcpu_events(cpu); if (ret < 0) { return ret; } - ret = kvm_get_debugregs(env); + ret = kvm_get_debugregs(cpu); if (ret < 0) { return ret; } @@ -1702,7 +1720,7 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) if (env->interrupt_request & CPU_INTERRUPT_NMI) { env->interrupt_request &= ~CPU_INTERRUPT_NMI; DPRINTF("injected NMI\n"); - ret = kvm_vcpu_ioctl(env, KVM_NMI); + ret = kvm_vcpu_ioctl(cpu, KVM_NMI); if (ret < 0) { fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", strerror(-ret)); @@ -1730,7 +1748,7 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) intr.irq = irq; DPRINTF("injected interrupt %d\n", irq); - ret = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr); + ret = kvm_vcpu_ioctl(cpu, KVM_INTERRUPT, &intr); if (ret < 0) { fprintf(stderr, "KVM: injection failed, interrupt lost (%s)\n", diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 8a59b706da..ad5bc66396 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -99,8 +99,10 @@ int kvm_arch_init(KVMState *s) return 0; } -static int kvm_arch_sync_sregs(CPUPPCState *cenv) +static int kvm_arch_sync_sregs(PowerPCCPU *cpu) { + CPUPPCState *cenv = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_sregs sregs; int ret; @@ -117,18 +119,20 @@ static int kvm_arch_sync_sregs(CPUPPCState *cenv) } } - ret = kvm_vcpu_ioctl(cenv, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret) { return ret; } sregs.pvr = cenv->spr[SPR_PVR]; - return kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs); + return kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs); } /* Set up a shared TLB array with KVM */ -static int kvm_booke206_tlb_init(CPUPPCState *env) +static int kvm_booke206_tlb_init(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_book3e_206_tlb_params params = {}; struct kvm_config_tlb cfg = {}; struct kvm_enable_cap encap = {}; @@ -161,7 +165,7 @@ static int kvm_booke206_tlb_init(CPUPPCState *env) encap.cap = KVM_CAP_SW_TLB; encap.args[0] = (uintptr_t)&cfg; - ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &encap); + ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap); if (ret < 0) { fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n", __func__, strerror(-ret)); @@ -385,7 +389,7 @@ int kvm_arch_init_vcpu(CPUState *cs) kvm_fixup_page_sizes(cenv); /* Synchronize sregs with kvm */ - ret = kvm_arch_sync_sregs(cenv); + ret = kvm_arch_sync_sregs(cpu); if (ret) { return ret; } @@ -395,7 +399,7 @@ int kvm_arch_init_vcpu(CPUState *cs) /* Some targets support access to KVM's guest TLB. */ switch (cenv->mmu_model) { case POWERPC_MMU_BOOKE206: - ret = kvm_booke206_tlb_init(cenv); + ret = kvm_booke206_tlb_init(cpu); break; default: break; @@ -408,8 +412,10 @@ void kvm_arch_reset_vcpu(CPUState *cpu) { } -static void kvm_sw_tlb_put(CPUPPCState *env) +static void kvm_sw_tlb_put(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_dirty_tlb dirty_tlb; unsigned char *bitmap; int ret; @@ -424,7 +430,7 @@ static void kvm_sw_tlb_put(CPUPPCState *env) dirty_tlb.bitmap = (uintptr_t)bitmap; dirty_tlb.num_dirty = env->nb_tlb; - ret = kvm_vcpu_ioctl(env, KVM_DIRTY_TLB, &dirty_tlb); + ret = kvm_vcpu_ioctl(cs, KVM_DIRTY_TLB, &dirty_tlb); if (ret) { fprintf(stderr, "%s: KVM_DIRTY_TLB: %s\n", __func__, strerror(-ret)); @@ -441,9 +447,10 @@ int kvm_arch_put_registers(CPUState *cs, int level) int ret; int i; - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); - if (ret < 0) + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); + if (ret < 0) { return ret; + } regs.ctr = env->ctr; regs.lr = env->lr; @@ -468,12 +475,12 @@ int kvm_arch_put_registers(CPUState *cs, int level) for (i = 0;i < 32; i++) regs.gpr[i] = env->gpr[i]; - ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); if (ret < 0) return ret; if (env->tlb_dirty) { - kvm_sw_tlb_put(env); + kvm_sw_tlb_put(cpu); env->tlb_dirty = false; } @@ -506,7 +513,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) | env->IBAT[1][i]; } - ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs); if (ret) { return ret; } @@ -519,7 +526,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) .addr = (uintptr_t) &hior, }; - ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, ®); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); if (ret) { return ret; } @@ -537,7 +544,7 @@ int kvm_arch_get_registers(CPUState *cs) uint32_t cr; int i, ret; - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); if (ret < 0) return ret; @@ -571,7 +578,7 @@ int kvm_arch_get_registers(CPUState *cs) env->gpr[i] = regs.gpr[i]; if (cap_booke_sregs) { - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -675,7 +682,7 @@ int kvm_arch_get_registers(CPUState *cs) } if (cap_segstate) { - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -707,7 +714,7 @@ int kvm_arch_get_registers(CPUState *cs) return 0; } -int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) +int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) { unsigned virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET; @@ -719,7 +726,7 @@ int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) return 0; } - kvm_vcpu_ioctl(env, KVM_INTERRUPT, &virq); + kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq); return 0; } @@ -753,7 +760,7 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) irq = KVM_INTERRUPT_SET; dprintf("injected interrupt %d\n", irq); - r = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &irq); + r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq); if (r < 0) printf("cpu %d fail inject %x\n", env->cpu_index, irq); @@ -1007,13 +1014,15 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) return 0; } -void kvmppc_set_papr(CPUPPCState *env) +void kvmppc_set_papr(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_enable_cap cap = {}; int ret; cap.cap = KVM_CAP_PPC_PAPR; - ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap); + ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap); if (ret) { cpu_abort(env, "This KVM version does not support PAPR\n"); diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index baad6eb75b..369c7fe12c 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -20,8 +20,8 @@ uint64_t kvmppc_get_clockfreq(void); uint32_t kvmppc_get_vmx(void); uint32_t kvmppc_get_dfp(void); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); -int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level); -void kvmppc_set_papr(CPUPPCState *env); +int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); +void kvmppc_set_papr(PowerPCCPU *cpu); int kvmppc_smt_threads(void); #ifndef CONFIG_USER_ONLY off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); @@ -65,12 +65,12 @@ static inline int kvmppc_read_segment_page_sizes(uint32_t *prop, int maxcells) return -1; } -static inline int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level) +static inline int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) { return -1; } -static inline void kvmppc_set_papr(CPUPPCState *env) +static inline void kvmppc_set_papr(PowerPCCPU *cpu) { } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 0f9a1f7340..7e7e3b7199 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -296,21 +296,21 @@ void s390x_cpu_timer(void *opaque); int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall); #ifdef CONFIG_KVM -void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code); -void kvm_s390_virtio_irq(CPUS390XState *env, int config_change, uint64_t token); -void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, +void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code); +void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token); +void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm); #else -static inline void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code) +static inline void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) { } -static inline void kvm_s390_virtio_irq(CPUS390XState *env, int config_change, +static inline void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { } -static inline void kvm_s390_interrupt_internal(CPUS390XState *env, int type, +static inline void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm) { diff --git a/target-s390x/interrupt.c b/target-s390x/interrupt.c index c1b034f775..97487bd631 100644 --- a/target-s390x/interrupt.c +++ b/target-s390x/interrupt.c @@ -19,7 +19,8 @@ void s390_sclp_extint(uint32_t parm) if (kvm_enabled()) { #ifdef CONFIG_KVM - kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE, parm, 0, 1); + kvm_s390_interrupt_internal(dummy_cpu, KVM_S390_INT_SERVICE, parm, + 0, 1); #endif } else { env->psw.addr += 4; diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index d4e6ab2db8..5422678330 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -74,10 +74,9 @@ int kvm_arch_init(KVMState *s) int kvm_arch_init_vcpu(CPUState *cpu) { - CPUS390XState *env = &S390_CPU(cpu)->env; int ret = 0; - if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) { + if (kvm_vcpu_ioctl(cpu, KVM_S390_INITIAL_RESET, NULL) < 0) { perror("cannot init reset vcpu"); } @@ -111,7 +110,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) for (i = 0; i < 16; i++) { regs.gprs[i] = env->regs[i]; } - ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s); if (ret < 0) { return ret; } @@ -136,7 +135,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) sregs.acrs[i] = env->aregs[i]; sregs.crs[i] = env->cregs[i]; } - ret = kvm_vcpu_ioctl(env, KVM_SET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -171,7 +170,7 @@ int kvm_arch_get_registers(CPUState *cs) env->regs[i] = env->kvm_run->s.regs.gprs[i]; } } else { - ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); + ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); if (ret < 0) { return ret; } @@ -189,7 +188,7 @@ int kvm_arch_get_registers(CPUState *cs) env->cregs[i] = env->kvm_run->s.regs.crs[i]; } } else { - ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs); + ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret < 0) { return ret; } @@ -289,9 +288,11 @@ int kvm_arch_process_async_events(CPUState *cs) return cpu->env.halted; } -void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, +void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm) { + CPUS390XState *env = &cpu->env; + CPUState *cs = CPU(cpu); struct kvm_s390_interrupt kvmint; int r; @@ -306,7 +307,7 @@ void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, if (vm) { r = kvm_vm_ioctl(env->kvm_state, KVM_S390_INTERRUPT, &kvmint); } else { - r = kvm_vcpu_ioctl(env, KVM_S390_INTERRUPT, &kvmint); + r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint); } if (r < 0) { @@ -315,20 +316,20 @@ void kvm_s390_interrupt_internal(CPUS390XState *env, int type, uint32_t parm, } } -void kvm_s390_virtio_irq(CPUS390XState *env, int config_change, uint64_t token) +void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { - kvm_s390_interrupt_internal(env, KVM_S390_INT_VIRTIO, config_change, + kvm_s390_interrupt_internal(cpu, KVM_S390_INT_VIRTIO, config_change, token, 1); } -void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code) +void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) { - kvm_s390_interrupt_internal(env, type, code, 0, 0); + kvm_s390_interrupt_internal(cpu, type, code, 0, 0); } -static void enter_pgmcheck(CPUS390XState *env, uint16_t code) +static void enter_pgmcheck(S390CPU *cpu, uint16_t code) { - kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); + kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code); } static inline void setcc(CPUS390XState *env, uint64_t cc) @@ -340,9 +341,10 @@ static inline void setcc(CPUS390XState *env, uint64_t cc) env->psw.mask |= (cc & 3) << 44; } -static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run, +static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, uint16_t ipbh0) { + CPUS390XState *env = &cpu->env; uint32_t sccb; uint64_t code; int r = 0; @@ -353,14 +355,14 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run, r = sclp_service_call(sccb, code); if (r < 0) { - enter_pgmcheck(env, -r); + enter_pgmcheck(cpu, -r); } setcc(env, r); return 0; } -static int handle_priv(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) +static int handle_priv(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { int r = 0; uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16; @@ -368,7 +370,7 @@ static int handle_priv(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) dprintf("KVM: PRIV: %d\n", ipa1); switch (ipa1) { case PRIV_SCLP_CALL: - r = kvm_sclp_service_call(env, run, ipbh0); + r = kvm_sclp_service_call(cpu, run, ipbh0); break; default: dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); @@ -411,7 +413,7 @@ static int s390_cpu_restart(S390CPU *cpu) { CPUS390XState *env = &cpu->env; - kvm_s390_interrupt(env, KVM_S390_RESTART, 0); + kvm_s390_interrupt(cpu, KVM_S390_RESTART, 0); s390_add_running_cpu(env); qemu_cpu_kick(CPU(cpu)); dprintf("DONE: SIGP cpu restart: %p\n", env); @@ -425,12 +427,13 @@ static int s390_store_status(CPUS390XState *env, uint32_t parameter) return -1; } -static int s390_cpu_initial_reset(CPUS390XState *env) +static int s390_cpu_initial_reset(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; int i; s390_del_running_cpu(env); - if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) { + if (kvm_vcpu_ioctl(CPU(cpu), KVM_S390_INITIAL_RESET, NULL) < 0) { perror("cannot init reset vcpu"); } @@ -489,7 +492,7 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) /* make the caller panic */ return -1; case SIGP_INITIAL_CPU_RESET: - r = s390_cpu_initial_reset(target_env); + r = s390_cpu_initial_reset(target_cpu); break; default: fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", order_code); @@ -501,8 +504,9 @@ out: return 0; } -static int handle_instruction(CPUS390XState *env, struct kvm_run *run) +static int handle_instruction(S390CPU *cpu, struct kvm_run *run) { + CPUS390XState *env = &cpu->env; unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00); uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff; int ipb_code = (run->s390_sieic.ipb & 0x0fff0000) >> 16; @@ -511,7 +515,7 @@ static int handle_instruction(CPUS390XState *env, struct kvm_run *run) dprintf("handle_instruction 0x%x 0x%x\n", run->s390_sieic.ipa, run->s390_sieic.ipb); switch (ipa0) { case IPA0_PRIV: - r = handle_priv(env, run, ipa1); + r = handle_priv(cpu, run, ipa1); break; case IPA0_DIAG: r = handle_diag(env, run, ipb_code); @@ -522,7 +526,7 @@ static int handle_instruction(CPUS390XState *env, struct kvm_run *run) } if (r < 0) { - enter_pgmcheck(env, 0x0001); + enter_pgmcheck(cpu, 0x0001); } return 0; } @@ -533,8 +537,9 @@ static bool is_special_wait_psw(CPUS390XState *env) return env->kvm_run->psw_addr == 0xfffUL; } -static int handle_intercept(CPUS390XState *env) +static int handle_intercept(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; struct kvm_run *run = env->kvm_run; int icpt_code = run->s390_sieic.icptcode; int r = 0; @@ -543,7 +548,7 @@ static int handle_intercept(CPUS390XState *env) (long)env->kvm_run->psw_addr); switch (icpt_code) { case ICPT_INSTRUCTION: - r = handle_instruction(env, run); + r = handle_instruction(cpu, run); break; case ICPT_WAITPSW: if (s390_del_running_cpu(env) == 0 && @@ -578,12 +583,11 @@ static int handle_intercept(CPUS390XState *env) int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { S390CPU *cpu = S390_CPU(cs); - CPUS390XState *env = &cpu->env; int ret = 0; switch (run->exit_reason) { case KVM_EXIT_S390_SIEIC: - ret = handle_intercept(env); + ret = handle_intercept(cpu); break; case KVM_EXIT_S390_RESET: qemu_system_reset_request(); diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 38d8f2a627..0834a1992b 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -57,7 +57,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) if (kvm_enabled()) { #ifdef CONFIG_KVM - kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); + kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code); #endif } else { env->int_pgm_code = code; From 7058581a26f4299e0b7e05677c64c1b5a50d0e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 03:55:58 +0100 Subject: [PATCH 0016/1634] ppc: Pass PowerPCCPU to ppc_set_irq() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt static caller functions. This cleans up after passing PowerPCCPU to kvmppc_set_interrupt(). Signed-off-by: Andreas Färber --- hw/ppc.c | 66 ++++++++++++++++++++++++++++++-------------------- hw/ppc.h | 2 +- hw/ppc_booke.c | 28 ++++++++++++++------- 3 files changed, 60 insertions(+), 36 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index e99a93db96..6db595f4e6 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -50,8 +50,9 @@ static void cpu_ppc_tb_stop (CPUPPCState *env); static void cpu_ppc_tb_start (CPUPPCState *env); -void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) { + CPUPPCState *env = &cpu->env; unsigned int old_pending = env->pending_interrupts; if (level) { @@ -65,7 +66,7 @@ void ppc_set_irq(CPUPPCState *env, int n_IRQ, int level) if (old_pending != env->pending_interrupts) { #ifdef CONFIG_KVM - kvmppc_set_interrupt(ppc_env_get_cpu(env), n_IRQ, level); + kvmppc_set_interrupt(cpu, n_IRQ, level); #endif } @@ -100,13 +101,13 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC6xx_INPUT_SMI: /* Level sensitive - active high */ LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_SMI, level); + ppc_set_irq(cpu, PPC_INTERRUPT_SMI, level); break; case PPC6xx_INPUT_MCP: /* Negative edge sensitive */ @@ -116,7 +117,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) if (cur_level == 1 && level == 0) { LOG_IRQ("%s: raise machine check state\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); } break; case PPC6xx_INPUT_CKSTP_IN: @@ -138,7 +139,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) case PPC6xx_INPUT_SRESET: LOG_IRQ("%s: set the RESET IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); break; default: /* Unknown pin - do nothing */ @@ -178,13 +179,13 @@ static void ppc970_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC970_INPUT_THINT: /* Level sensitive - active high */ LOG_IRQ("%s: set the SMI IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_THERM, level); + ppc_set_irq(cpu, PPC_INTERRUPT_THERM, level); break; case PPC970_INPUT_MCP: /* Negative edge sensitive */ @@ -194,7 +195,7 @@ static void ppc970_set_irq(void *opaque, int pin, int level) if (cur_level == 1 && level == 0) { LOG_IRQ("%s: raise machine check state\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, 1); } break; case PPC970_INPUT_CKSTP: @@ -218,7 +219,7 @@ static void ppc970_set_irq(void *opaque, int pin, int level) case PPC970_INPUT_SRESET: LOG_IRQ("%s: set the RESET IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_RESET, level); + ppc_set_irq(cpu, PPC_INTERRUPT_RESET, level); break; case PPC970_INPUT_TBEN: LOG_IRQ("%s: set the TBEN state to %d\n", __func__, @@ -259,7 +260,7 @@ static void power7_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; default: /* Unknown pin - do nothing */ @@ -319,13 +320,13 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the critical IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); break; case PPC40x_INPUT_INT: /* Level sensitive - active high */ LOG_IRQ("%s: set the external IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPC40x_INPUT_HALT: /* Level sensitive - active low */ @@ -342,7 +343,7 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) /* Level sensitive - active high */ LOG_IRQ("%s: set the debug pin state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */ @@ -387,26 +388,26 @@ static void ppce500_set_irq(void *opaque, int pin, int level) case PPCE500_INPUT_RESET_CORE: if (level) { LOG_IRQ("%s: reset the PowerPC core\n", __func__); - ppc_set_irq(env, PPC_INTERRUPT_MCK, level); + ppc_set_irq(cpu, PPC_INTERRUPT_MCK, level); } break; case PPCE500_INPUT_CINT: /* Level sensitive - active high */ LOG_IRQ("%s: set the critical IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_CEXT, level); break; case PPCE500_INPUT_INT: /* Level sensitive - active high */ LOG_IRQ("%s: set the core IRQ state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_EXT, level); + ppc_set_irq(cpu, PPC_INTERRUPT_EXT, level); break; case PPCE500_INPUT_DEBUG: /* Level sensitive - active high */ LOG_IRQ("%s: set the debug pin state to %d\n", __func__, level); - ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); + ppc_set_irq(cpu, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */ @@ -645,16 +646,20 @@ uint64_t cpu_ppc_load_purr (CPUPPCState *env) */ static inline void cpu_ppc_decr_excp(CPUPPCState *env) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + /* Raise it */ LOG_TB("raise decrementer exception\n"); - ppc_set_irq(env, PPC_INTERRUPT_DECR, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); } static inline void cpu_ppc_hdecr_excp(CPUPPCState *env) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + /* Raise it */ LOG_TB("raise decrementer exception\n"); - ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1); + ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); } static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp, @@ -829,12 +834,14 @@ struct ppc40x_timer_t { /* Fixed interval timer */ static void cpu_4xx_fit_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; uint64_t now, next; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; now = qemu_get_clock_ns(vm_clock); @@ -860,8 +867,9 @@ static void cpu_4xx_fit_cb (void *opaque) next++; qemu_mod_timer(ppc40x_timer->fit_timer, next); env->spr[SPR_40x_TSR] |= 1 << 26; - if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) - ppc_set_irq(env, PPC_INTERRUPT_FIT, 1); + if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1); + } LOG_TB("%s: ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx "\n", __func__, (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1), env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]); @@ -897,16 +905,19 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp) static void cpu_4xx_pit_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; env->spr[SPR_40x_TSR] |= 1 << 27; - if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) - ppc_set_irq(env, ppc40x_timer->decr_excp, 1); + if ((env->spr[SPR_40x_TCR] >> 26) & 0x1) { + ppc_set_irq(cpu, ppc40x_timer->decr_excp, 1); + } start_stop_pit(env, tb_env, 1); LOG_TB("%s: ar %d ir %d TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " " "%016" PRIx64 "\n", __func__, @@ -919,12 +930,14 @@ static void cpu_4xx_pit_cb (void *opaque) /* Watchdog timer */ static void cpu_4xx_wdt_cb (void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; ppc40x_timer_t *ppc40x_timer; uint64_t now, next; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; ppc40x_timer = tb_env->opaque; now = qemu_get_clock_ns(vm_clock); @@ -961,8 +974,9 @@ static void cpu_4xx_wdt_cb (void *opaque) qemu_mod_timer(ppc40x_timer->wdt_timer, next); ppc40x_timer->wdt_next = next; env->spr[SPR_40x_TSR] |= 1 << 30; - if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) - ppc_set_irq(env, PPC_INTERRUPT_WDT, 1); + if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) { + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, 1); + } break; case 0x3: env->spr[SPR_40x_TSR] &= ~0x30000000; diff --git a/hw/ppc.h b/hw/ppc.h index 2f3ea277bc..64463ad388 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -1,4 +1,4 @@ -void ppc_set_irq (CPUPPCState *env, int n_IRQ, int level); +void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level); /* PowerPC hardware exceptions management helpers */ typedef void (*clk_setup_cb)(void *opaque, uint32_t freq); diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index d51e7fad67..da6bc4a283 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -71,17 +71,19 @@ struct booke_timer_t { uint32_t flags; }; -static void booke_update_irq(CPUPPCState *env) +static void booke_update_irq(PowerPCCPU *cpu) { - ppc_set_irq(env, PPC_INTERRUPT_DECR, + CPUPPCState *env = &cpu->env; + + ppc_set_irq(cpu, PPC_INTERRUPT_DECR, (env->spr[SPR_BOOKE_TSR] & TSR_DIS && env->spr[SPR_BOOKE_TCR] & TCR_DIE)); - ppc_set_irq(env, PPC_INTERRUPT_WDT, + ppc_set_irq(cpu, PPC_INTERRUPT_WDT, (env->spr[SPR_BOOKE_TSR] & TSR_WIS && env->spr[SPR_BOOKE_TCR] & TCR_WIE)); - ppc_set_irq(env, PPC_INTERRUPT_FIT, + ppc_set_irq(cpu, PPC_INTERRUPT_FIT, (env->spr[SPR_BOOKE_TSR] & TSR_FIS && env->spr[SPR_BOOKE_TCR] & TCR_FIE)); } @@ -154,9 +156,10 @@ static void booke_update_fixed_timer(CPUPPCState *env, static void booke_decr_cb(void *opaque) { CPUPPCState *env = opaque; + PowerPCCPU *cpu = ppc_env_get_cpu(env); env->spr[SPR_BOOKE_TSR] |= TSR_DIS; - booke_update_irq(env); + booke_update_irq(cpu); if (env->spr[SPR_BOOKE_TCR] & TCR_ARE) { /* Auto Reload */ @@ -166,16 +169,18 @@ static void booke_decr_cb(void *opaque) static void booke_fit_cb(void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; booke_timer = tb_env->opaque; env->spr[SPR_BOOKE_TSR] |= TSR_FIS; - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_fit_target(env, tb_env), @@ -185,17 +190,19 @@ static void booke_fit_cb(void *opaque) static void booke_wdt_cb(void *opaque) { + PowerPCCPU *cpu; CPUPPCState *env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; env = opaque; + cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; booke_timer = tb_env->opaque; /* TODO: There's lots of complicated stuff to do here */ - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_wdt_target(env, tb_env), @@ -205,19 +212,22 @@ static void booke_wdt_cb(void *opaque) void store_booke_tsr(CPUPPCState *env, target_ulong val) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->spr[SPR_BOOKE_TSR] &= ~val; - booke_update_irq(env); + booke_update_irq(cpu); } void store_booke_tcr(CPUPPCState *env, target_ulong val) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env = env->tb_env; booke_timer_t *booke_timer = tb_env->opaque; tb_env = env->tb_env; env->spr[SPR_BOOKE_TCR] = val; - booke_update_irq(env); + booke_update_irq(cpu); booke_update_fixed_timer(env, booke_get_fit_target(env, tb_env), From 7e0a924734e7bfad7568bf57fec68bfecd5c2575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 04:18:02 +0100 Subject: [PATCH 0017/1634] ppc: Pass PowerPCCPU to [h]decr callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleans up after passing PowerPCCPU to ppc_set_irq(). Signed-off-by: Andreas Färber --- hw/ppc.c | 60 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 6db595f4e6..b1b93a1e7d 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -644,30 +644,27 @@ uint64_t cpu_ppc_load_purr (CPUPPCState *env) /* When decrementer expires, * all we need to do is generate or queue a CPU exception */ -static inline void cpu_ppc_decr_excp(CPUPPCState *env) +static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); - /* Raise it */ LOG_TB("raise decrementer exception\n"); ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1); } -static inline void cpu_ppc_hdecr_excp(CPUPPCState *env) +static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); - /* Raise it */ LOG_TB("raise decrementer exception\n"); ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); } -static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp, - struct QEMUTimer *timer, - void (*raise_excp)(CPUPPCState *), - uint32_t decr, uint32_t value, - int is_excp) +static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, + struct QEMUTimer *timer, + void (*raise_excp)(PowerPCCPU *), + uint32_t decr, uint32_t value, + int is_excp) { + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env = env->tb_env; uint64_t now, next; @@ -697,53 +694,61 @@ static void __cpu_ppc_store_decr (CPUPPCState *env, uint64_t *nextp, if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000) && !(decr & 0x80000000)) { - (*raise_excp)(env); + (*raise_excp)(cpu); } } -static inline void _cpu_ppc_store_decr(CPUPPCState *env, uint32_t decr, +static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr, uint32_t value, int is_excp) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; - __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer, + __cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer, &cpu_ppc_decr_excp, decr, value, is_excp); } void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value) { - _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0); } static void cpu_ppc_decr_cb (void *opaque) { - _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); + CPUPPCState *env = opaque; + + _cpu_ppc_store_decr(ppc_env_get_cpu(env), 0x00000000, 0xFFFFFFFF, 1); } -static inline void _cpu_ppc_store_hdecr(CPUPPCState *env, uint32_t hdecr, +static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr, uint32_t value, int is_excp) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; if (tb_env->hdecr_timer != NULL) { - __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer, + __cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer, &cpu_ppc_hdecr_excp, hdecr, value, is_excp); } } void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value) { - _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0); + PowerPCCPU *cpu = ppc_env_get_cpu(env); + + _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0); } static void cpu_ppc_hdecr_cb (void *opaque) { - _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1); + CPUPPCState *env = opaque; + + _cpu_ppc_store_hdecr(ppc_env_get_cpu(env), 0x00000000, 0xFFFFFFFF, 1); } -static void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) +static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) { - ppc_tb_t *tb_env = env->tb_env; + ppc_tb_t *tb_env = cpu->env.tb_env; tb_env->purr_load = value; tb_env->purr_start = qemu_get_clock_ns(vm_clock); @@ -752,6 +757,7 @@ static void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value) static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) { CPUPPCState *env = opaque; + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env = env->tb_env; tb_env->tb_freq = freq; @@ -760,9 +766,9 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) * if a decrementer exception is pending when it enables msr_ee at startup, * it's not ready to handle it... */ - _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - cpu_ppc_store_purr(env, 0x0000000000000000ULL); + _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0); + cpu_ppc_store_purr(cpu, 0x0000000000000000ULL); } /* Set up (once) timebase frequency (in Hz) */ From 50c680f06ca81aebc91ac4a325f194b2d8396721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 04:26:55 +0100 Subject: [PATCH 0018/1634] ppc: Pass PowerPCCPU to [h]decr timer callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleans up after passing PowerPCCPU to [h]decr exception callbacks. Signed-off-by: Andreas Färber --- hw/ppc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index b1b93a1e7d..8c05eb308d 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -714,11 +714,11 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value) _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0); } -static void cpu_ppc_decr_cb (void *opaque) +static void cpu_ppc_decr_cb(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; - _cpu_ppc_store_decr(ppc_env_get_cpu(env), 0x00000000, 0xFFFFFFFF, 1); + _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1); } static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr, @@ -739,11 +739,11 @@ void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value) _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0); } -static void cpu_ppc_hdecr_cb (void *opaque) +static void cpu_ppc_hdecr_cb(void *opaque) { - CPUPPCState *env = opaque; + PowerPCCPU *cpu = opaque; - _cpu_ppc_store_hdecr(ppc_env_get_cpu(env), 0x00000000, 0xFFFFFFFF, 1); + _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1); } static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value) @@ -774,17 +774,19 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq) /* Set up (once) timebase frequency (in Hz) */ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env; tb_env = g_malloc0(sizeof(ppc_tb_t)); env->tb_env = tb_env; tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED; /* Create new timer */ - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, env); + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu); if (0) { /* XXX: find a suitable condition to enable the hypervisor decrementer */ - tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, env); + tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb, + cpu); } else { tb_env->hdecr_timer = NULL; } From ee0c98e650da0ce1e4e17dc1e2bbb946cde2c45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 04:35:15 +0100 Subject: [PATCH 0019/1634] ppc_booke: Pass PowerPCCPU to {decr,fit,wdt} timer callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleans up after passing PowerPCCPU to booke_update_irq(). Signed-off-by: Andreas Färber --- hw/ppc_booke.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index da6bc4a283..5748063f45 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -155,8 +155,8 @@ static void booke_update_fixed_timer(CPUPPCState *env, static void booke_decr_cb(void *opaque) { - CPUPPCState *env = opaque; - PowerPCCPU *cpu = ppc_env_get_cpu(env); + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; env->spr[SPR_BOOKE_TSR] |= TSR_DIS; booke_update_irq(cpu); @@ -169,13 +169,11 @@ static void booke_decr_cb(void *opaque) static void booke_fit_cb(void *opaque) { - PowerPCCPU *cpu; - CPUPPCState *env; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; - env = opaque; - cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; booke_timer = tb_env->opaque; env->spr[SPR_BOOKE_TSR] |= TSR_FIS; @@ -190,13 +188,11 @@ static void booke_fit_cb(void *opaque) static void booke_wdt_cb(void *opaque) { - PowerPCCPU *cpu; - CPUPPCState *env; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; ppc_tb_t *tb_env; booke_timer_t *booke_timer; - env = opaque; - cpu = ppc_env_get_cpu(env); tb_env = env->tb_env; booke_timer = tb_env->opaque; @@ -243,6 +239,7 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env; booke_timer_t *booke_timer; @@ -255,10 +252,10 @@ void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags) tb_env->tb_freq = freq; tb_env->decr_freq = freq; tb_env->opaque = booke_timer; - tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, env); + tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu); booke_timer->fit_timer = - qemu_new_timer_ns(vm_clock, &booke_fit_cb, env); + qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); booke_timer->wdt_timer = - qemu_new_timer_ns(vm_clock, &booke_wdt_cb, env); + qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); } From 2f9859fb49cb3c6ec876bc0bf709f28afcdd2384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 04:47:33 +0100 Subject: [PATCH 0020/1634] ppc4xx_devs: Return PowerPCCPU from ppc4xx_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares for passing PowerPCCPU to ppc_booke_timers_init(). Signed-off-by: Andreas Färber --- hw/ppc405_uc.c | 8 ++++++-- hw/ppc4xx.h | 6 +++--- hw/ppc4xx_devs.c | 8 ++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 0f458ef772..373b8f3324 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -2111,12 +2111,14 @@ CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem, { clk_setup_t clk_setup[PPC405CR_CLK_NB]; qemu_irq dma_irqs[4]; + PowerPCCPU *cpu; CPUPPCState *env; qemu_irq *pic, *irqs; memset(clk_setup, 0, sizeof(clk_setup)); - env = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], + cpu = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK], &clk_setup[PPC405CR_TMR_CLK], sysclk); + env = &cpu->env; /* Memory mapped devices registers */ /* PLB arbitrer */ ppc4xx_plb_init(env); @@ -2460,13 +2462,15 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, { clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup; qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4]; + PowerPCCPU *cpu; CPUPPCState *env; qemu_irq *pic, *irqs; memset(clk_setup, 0, sizeof(clk_setup)); /* init CPUs */ - env = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], + cpu = ppc4xx_init("405ep", &clk_setup[PPC405EP_CPU_CLK], &tlb_clk_setup, sysclk); + env = &cpu->env; clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb; clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque; /* Internal devices init */ diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index d795ced57e..5d891aeae6 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -28,9 +28,9 @@ #include "pci.h" /* PowerPC 4xx core initialization */ -CPUPPCState *ppc4xx_init (const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk); +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk); /* PowerPC 4xx universal interrupt controller */ enum { diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index bac8d8769a..761cb595ae 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -47,9 +47,9 @@ static void ppc4xx_reset(void *opaque) /*****************************************************************************/ /* Generic PowerPC 4xx processor instantiation */ -CPUPPCState *ppc4xx_init (const char *cpu_model, - clk_setup_t *cpu_clk, clk_setup_t *tb_clk, - uint32_t sysclk) +PowerPCCPU *ppc4xx_init(const char *cpu_model, + clk_setup_t *cpu_clk, clk_setup_t *tb_clk, + uint32_t sysclk) { PowerPCCPU *cpu; CPUPPCState *env; @@ -72,7 +72,7 @@ CPUPPCState *ppc4xx_init (const char *cpu_model, /* Register qemu callbacks */ qemu_register_reset(ppc4xx_reset, cpu); - return env; + return cpu; } /*****************************************************************************/ From a34a92b9ecd8d25bd1de9df601ed31ccd8ebcae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 04:43:18 +0100 Subject: [PATCH 0021/1634] ppc_booke: Pass PowerPCCPU to ppc_booke_timers_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleans up after passing PowerPCCPU to timer callbacks. Signed-off-by: Andreas Färber --- hw/ppc.h | 2 +- hw/ppc/e500.c | 2 +- hw/ppc405_uc.c | 2 +- hw/ppc440_bamboo.c | 2 +- hw/ppc_booke.c | 5 ++--- hw/virtex_ml507.c | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/ppc.h b/hw/ppc.h index 64463ad388..ec33f9c6b9 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -89,4 +89,4 @@ enum { #define PPC_SERIAL_MM_BAUDBASE 399193 /* ppc_booke.c */ -void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags); +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags); diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index af6b67143a..55923595ca 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -495,7 +495,7 @@ void ppce500_init(PPCE500Params *params) env->mpic_cpu_base = MPC8544_CCSRBAR_BASE + MPC8544_MPIC_REGS_OFFSET + 0x20000; - ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500); + ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); /* Register reset handler */ if (!i) { diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 373b8f3324..fe71784cdc 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -2482,7 +2482,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, /* OBP arbitrer */ ppc4xx_opba_init(0xef600600); /* Initialize timers */ - ppc_booke_timers_init(env, sysclk, 0); + ppc_booke_timers_init(cpu, sysclk, 0); /* Universal interrupt controller */ irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); irqs[PPCUIC_OUTPUT_INT] = diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index cc85607cb7..d9f0f81d62 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -195,7 +195,7 @@ static void bamboo_init(QEMUMachineInitArgs *args) env = &cpu->env; qemu_register_reset(main_cpu_reset, cpu); - ppc_booke_timers_init(env, 400000000, 0); + ppc_booke_timers_init(cpu, 400000000, 0); ppc_dcr_init(env, NULL, NULL); /* interrupt controller */ diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index 5748063f45..f2c0409f94 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -237,16 +237,15 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) } -void ppc_booke_timers_init(CPUPPCState *env, uint32_t freq, uint32_t flags) +void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); ppc_tb_t *tb_env; booke_timer_t *booke_timer; tb_env = g_malloc0(sizeof(ppc_tb_t)); booke_timer = g_malloc0(sizeof(booke_timer_t)); - env->tb_env = tb_env; + cpu->env.tb_env = tb_env; tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED; tb_env->tb_freq = freq; diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 6ab8fee0c1..1a19cd2d08 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -94,7 +94,7 @@ static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size, } env = &cpu->env; - ppc_booke_timers_init(env, sysclk, 0/* no flags */); + ppc_booke_timers_init(cpu, sysclk, 0/* no flags */); ppc_dcr_init(env, NULL, NULL); From a60f24b56b07f46453424263b276b0879c25c4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 05:35:08 +0100 Subject: [PATCH 0022/1634] cpu: Move kvm_state field into CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt some functions to take CPUState / {PowerPC,S390}CPU argument. Signed-off-by: Andreas Färber --- cpu-defs.h | 2 -- include/qemu/cpu.h | 3 +++ kvm-all.c | 28 ++++++++++++++-------------- kvm.h | 4 ++-- target-i386/cpu.c | 7 +++++-- target-i386/kvm.c | 22 +++++++++++----------- target-ppc/kvm.c | 33 ++++++++++++++++++++------------- target-s390x/kvm.c | 5 ++--- 8 files changed, 57 insertions(+), 47 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index a382e35248..9ed54cf444 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -135,7 +135,6 @@ typedef struct icount_decr_u16 { #endif struct kvm_run; -struct KVMState; struct qemu_work_item; typedef struct CPUBreakpoint { @@ -205,7 +204,6 @@ typedef struct CPUWatchpoint { void *opaque; \ \ const char *cpu_model_str; \ - struct KVMState *kvm_state; \ struct kvm_run *kvm_run; #endif diff --git a/include/qemu/cpu.h b/include/qemu/cpu.h index b8f8dd1d13..03962eff69 100644 --- a/include/qemu/cpu.h +++ b/include/qemu/cpu.h @@ -52,6 +52,8 @@ typedef struct CPUClass { void (*reset)(CPUState *cpu); } CPUClass; +struct KVMState; + /** * CPUState: * @created: Indicates whether the CPU thread has been successfully created. @@ -82,6 +84,7 @@ struct CPUState { int kvm_fd; bool kvm_vcpu_dirty; #endif + struct KVMState *kvm_state; /* TODO Move common fields from CPUArchState here. */ }; diff --git a/kvm-all.c b/kvm-all.c index 5f1d1fed2c..ba139ab13c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -230,7 +230,7 @@ int kvm_init_vcpu(CPUArchState *env) } cpu->kvm_fd = ret; - env->kvm_state = s; + cpu->kvm_state = s; cpu->kvm_vcpu_dirty = true; mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); @@ -1763,12 +1763,12 @@ void kvm_setup_guest_memory(void *start, size_t size) } #ifdef KVM_CAP_SET_GUEST_DEBUG -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, target_ulong pc) { struct kvm_sw_breakpoint *bp; - QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) { + QTAILQ_FOREACH(bp, &cpu->kvm_state->kvm_sw_breakpoints, entry) { if (bp->pc == pc) { return bp; } @@ -1776,23 +1776,23 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, return NULL; } -int kvm_sw_breakpoints_active(CPUArchState *env) +int kvm_sw_breakpoints_active(CPUState *cpu) { - return !QTAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints); + return !QTAILQ_EMPTY(&cpu->kvm_state->kvm_sw_breakpoints); } struct kvm_set_guest_debug_data { struct kvm_guest_debug dbg; - CPUArchState *env; + CPUState *cpu; int err; }; static void kvm_invoke_set_guest_debug(void *data) { struct kvm_set_guest_debug_data *dbg_data = data; - CPUState *cpu = ENV_GET_CPU(dbg_data->env); - dbg_data->err = kvm_vcpu_ioctl(cpu, KVM_SET_GUEST_DEBUG, &dbg_data->dbg); + dbg_data->err = kvm_vcpu_ioctl(dbg_data->cpu, KVM_SET_GUEST_DEBUG, + &dbg_data->dbg); } int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) @@ -1806,7 +1806,7 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap) data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; } kvm_arch_update_guest_debug(cpu, &data.dbg); - data.env = env; + data.cpu = cpu; run_on_cpu(cpu, kvm_invoke_set_guest_debug, &data); return data.err; @@ -1821,7 +1821,7 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, int err; if (type == GDB_BREAKPOINT_SW) { - bp = kvm_find_sw_breakpoint(current_env, addr); + bp = kvm_find_sw_breakpoint(current_cpu, addr); if (bp) { bp->use_count++; return 0; @@ -1840,7 +1840,7 @@ int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr, return err; } - QTAILQ_INSERT_HEAD(¤t_env->kvm_state->kvm_sw_breakpoints, + QTAILQ_INSERT_HEAD(¤t_cpu->kvm_state->kvm_sw_breakpoints, bp, entry); } else { err = kvm_arch_insert_hw_breakpoint(addr, len, type); @@ -1867,7 +1867,7 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, int err; if (type == GDB_BREAKPOINT_SW) { - bp = kvm_find_sw_breakpoint(current_env, addr); + bp = kvm_find_sw_breakpoint(current_cpu, addr); if (!bp) { return -ENOENT; } @@ -1882,7 +1882,7 @@ int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr, return err; } - QTAILQ_REMOVE(¤t_env->kvm_state->kvm_sw_breakpoints, bp, entry); + QTAILQ_REMOVE(¤t_cpu->kvm_state->kvm_sw_breakpoints, bp, entry); g_free(bp); } else { err = kvm_arch_remove_hw_breakpoint(addr, len, type); @@ -1904,7 +1904,7 @@ void kvm_remove_all_breakpoints(CPUArchState *current_env) { CPUState *current_cpu = ENV_GET_CPU(current_env); struct kvm_sw_breakpoint *bp, *next; - KVMState *s = current_env->kvm_state; + KVMState *s = current_cpu->kvm_state; CPUArchState *env; CPUState *cpu; diff --git a/kvm.h b/kvm.h index a2375ff469..6ddcdc5e8b 100644 --- a/kvm.h +++ b/kvm.h @@ -207,10 +207,10 @@ struct kvm_sw_breakpoint { QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint); -struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUArchState *env, +struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, target_ulong pc); -int kvm_sw_breakpoints_active(CPUArchState *env); +int kvm_sw_breakpoints_active(CPUState *cpu); int kvm_arch_insert_sw_breakpoint(CPUState *current_cpu, struct kvm_sw_breakpoint *bp); diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 7be3ad82cb..04a90c5e21 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1636,6 +1636,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { + X86CPU *cpu = x86_env_get_cpu(env); + CPUState *cs = CPU(cpu); + /* test if maximum index reached */ if (index & 0x80000000) { if (index > env->cpuid_xlevel) { @@ -1752,7 +1755,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, case 0xA: /* Architectural Performance Monitoring Leaf */ if (kvm_enabled()) { - KVMState *s = env->kvm_state; + KVMState *s = cs->kvm_state; *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); @@ -1775,7 +1778,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; } if (kvm_enabled()) { - KVMState *s = env->kvm_state; + KVMState *s = cs->kvm_state; *eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX); *ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index b2efa1e928..ff5c9cd1cd 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -316,7 +316,7 @@ int kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr) if ((env->mcg_cap & MCG_SER_P) && addr && (code == BUS_MCEERR_AR || code == BUS_MCEERR_AO)) { if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_host(env->kvm_state, addr, &paddr)) { + !kvm_physical_memory_addr_from_host(c->kvm_state, addr, &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!\n"); /* Hope we are lucky for AO MCE */ @@ -348,8 +348,8 @@ int kvm_arch_on_sigbus(int code, void *addr) /* Hope we are lucky for AO MCE */ if (qemu_ram_addr_from_host(addr, &ram_addr) || - !kvm_physical_memory_addr_from_host(first_cpu->kvm_state, addr, - &paddr)) { + !kvm_physical_memory_addr_from_host(CPU(first_cpu)->kvm_state, + addr, &paddr)) { fprintf(stderr, "Hardware memory error for memory used by " "QEMU itself instead of guest system!: %p\n", addr); return 0; @@ -579,12 +579,12 @@ int kvm_arch_init_vcpu(CPUState *cs) if (((env->cpuid_version >> 8)&0xF) >= 6 && (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA) - && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) { + && kvm_check_extension(cs->kvm_state, KVM_CAP_MCE) > 0) { uint64_t mcg_cap; int banks; int ret; - ret = kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks); + ret = kvm_get_mce_cap_supported(cs->kvm_state, &mcg_cap, &banks); if (ret < 0) { fprintf(stderr, "kvm_get_mce_cap_supported: %s", strerror(-ret)); return ret; @@ -612,7 +612,7 @@ int kvm_arch_init_vcpu(CPUState *cs) return r; } - r = kvm_check_extension(env->kvm_state, KVM_CAP_TSC_CONTROL); + r = kvm_check_extension(cs->kvm_state, KVM_CAP_TSC_CONTROL); if (r && env->tsc_khz) { r = kvm_vcpu_ioctl(cs, KVM_SET_TSC_KHZ, env->tsc_khz); if (r < 0) { @@ -1977,9 +1977,10 @@ void kvm_arch_remove_all_hw_breakpoints(void) static CPUWatchpoint hw_watchpoint; -static int kvm_handle_debug(CPUX86State *env, +static int kvm_handle_debug(X86CPU *cpu, struct kvm_debug_exit_arch *arch_info) { + CPUX86State *env = &cpu->env; int ret = 0; int n; @@ -2011,7 +2012,7 @@ static int kvm_handle_debug(CPUX86State *env, } } } - } else if (kvm_find_sw_breakpoint(env, arch_info->pc)) { + } else if (kvm_find_sw_breakpoint(CPU(cpu), arch_info->pc)) { ret = EXCP_DEBUG; } if (ret == 0) { @@ -2028,7 +2029,6 @@ static int kvm_handle_debug(CPUX86State *env, void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) { - CPUX86State *env = &X86_CPU(cpu)->env; const uint8_t type_code[] = { [GDB_BREAKPOINT_HW] = 0x0, [GDB_WATCHPOINT_WRITE] = 0x1, @@ -2039,7 +2039,7 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg) }; int n; - if (kvm_sw_breakpoints_active(env)) { + if (kvm_sw_breakpoints_active(cpu)) { dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; } if (nb_hw_breakpoint > 0) { @@ -2106,7 +2106,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) break; case KVM_EXIT_DEBUG: DPRINTF("kvm_exit_debug\n"); - ret = kvm_handle_debug(env, &run->debug.arch); + ret = kvm_handle_debug(cpu, &run->debug.arch); break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index ad5bc66396..eb52b76bdc 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -140,7 +140,7 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu) int ret, i; if (!kvm_enabled() || - !kvm_check_extension(env->kvm_state, KVM_CAP_SW_TLB)) { + !kvm_check_extension(cs->kvm_state, KVM_CAP_SW_TLB)) { return 0; } @@ -178,9 +178,12 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu) #if defined(TARGET_PPC64) -static void kvm_get_fallback_smmu_info(CPUPPCState *env, +static void kvm_get_fallback_smmu_info(PowerPCCPU *cpu, struct kvm_ppc_smmu_info *info) { + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); + memset(info, 0, sizeof(*info)); /* We don't have the new KVM_PPC_GET_SMMU_INFO ioctl, so @@ -206,7 +209,7 @@ static void kvm_get_fallback_smmu_info(CPUPPCState *env, * implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit * this fallback. */ - if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO)) { /* No flags */ info->flags = 0; info->slb_size = 64; @@ -262,18 +265,19 @@ static void kvm_get_fallback_smmu_info(CPUPPCState *env, } } -static void kvm_get_smmu_info(CPUPPCState *env, struct kvm_ppc_smmu_info *info) +static void kvm_get_smmu_info(PowerPCCPU *cpu, struct kvm_ppc_smmu_info *info) { + CPUState *cs = CPU(cpu); int ret; - if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_SMMU_INFO)) { - ret = kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_SMMU_INFO, info); + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_SMMU_INFO)) { + ret = kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_SMMU_INFO, info); if (ret == 0) { return; } } - kvm_get_fallback_smmu_info(env, info); + kvm_get_fallback_smmu_info(cpu, info); } static long getrampagesize(void) @@ -316,10 +320,11 @@ static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift) return (1ul << shift) <= rampgsize; } -static void kvm_fixup_page_sizes(CPUPPCState *env) +static void kvm_fixup_page_sizes(PowerPCCPU *cpu) { static struct kvm_ppc_smmu_info smmu_info; static bool has_smmu_info; + CPUPPCState *env = &cpu->env; long rampagesize; int iq, ik, jq, jk; @@ -330,7 +335,7 @@ static void kvm_fixup_page_sizes(CPUPPCState *env) /* Collect MMU info from kernel if not already */ if (!has_smmu_info) { - kvm_get_smmu_info(env, &smmu_info); + kvm_get_smmu_info(cpu, &smmu_info); has_smmu_info = true; } @@ -373,7 +378,7 @@ static void kvm_fixup_page_sizes(CPUPPCState *env) } #else /* defined (TARGET_PPC64) */ -static inline void kvm_fixup_page_sizes(CPUPPCState *env) +static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu) { } @@ -386,7 +391,7 @@ int kvm_arch_init_vcpu(CPUState *cs) int ret; /* Gather server mmu info from KVM and update the CPU state */ - kvm_fixup_page_sizes(cenv); + kvm_fixup_page_sizes(cpu); /* Synchronize sregs with kvm */ ret = kvm_arch_sync_sregs(cpu); @@ -986,12 +991,14 @@ uint32_t kvmppc_get_dfp(void) int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); uint32_t *hc = (uint32_t*)buf; struct kvm_ppc_pvinfo pvinfo; - if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO) && - !kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) { + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) && + !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) { memcpy(buf, pvinfo.hcall, buf_len); return 0; diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 5422678330..4e343041fa 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -291,12 +291,11 @@ int kvm_arch_process_async_events(CPUState *cs) void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm) { - CPUS390XState *env = &cpu->env; CPUState *cs = CPU(cpu); struct kvm_s390_interrupt kvmint; int r; - if (!env->kvm_state) { + if (!cs->kvm_state) { return; } @@ -305,7 +304,7 @@ void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, kvmint.parm64 = parm64; if (vm) { - r = kvm_vm_ioctl(env->kvm_state, KVM_S390_INTERRUPT, &kvmint); + r = kvm_vm_ioctl(cs->kvm_state, KVM_S390_INTERRUPT, &kvmint); } else { r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint); } From f7575c96c6058763fe3bd8dd26f3d09473f2df36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 1 Dec 2012 06:18:14 +0100 Subject: [PATCH 0023/1634] cpu: Move kvm_run into CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass CPUState / {X86,S390}CPU to helper functions. Signed-off-by: Andreas Färber --- cpu-defs.h | 4 +-- include/qemu/cpu.h | 2 ++ kvm-all.c | 8 ++--- target-i386/kvm.c | 9 +++--- target-s390x/kvm.c | 77 ++++++++++++++++++++++++---------------------- 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 9ed54cf444..caea72b5be 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -134,7 +134,6 @@ typedef struct icount_decr_u16 { } icount_decr_u16; #endif -struct kvm_run; struct qemu_work_item; typedef struct CPUBreakpoint { @@ -203,7 +202,6 @@ typedef struct CPUWatchpoint { /* user data */ \ void *opaque; \ \ - const char *cpu_model_str; \ - struct kvm_run *kvm_run; + const char *cpu_model_str; #endif diff --git a/include/qemu/cpu.h b/include/qemu/cpu.h index 03962eff69..fa3ffdbc2a 100644 --- a/include/qemu/cpu.h +++ b/include/qemu/cpu.h @@ -53,6 +53,7 @@ typedef struct CPUClass { } CPUClass; struct KVMState; +struct kvm_run; /** * CPUState: @@ -85,6 +86,7 @@ struct CPUState { bool kvm_vcpu_dirty; #endif struct KVMState *kvm_state; + struct kvm_run *kvm_run; /* TODO Move common fields from CPUArchState here. */ }; diff --git a/kvm-all.c b/kvm-all.c index ba139ab13c..f687229da8 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -240,9 +240,9 @@ int kvm_init_vcpu(CPUArchState *env) goto err; } - env->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, + cpu->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, cpu->kvm_fd, 0); - if (env->kvm_run == MAP_FAILED) { + if (cpu->kvm_run == MAP_FAILED) { ret = -errno; DPRINTF("mmap'ing vcpu state failed\n"); goto err; @@ -250,7 +250,7 @@ int kvm_init_vcpu(CPUArchState *env) if (s->coalesced_mmio && !s->coalesced_mmio_ring) { s->coalesced_mmio_ring = - (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE; + (void *)cpu->kvm_run + s->coalesced_mmio * PAGE_SIZE; } ret = kvm_arch_init_vcpu(cpu); @@ -1529,7 +1529,7 @@ void kvm_cpu_synchronize_post_init(CPUArchState *env) int kvm_cpu_exec(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); - struct kvm_run *run = env->kvm_run; + struct kvm_run *run = cpu->kvm_run; int ret, run_ret; DPRINTF("kvm_cpu_exec()\n"); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index ff5c9cd1cd..53096c97b4 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1859,9 +1859,11 @@ static int kvm_handle_halt(X86CPU *cpu) return 0; } -static int kvm_handle_tpr_access(CPUX86State *env) +static int kvm_handle_tpr_access(X86CPU *cpu) { - struct kvm_run *run = env->kvm_run; + CPUX86State *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct kvm_run *run = cs->kvm_run; apic_handle_tpr_access_report(env->apic_state, run->tpr_access.rip, run->tpr_access.is_write ? TPR_ACCESS_WRITE @@ -2067,7 +2069,6 @@ static bool host_supports_vmx(void) int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; uint64_t code; int ret; @@ -2080,7 +2081,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ret = 0; break; case KVM_EXIT_TPR_ACCESS: - ret = kvm_handle_tpr_access(env); + ret = kvm_handle_tpr_access(cpu); break; case KVM_EXIT_FAIL_ENTRY: code = run->fail_entry.hardware_entry_failure_reason; diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 4e343041fa..0b640928fc 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -98,13 +98,13 @@ int kvm_arch_put_registers(CPUState *cs, int level) int i; /* always save the PSW and the GPRS*/ - env->kvm_run->psw_addr = env->psw.addr; - env->kvm_run->psw_mask = env->psw.mask; + cs->kvm_run->psw_addr = env->psw.addr; + cs->kvm_run->psw_mask = env->psw.mask; - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { for (i = 0; i < 16; i++) { - env->kvm_run->s.regs.gprs[i] = env->regs[i]; - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS; + cs->kvm_run->s.regs.gprs[i] = env->regs[i]; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS; } } else { for (i = 0; i < 16; i++) { @@ -122,14 +122,14 @@ int kvm_arch_put_registers(CPUState *cs, int level) } if (cap_sync_regs && - env->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && - env->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { + cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && + cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { for (i = 0; i < 16; i++) { - env->kvm_run->s.regs.acrs[i] = env->aregs[i]; - env->kvm_run->s.regs.crs[i] = env->cregs[i]; + cs->kvm_run->s.regs.acrs[i] = env->aregs[i]; + cs->kvm_run->s.regs.crs[i] = env->cregs[i]; } - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS; - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS; } else { for (i = 0; i < 16; i++) { sregs.acrs[i] = env->aregs[i]; @@ -142,9 +142,9 @@ int kvm_arch_put_registers(CPUState *cs, int level) } /* Finally the prefix */ - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { - env->kvm_run->s.regs.prefix = env->psa; - env->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX; + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { + cs->kvm_run->s.regs.prefix = env->psa; + cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX; } else { /* prefix is only supported via sync regs */ } @@ -161,13 +161,13 @@ int kvm_arch_get_registers(CPUState *cs) int i; /* get the PSW */ - env->psw.addr = env->kvm_run->psw_addr; - env->psw.mask = env->kvm_run->psw_mask; + env->psw.addr = cs->kvm_run->psw_addr; + env->psw.mask = cs->kvm_run->psw_mask; /* the GPRS */ - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_GPRS) { for (i = 0; i < 16; i++) { - env->regs[i] = env->kvm_run->s.regs.gprs[i]; + env->regs[i] = cs->kvm_run->s.regs.gprs[i]; } } else { ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s); @@ -181,11 +181,11 @@ int kvm_arch_get_registers(CPUState *cs) /* The ACRS and CRS */ if (cap_sync_regs && - env->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && - env->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { + cs->kvm_run->kvm_valid_regs & KVM_SYNC_ACRS && + cs->kvm_run->kvm_valid_regs & KVM_SYNC_CRS) { for (i = 0; i < 16; i++) { - env->aregs[i] = env->kvm_run->s.regs.acrs[i]; - env->cregs[i] = env->kvm_run->s.regs.crs[i]; + env->aregs[i] = cs->kvm_run->s.regs.acrs[i]; + env->cregs[i] = cs->kvm_run->s.regs.crs[i]; } } else { ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); @@ -199,8 +199,8 @@ int kvm_arch_get_registers(CPUState *cs) } /* Finally the prefix */ - if (cap_sync_regs && env->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { - env->psa = env->kvm_run->s.regs.prefix; + if (cap_sync_regs && cs->kvm_run->kvm_valid_regs & KVM_SYNC_PREFIX) { + env->psa = cs->kvm_run->s.regs.prefix; } else { /* no prefix without sync regs */ } @@ -331,10 +331,13 @@ static void enter_pgmcheck(S390CPU *cpu, uint16_t code) kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code); } -static inline void setcc(CPUS390XState *env, uint64_t cc) +static inline void setcc(S390CPU *cpu, uint64_t cc) { - env->kvm_run->psw_mask &= ~(3ull << 44); - env->kvm_run->psw_mask |= (cc & 3) << 44; + CPUS390XState *env = &cpu->env; + CPUState *cs = CPU(cpu); + + cs->kvm_run->psw_mask &= ~(3ull << 44); + cs->kvm_run->psw_mask |= (cc & 3) << 44; env->psw.mask &= ~(3ul << 44); env->psw.mask |= (cc & 3) << 44; @@ -356,7 +359,7 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, if (r < 0) { enter_pgmcheck(cpu, -r); } - setcc(env, r); + setcc(cpu, r); return 0; } @@ -446,8 +449,9 @@ static int s390_cpu_initial_reset(S390CPU *cpu) return 0; } -static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) +static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) { + CPUS390XState *env = &cpu->env; uint8_t order_code; uint32_t parameter; uint16_t cpu_addr; @@ -499,7 +503,7 @@ static int handle_sigp(CPUS390XState *env, struct kvm_run *run, uint8_t ipa1) } out: - setcc(env, r ? 3 : 0); + setcc(cpu, r ? 3 : 0); return 0; } @@ -520,7 +524,7 @@ static int handle_instruction(S390CPU *cpu, struct kvm_run *run) r = handle_diag(env, run, ipb_code); break; case IPA0_SIGP: - r = handle_sigp(env, run, ipa1); + r = handle_sigp(cpu, run, ipa1); break; } @@ -530,28 +534,29 @@ static int handle_instruction(S390CPU *cpu, struct kvm_run *run) return 0; } -static bool is_special_wait_psw(CPUS390XState *env) +static bool is_special_wait_psw(CPUState *cs) { /* signal quiesce */ - return env->kvm_run->psw_addr == 0xfffUL; + return cs->kvm_run->psw_addr == 0xfffUL; } static int handle_intercept(S390CPU *cpu) { CPUS390XState *env = &cpu->env; - struct kvm_run *run = env->kvm_run; + CPUState *cs = CPU(cpu); + struct kvm_run *run = cs->kvm_run; int icpt_code = run->s390_sieic.icptcode; int r = 0; dprintf("intercept: 0x%x (at 0x%lx)\n", icpt_code, - (long)env->kvm_run->psw_addr); + (long)cs->kvm_run->psw_addr); switch (icpt_code) { case ICPT_INSTRUCTION: r = handle_instruction(cpu, run); break; case ICPT_WAITPSW: if (s390_del_running_cpu(env) == 0 && - is_special_wait_psw(env)) { + is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } r = EXCP_HALTED; From 62e0c095450f6a7eb37914991f3f7966aa4da7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 9 Dec 2012 20:15:31 +0100 Subject: [PATCH 0024/1634] MAINTAINERS: Include X86CPU in CPU maintenance area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document that the x86 CPU refactorings are going through the qom-cpu tree. This does not contradict the established practice that patches adding KVM features to the x86 CPU go through the KVM maintainers, it merely takes it out of target-i386 TCG's Odd Fixes status. Signed-off-by: Andreas Färber Cc: Marcello Tosatti --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2ede20d60b..61d5a4b009 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -599,6 +599,7 @@ M: Andreas Färber S: Supported F: qom/cpu.c F: include/qemu/cpu.h +F: target-i386/cpu.c Device Tree M: Peter Crosthwaite From 15faf946f7a17a5fab0d05a2312d43249d81af3c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 20 Dec 2012 08:19:16 +0100 Subject: [PATCH 0025/1634] Update seabios to a810e4e72a0d42c7bc04eda57382f8e019add901 git shortlog: Kevin O'Connor (6): floppy: Minor - reduce handle_0e code size when CONFIG_FLOPPY is disabled. vga: Minor comment spelling fix. Don't recursively evaluate CFLAGS variables. Don't use gcc's -combine option. Add compile checking phase to build. acpi: Use prt_slot() macro to describe irq pins of first PCI device. Laszlo Ersek (1): maininit(): print machine UUID under seabios version message Paolo Bonzini (1): acpi: reintroduce LNKS Paolo's patch fixes the FreeBSD boot failure. Cc: qemu-stable@nongnu.org Signed-off-by: Gerd Hoffmann --- pc-bios/acpi-dsdt.aml | Bin 4438 -> 4521 bytes pc-bios/bios.bin | Bin 262144 -> 131072 bytes pc-bios/q35-acpi-dsdt.aml | Bin 7458 -> 7458 bytes roms/seabios | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/acpi-dsdt.aml b/pc-bios/acpi-dsdt.aml index 18b4dc1aa53859593604abe598b05784b116a360..00224eabb7b92de601edc5cc41b444c4ca8cb9da 100644 GIT binary patch delta 175 zcmcbnv{G5wCDSOQWD P6bcRsX54(9znu{PZH*~z delta 91 zcmZ3fd`(H&CD*ruv5H% qYe|5!rvXQNKv0N~=VTo=Q*Le+p8x+rs<}8f=dmSoZdMX#X9NHb#TIb@ diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 3eefff4cf81a37e0cbd20d3cf0da7b2dd11c34d5..3910875311ceaed814f902e9e4e7e29cdf340fc6 100644 GIT binary patch delta 44263 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

TuRymwO&F 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 diff --git a/pc-bios/q35-acpi-dsdt.aml b/pc-bios/q35-acpi-dsdt.aml index 8a5055951485d7b14ba44e6c99ecd32bf1ad446e..e50641cc53416c14133bfc7ae48f35fb14116781 100644 GIT binary patch delta 44 xcmZ2vwa7}@CDu{v{CuL3;^NE3DN)n diff --git a/roms/seabios b/roms/seabios index e8a76b0f22..a810e4e72a 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit e8a76b0f225bba5ba9d63ab227e0a37b3beb1059 +Subproject commit a810e4e72a0d42c7bc04eda57382f8e019add901 From d2a0ccc613ccc48c7240f99e1ce05e0acce6e2a1 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 17 Dec 2012 13:01:07 +0200 Subject: [PATCH 0026/1634] virtio: make bindings typesafe Move bindings from opaque to DeviceState. This gives us better type safety with no performance cost. Add macros to make future QOM work easier. Signed-off-by: Michael S. Tsirkin --- hw/s390-virtio-bus.c | 24 ++++++++++++---- hw/virtio-pci.c | 67 ++++++++++++++++++++++++++------------------ hw/virtio.c | 2 +- hw/virtio.h | 26 ++++++++--------- 4 files changed, 73 insertions(+), 46 deletions(-) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 963b4f0dc2..84fba9674c 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -136,7 +136,7 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) bus->dev_offs += dev_len; - virtio_bind_device(vdev, &virtio_s390_bindings, dev); + virtio_bind_device(vdev, &virtio_s390_bindings, DEVICE(dev)); dev->host_features = vdev->get_features(vdev, dev->host_features); s390_virtio_device_sync(dev); s390_virtio_reset_idx(dev); @@ -363,9 +363,23 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem) return NULL; } -static void virtio_s390_notify(void *opaque, uint16_t vector) +/* DeviceState to VirtIOS390Device. Note: used on datapath, + * be careful and test performance if you change this. + */ +static inline VirtIOS390Device *to_virtio_s390_device_fast(DeviceState *d) { - VirtIOS390Device *dev = (VirtIOS390Device*)opaque; + return container_of(d, VirtIOS390Device, qdev); +} + +/* DeviceState to VirtIOS390Device. TODO: use QOM. */ +static inline VirtIOS390Device *to_virtio_s390_device(DeviceState *d) +{ + return container_of(d, VirtIOS390Device, qdev); +} + +static void virtio_s390_notify(DeviceState *d, uint16_t vector) +{ + VirtIOS390Device *dev = to_virtio_s390_device_fast(d); uint64_t token = s390_virtio_device_vq_token(dev, vector); S390CPU *cpu = s390_cpu_addr2state(0); CPUS390XState *env = &cpu->env; @@ -373,9 +387,9 @@ static void virtio_s390_notify(void *opaque, uint16_t vector) s390_virtio_irq(env, 0, token); } -static unsigned virtio_s390_get_features(void *opaque) +static unsigned virtio_s390_get_features(DeviceState *d) { - VirtIOS390Device *dev = (VirtIOS390Device*)opaque; + VirtIOS390Device *dev = to_virtio_s390_device(d); return dev->host_features; } diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index d2d2454493..1f1a285ce8 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -96,35 +96,48 @@ bool virtio_is_big_endian(void); /* virtio device */ - -static void virtio_pci_notify(void *opaque, uint16_t vector) +/* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */ +static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d) { - VirtIOPCIProxy *proxy = opaque; + return container_of(d, VirtIOPCIProxy, pci_dev.qdev); +} + +/* DeviceState to VirtIOPCIProxy. Note: used on datapath, + * be careful and test performance if you change this. + */ +static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d) +{ + return container_of(d, VirtIOPCIProxy, pci_dev.qdev); +} + +static void virtio_pci_notify(DeviceState *d, uint16_t vector) +{ + VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d); if (msix_enabled(&proxy->pci_dev)) msix_notify(&proxy->pci_dev, vector); else qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1); } -static void virtio_pci_save_config(void * opaque, QEMUFile *f) +static void virtio_pci_save_config(DeviceState *d, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); pci_device_save(&proxy->pci_dev, f); msix_save(&proxy->pci_dev, f); if (msix_present(&proxy->pci_dev)) qemu_put_be16(f, proxy->vdev->config_vector); } -static void virtio_pci_save_queue(void * opaque, int n, QEMUFile *f) +static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); if (msix_present(&proxy->pci_dev)) qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n)); } -static int virtio_pci_load_config(void * opaque, QEMUFile *f) +static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); int ret; ret = pci_device_load(&proxy->pci_dev, f); if (ret) { @@ -143,9 +156,9 @@ static int virtio_pci_load_config(void * opaque, QEMUFile *f) return 0; } -static int virtio_pci_load_queue(void * opaque, int n, QEMUFile *f) +static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); uint16_t vector; if (msix_present(&proxy->pci_dev)) { qemu_get_be16s(f, &vector); @@ -243,7 +256,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) void virtio_pci_reset(DeviceState *d) { - VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev); + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); virtio_pci_stop_ioeventfd(proxy); virtio_reset(proxy->vdev); msix_unuse_all_vectors(&proxy->pci_dev); @@ -463,9 +476,9 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, } } -static unsigned virtio_pci_get_features(void *opaque) +static unsigned virtio_pci_get_features(DeviceState *d) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); return proxy->host_features; } @@ -567,9 +580,9 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) } } -static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) +static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtQueue *vq = virtio_get_queue(proxy->vdev, n); EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); @@ -587,15 +600,15 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) return 0; } -static bool virtio_pci_query_guest_notifiers(void *opaque) +static bool virtio_pci_query_guest_notifiers(DeviceState *d) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); return msix_enabled(&proxy->pci_dev); } -static int virtio_pci_set_guest_notifiers(void *opaque, bool assign) +static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = proxy->vdev; int r, n; @@ -611,7 +624,7 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign) break; } - r = virtio_pci_set_guest_notifier(opaque, n, assign); + r = virtio_pci_set_guest_notifier(d, n, assign); if (r < 0) { goto assign_error; } @@ -636,14 +649,14 @@ assign_error: /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ assert(assign); while (--n >= 0) { - virtio_pci_set_guest_notifier(opaque, n, !assign); + virtio_pci_set_guest_notifier(d, n, !assign); } return r; } -static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign) +static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); /* Stop using ioeventfd for virtqueue kick if the device starts using host * notifiers. This makes it easy to avoid stepping on each others' toes. @@ -659,9 +672,9 @@ static int virtio_pci_set_host_notifier(void *opaque, int n, bool assign) return virtio_pci_set_host_notifier_internal(proxy, n, assign, false); } -static void virtio_pci_vmstate_change(void *opaque, bool running) +static void virtio_pci_vmstate_change(DeviceState *d, bool running) { - VirtIOPCIProxy *proxy = opaque; + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); if (running) { /* Try to find out if the guest has bus master disabled, but is @@ -726,7 +739,7 @@ void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev) proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; } - virtio_bind_device(vdev, &virtio_pci_bindings, proxy); + virtio_bind_device(vdev, &virtio_pci_bindings, DEVICE(proxy)); proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE; proxy->host_features = vdev->get_features(vdev, proxy->host_features); diff --git a/hw/virtio.c b/hw/virtio.c index 0455a9e8f3..77b53a9c21 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -935,7 +935,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, } void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, - void *opaque) + DeviceState *opaque) { vdev->binding = binding; vdev->binding_opaque = opaque; diff --git a/hw/virtio.h b/hw/virtio.h index 541600484e..1dec9dce07 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -91,17 +91,17 @@ typedef struct VirtQueueElement } VirtQueueElement; typedef struct { - void (*notify)(void * opaque, uint16_t vector); - void (*save_config)(void * opaque, QEMUFile *f); - void (*save_queue)(void * opaque, int n, QEMUFile *f); - int (*load_config)(void * opaque, QEMUFile *f); - int (*load_queue)(void * opaque, int n, QEMUFile *f); - int (*load_done)(void * opaque, QEMUFile *f); - unsigned (*get_features)(void * opaque); - bool (*query_guest_notifiers)(void * opaque); - int (*set_guest_notifiers)(void * opaque, bool assigned); - int (*set_host_notifier)(void * opaque, int n, bool assigned); - void (*vmstate_change)(void * opaque, bool running); + void (*notify)(DeviceState *d, uint16_t vector); + void (*save_config)(DeviceState *d, QEMUFile *f); + void (*save_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_config)(DeviceState *d, QEMUFile *f); + int (*load_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_done)(DeviceState *d, QEMUFile *f); + unsigned (*get_features)(DeviceState *d); + bool (*query_guest_notifiers)(DeviceState *d); + int (*set_guest_notifiers)(DeviceState *d, bool assigned); + int (*set_host_notifier)(DeviceState *d, int n, bool assigned); + void (*vmstate_change)(DeviceState *d, bool running); } VirtIOBindings; #define VIRTIO_PCI_QUEUE_MAX 64 @@ -128,7 +128,7 @@ struct VirtIODevice void (*set_status)(VirtIODevice *vdev, uint8_t val); VirtQueue *vq; const VirtIOBindings *binding; - void *binding_opaque; + DeviceState *binding_opaque; uint16_t device_id; bool vm_running; VMChangeStateEntry *vmstate; @@ -191,7 +191,7 @@ void virtio_update_irq(VirtIODevice *vdev); int virtio_set_features(VirtIODevice *vdev, uint32_t val); void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding, - void *opaque); + DeviceState *opaque); /* Base devices. */ typedef struct VirtIOBlkConf VirtIOBlkConf; From 586502189edf9fd0f89a83de96717a2ea826fdb0 Mon Sep 17 00:00:00 2001 From: Lei Li Date: Fri, 21 Dec 2012 12:26:38 +0800 Subject: [PATCH 0027/1634] qemu-char: Inherit ptys and improve output from -serial pty Changes since V1: - Avoid crashing since qemu_opts_id() may return null on some systems according to Markus's suggestion. When controlling a qemu instance from another program, it's hard to know which serial port or monitor device is redirected to which pty. With more than one device using "pty" a lot of guesswork is involved. $ ./x86_64-softmmu/qemu-system-x86_64 -serial pty -serial pty -monitor pty char device redirected to /dev/pts/5 char device redirected to /dev/pts/6 char device redirected to /dev/pts/7 Although we can find out what everything else is connected to by the "info chardev" with "-monitor stdio" in the command line, It'd be very useful to be able to have qemu inherit pseudo-tty file descriptors so they could just be specified on the command line like: $ ./x86_64-softmmu/qemu-system-x86_64 -serial pty -serial pty -monitor pty char device compat_monitor0 redirected to /dev/pts/5 char device serial0 redirected to /dev/pts/6 char device serial1 redirected to /dev/pts/7 Referred link: https://bugs.launchpad.net/qemu/+bug/938552 Signed-off-by: Lei Li Signed-off-by: Anthony Liguori --- qemu-char.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index 6113d0ab60..c6382a93f5 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -980,6 +980,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) CharDriverState *chr; PtyCharDriver *s; struct termios tty; + const char *label; int master_fd, slave_fd, len; #if defined(__OpenBSD__) || defined(__DragonFly__) char pty_name[PATH_MAX]; @@ -1005,7 +1006,12 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) chr->filename = g_malloc(len); snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd)); qemu_opt_set(opts, "path", q_ptsname(master_fd)); - fprintf(stderr, "char device redirected to %s\n", q_ptsname(master_fd)); + + label = qemu_opts_id(opts); + fprintf(stderr, "char device%s%s redirected to %s\n", + label ? " " : "", + label ?: "", + q_ptsname(master_fd)); s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; From 57f26ae72983095d0258e391041dfb8864f769e5 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 20 Dec 2012 16:43:48 -0200 Subject: [PATCH 0028/1634] target-i386: CPUID: return highest basic leaf if eax > cpuid_xlevel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a subtle bug. A bug that probably won't cause trouble for any existing OS, but a bug anyway: Intel SDM Volume 2, CPUID Instruction states: > Two types of information are returned: basic and extended function > information. If a value entered for CPUID.EAX is higher than the maximum > input value for basic or extended function for that processor then the > data for the highest basic information leaf is returned. For example, > using the Intel Core i7 processor, the following is true: > > CPUID.EAX = 05H (* Returns MONITOR/MWAIT leaf. *) > CPUID.EAX = 0AH (* Returns Architectural Performance Monitoring leaf. *) > CPUID.EAX = 0BH (* Returns Extended Topology Enumeration leaf. *) > CPUID.EAX = 0CH (* INVALID: Returns the same information as CPUID.EAX = 0BH. *) > CPUID.EAX = 80000008H (* Returns linear/physical address size data. *) > CPUID.EAX = 8000000AH (* INVALID: Returns same information as CPUID.EAX = 0BH. *) AMD's CPUID Specification, on the other hand, is less specific: > The CPUID instruction supports two sets or ranges of functions, > standard and extended. > > • The smallest function number of the standard function range is > Fn0000_0000. The largest function num- ber of the standard function > range, for a particular implementation, is returned in CPUID > Fn0000_0000_EAX. > > • The smallest function number of the extended function range is > Fn8000_0000. The largest function num- ber of the extended function > range, for a particular implementation, is returned in CPUID > Fn8000_0000_EAX. > > Functions that are neither standard nor extended are undefined and > should not be relied upon. QEMU's behavior matched Intel's specification before, but this was changed by commit b3baa152aaef1905876670590275c2dd0bbb088c. This patch restores the behavior documented by Intel when cpuid_xlevel2 is 0. The existing behavior when cpuid_xlevel2 is set (falling back to level=cpuid_xlevel) is being kept, as I couldn't find any public documentation on the CPUID 0xC0000000 function range on Centaur CPUs. Signed-off-by: Eduardo Habkost Signed-off-by: Anthony Liguori --- target-i386/cpu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1837f5af04..3cd1cee540 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1648,7 +1648,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, index = env->cpuid_xlevel; } } else { - index = env->cpuid_xlevel; + /* Intel documentation states that invalid EAX input will + * return the same information as EAX=cpuid_level + * (Intel SDM Vol. 2A - Instruction Set Reference - CPUID) + */ + index = env->cpuid_level; } } } else { From 6265e4ff327763b6362cba472e2b46f2dcf18762 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 23 Nov 2012 12:12:01 +0100 Subject: [PATCH 0029/1634] win32: Switch thread abstraction to us TLS variable internally We already depend on working __thread support for coroutines, so this complication here is no longer needed. Reviewed-by: Paolo Bonzini Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- qemu-thread-win32.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c index 8037b39045..517878dcc1 100644 --- a/qemu-thread-win32.c +++ b/qemu-thread-win32.c @@ -239,7 +239,7 @@ struct QemuThreadData { CRITICAL_SECTION cs; }; -static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES; +static __thread QemuThreadData *qemu_thread_data; static unsigned __stdcall win32_start_routine(void *arg) { @@ -251,14 +251,15 @@ static unsigned __stdcall win32_start_routine(void *arg) g_free(data); data = NULL; } - TlsSetValue(qemu_thread_tls_index, data); + qemu_thread_data = data; qemu_thread_exit(start_routine(thread_arg)); abort(); } void qemu_thread_exit(void *arg) { - QemuThreadData *data = TlsGetValue(qemu_thread_tls_index); + QemuThreadData *data = qemu_thread_data; + if (data) { assert(data->mode != QEMU_THREAD_DETACHED); data->ret = arg; @@ -298,25 +299,13 @@ void *qemu_thread_join(QemuThread *thread) return ret; } -static inline void qemu_thread_init(void) -{ - if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) { - qemu_thread_tls_index = TlsAlloc(); - if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) { - error_exit(ERROR_NO_SYSTEM_RESOURCES, __func__); - } - } -} - - void qemu_thread_create(QemuThread *thread, void *(*start_routine)(void *), void *arg, int mode) { HANDLE hThread; - struct QemuThreadData *data; - qemu_thread_init(); + data = g_malloc(sizeof *data); data->start_routine = start_routine; data->arg = arg; @@ -338,8 +327,7 @@ void qemu_thread_create(QemuThread *thread, void qemu_thread_get_self(QemuThread *thread) { - qemu_thread_init(); - thread->data = TlsGetValue(qemu_thread_tls_index); + thread->data = qemu_thread_data; thread->tid = GetCurrentThreadId(); } From eac236ea7bfc1902126be70459e320591078df5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Llu=C3=ADs=20Vilanova?= Date: Fri, 14 Dec 2012 20:13:09 +0100 Subject: [PATCH 0030/1634] build: Use separate makefile for "trace/" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Paolo Bonzini Signed-off-by: Lluís Vilanova -- Changes in v2: * Do not depend on "qemu-timer-common.o". * Use "$(obj)" in rules to refer to the build sub-directory. * Remove dependencies against "$(GENERATED_HEADERS)". Cc: Paolo Bonzini Signed-off-by: Anthony Liguori --- .gitignore | 8 ++-- Makefile | 17 ++++--- Makefile.objs | 64 ++------------------------ scripts/tracetool/backend/dtrace.py | 2 +- scripts/tracetool/format/h.py | 6 +-- trace.h | 6 +++ trace/Makefile.objs | 70 +++++++++++++++++++++++++++++ 7 files changed, 97 insertions(+), 76 deletions(-) create mode 100644 trace.h create mode 100644 trace/Makefile.objs diff --git a/.gitignore b/.gitignore index 3a417656e2..0e3816918c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,10 @@ config-all-devices.* config-all-disas.* config-host.* config-target.* -trace.h -trace.c -trace-dtrace.h -trace-dtrace.dtrace +trace/generated-tracers.h +trace/generated-tracers.c +trace/generated-tracers-dtrace.h +trace/generated-tracers-dtrace.dtrace *-timestamp *-softmmu *-darwin-user diff --git a/Makefile b/Makefile index a0321dd7f0..a7ac04b9ae 100644 --- a/Makefile +++ b/Makefile @@ -31,12 +31,15 @@ ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail)) endif endif -GENERATED_HEADERS = config-host.h trace.h qemu-options.def -ifeq ($(TRACE_BACKEND),dtrace) -GENERATED_HEADERS += trace-dtrace.h -endif +GENERATED_HEADERS = config-host.h qemu-options.def GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h -GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c trace.c +GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c + +GENERATED_HEADERS += trace/generated-tracers.h +ifeq ($(TRACE_BACKEND),dtrace) +GENERATED_HEADERS += trace/generated-tracers-dtrace.h +endif +GENERATED_SOURCES += trace/generated-tracers.c # Don't try to regenerate Makefile or configure # We don't generate any of them @@ -233,9 +236,9 @@ clean: rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -Rf .libs rm -f qemu-img-cmds.h - rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp @# May not be present in GENERATED_HEADERS - rm -f trace-dtrace.h trace-dtrace.h-timestamp + rm -f trace/generated-tracers-dtrace.dtrace* + rm -f trace/generated-tracers-dtrace.h* rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp) rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp) rm -rf qapi-generated diff --git a/Makefile.objs b/Makefile.objs index 4ef0a718d2..3a3a4028c5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -133,66 +133,7 @@ universal-obj-y += disas/ ###################################################################### # trace -ifeq ($(TRACE_BACKEND),dtrace) -TRACE_H_EXTRA_DEPS=trace-dtrace.h -endif -trace.h: trace.h-timestamp $(TRACE_H_EXTRA_DEPS) -trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak - $(call quiet-command,$(TRACETOOL) \ - --format=h \ - --backend=$(TRACE_BACKEND) \ - < $< > $@," GEN trace.h") - @cmp -s $@ trace.h || cp $@ trace.h - -trace.c: trace.c-timestamp -trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak - $(call quiet-command,$(TRACETOOL) \ - --format=c \ - --backend=$(TRACE_BACKEND) \ - < $< > $@," GEN trace.c") - @cmp -s $@ trace.c || cp $@ trace.c - -trace.o: trace.c $(GENERATED_HEADERS) - -trace-dtrace.h: trace-dtrace.dtrace - $(call quiet-command,dtrace -o $@ -h -s $<, " GEN trace-dtrace.h") - -# Normal practice is to name DTrace probe file with a '.d' extension -# but that gets picked up by QEMU's Makefile as an external dependency -# rule file. So we use '.dtrace' instead -trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp -trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak - $(call quiet-command,$(TRACETOOL) \ - --format=d \ - --backend=$(TRACE_BACKEND) \ - < $< > $@," GEN trace-dtrace.dtrace") - @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace - -trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) - $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o") - -ifeq ($(LIBTOOL),) -trace-dtrace.lo: trace-dtrace.dtrace - @echo "missing libtool. please install and rerun configure."; exit 1 -else -trace-dtrace.lo: trace-dtrace.dtrace - $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN trace-dtrace.o") -endif - -trace/simple.o: trace/simple.c $(GENERATED_HEADERS) - -trace-obj-$(CONFIG_TRACE_DTRACE) += trace-dtrace.o -ifneq ($(TRACE_BACKEND),dtrace) -trace-obj-y = trace.o -endif - -trace-obj-$(CONFIG_TRACE_DEFAULT) += trace/default.o -trace-obj-$(CONFIG_TRACE_SIMPLE) += trace/simple.o -trace-obj-$(CONFIG_TRACE_SIMPLE) += qemu-timer-common.o -trace-obj-$(CONFIG_TRACE_STDERR) += trace/stderr.o -trace-obj-y += trace/control.o - -$(trace-obj-y): $(GENERATED_HEADERS) +trace-obj-y += trace/ universal-obj-y += $(trace-obj-y) @@ -239,5 +180,6 @@ nested-vars += \ user-obj-y \ common-obj-y \ universal-obj-y \ - extra-obj-y + extra-obj-y \ + trace-obj-y dummy := $(call unnest-vars) diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py index 23c43e2772..ad5eb3b0ab 100644 --- a/scripts/tracetool/backend/dtrace.py +++ b/scripts/tracetool/backend/dtrace.py @@ -37,7 +37,7 @@ def c(events): def h(events): - out('#include "trace-dtrace.h"', + out('#include "trace/generated-tracers-dtrace.h"', '') for e in events: diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index 6ffb3c2f4e..9a58de1331 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -19,8 +19,8 @@ from tracetool import out def begin(events): out('/* This file is autogenerated by tracetool, do not edit. */', '', - '#ifndef TRACE_H', - '#define TRACE_H', + '#ifndef TRACE__GENERATED_TRACERS_H', + '#define TRACE__GENERATED_TRACERS_H', '', '#include "qemu-common.h"') @@ -32,7 +32,7 @@ def end(events): enabled = 1 out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled)) out('', - '#endif /* TRACE_H */') + '#endif /* TRACE__GENERATED_TRACERS_H */') def nop(events): for e in events: diff --git a/trace.h b/trace.h new file mode 100644 index 0000000000..c15f498128 --- /dev/null +++ b/trace.h @@ -0,0 +1,6 @@ +#ifndef TRACE_H +#define TRACE_H + +#include "trace/generated-tracers.h" + +#endif /* TRACE_H */ diff --git a/trace/Makefile.objs b/trace/Makefile.objs new file mode 100644 index 0000000000..b791723696 --- /dev/null +++ b/trace/Makefile.objs @@ -0,0 +1,70 @@ +# -*- mode: makefile -*- + +###################################################################### +# Auto-generated tracing routines + +ifeq ($(TRACE_BACKEND),dtrace) +TRACE_H_EXTRA_DEPS=$(obj)/generated-tracers-dtrace.h +endif +$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(TRACE_H_EXTRA_DEPS) +$(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=h \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp +$(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=c \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h + +ifneq ($(TRACE_BACKEND),dtrace) +trace-obj-y += generated-tracers.o +endif + + +###################################################################### +# Auto-generated DTrace code + +# Normal practice is to name DTrace probe file with a '.d' extension +# but that gets picked up by QEMU's Makefile as an external dependency +# rule file. So we use '.dtrace' instead +$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp +$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak + $(call quiet-command,$(TRACETOOL) \ + --format=d \ + --backend=$(TRACE_BACKEND) \ + < $< > $@," GEN $(patsubst %-timestamp,%,$@)") + @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) + +$(obj)/generated-tracers-dtrace.h: trace/generated-tracers-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") + +$(obj)/generated-tracers-dtrace.o: trace/generated-tracers-dtrace.dtrace + $(call quiet-command,dtrace -o $@ -G -s $<, " GEN $@") + +trace-obj-$(CONFIG_TRACE_DTRACE) += generated-tracers-dtrace.o + + +ifeq ($(LIBTOOL),) +$(obj)/generated-tracers-dtrace.lo: $(obj)/generated-tracers-dtrace.dtrace + @echo "missing libtool. please install and rerun configure."; exit 1 +else +$(obj)/generated-tracers-dtrace.lo: $(obj)/generated-tracers-dtrace.dtrace + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC dtrace -o $@ -G -s $<, " lt GEN $@") +endif + + +###################################################################### +# Backend code + +trace-obj-$(CONFIG_TRACE_DEFAULT) += default.o +trace-obj-$(CONFIG_TRACE_SIMPLE) += simple.o +trace-obj-$(CONFIG_TRACE_STDERR) += stderr.o +trace-obj-y += control.o From 2915efbfa8efadaa2806e827ba92b8dba4f7cd52 Mon Sep 17 00:00:00 2001 From: Alex Horn Date: Wed, 5 Dec 2012 12:34:06 +0000 Subject: [PATCH 0031/1634] tmp105: Create API for TMP105 temperature sensor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Define enum for TMP105 registers * Move tmp105_set() from I2C to TMP105 header * Document units and range of temperature as preconditions Reviewed-by: Andreas Färber Signed-off-by: Alex Horn Signed-off-by: Anthony Liguori --- hw/i2c.h | 3 --- hw/tmp105.c | 17 +++++++------- hw/tmp105.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 hw/tmp105.h diff --git a/hw/i2c.h b/hw/i2c.h index 0f5682b4b0..883b5c588d 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -73,9 +73,6 @@ void *wm8750_dac_buffer(void *opaque, int samples); void wm8750_dac_commit(void *opaque); void wm8750_set_bclk_in(void *opaque, int new_hz); -/* tmp105.c */ -void tmp105_set(I2CSlave *i2c, int temp); - /* lm832x.c */ void lm832x_key_event(DeviceState *dev, int key, int state); diff --git a/hw/tmp105.c b/hw/tmp105.c index 8e8dbd94eb..9c67e644dd 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -20,6 +20,7 @@ #include "hw.h" #include "i2c.h" +#include "tmp105.h" typedef struct { I2CSlave i2c; @@ -92,22 +93,22 @@ static void tmp105_read(TMP105State *s) } switch (s->pointer & 3) { - case 0: /* Temperature */ + case TMP105_REG_TEMPERATURE: s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8); s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) & (0xf0 << ((~s->config >> 5) & 3)); /* R */ break; - case 1: /* Configuration */ + case TMP105_REG_CONFIG: s->buf[s->len ++] = s->config; break; - case 2: /* T_LOW */ + case TMP105_REG_T_LOW: s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8; s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0; break; - case 3: /* T_HIGH */ + case TMP105_REG_T_HIGH: s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8; s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0; break; @@ -117,10 +118,10 @@ static void tmp105_read(TMP105State *s) static void tmp105_write(TMP105State *s) { switch (s->pointer & 3) { - case 0: /* Temperature */ + case TMP105_REG_TEMPERATURE: break; - case 1: /* Configuration */ + case TMP105_REG_CONFIG: if (s->buf[0] & ~s->config & (1 << 0)) /* SD */ printf("%s: TMP105 shutdown\n", __FUNCTION__); s->config = s->buf[0]; @@ -128,8 +129,8 @@ static void tmp105_write(TMP105State *s) tmp105_alarm_update(s); break; - case 2: /* T_LOW */ - case 3: /* T_HIGH */ + case TMP105_REG_T_LOW: + case TMP105_REG_T_HIGH: if (s->len >= 3) s->limit[s->pointer & 1] = (int16_t) ((((uint16_t) s->buf[0]) << 8) | s->buf[1]); diff --git a/hw/tmp105.h b/hw/tmp105.h new file mode 100644 index 0000000000..51eff4be1c --- /dev/null +++ b/hw/tmp105.h @@ -0,0 +1,67 @@ +/* + * Texas Instruments TMP105 Temperature Sensor + * + * Browse the data sheet: + * + * http://www.ti.com/lit/gpn/tmp105 + * + * Copyright (C) 2012 Alex Horn + * Copyright (C) 2008-2012 Andrzej Zaborowski + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ +#ifndef QEMU_TMP105_H +#define QEMU_TMP105_H + +#include "i2c.h" + +/** + * TMP105Reg: + * @TMP105_REG_TEMPERATURE: Temperature register + * @TMP105_REG_CONFIG: Configuration register + * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst) + * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS) + * + * The following temperature sensors are + * compatible with the TMP105 registers: + * - adt75 + * - ds1775 + * - ds75 + * - lm75 + * - lm75a + * - max6625 + * - max6626 + * - mcp980x + * - stds75 + * - tcn75 + * - tmp100 + * - tmp101 + * - tmp105 + * - tmp175 + * - tmp275 + * - tmp75 + **/ +typedef enum TMP105Reg { + TMP105_REG_TEMPERATURE = 0, + TMP105_REG_CONFIG, + TMP105_REG_T_LOW, + TMP105_REG_T_HIGH, +} TMP105Reg; + +/** + * tmp105_set: + * @i2c: dispatcher to TMP105 hardware model + * @temp: temperature with 0.001 centigrades units in the range -40 C to +125 C + * + * Sets the temperature of the TMP105 hardware model. + * + * Bits 5 and 6 (value 32 and 64) in the register indexed by TMP105_REG_CONFIG + * determine the precision of the temperature. See Table 8 in the data sheet. + * + * @see_also: I2C_SLAVE macro + * @see_also: http://www.ti.com/lit/gpn/tmp105 + */ +void tmp105_set(I2CSlave *i2c, int temp); + +#endif From 74880fe27d2120ab3861dc857ecd025db1a67038 Mon Sep 17 00:00:00 2001 From: Robert Schiele Date: Tue, 4 Dec 2012 16:58:08 +0100 Subject: [PATCH 0032/1634] configure: allow disabling pixman if not needed When we build neither any system emulation targets nor the tools there is actually no need for pixman library. In that case do not enforce presence of that library on the system. Reviewed-by: Andreas F=E4rber Signed-off-by: Robert Schiele Signed-off-by: Anthony Liguori --- configure | 18 ++++++++++++++++-- target-unicore32/helper.c | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 14f05c7b90..99c1ec3467 100755 --- a/configure +++ b/configure @@ -656,6 +656,8 @@ for opt do ;; --without-system-pixman) pixman="internal" ;; + --without-pixman) pixman="none" + ;; --disable-sdl) sdl="no" ;; --enable-sdl) sdl="yes" @@ -2130,13 +2132,25 @@ fi # pixman support probe if test "$pixman" = ""; then - if $pkg_config pixman-1 > /dev/null 2>&1; then + if test "$want_tools" = "no" -a "$softmmu" = "no"; then + pixman="none" + elif $pkg_config pixman-1 > /dev/null 2>&1; then pixman="system" else pixman="internal" fi fi -if test "$pixman" = "system"; then +if test "$pixman" = "none"; then + if test "$want_tools" != "no" -o "$softmmu" != "no"; then + echo "ERROR: pixman disabled but system emulation or tools build" + echo " enabled. You can turn off pixman only if you also" + echo " disable all system emulation targets and the tools" + echo " build with '--disable-tools --disable-system'." + exit 1 + fi + pixman_cflags= + pixman_libs= +elif test "$pixman" = "system"; then pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null` pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null` else diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index ff4f628404..5359538ea5 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -13,7 +13,9 @@ #include "exec/gdbstub.h" #include "helper.h" #include "qemu/host-utils.h" +#ifndef CONFIG_USER_ONLY #include "ui/console.h" +#endif #undef DEBUG_UC32 From a2685bcc80f61aa612e0d8cfd91086857ae2942e Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Wed, 19 Dec 2012 17:46:15 +0200 Subject: [PATCH 0033/1634] MAINTAINERS: Take over kvm maintenance Replace Avi with myself as kvm maintainer. Signed-off-by: Gleb Natapov Signed-off-by: Anthony Liguori --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c1b16c5fe4..3e9dbc271d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -132,7 +132,7 @@ Guest CPU Cores (KVM): ---------------------- Overall -M: Avi Kivity +M: Gleb Natapov M: Marcelo Tosatti L: kvm@vger.kernel.org S: Supported @@ -150,7 +150,7 @@ S: Maintained F: target-s390x/kvm.c X86 -M: Avi Kivity +M: Gleb Natapov M: Marcelo Tosatti L: kvm@vger.kernel.org S: Supported From 0a2a59d35cbabf63c91340a1c62038e3e60538c1 Mon Sep 17 00:00:00 2001 From: Xudong Hao Date: Thu, 20 Dec 2012 11:07:23 +0800 Subject: [PATCH 0034/1634] qemu-kvm/pci-assign: 64 bits bar emulation Enable 64 bits bar emulation. Test pass with the current seabios which already support 64bit pci bars. Signed-off-by: Xudong Hao Reviewed-by: Alex Williamson Signed-off-by: Gleb Natapov --- hw/kvm/pci-assign.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c index e80dad009c..addc205596 100644 --- a/hw/kvm/pci-assign.c +++ b/hw/kvm/pci-assign.c @@ -46,6 +46,7 @@ #define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_DMA 0x00000800 #define IORESOURCE_PREFETCH 0x00002000 /* No side effects */ +#define IORESOURCE_MEM_64 0x00100000 //#define DEVICE_ASSIGNMENT_DEBUG @@ -442,9 +443,13 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, /* handle memory io regions */ if (cur_region->type & IORESOURCE_MEM) { - int t = cur_region->type & IORESOURCE_PREFETCH - ? PCI_BASE_ADDRESS_MEM_PREFETCH - : PCI_BASE_ADDRESS_SPACE_MEMORY; + int t = PCI_BASE_ADDRESS_SPACE_MEMORY; + if (cur_region->type & IORESOURCE_PREFETCH) { + t |= PCI_BASE_ADDRESS_MEM_PREFETCH; + } + if (cur_region->type & IORESOURCE_MEM_64) { + t |= PCI_BASE_ADDRESS_MEM_TYPE_64; + } /* map physical memory */ pci_dev->v_addrs[i].u.r_virtbase = mmap(NULL, cur_region->size, @@ -632,7 +637,8 @@ again: rp->valid = 0; rp->resource_fd = -1; size = end - start + 1; - flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; + flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH + | IORESOURCE_MEM_64; if (size == 0 || (flags & ~IORESOURCE_PREFETCH) == 0) { continue; } From 812d2594d558f7c4f95c99c8fc58adc47ab68eb3 Mon Sep 17 00:00:00 2001 From: Knut Omang Date: Tue, 18 Dec 2012 22:36:29 +0100 Subject: [PATCH 0035/1634] pcie: Fix bug in pcie_ext_cap_set_next Upper 16 bits of the PCIe Extended Capability Header was truncated during update, also breaking pcie_add_capability. Signed-off-by: Knut Omang Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 6c916d15ec..485c94c1b2 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -494,7 +494,7 @@ uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id) static void pcie_ext_cap_set_next(PCIDevice *dev, uint16_t pos, uint16_t next) { - uint16_t header = pci_get_long(dev->config + pos); + uint32_t header = pci_get_long(dev->config + pos); assert(!(next & (PCI_EXT_CAP_ALIGN - 1))); header = (header & ~PCI_EXT_CAP_NEXT_MASK) | ((next << PCI_EXT_CAP_NEXT_SHIFT) & PCI_EXT_CAP_NEXT_MASK); From bbef882cc1938fa5a6e1b36a50d79ce5c0cefb81 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 12 Dec 2012 16:10:02 +0200 Subject: [PATCH 0036/1634] msi: add API to get notified about pending bit poll Update all users. Signed-off-by: Michael S. Tsirkin --- hw/pci/msix.c | 13 ++++++++++++- hw/pci/msix.h | 3 ++- hw/pci/pci.h | 4 ++++ hw/vfio_pci.c | 2 +- hw/virtio-pci.c | 3 ++- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 073e22c315..a285d18197 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -191,6 +191,11 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, unsigned size) { PCIDevice *dev = opaque; + if (dev->msix_vector_poll_notifier) { + unsigned vector_start = addr * 8; + unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr); + dev->msix_vector_poll_notifier(dev, vector_start, vector_end); + } return pci_get_long(dev->msix_pba + addr); } @@ -513,7 +518,8 @@ static void msix_unset_notifier_for_vector(PCIDevice *dev, unsigned int vector) int msix_set_vector_notifiers(PCIDevice *dev, MSIVectorUseNotifier use_notifier, - MSIVectorReleaseNotifier release_notifier) + MSIVectorReleaseNotifier release_notifier, + MSIVectorPollNotifier poll_notifier) { int vector, ret; @@ -521,6 +527,7 @@ int msix_set_vector_notifiers(PCIDevice *dev, dev->msix_vector_use_notifier = use_notifier; dev->msix_vector_release_notifier = release_notifier; + dev->msix_vector_poll_notifier = poll_notifier; if ((dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & (MSIX_ENABLE_MASK | MSIX_MASKALL_MASK)) == MSIX_ENABLE_MASK) { @@ -531,6 +538,9 @@ int msix_set_vector_notifiers(PCIDevice *dev, } } } + if (dev->msix_vector_poll_notifier) { + dev->msix_vector_poll_notifier(dev, 0, dev->msix_entries_nr); + } return 0; undo: @@ -557,4 +567,5 @@ void msix_unset_vector_notifiers(PCIDevice *dev) } dev->msix_vector_use_notifier = NULL; dev->msix_vector_release_notifier = NULL; + dev->msix_vector_poll_notifier = NULL; } diff --git a/hw/pci/msix.h b/hw/pci/msix.h index ff07ae2e8f..ea85d02264 100644 --- a/hw/pci/msix.h +++ b/hw/pci/msix.h @@ -36,6 +36,7 @@ void msix_reset(PCIDevice *dev); int msix_set_vector_notifiers(PCIDevice *dev, MSIVectorUseNotifier use_notifier, - MSIVectorReleaseNotifier release_notifier); + MSIVectorReleaseNotifier release_notifier, + MSIVectorPollNotifier poll_notifier); void msix_unset_vector_notifiers(PCIDevice *dev); #endif diff --git a/hw/pci/pci.h b/hw/pci/pci.h index 3152050856..72927e3149 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -187,6 +187,9 @@ typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev); typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector, MSIMessage msg); typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector); +typedef void (*MSIVectorPollNotifier)(PCIDevice *dev, + unsigned int vector_start, + unsigned int vector_end); struct PCIDevice { DeviceState qdev; @@ -271,6 +274,7 @@ struct PCIDevice { /* MSI-X notifiers */ MSIVectorUseNotifier msix_vector_use_notifier; MSIVectorReleaseNotifier msix_vector_release_notifier; + MSIVectorPollNotifier msix_vector_poll_notifier; }; void pci_register_bar(PCIDevice *pci_dev, int region_num, diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 41fb7ad1de..28c83031d0 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -698,7 +698,7 @@ static void vfio_enable_msix(VFIODevice *vdev) vdev->interrupt = VFIO_INT_MSIX; if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, - vfio_msix_vector_release)) { + vfio_msix_vector_release, NULL)) { error_report("vfio: msix_set_vector_notifiers failed\n"); } diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 1f1a285ce8..37e8b2d255 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -637,7 +637,8 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) msix_nr_vectors_allocated(&proxy->pci_dev)); r = msix_set_vector_notifiers(&proxy->pci_dev, kvm_virtio_pci_vector_use, - kvm_virtio_pci_vector_release); + kvm_virtio_pci_vector_release, + NULL); if (r < 0) { goto assign_error; } From 70f8ee395afda6d96b15cb9a5b311af7720dded0 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 18 Dec 2012 13:54:32 +0200 Subject: [PATCH 0037/1634] msix: expose access to masked/pending state For use by poll handler. Signed-off-by: Michael S. Tsirkin --- hw/pci/msix.c | 6 +++--- hw/pci/msix.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index a285d18197..9eee6570c2 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -65,7 +65,7 @@ static int msix_is_pending(PCIDevice *dev, int vector) return *msix_pending_byte(dev, vector) & msix_pending_mask(vector); } -static void msix_set_pending(PCIDevice *dev, int vector) +void msix_set_pending(PCIDevice *dev, unsigned int vector) { *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); } @@ -75,13 +75,13 @@ static void msix_clr_pending(PCIDevice *dev, int vector) *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); } -static bool msix_vector_masked(PCIDevice *dev, int vector, bool fmask) +static bool msix_vector_masked(PCIDevice *dev, unsigned int vector, bool fmask) { unsigned offset = vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; return fmask || dev->msix_table[offset] & PCI_MSIX_ENTRY_CTRL_MASKBIT; } -static bool msix_is_masked(PCIDevice *dev, int vector) +bool msix_is_masked(PCIDevice *dev, unsigned int vector) { return msix_vector_masked(dev, vector, dev->msix_function_masked); } diff --git a/hw/pci/msix.h b/hw/pci/msix.h index ea85d02264..d0c4429843 100644 --- a/hw/pci/msix.h +++ b/hw/pci/msix.h @@ -26,6 +26,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f); int msix_enabled(PCIDevice *dev); int msix_present(PCIDevice *dev); +bool msix_is_masked(PCIDevice *dev, unsigned vector); +void msix_set_pending(PCIDevice *dev, unsigned vector); + int msix_vector_use(PCIDevice *dev, unsigned vector); void msix_vector_unuse(PCIDevice *dev, unsigned vector); void msix_unuse_all_vectors(PCIDevice *dev); From 89d62be9f4fb538db7f919a2be7df2544ffc02c5 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 18 Dec 2012 14:02:46 +0200 Subject: [PATCH 0038/1634] virtio-pci: don't poll masked vectors At the moment, when irqfd is in use but a vector is masked, qemu will poll it and handle vector masks in userspace. Since almost no one ever looks at the pending bits, it is better to defer this until pending bits are actually read. Implement this optimization using the new poll notifier. Signed-off-by: Michael S. Tsirkin --- hw/virtio-pci.c | 52 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 37e8b2d255..af9a56c757 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -508,8 +508,6 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, } return ret; } - - virtio_queue_set_guest_notifier_fd_handler(vq, true, true); return 0; } @@ -528,8 +526,6 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, if (--irqfd->users == 0) { kvm_irqchip_release_virq(kvm_state, irqfd->virq); } - - virtio_queue_set_guest_notifier_fd_handler(vq, true, false); } static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector, @@ -580,7 +576,36 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) } } -static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign) +static void kvm_virtio_pci_vector_poll(PCIDevice *dev, + unsigned int vector_start, + unsigned int vector_end) +{ + VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); + VirtIODevice *vdev = proxy->vdev; + int queue_no; + unsigned int vector; + EventNotifier *notifier; + VirtQueue *vq; + + for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } + vector = virtio_queue_vector(vdev, queue_no); + if (vector < vector_start || vector >= vector_end || + !msix_is_masked(dev, vector)) { + continue; + } + vq = virtio_get_queue(vdev, queue_no); + notifier = virtio_queue_get_guest_notifier(vq); + if (event_notifier_test_and_clear(notifier)) { + msix_set_pending(dev, vector); + } + } +} + +static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, + bool with_irqfd) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtQueue *vq = virtio_get_queue(proxy->vdev, n); @@ -591,9 +616,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign) if (r < 0) { return r; } - virtio_queue_set_guest_notifier_fd_handler(vq, true, false); + virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); } else { - virtio_queue_set_guest_notifier_fd_handler(vq, false, false); + virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); event_notifier_cleanup(notifier); } @@ -611,9 +636,11 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = proxy->vdev; int r, n; + bool with_irqfd = msix_enabled(&proxy->pci_dev) && + kvm_msi_via_irqfd_enabled(); /* Must unset vector notifier while guest notifier is still assigned */ - if (kvm_msi_via_irqfd_enabled() && !assign) { + if (proxy->vector_irqfd && !assign) { msix_unset_vector_notifiers(&proxy->pci_dev); g_free(proxy->vector_irqfd); proxy->vector_irqfd = NULL; @@ -624,21 +651,22 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) break; } - r = virtio_pci_set_guest_notifier(d, n, assign); + r = virtio_pci_set_guest_notifier(d, n, assign, + kvm_msi_via_irqfd_enabled()); if (r < 0) { goto assign_error; } } /* Must set vector notifier after guest notifier has been assigned */ - if (kvm_msi_via_irqfd_enabled() && assign) { + if (with_irqfd && assign) { proxy->vector_irqfd = g_malloc0(sizeof(*proxy->vector_irqfd) * msix_nr_vectors_allocated(&proxy->pci_dev)); r = msix_set_vector_notifiers(&proxy->pci_dev, kvm_virtio_pci_vector_use, kvm_virtio_pci_vector_release, - NULL); + kvm_virtio_pci_vector_poll); if (r < 0) { goto assign_error; } @@ -650,7 +678,7 @@ assign_error: /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ assert(assign); while (--n >= 0) { - virtio_pci_set_guest_notifier(d, n, !assign); + virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd); } return r; } From 62054c06d4d1d0d54ef87c2d9154efec00ad170c Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Sun, 23 Dec 2012 23:25:09 +0200 Subject: [PATCH 0039/1634] usb/redirect.c: unbreak compilation due to include/char/char.h Broken since: commit 927d4878b0ff319ed87fed9363f314613b0a5ed9 Author: Paolo Bonzini Date: Mon Dec 17 18:20:05 2012 +0100 softmmu: move remaining include files to include/ subdirectories Signed-off-by: Alon Levy Signed-off-by: Blue Swirl --- hw/usb/redirect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index b65e8682b6..0abe1ff4d1 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -30,6 +30,7 @@ #include "monitor/monitor.h" #include "sysemu/sysemu.h" #include "qemu/iov.h" +#include "char/char.h" #include #include From 927fa909d5d5cf8c07673cd16a6d3bdc81250bc0 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Fri, 28 Dec 2012 01:38:11 -0500 Subject: [PATCH 0040/1634] Disable semaphores fallback code for OpenBSD Disable the semaphores fallback code for OpenBSD as modern OpenBSD releases now have sem_timedwait(). Signed-off-by: Brad Smith Signed-off-by: Blue Swirl --- include/qemu/thread-posix.h | 2 +- qemu-thread-posix.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/qemu/thread-posix.h b/include/qemu/thread-posix.h index 380bae209b..0f30dccb53 100644 --- a/include/qemu/thread-posix.h +++ b/include/qemu/thread-posix.h @@ -12,7 +12,7 @@ struct QemuCond { }; struct QemuSemaphore { -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_t lock; pthread_cond_t cond; int count; diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c index 7be292ed68..6374df3328 100644 --- a/qemu-thread-posix.c +++ b/qemu-thread-posix.c @@ -122,7 +122,7 @@ void qemu_sem_init(QemuSemaphore *sem, int init) { int rc; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) rc = pthread_mutex_init(&sem->lock, NULL); if (rc != 0) { error_exit(rc, __func__); @@ -147,7 +147,7 @@ void qemu_sem_destroy(QemuSemaphore *sem) { int rc; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) rc = pthread_cond_destroy(&sem->cond); if (rc < 0) { error_exit(rc, __func__); @@ -168,7 +168,7 @@ void qemu_sem_post(QemuSemaphore *sem) { int rc; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_lock(&sem->lock); if (sem->count == INT_MAX) { rc = EINVAL; @@ -206,7 +206,7 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms) int rc; struct timespec ts; -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) compute_abs_deadline(&ts, ms); pthread_mutex_lock(&sem->lock); --sem->count; @@ -248,7 +248,7 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms) void qemu_sem_wait(QemuSemaphore *sem) { -#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__NetBSD__) +#if defined(__APPLE__) || defined(__NetBSD__) pthread_mutex_lock(&sem->lock); --sem->count; while (sem->count < 0) { From afcb92beac9e477e5ae5c36bf38830e225e2235f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 7 Dec 2012 15:07:17 -0600 Subject: [PATCH 0041/1634] tcg: Add TCGV_IS_UNUSED_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Aurelien Jarno Signed-off-by: Richard Henderson Reviewed-by: Andreas Färber Signed-off-by: Blue Swirl --- tcg/tcg-op.h | 2 ++ tcg/tcg.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 0b3cb0be3a..91c9d80dd5 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2329,6 +2329,7 @@ static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, #define tcg_gen_qemu_ldst_op tcg_gen_op3i_i32 #define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i32 #define TCGV_UNUSED(x) TCGV_UNUSED_I32(x) +#define TCGV_IS_UNUSED(x) TCGV_IS_UNUSED_I32(x) #define TCGV_EQUAL(a, b) TCGV_EQUAL_I32(a, b) #else #define TCGv TCGv_i64 @@ -2340,6 +2341,7 @@ static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, #define tcg_gen_qemu_ldst_op tcg_gen_op3i_i64 #define tcg_gen_qemu_ldst_op_i64 tcg_gen_qemu_ldst_op_i64_i64 #define TCGV_UNUSED(x) TCGV_UNUSED_I64(x) +#define TCGV_IS_UNUSED(x) TCGV_IS_UNUSED_I64(x) #define TCGV_EQUAL(a, b) TCGV_EQUAL_I64(a, b) #endif diff --git a/tcg/tcg.h b/tcg/tcg.h index b2e2a25653..a4279725a6 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -270,6 +270,9 @@ typedef int TCGv_i64; #define TCGV_UNUSED_I32(x) x = MAKE_TCGV_I32(-1) #define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1) +#define TCGV_IS_UNUSED_I32(x) (GET_TCGV_I32(x) == -1) +#define TCGV_IS_UNUSED_I64(x) (GET_TCGV_I64(x) == -1) + /* call flags */ /* Helper does not read globals (either directly or through an exception). It implies TCG_CALL_NO_WRITE_GLOBALS. */ From 76a347e1cd0c2d6959461c89dda15ef5c4140da6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 28 Dec 2012 14:17:02 -0800 Subject: [PATCH 0042/1634] tcg-i386: Perform cmov detection at runtime for 32-bit. Existing compile-time detection is spotty at best. Convert it all to runtime detection instead. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- configure | 19 +++++++++++++++++++ tcg/i386/tcg-target.c | 31 ++++++++++++++++++++++++++++++- tcg/i386/tcg-target.h | 5 ----- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 99c1ec3467..b0c7e542c6 100755 --- a/configure +++ b/configure @@ -3086,6 +3086,21 @@ if compile_prog "" "" ; then has_environ=yes fi +######################################## +# check if cpuid.h is usable. + +cpuid_h=no +cat > $TMPC << EOF +#include +int main(void) { + return 0; +} +EOF +if compile_prog "" "" ; then + cpuid_h=yes +fi + + ########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -3611,6 +3626,10 @@ if test "$has_environ" = "yes" ; then echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak fi +if test "$cpuid_h" = "yes" ; then + echo "CONFIG_CPUID_H=y" >> $config_host_mak +fi + if test "$glusterfs" = "yes" ; then echo "CONFIG_GLUSTERFS=y" >> $config_host_mak fi diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index ae8274652a..e0838748a9 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -97,6 +97,18 @@ static const int tcg_target_call_oarg_regs[] = { # define TCG_REG_L1 TCG_REG_EDX #endif +/* For 32-bit, we are going to attempt to determine at runtime whether cmov + is available. However, the host compiler must supply , as we're + not going to go so far as our own inline assembly. */ +#if TCG_TARGET_REG_BITS == 64 +# define have_cmov 1 +#elif defined(CONFIG_CPUID_H) +#include +static bool have_cmov; +#else +# define have_cmov 0 +#endif + static uint8_t *tb_ret_addr; static void patch_reloc(uint8_t *code_ptr, int type, @@ -943,7 +955,14 @@ static void tcg_out_movcond32(TCGContext *s, TCGCond cond, TCGArg dest, TCGArg v1) { tcg_out_cmp(s, c1, c2, const_c2, 0); - tcg_out_modrm(s, OPC_CMOVCC | tcg_cond_to_jcc[cond], dest, v1); + if (have_cmov) { + tcg_out_modrm(s, OPC_CMOVCC | tcg_cond_to_jcc[cond], dest, v1); + } else { + int over = gen_new_label(); + tcg_out_jxx(s, tcg_cond_to_jcc[tcg_invert_cond(cond)], over, 1); + tcg_out_mov(s, TCG_TYPE_I32, dest, v1); + tcg_out_label(s, over, s->code_ptr); + } } #if TCG_TARGET_REG_BITS == 64 @@ -2243,6 +2262,16 @@ static void tcg_target_qemu_prologue(TCGContext *s) static void tcg_target_init(TCGContext *s) { + /* For 32-bit, 99% certainty that we're running on hardware that supports + cmov, but we still need to check. In case cmov is not available, we'll + use a small forward branch. */ +#ifndef have_cmov + { + unsigned a, b, c, d; + have_cmov = (__get_cpuid(1, &a, &b, &c, &d) && (d & bit_CMOV)); + } +#endif + #if !defined(CONFIG_USER_ONLY) /* fail safe */ if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 5352ac0254..e63db9cfe9 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -91,12 +91,7 @@ typedef enum { #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 1 -#if defined(__x86_64__) || defined(__i686__) -/* Use cmov only if the compiler is already doing so. */ #define TCG_TARGET_HAS_movcond_i32 1 -#else -#define TCG_TARGET_HAS_movcond_i32 0 -#endif #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 From 753d99d38b5877440dde2705e30ca60e2ec62965 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 28 Dec 2012 14:19:35 -0800 Subject: [PATCH 0043/1634] tcg-hppa: Fix typo in brcond2 Reported-by: Stuart Brady Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/hppa/tcg-target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index 5b27cf6f12..656e73621a 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -824,7 +824,7 @@ static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, tcg_out_brcond(s, TCG_COND_EQ, ah, bh, bhconst, label_index); break; case TCG_COND_NE: - tcg_out_brcond(s, TCG_COND_NE, al, bl, bhconst, label_index); + tcg_out_brcond(s, TCG_COND_NE, al, bl, blconst, label_index); tcg_out_brcond(s, TCG_COND_NE, ah, bh, bhconst, label_index); break; default: From a795ef8dcb8cbadffc996c41ff38927a97645234 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Fri, 28 Dec 2012 01:00:26 -0500 Subject: [PATCH 0044/1634] Fix semaphores fallback code As reported in bug 1087114 the semaphores fallback code is broken which results in QEMU crashing and making QEMU unusable. This patch is from Paolo. This needs to be back ported to the 1.3 stable tree as well. Signed-off-by: Paolo Bonzini Signed-off-by: Brad Smith Signed-off-by: Blue Swirl --- qemu-thread-posix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c index 6374df3328..4489abf1d8 100644 --- a/qemu-thread-posix.c +++ b/qemu-thread-posix.c @@ -213,6 +213,7 @@ int qemu_sem_timedwait(QemuSemaphore *sem, int ms) while (sem->count < 0) { rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); if (rc == ETIMEDOUT) { + ++sem->count; break; } if (rc != 0) { From eec8972a5bc744eda695a86a984d746c240dff90 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Thu, 6 Dec 2012 20:30:35 +0100 Subject: [PATCH 0045/1634] target-mips: Fix incorrect reads and writes to DSPControl register Upper 4 bits of ccond (bits 31..28 ) of DSPControl register are not used in the MIPS32 architecture. They are used in the MIPS64 architecture. For MIPS32 these bits must be written as zero, and return zero on read. The change fixes writes (WRDSP) and reads (RDDSP) to the register. It also fixes the tests that use these instructions, and makes them smaller and simpler. Signed-off-by: Petar Jovanovic Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 8 ++++++++ tests/tcg/mips/mips32-dsp/rddsp.c | 32 ++++++++++++------------------- tests/tcg/mips/mips32-dsp/wrdsp.c | 32 ++++++++++++------------------- 3 files changed, 32 insertions(+), 40 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 14daf91950..acf7ceb1d1 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -3948,7 +3948,11 @@ void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env) if (mask[4] == 1) { overwrite &= 0x00FFFFFF; newbits &= 0x00FFFFFF; +#if defined(TARGET_MIPS64) newbits |= 0xFF000000 & rs; +#else + newbits |= 0x0F000000 & rs; +#endif } if (mask[5] == 1) { @@ -3999,7 +4003,11 @@ target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env) } if (mask[4] == 1) { +#if defined(TARGET_MIPS64) temp |= dsp & 0xFF000000; +#else + temp |= dsp & 0x0F000000; +#endif } if (mask[5] == 1) { diff --git a/tests/tcg/mips/mips32-dsp/rddsp.c b/tests/tcg/mips/mips32-dsp/rddsp.c index e8948ec1d9..2f30285033 100644 --- a/tests/tcg/mips/mips32-dsp/rddsp.c +++ b/tests/tcg/mips/mips32-dsp/rddsp.c @@ -6,14 +6,13 @@ int main() int dsp_i, dsp_o; int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i; int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o; - int ccond_r, outflag_r, efi_r, c_r, scount_r, pos_r; - ccond_i = 0x000000BC;/* 4 */ - outflag_i = 0x0000001B;/* 3 */ - efi_i = 0x00000001;/* 5 */ - c_i = 0x00000001;/* 2 */ - scount_i = 0x0000000F;/* 1 */ - pos_i = 0x0000000C;/* 0 */ + ccond_i = 0x0000000C; /* 4 */ + outflag_i = 0x0000001B; /* 3 */ + efi_i = 0x00000001; /* 5 */ + c_i = 0x00000001; /* 2 */ + scount_i = 0x0000000F; /* 1 */ + pos_i = 0x0000000C; /* 0 */ dsp_i = (ccond_i << 24) | \ (outflag_i << 16) | \ @@ -22,13 +21,6 @@ int main() (scount_i << 7) | \ pos_i; - ccond_r = ccond_i; - outflag_r = outflag_i; - efi_r = efi_i; - c_r = c_i; - scount_r = scount_i; - pos_r = pos_i; - __asm ("wrdsp %1, 0x3F\n\t" "rddsp %0, 0x3F\n\t" @@ -43,12 +35,12 @@ int main() scount_o = (dsp_o >> 7) & 0x3F; pos_o = dsp_o & 0x1F; - assert(ccond_o == ccond_r); - assert(outflag_o == outflag_r); - assert(efi_o == efi_r); - assert(c_o == c_r); - assert(scount_o == scount_r); - assert(pos_o == pos_r); + assert(ccond_o == ccond_i); + assert(outflag_o == outflag_i); + assert(efi_o == efi_i); + assert(c_o == c_i); + assert(scount_o == scount_i); + assert(pos_o == pos_i); return 0; } diff --git a/tests/tcg/mips/mips32-dsp/wrdsp.c b/tests/tcg/mips/mips32-dsp/wrdsp.c index e8948ec1d9..dc54943a99 100644 --- a/tests/tcg/mips/mips32-dsp/wrdsp.c +++ b/tests/tcg/mips/mips32-dsp/wrdsp.c @@ -6,14 +6,13 @@ int main() int dsp_i, dsp_o; int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i; int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o; - int ccond_r, outflag_r, efi_r, c_r, scount_r, pos_r; - ccond_i = 0x000000BC;/* 4 */ - outflag_i = 0x0000001B;/* 3 */ - efi_i = 0x00000001;/* 5 */ - c_i = 0x00000001;/* 2 */ - scount_i = 0x0000000F;/* 1 */ - pos_i = 0x0000000C;/* 0 */ + ccond_i = 0x000000BC; /* 4 */ + outflag_i = 0x0000001B; /* 3 */ + efi_i = 0x00000001; /* 5 */ + c_i = 0x00000001; /* 2 */ + scount_i = 0x0000000F; /* 1 */ + pos_i = 0x0000000C; /* 0 */ dsp_i = (ccond_i << 24) | \ (outflag_i << 16) | \ @@ -22,13 +21,6 @@ int main() (scount_i << 7) | \ pos_i; - ccond_r = ccond_i; - outflag_r = outflag_i; - efi_r = efi_i; - c_r = c_i; - scount_r = scount_i; - pos_r = pos_i; - __asm ("wrdsp %1, 0x3F\n\t" "rddsp %0, 0x3F\n\t" @@ -43,12 +35,12 @@ int main() scount_o = (dsp_o >> 7) & 0x3F; pos_o = dsp_o & 0x1F; - assert(ccond_o == ccond_r); - assert(outflag_o == outflag_r); - assert(efi_o == efi_r); - assert(c_o == c_r); - assert(scount_o == scount_r); - assert(pos_o == pos_r); + assert(ccond_o == (ccond_i & 0x0F)); + assert(outflag_o == outflag_i); + assert(efi_o == efi_i); + assert(c_o == c_i); + assert(scount_o == scount_i); + assert(pos_o == pos_i); return 0; } From b8abbbe8df5e04085f4b85fc4f7cf85efbcd492c Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Mon, 10 Dec 2012 16:28:17 +0100 Subject: [PATCH 0046/1634] target-mips: Fix for helpers for EXTR_* instructions The change removes some unnecessary and incorrect code for EXTR_S.H. Further, it corrects the mask for shift value in the EXTR_ instructions. It also extends the existing tests so they trigger the issues corrected with the change. Signed-off-by: Petar Jovanovic Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 45 ++++++-------------------- tests/tcg/mips/mips32-dsp/extr_r_w.c | 23 +++++++++++++ tests/tcg/mips/mips32-dsp/extr_rs_w.c | 23 +++++++++++++ tests/tcg/mips/mips32-dsp/extr_s_h.c | 23 +++++++++++++ tests/tcg/mips/mips32-dsp/extr_w.c | 23 +++++++++++++ tests/tcg/mips/mips32-dsp/extrv_r_w.c | 25 ++++++++++++++ tests/tcg/mips/mips32-dsp/extrv_rs_w.c | 25 ++++++++++++++ tests/tcg/mips/mips32-dsp/extrv_s_h.c | 17 ++++++++++ tests/tcg/mips/mips32-dsp/extrv_w.c | 26 +++++++++++++++ 9 files changed, 195 insertions(+), 35 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index acf7ceb1d1..ee0c8724c7 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -484,35 +484,6 @@ static inline uint8_t mipsdsp_rrshift1_sub_u8(uint8_t a, uint8_t b) return (temp >> 1) & 0x00FF; } -static inline int64_t mipsdsp_rashift_short_acc(int32_t ac, - int32_t shift, - CPUMIPSState *env) -{ - int32_t sign, temp31; - int64_t temp, acc; - - sign = (env->active_tc.HI[ac] >> 31) & 0x01; - acc = ((int64_t)env->active_tc.HI[ac] << 32) | - ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF); - if (shift == 0) { - temp = acc; - } else { - if (sign == 0) { - temp = (((int64_t)0x01 << (32 - shift + 1)) - 1) & (acc >> shift); - } else { - temp = ((((int64_t)0x01 << (shift + 1)) - 1) << (32 - shift)) | - (acc >> shift); - } - } - - temp31 = (temp >> 31) & 0x01; - if (sign != temp31) { - set_DSPControl_overflow_flag(1, 23, env); - } - - return temp; -} - /* 128 bits long. p[0] is LO, p[1] is HI. */ static inline void mipsdsp_rndrashift_short_acc(int64_t *p, int32_t ac, @@ -3407,7 +3378,7 @@ target_ulong helper_extr_w(target_ulong ac, target_ulong shift, int32_t tempI; int64_t tempDL[2]; - shift = shift & 0x0F; + shift = shift & 0x1F; mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env); if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && @@ -3435,7 +3406,7 @@ target_ulong helper_extr_r_w(target_ulong ac, target_ulong shift, { int64_t tempDL[2]; - shift = shift & 0x0F; + shift = shift & 0x1F; mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env); if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && @@ -3462,7 +3433,7 @@ target_ulong helper_extr_rs_w(target_ulong ac, target_ulong shift, int32_t tempI, temp64; int64_t tempDL[2]; - shift = shift & 0x0F; + shift = shift & 0x1F; mipsdsp_rndrashift_short_acc(tempDL, ac, shift, env); if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && @@ -3645,11 +3616,15 @@ target_ulong helper_dextr_rs_l(target_ulong ac, target_ulong shift, target_ulong helper_extr_s_h(target_ulong ac, target_ulong shift, CPUMIPSState *env) { - int64_t temp; + int64_t temp, acc; - shift = shift & 0x0F; + shift = shift & 0x1F; + + acc = ((int64_t)env->active_tc.HI[ac] << 32) | + ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF); + + temp = acc >> shift; - temp = mipsdsp_rashift_short_acc(ac, shift, env); if (temp > (int64_t)0x7FFF) { temp = 0x00007FFF; set_DSPControl_overflow_flag(1, 23, env); diff --git a/tests/tcg/mips/mips32-dsp/extr_r_w.c b/tests/tcg/mips/mips32-dsp/extr_r_w.c index 0beeefd366..02e022427a 100644 --- a/tests/tcg/mips/mips32-dsp/extr_r_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_r_w.c @@ -44,5 +44,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_r.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_rs_w.c b/tests/tcg/mips/mips32-dsp/extr_rs_w.c index 24c748db20..c3a22ee704 100644 --- a/tests/tcg/mips/mips32-dsp/extr_rs_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_rs_w.c @@ -44,5 +44,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_rs.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_s_h.c b/tests/tcg/mips/mips32-dsp/extr_s_h.c index b2129134c8..9bc2a63cc2 100644 --- a/tests/tcg/mips/mips32-dsp/extr_s_h.c +++ b/tests/tcg/mips/mips32-dsp/extr_s_h.c @@ -59,5 +59,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dsp */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x123; + acl = 0x87654321; + result = 0x1238; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_s.h %0, $ac1, 28\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_w.c b/tests/tcg/mips/mips32-dsp/extr_w.c index 02ab9ecaae..bd6b0b95c2 100644 --- a/tests/tcg/mips/mips32-dsp/extr_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_w.c @@ -44,5 +44,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_r_w.c b/tests/tcg/mips/mips32-dsp/extrv_r_w.c index 005807b142..2403b3afe4 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_r_w.c +++ b/tests/tcg/mips/mips32-dsp/extrv_r_w.c @@ -50,5 +50,30 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + rs = 31; + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv_r.w %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_rs_w.c b/tests/tcg/mips/mips32-dsp/extrv_rs_w.c index c2d8513bb6..ccceeb9f4c 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_rs_w.c +++ b/tests/tcg/mips/mips32-dsp/extrv_rs_w.c @@ -48,5 +48,30 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + rs = 0x1F; + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv_rs.w %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_s_h.c b/tests/tcg/mips/mips32-dsp/extrv_s_h.c index 8c13b5eda5..feac3e2e33 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_s_h.c +++ b/tests/tcg/mips/mips32-dsp/extrv_s_h.c @@ -67,5 +67,22 @@ int main() assert(dsp == 0); assert(result == rt); + rs = 0x1C; + ach = 0x123; + acl = 0x87654321; + result = 0x1238; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv_s.h %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extrv_w.c b/tests/tcg/mips/mips32-dsp/extrv_w.c index 9cb493df39..9e8b238a04 100644 --- a/tests/tcg/mips/mips32-dsp/extrv_w.c +++ b/tests/tcg/mips/mips32-dsp/extrv_w.c @@ -50,5 +50,31 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + rs = 31; + ach = 0x3fffffff; + acl = 0x2bcdef01; + result = 0x7ffffffe; + __asm + ("wrdsp %1, 0x01\n\t" + "mthi %3, $ac1\n\t" + "mtlo %4, $ac1\n\t" + "extrv.w %0, $ac1, %2\n\t" + "rddsp %1\n\t" + : "=r"(rt), "+r"(dsp) + : "r"(rs), "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + + return 0; } From 79eb8392db19a916f6a3277f7cd36fb22c2bdbaf Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 22 Dec 2012 13:38:19 +0100 Subject: [PATCH 0047/1634] target-mips: Remove semicolon from macro definition Macro RESTORE_FLUSH_MODE is similar to RESTORE_ROUNDING_MODE but included a semicolon. The code which uses that macro also includes a semicolon, so the result was an empty statement. Remove the superfluous semicolon from the macro definition. Signed-off-by: Stefan Weil Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e85edce6fa..e3ab05cbb0 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2175,7 +2175,7 @@ static unsigned int ieee_rm[] = { set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) #define RESTORE_FLUSH_MODE \ - set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status); + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status) target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) { From fe65a1fad6aa140769ffda31c34a109f7d2df101 Mon Sep 17 00:00:00 2001 From: Dongxue Zhang Date: Tue, 11 Dec 2012 22:28:28 +0800 Subject: [PATCH 0048/1634] Fix my email address Fix my email address, last time it's wrong. Signed-off-by: Dongxue Zhang Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index ee0c8724c7..a33e2bf9fd 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -2,7 +2,7 @@ * MIPS ASE DSP Instruction emulation helpers for QEMU. * * Copyright (c) 2012 Jia Liu - * Dongxue Zhang + * Dongxue Zhang * 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 From c4aaba92e516ad061dff7ac2ae3c2b2b7058c404 Mon Sep 17 00:00:00 2001 From: "Jovanovic, Petar" Date: Tue, 11 Dec 2012 15:06:35 +0000 Subject: [PATCH 0049/1634] target-mips: Make repl_ph to sign extend to target-long The immediate value is 9bits, should sign-extend to 16bits. The return value to register should sign-extend to target_long, as Richard says, removing an unnecessary cast works fun. Signed-off-by: Dongxue Zhang Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index e81ff38476..6281e70471 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -13769,9 +13769,10 @@ static void gen_mipsdsp_bitinsn(CPUMIPSState *env, DisasContext *ctx, check_dsp(ctx); { imm = (ctx->opcode >> 16) & 0x03FF; + imm = (int16_t)(imm << 6) >> 6; tcg_gen_movi_tl(cpu_gpr[ret], \ (target_long)((int32_t)imm << 16 | \ - (uint32_t)(uint16_t)imm)); + (uint16_t)imm)); } break; case OPC_REPLV_PH: From 0f0b93980572726e69e32ff13e2d7fb72b936157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E9=9F=8B=E4=BB=BB=20=28Wei-Ren=20Chen=29?= Date: Tue, 11 Dec 2012 00:15:55 +0800 Subject: [PATCH 0050/1634] target-mips: Use EXCP_SC rather than a magic number From the discussion on the ML [1], the exception limit defined by magic number 0x100 is actually EXCP_SC defined in cpu.h. Replace the magic number with EXCP_SC. Remove "#if 1 .. #endif" as well. [1] http://lists.gnu.org/archive/html/qemu-devel/2012-11/msg03080.html Signed-off-by: Chen Wei-Ren Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e3ab05cbb0..d833d78b4f 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -38,10 +38,9 @@ static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, int error_code, uintptr_t pc) { -#if 1 - if (exception < 0x100) + if (exception < EXCP_SC) { qemu_log("%s: %d %d\n", __func__, exception, error_code); -#endif + } env->exception_index = exception; env->error_code = error_code; From 5928023cef87847a295035487397b9ec701fdd6b Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 24 Nov 2012 23:03:13 +0100 Subject: [PATCH 0051/1634] pflash_cfi01: Suppress warning when Linux probes for AMD flash There are several ARM and MIPS boards which are manufactured with either Intel (pflash_cfi01.c) or AMD (pflash_cfi02.c) flash memory. The Linux kernel supports both and first probes for AMD flash which resulted in one or two warnings from the Intel flash emulation: pflash_write: Unimplemented flash cmd sequence (offset 0000000000000000, wcycle 0x0 cmd 0x0 value 0xf000f0) pflash_write: Unimplemented flash cmd sequence (offset 0000000000000000, wcycle 0x0 cmd 0x0 value 0xf0) These warnings confuse users, so suppress them. Signed-off-by: Stefan Weil Signed-off-by: Aurelien Jarno --- hw/pflash_cfi01.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 95e07e7cdb..aadedefb25 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -319,6 +319,9 @@ static void pflash_write(pflash_t *pfl, hwaddr offset, DPRINTF("%s: Write to buffer\n", __func__); pfl->status |= 0x80; /* Ready! */ break; + case 0xf0: /* Probe for AMD flash */ + DPRINTF("%s: Probe for AMD flash\n", __func__); + goto reset_flash; case 0xff: /* Read array mode */ DPRINTF("%s: Read array mode\n", __func__); goto reset_flash; From 4065742ac0f3c84abdd8d718b44a88f3ac56015a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 14 Nov 2012 11:43:23 +0100 Subject: [PATCH 0052/1634] raw-posix: add raw_get_aio_fd() for virtio-blk-data-plane The raw_get_aio_fd() function allows virtio-blk-data-plane to get the file descriptor of a raw image file with Linux AIO enabled. This interface is really a layering violation that can be resolved once the block layer is able to run outside the global mutex - at that point virtio-blk-data-plane will switch from custom Linux AIO code to using the block layer. Signed-off-by: Stefan Hajnoczi --- block/raw-posix.c | 34 ++++++++++++++++++++++++++++++++++ include/block/block.h | 9 +++++++++ 2 files changed, 43 insertions(+) diff --git a/block/raw-posix.c b/block/raw-posix.c index 91159c7887..87d888ed01 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1776,6 +1776,40 @@ static BlockDriver bdrv_host_cdrom = { }; #endif /* __FreeBSD__ */ +#ifdef CONFIG_LINUX_AIO +/** + * Return the file descriptor for Linux AIO + * + * This function is a layering violation and should be removed when it becomes + * possible to call the block layer outside the global mutex. It allows the + * caller to hijack the file descriptor so I/O can be performed outside the + * block layer. + */ +int raw_get_aio_fd(BlockDriverState *bs) +{ + BDRVRawState *s; + + if (!bs->drv) { + return -ENOMEDIUM; + } + + if (bs->drv == bdrv_find_format("raw")) { + bs = bs->file; + } + + /* raw-posix has several protocols so just check for raw_aio_readv */ + if (bs->drv->bdrv_aio_readv != raw_aio_readv) { + return -ENOTSUP; + } + + s = bs->opaque; + if (!s->use_aio) { + return -ENOTSUP; + } + return s->fd; +} +#endif /* CONFIG_LINUX_AIO */ + static void bdrv_file_init(void) { /* diff --git a/include/block/block.h b/include/block/block.h index b81d200b03..0719339231 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -365,6 +365,15 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs); void bdrv_set_in_use(BlockDriverState *bs, int in_use); int bdrv_in_use(BlockDriverState *bs); +#ifdef CONFIG_LINUX_AIO +int raw_get_aio_fd(BlockDriverState *bs); +#else +static inline int raw_get_aio_fd(BlockDriverState *bs) +{ + return -ENOTSUP; +} +#endif + enum BlockAcctType { BDRV_ACCT_READ, BDRV_ACCT_WRITE, From 583f6e7bbd24b31f7eecd5c21ba0a5a5a77f52f1 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 14 Nov 2012 15:04:15 +0100 Subject: [PATCH 0053/1634] configure: add CONFIG_VIRTIO_BLK_DATA_PLANE The virtio-blk-data-plane feature only works with Linux AIO. Therefore add a ./configure option and necessary checks to implement this dependency. Signed-off-by: Stefan Hajnoczi --- configure | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/configure b/configure index b0c7e542c6..cc1e20ac54 100755 --- a/configure +++ b/configure @@ -223,6 +223,7 @@ libiscsi="" coroutine="" seccomp="" glusterfs="" +virtio_blk_data_plane="" # parse CC options first for opt do @@ -882,6 +883,10 @@ for opt do ;; --enable-glusterfs) glusterfs="yes" ;; + --disable-virtio-blk-data-plane) virtio_blk_data_plane="no" + ;; + --enable-virtio-blk-data-plane) virtio_blk_data_plane="yes" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -2273,6 +2278,17 @@ EOF fi fi +########################################## +# adjust virtio-blk-data-plane based on linux-aio + +if test "$virtio_blk_data_plane" = "yes" -a \ + "$linux_aio" != "yes" ; then + echo "Error: virtio-blk-data-plane requires Linux AIO, please try --enable-linux-aio" + exit 1 +elif test -z "$virtio_blk_data_plane" ; then + virtio_blk_data_plane=$linux_aio +fi + ########################################## # attr probe @@ -3289,6 +3305,7 @@ echo "build guest agent $guest_agent" echo "seccomp support $seccomp" echo "coroutine backend $coroutine_backend" echo "GlusterFS support $glusterfs" +echo "virtio-blk-data-plane $virtio_blk_data_plane" if test "$sdl_too_old" = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -3634,6 +3651,10 @@ if test "$glusterfs" = "yes" ; then echo "CONFIG_GLUSTERFS=y" >> $config_host_mak fi +if test "$virtio_blk_data_plane" = "yes" ; then + echo "CONFIG_VIRTIO_BLK_DATA_PLANE=y" >> $config_host_mak +fi + # USB host support case "$usb" in linux) From 185ecf40e3589fc2717b0856ee1df05dd63a46dd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 20 Nov 2012 10:30:08 +0100 Subject: [PATCH 0054/1634] dataplane: add host memory mapping code The data plane thread needs to map guest physical addresses to host pointers. Normally this is done with cpu_physical_memory_map() but the function assumes the global mutex is held. The data plane thread does not touch the global mutex and therefore needs a thread-safe memory mapping mechanism. Hostmem registers a MemoryListener similar to how vhost collects and pushes memory region information into the kernel. There is a fine-grained lock on the regions list which is held during lookup and when installing a new regions list. When the physical memory map changes the MemoryListener callbacks are invoked. They build up a new list of memory regions which is finally installed when the list has been completed. Signed-off-by: Stefan Hajnoczi --- hw/Makefile.objs | 2 +- hw/dataplane/Makefile.objs | 3 + hw/dataplane/hostmem.c | 176 +++++++++++++++++++++++++++++++++++++ hw/dataplane/hostmem.h | 57 ++++++++++++ 4 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 hw/dataplane/Makefile.objs create mode 100644 hw/dataplane/hostmem.c create mode 100644 hw/dataplane/hostmem.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index d75f2f0bd7..5ac49134bd 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y = usb/ ide/ pci/ +common-obj-y = usb/ ide/ pci/ dataplane/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o common-obj-$(CONFIG_VIRTIO) += virtio-rng.o diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs new file mode 100644 index 0000000000..8c8dea1b21 --- /dev/null +++ b/hw/dataplane/Makefile.objs @@ -0,0 +1,3 @@ +ifeq ($(CONFIG_VIRTIO), y) +common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o +endif diff --git a/hw/dataplane/hostmem.c b/hw/dataplane/hostmem.c new file mode 100644 index 0000000000..380537e06d --- /dev/null +++ b/hw/dataplane/hostmem.c @@ -0,0 +1,176 @@ +/* + * Thread-safe guest to host memory mapping + * + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * 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 "exec/address-spaces.h" +#include "hostmem.h" + +static int hostmem_lookup_cmp(const void *phys_, const void *region_) +{ + hwaddr phys = *(const hwaddr *)phys_; + const HostMemRegion *region = region_; + + if (phys < region->guest_addr) { + return -1; + } else if (phys >= region->guest_addr + region->size) { + return 1; + } else { + return 0; + } +} + +/** + * Map guest physical address to host pointer + */ +void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write) +{ + HostMemRegion *region; + void *host_addr = NULL; + hwaddr offset_within_region; + + qemu_mutex_lock(&hostmem->current_regions_lock); + region = bsearch(&phys, hostmem->current_regions, + hostmem->num_current_regions, + sizeof(hostmem->current_regions[0]), + hostmem_lookup_cmp); + if (!region) { + goto out; + } + if (is_write && region->readonly) { + goto out; + } + offset_within_region = phys - region->guest_addr; + if (len <= region->size - offset_within_region) { + host_addr = region->host_addr + offset_within_region; + } +out: + qemu_mutex_unlock(&hostmem->current_regions_lock); + + return host_addr; +} + +/** + * Install new regions list + */ +static void hostmem_listener_commit(MemoryListener *listener) +{ + HostMem *hostmem = container_of(listener, HostMem, listener); + + qemu_mutex_lock(&hostmem->current_regions_lock); + g_free(hostmem->current_regions); + hostmem->current_regions = hostmem->new_regions; + hostmem->num_current_regions = hostmem->num_new_regions; + qemu_mutex_unlock(&hostmem->current_regions_lock); + + /* Reset new regions list */ + hostmem->new_regions = NULL; + hostmem->num_new_regions = 0; +} + +/** + * Add a MemoryRegionSection to the new regions list + */ +static void hostmem_append_new_region(HostMem *hostmem, + MemoryRegionSection *section) +{ + void *ram_ptr = memory_region_get_ram_ptr(section->mr); + size_t num = hostmem->num_new_regions; + size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]); + + hostmem->new_regions = g_realloc(hostmem->new_regions, new_size); + hostmem->new_regions[num] = (HostMemRegion){ + .host_addr = ram_ptr + section->offset_within_region, + .guest_addr = section->offset_within_address_space, + .size = section->size, + .readonly = section->readonly, + }; + hostmem->num_new_regions++; +} + +static void hostmem_listener_append_region(MemoryListener *listener, + MemoryRegionSection *section) +{ + HostMem *hostmem = container_of(listener, HostMem, listener); + + /* Ignore non-RAM regions, we may not be able to map them */ + if (!memory_region_is_ram(section->mr)) { + return; + } + + /* Ignore regions with dirty logging, we cannot mark them dirty */ + if (memory_region_is_logging(section->mr)) { + return; + } + + hostmem_append_new_region(hostmem, section); +} + +/* We don't implement most MemoryListener callbacks, use these nop stubs */ +static void hostmem_listener_dummy(MemoryListener *listener) +{ +} + +static void hostmem_listener_section_dummy(MemoryListener *listener, + MemoryRegionSection *section) +{ +} + +static void hostmem_listener_eventfd_dummy(MemoryListener *listener, + MemoryRegionSection *section, + bool match_data, uint64_t data, + EventNotifier *e) +{ +} + +static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener, + MemoryRegionSection *section, + hwaddr addr, hwaddr len) +{ +} + +void hostmem_init(HostMem *hostmem) +{ + memset(hostmem, 0, sizeof(*hostmem)); + + qemu_mutex_init(&hostmem->current_regions_lock); + + hostmem->listener = (MemoryListener){ + .begin = hostmem_listener_dummy, + .commit = hostmem_listener_commit, + .region_add = hostmem_listener_append_region, + .region_del = hostmem_listener_section_dummy, + .region_nop = hostmem_listener_append_region, + .log_start = hostmem_listener_section_dummy, + .log_stop = hostmem_listener_section_dummy, + .log_sync = hostmem_listener_section_dummy, + .log_global_start = hostmem_listener_dummy, + .log_global_stop = hostmem_listener_dummy, + .eventfd_add = hostmem_listener_eventfd_dummy, + .eventfd_del = hostmem_listener_eventfd_dummy, + .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy, + .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy, + .priority = 10, + }; + + memory_listener_register(&hostmem->listener, &address_space_memory); + if (hostmem->num_new_regions > 0) { + hostmem_listener_commit(&hostmem->listener); + } +} + +void hostmem_finalize(HostMem *hostmem) +{ + memory_listener_unregister(&hostmem->listener); + g_free(hostmem->new_regions); + g_free(hostmem->current_regions); + qemu_mutex_destroy(&hostmem->current_regions_lock); +} diff --git a/hw/dataplane/hostmem.h b/hw/dataplane/hostmem.h new file mode 100644 index 0000000000..b2cf09333f --- /dev/null +++ b/hw/dataplane/hostmem.h @@ -0,0 +1,57 @@ +/* + * Thread-safe guest to host memory mapping + * + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HOSTMEM_H +#define HOSTMEM_H + +#include "exec/memory.h" +#include "qemu/thread.h" + +typedef struct { + void *host_addr; + hwaddr guest_addr; + uint64_t size; + bool readonly; +} HostMemRegion; + +typedef struct { + /* The listener is invoked when regions change and a new list of regions is + * built up completely before they are installed. + */ + MemoryListener listener; + HostMemRegion *new_regions; + size_t num_new_regions; + + /* Current regions are accessed from multiple threads either to lookup + * addresses or to install a new list of regions. The lock protects the + * pointer and the regions. + */ + QemuMutex current_regions_lock; + HostMemRegion *current_regions; + size_t num_current_regions; +} HostMem; + +void hostmem_init(HostMem *hostmem); +void hostmem_finalize(HostMem *hostmem); + +/** + * Map a guest physical address to a pointer + * + * Note that there is map/unmap mechanism here. The caller must ensure that + * mapped memory is no longer used across events like hot memory unplug. This + * can be done with other mechanisms like bdrv_drain_all() that quiesce + * in-flight I/O. + */ +void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write); + +#endif /* HOSTMEM_H */ From 88807f89d945acad54c8365ff7b6ef0f0d0ddd56 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 14 Nov 2012 15:15:50 +0100 Subject: [PATCH 0055/1634] dataplane: add virtqueue vring code The virtio-blk-data-plane cannot access memory using the usual QEMU functions since it executes outside the global mutex and the memory APIs are this time are not thread-safe. This patch introduces a virtqueue module based on the kernel's vhost vring code. The trick is that we map guest memory ahead of time and access it cheaply outside the global mutex. Once the hardware emulation code can execute outside the global mutex it will be possible to drop this code. Signed-off-by: Stefan Hajnoczi --- hw/dataplane/Makefile.objs | 2 +- hw/dataplane/vring.c | 362 +++++++++++++++++++++++++++++++++++++ hw/dataplane/vring.h | 62 +++++++ trace-events | 3 + 4 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 hw/dataplane/vring.c create mode 100644 hw/dataplane/vring.h diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs index 8c8dea1b21..34e6d579ec 100644 --- a/hw/dataplane/Makefile.objs +++ b/hw/dataplane/Makefile.objs @@ -1,3 +1,3 @@ ifeq ($(CONFIG_VIRTIO), y) -common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o +common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o endif diff --git a/hw/dataplane/vring.c b/hw/dataplane/vring.c new file mode 100644 index 0000000000..d5d4ef45d1 --- /dev/null +++ b/hw/dataplane/vring.c @@ -0,0 +1,362 @@ +/* Copyright 2012 Red Hat, Inc. + * Copyright IBM, Corp. 2012 + * + * Based on Linux 2.6.39 vhost code: + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2006 Rusty Russell IBM Corporation + * + * Author: Michael S. Tsirkin + * Stefan Hajnoczi + * + * Inspiration, some code, and most witty comments come from + * Documentation/virtual/lguest/lguest.c, by Rusty Russell + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include "trace.h" +#include "hw/dataplane/vring.h" + +/* Map the guest's vring to host memory */ +bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) +{ + hwaddr vring_addr = virtio_queue_get_ring_addr(vdev, n); + hwaddr vring_size = virtio_queue_get_ring_size(vdev, n); + void *vring_ptr; + + vring->broken = false; + + hostmem_init(&vring->hostmem); + vring_ptr = hostmem_lookup(&vring->hostmem, vring_addr, vring_size, true); + if (!vring_ptr) { + error_report("Failed to map vring " + "addr %#" HWADDR_PRIx " size %" HWADDR_PRIu, + vring_addr, vring_size); + vring->broken = true; + return false; + } + + vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096); + + vring->last_avail_idx = 0; + vring->last_used_idx = 0; + vring->signalled_used = 0; + vring->signalled_used_valid = false; + + trace_vring_setup(virtio_queue_get_ring_addr(vdev, n), + vring->vr.desc, vring->vr.avail, vring->vr.used); + return true; +} + +void vring_teardown(Vring *vring) +{ + hostmem_finalize(&vring->hostmem); +} + +/* Disable guest->host notifies */ +void vring_disable_notification(VirtIODevice *vdev, Vring *vring) +{ + if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) { + vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY; + } +} + +/* Enable guest->host notifies + * + * Return true if the vring is empty, false if there are more requests. + */ +bool vring_enable_notification(VirtIODevice *vdev, Vring *vring) +{ + if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { + vring_avail_event(&vring->vr) = vring->vr.avail->idx; + } else { + vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY; + } + smp_mb(); /* ensure update is seen before reading avail_idx */ + return !vring_more_avail(vring); +} + +/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */ +bool vring_should_notify(VirtIODevice *vdev, Vring *vring) +{ + uint16_t old, new; + bool v; + /* Flush out used index updates. This is paired + * with the barrier that the Guest executes when enabling + * interrupts. */ + smp_mb(); + + if ((vdev->guest_features & VIRTIO_F_NOTIFY_ON_EMPTY) && + unlikely(vring->vr.avail->idx == vring->last_avail_idx)) { + return true; + } + + if (!(vdev->guest_features & VIRTIO_RING_F_EVENT_IDX)) { + return !(vring->vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT); + } + old = vring->signalled_used; + v = vring->signalled_used_valid; + new = vring->signalled_used = vring->last_used_idx; + vring->signalled_used_valid = true; + + if (unlikely(!v)) { + return true; + } + + return vring_need_event(vring_used_event(&vring->vr), new, old); +} + +/* This is stolen from linux/drivers/vhost/vhost.c. */ +static int get_indirect(Vring *vring, + struct iovec iov[], struct iovec *iov_end, + unsigned int *out_num, unsigned int *in_num, + struct vring_desc *indirect) +{ + struct vring_desc desc; + unsigned int i = 0, count, found = 0; + + /* Sanity check */ + if (unlikely(indirect->len % sizeof(desc))) { + error_report("Invalid length in indirect descriptor: " + "len %#x not multiple of %#zx", + indirect->len, sizeof(desc)); + vring->broken = true; + return -EFAULT; + } + + count = indirect->len / sizeof(desc); + /* Buffers are chained via a 16 bit next field, so + * we can have at most 2^16 of these. */ + if (unlikely(count > USHRT_MAX + 1)) { + error_report("Indirect buffer length too big: %d", indirect->len); + vring->broken = true; + return -EFAULT; + } + + do { + struct vring_desc *desc_ptr; + + /* Translate indirect descriptor */ + desc_ptr = hostmem_lookup(&vring->hostmem, + indirect->addr + found * sizeof(desc), + sizeof(desc), false); + if (!desc_ptr) { + error_report("Failed to map indirect descriptor " + "addr %#" PRIx64 " len %zu", + (uint64_t)indirect->addr + found * sizeof(desc), + sizeof(desc)); + vring->broken = true; + return -EFAULT; + } + desc = *desc_ptr; + + /* Ensure descriptor has been loaded before accessing fields */ + barrier(); /* read_barrier_depends(); */ + + if (unlikely(++found > count)) { + error_report("Loop detected: last one at %u " + "indirect size %u", i, count); + vring->broken = true; + return -EFAULT; + } + + if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) { + error_report("Nested indirect descriptor"); + vring->broken = true; + return -EFAULT; + } + + /* Stop for now if there are not enough iovecs available. */ + if (iov >= iov_end) { + return -ENOBUFS; + } + + iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len, + desc.flags & VRING_DESC_F_WRITE); + if (!iov->iov_base) { + error_report("Failed to map indirect descriptor" + "addr %#" PRIx64 " len %u", + (uint64_t)desc.addr, desc.len); + vring->broken = true; + return -EFAULT; + } + iov->iov_len = desc.len; + iov++; + + /* If this is an input descriptor, increment that count. */ + if (desc.flags & VRING_DESC_F_WRITE) { + *in_num += 1; + } else { + /* If it's an output descriptor, they're all supposed + * to come before any input descriptors. */ + if (unlikely(*in_num)) { + error_report("Indirect descriptor " + "has out after in: idx %u", i); + vring->broken = true; + return -EFAULT; + } + *out_num += 1; + } + i = desc.next; + } while (desc.flags & VRING_DESC_F_NEXT); + return 0; +} + +/* This looks in the virtqueue and for the first available buffer, and converts + * it to an iovec for convenient access. Since descriptors consist of some + * number of output then some number of input descriptors, it's actually two + * iovecs, but we pack them into one and note how many of each there were. + * + * This function returns the descriptor number found, or vq->num (which is + * never a valid descriptor number) if none was found. A negative code is + * returned on error. + * + * Stolen from linux/drivers/vhost/vhost.c. + */ +int vring_pop(VirtIODevice *vdev, Vring *vring, + struct iovec iov[], struct iovec *iov_end, + unsigned int *out_num, unsigned int *in_num) +{ + struct vring_desc desc; + unsigned int i, head, found = 0, num = vring->vr.num; + uint16_t avail_idx, last_avail_idx; + + /* If there was a fatal error then refuse operation */ + if (vring->broken) { + return -EFAULT; + } + + /* Check it isn't doing very strange things with descriptor numbers. */ + last_avail_idx = vring->last_avail_idx; + avail_idx = vring->vr.avail->idx; + barrier(); /* load indices now and not again later */ + + if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) { + error_report("Guest moved used index from %u to %u", + last_avail_idx, avail_idx); + vring->broken = true; + return -EFAULT; + } + + /* If there's nothing new since last we looked. */ + if (avail_idx == last_avail_idx) { + return -EAGAIN; + } + + /* Only get avail ring entries after they have been exposed by guest. */ + smp_rmb(); + + /* Grab the next descriptor number they're advertising, and increment + * the index we've seen. */ + head = vring->vr.avail->ring[last_avail_idx % num]; + + /* If their number is silly, that's an error. */ + if (unlikely(head >= num)) { + error_report("Guest says index %u > %u is available", head, num); + vring->broken = true; + return -EFAULT; + } + + if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { + vring_avail_event(&vring->vr) = vring->vr.avail->idx; + } + + /* When we start there are none of either input nor output. */ + *out_num = *in_num = 0; + + i = head; + do { + if (unlikely(i >= num)) { + error_report("Desc index is %u > %u, head = %u", i, num, head); + vring->broken = true; + return -EFAULT; + } + if (unlikely(++found > num)) { + error_report("Loop detected: last one at %u vq size %u head %u", + i, num, head); + vring->broken = true; + return -EFAULT; + } + desc = vring->vr.desc[i]; + + /* Ensure descriptor is loaded before accessing fields */ + barrier(); + + if (desc.flags & VRING_DESC_F_INDIRECT) { + int ret = get_indirect(vring, iov, iov_end, out_num, in_num, &desc); + if (ret < 0) { + return ret; + } + continue; + } + + /* If there are not enough iovecs left, stop for now. The caller + * should check if there are more descs available once they have dealt + * with the current set. + */ + if (iov >= iov_end) { + return -ENOBUFS; + } + + /* TODO handle non-contiguous memory across region boundaries */ + iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len, + desc.flags & VRING_DESC_F_WRITE); + if (!iov->iov_base) { + error_report("Failed to map vring desc addr %#" PRIx64 " len %u", + (uint64_t)desc.addr, desc.len); + vring->broken = true; + return -EFAULT; + } + iov->iov_len = desc.len; + iov++; + + if (desc.flags & VRING_DESC_F_WRITE) { + /* If this is an input descriptor, + * increment that count. */ + *in_num += 1; + } else { + /* If it's an output descriptor, they're all supposed + * to come before any input descriptors. */ + if (unlikely(*in_num)) { + error_report("Descriptor has out after in: idx %d", i); + vring->broken = true; + return -EFAULT; + } + *out_num += 1; + } + i = desc.next; + } while (desc.flags & VRING_DESC_F_NEXT); + + /* On success, increment avail index. */ + vring->last_avail_idx++; + return head; +} + +/* After we've used one of their buffers, we tell them about it. + * + * Stolen from linux/drivers/vhost/vhost.c. + */ +void vring_push(Vring *vring, unsigned int head, int len) +{ + struct vring_used_elem *used; + uint16_t new; + + /* Don't touch vring if a fatal error occurred */ + if (vring->broken) { + return; + } + + /* The virtqueue contains a ring of used buffers. Get a pointer to the + * next entry in that used ring. */ + used = &vring->vr.used->ring[vring->last_used_idx % vring->vr.num]; + used->id = head; + used->len = len; + + /* Make sure buffer is written before we update index. */ + smp_wmb(); + + new = vring->vr.used->idx = ++vring->last_used_idx; + if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) { + vring->signalled_used_valid = false; + } +} diff --git a/hw/dataplane/vring.h b/hw/dataplane/vring.h new file mode 100644 index 0000000000..3274f623f5 --- /dev/null +++ b/hw/dataplane/vring.h @@ -0,0 +1,62 @@ +/* Copyright 2012 Red Hat, Inc. and/or its affiliates + * Copyright IBM, Corp. 2012 + * + * Based on Linux 2.6.39 vhost code: + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2006 Rusty Russell IBM Corporation + * + * Author: Michael S. Tsirkin + * Stefan Hajnoczi + * + * Inspiration, some code, and most witty comments come from + * Documentation/virtual/lguest/lguest.c, by Rusty Russell + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#ifndef VRING_H +#define VRING_H + +#include +#include "qemu-common.h" +#include "hw/dataplane/hostmem.h" +#include "hw/virtio.h" + +typedef struct { + HostMem hostmem; /* guest memory mapper */ + struct vring vr; /* virtqueue vring mapped to host memory */ + uint16_t last_avail_idx; /* last processed avail ring index */ + uint16_t last_used_idx; /* last processed used ring index */ + uint16_t signalled_used; /* EVENT_IDX state */ + bool signalled_used_valid; + bool broken; /* was there a fatal error? */ +} Vring; + +static inline unsigned int vring_get_num(Vring *vring) +{ + return vring->vr.num; +} + +/* Are there more descriptors available? */ +static inline bool vring_more_avail(Vring *vring) +{ + return vring->vr.avail->idx != vring->last_avail_idx; +} + +/* Fail future vring_pop() and vring_push() calls until reset */ +static inline void vring_set_broken(Vring *vring) +{ + vring->broken = true; +} + +bool vring_setup(Vring *vring, VirtIODevice *vdev, int n); +void vring_teardown(Vring *vring); +void vring_disable_notification(VirtIODevice *vdev, Vring *vring); +bool vring_enable_notification(VirtIODevice *vdev, Vring *vring); +bool vring_should_notify(VirtIODevice *vdev, Vring *vring); +int vring_pop(VirtIODevice *vdev, Vring *vring, + struct iovec iov[], struct iovec *iov_end, + unsigned int *out_num, unsigned int *in_num); +void vring_push(Vring *vring, unsigned int head, int len); + +#endif /* VRING_H */ diff --git a/trace-events b/trace-events index bb7621eeb6..167d776eff 100644 --- a/trace-events +++ b/trace-events @@ -98,6 +98,9 @@ virtio_blk_rw_complete(void *req, int ret) "req %p ret %d" virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" +# hw/dataplane/vring.c +vring_setup(uint64_t physical, void *desc, void *avail, void *used) "vring physical %#"PRIx64" desc %p avail %p used %p" + # thread-pool.c thread_pool_submit(void *req, void *opaque) "req %p opaque %p" thread_pool_complete(void *req, void *opaque, int ret) "req %p opaque %p ret %d" From 71973b046120a13df4eaa9143bed5ba8a67abc7f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 14 Nov 2012 15:23:00 +0100 Subject: [PATCH 0056/1634] dataplane: add event loop Outside the safety of the global mutex we need to poll on file descriptors. I found epoll(2) is a convenient way to do that, although other options could replace this module in the future (such as an AioContext-based loop or glib's GMainLoop). One important feature of this small event loop implementation is that the loop can be terminated in a thread-safe way. This allows QEMU to stop the data plane thread cleanly. Signed-off-by: Stefan Hajnoczi --- hw/dataplane/Makefile.objs | 2 +- hw/dataplane/event-poll.c | 100 +++++++++++++++++++++++++++++++++++++ hw/dataplane/event-poll.h | 40 +++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 hw/dataplane/event-poll.c create mode 100644 hw/dataplane/event-poll.h diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs index 34e6d579ec..e26bd7d89a 100644 --- a/hw/dataplane/Makefile.objs +++ b/hw/dataplane/Makefile.objs @@ -1,3 +1,3 @@ ifeq ($(CONFIG_VIRTIO), y) -common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o +common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o endif diff --git a/hw/dataplane/event-poll.c b/hw/dataplane/event-poll.c new file mode 100644 index 0000000000..2b55c6e255 --- /dev/null +++ b/hw/dataplane/event-poll.c @@ -0,0 +1,100 @@ +/* + * Event loop with file descriptor polling + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * 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 +#include "hw/dataplane/event-poll.h" + +/* Add an event notifier and its callback for polling */ +void event_poll_add(EventPoll *poll, EventHandler *handler, + EventNotifier *notifier, EventCallback *callback) +{ + struct epoll_event event = { + .events = EPOLLIN, + .data.ptr = handler, + }; + handler->notifier = notifier; + handler->callback = callback; + if (epoll_ctl(poll->epoll_fd, EPOLL_CTL_ADD, + event_notifier_get_fd(notifier), &event) != 0) { + fprintf(stderr, "failed to add event handler to epoll: %m\n"); + exit(1); + } +} + +/* Event callback for stopping event_poll() */ +static void handle_stop(EventHandler *handler) +{ + /* Do nothing */ +} + +void event_poll_init(EventPoll *poll) +{ + /* Create epoll file descriptor */ + poll->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (poll->epoll_fd < 0) { + fprintf(stderr, "epoll_create1 failed: %m\n"); + exit(1); + } + + /* Set up stop notifier */ + if (event_notifier_init(&poll->stop_notifier, 0) < 0) { + fprintf(stderr, "failed to init stop notifier\n"); + exit(1); + } + event_poll_add(poll, &poll->stop_handler, + &poll->stop_notifier, handle_stop); +} + +void event_poll_cleanup(EventPoll *poll) +{ + event_notifier_cleanup(&poll->stop_notifier); + close(poll->epoll_fd); + poll->epoll_fd = -1; +} + +/* Block until the next event and invoke its callback */ +void event_poll(EventPoll *poll) +{ + EventHandler *handler; + struct epoll_event event; + int nevents; + + /* Wait for the next event. Only do one event per call to keep the + * function simple, this could be changed later. */ + do { + nevents = epoll_wait(poll->epoll_fd, &event, 1, -1); + } while (nevents < 0 && errno == EINTR); + if (unlikely(nevents != 1)) { + fprintf(stderr, "epoll_wait failed: %m\n"); + exit(1); /* should never happen */ + } + + /* Find out which event handler has become active */ + handler = event.data.ptr; + + /* Clear the eventfd */ + event_notifier_test_and_clear(handler->notifier); + + /* Handle the event */ + handler->callback(handler); +} + +/* Stop event_poll() + * + * This function can be used from another thread. + */ +void event_poll_notify(EventPoll *poll) +{ + event_notifier_set(&poll->stop_notifier); +} diff --git a/hw/dataplane/event-poll.h b/hw/dataplane/event-poll.h new file mode 100644 index 0000000000..3e8d3ec7d5 --- /dev/null +++ b/hw/dataplane/event-poll.h @@ -0,0 +1,40 @@ +/* + * Event loop with file descriptor polling + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef EVENT_POLL_H +#define EVENT_POLL_H + +#include "qemu/event_notifier.h" + +typedef struct EventHandler EventHandler; +typedef void EventCallback(EventHandler *handler); +struct EventHandler { + EventNotifier *notifier; /* eventfd */ + EventCallback *callback; /* callback function */ +}; + +typedef struct { + int epoll_fd; /* epoll(2) file descriptor */ + EventNotifier stop_notifier; /* stop poll notifier */ + EventHandler stop_handler; /* stop poll handler */ +} EventPoll; + +void event_poll_add(EventPoll *poll, EventHandler *handler, + EventNotifier *notifier, EventCallback *callback); +void event_poll_init(EventPoll *poll); +void event_poll_cleanup(EventPoll *poll); +void event_poll(EventPoll *poll); +void event_poll_notify(EventPoll *poll); + +#endif /* EVENT_POLL_H */ From 3e9ec521711ed033476098cfc7f23c992cc606a2 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 14 Nov 2012 15:30:09 +0100 Subject: [PATCH 0057/1634] dataplane: add Linux AIO request queue The IOQueue has a pool of iocb structs and a function to add new read/write requests. Multiple requests can be added before calling the submit function to actually tell the host kernel to begin I/O. This allows callers to batch requests and submit them in one go. The actual I/O is performed using Linux AIO. Signed-off-by: Stefan Hajnoczi --- hw/dataplane/Makefile.objs | 2 +- hw/dataplane/ioq.c | 117 +++++++++++++++++++++++++++++++++++++ hw/dataplane/ioq.h | 57 ++++++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 hw/dataplane/ioq.c create mode 100644 hw/dataplane/ioq.h diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs index e26bd7d89a..abd408f1da 100644 --- a/hw/dataplane/Makefile.objs +++ b/hw/dataplane/Makefile.objs @@ -1,3 +1,3 @@ ifeq ($(CONFIG_VIRTIO), y) -common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o +common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o ioq.o endif diff --git a/hw/dataplane/ioq.c b/hw/dataplane/ioq.c new file mode 100644 index 0000000000..0c9f5c4d60 --- /dev/null +++ b/hw/dataplane/ioq.c @@ -0,0 +1,117 @@ +/* + * Linux AIO request queue + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * 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 "hw/dataplane/ioq.h" + +void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs) +{ + int rc; + + ioq->fd = fd; + ioq->max_reqs = max_reqs; + + memset(&ioq->io_ctx, 0, sizeof ioq->io_ctx); + rc = io_setup(max_reqs, &ioq->io_ctx); + if (rc != 0) { + fprintf(stderr, "ioq io_setup failed %d\n", rc); + exit(1); + } + + rc = event_notifier_init(&ioq->io_notifier, 0); + if (rc != 0) { + fprintf(stderr, "ioq io event notifier creation failed %d\n", rc); + exit(1); + } + + ioq->freelist = g_malloc0(sizeof ioq->freelist[0] * max_reqs); + ioq->freelist_idx = 0; + + ioq->queue = g_malloc0(sizeof ioq->queue[0] * max_reqs); + ioq->queue_idx = 0; +} + +void ioq_cleanup(IOQueue *ioq) +{ + g_free(ioq->freelist); + g_free(ioq->queue); + + event_notifier_cleanup(&ioq->io_notifier); + io_destroy(ioq->io_ctx); +} + +EventNotifier *ioq_get_notifier(IOQueue *ioq) +{ + return &ioq->io_notifier; +} + +struct iocb *ioq_get_iocb(IOQueue *ioq) +{ + /* Underflow cannot happen since ioq is sized for max_reqs */ + assert(ioq->freelist_idx != 0); + + struct iocb *iocb = ioq->freelist[--ioq->freelist_idx]; + ioq->queue[ioq->queue_idx++] = iocb; + return iocb; +} + +void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb) +{ + /* Overflow cannot happen since ioq is sized for max_reqs */ + assert(ioq->freelist_idx != ioq->max_reqs); + + ioq->freelist[ioq->freelist_idx++] = iocb; +} + +struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov, + unsigned int count, long long offset) +{ + struct iocb *iocb = ioq_get_iocb(ioq); + + if (read) { + io_prep_preadv(iocb, ioq->fd, iov, count, offset); + } else { + io_prep_pwritev(iocb, ioq->fd, iov, count, offset); + } + io_set_eventfd(iocb, event_notifier_get_fd(&ioq->io_notifier)); + return iocb; +} + +int ioq_submit(IOQueue *ioq) +{ + int rc = io_submit(ioq->io_ctx, ioq->queue_idx, ioq->queue); + ioq->queue_idx = 0; /* reset */ + return rc; +} + +int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion, + void *opaque) +{ + struct io_event events[ioq->max_reqs]; + int nevents, i; + + do { + nevents = io_getevents(ioq->io_ctx, 0, ioq->max_reqs, events, NULL); + } while (nevents < 0 && errno == EINTR); + if (nevents < 0) { + return nevents; + } + + for (i = 0; i < nevents; i++) { + ssize_t ret = ((uint64_t)events[i].res2 << 32) | events[i].res; + + completion(events[i].obj, ret, opaque); + ioq_put_iocb(ioq, events[i].obj); + } + return nevents; +} diff --git a/hw/dataplane/ioq.h b/hw/dataplane/ioq.h new file mode 100644 index 0000000000..b49b5de7f4 --- /dev/null +++ b/hw/dataplane/ioq.h @@ -0,0 +1,57 @@ +/* + * Linux AIO request queue + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef IOQ_H +#define IOQ_H + +#include +#include "qemu/event_notifier.h" + +typedef struct { + int fd; /* file descriptor */ + unsigned int max_reqs; /* max length of freelist and queue */ + + io_context_t io_ctx; /* Linux AIO context */ + EventNotifier io_notifier; /* Linux AIO eventfd */ + + /* Requests can complete in any order so a free list is necessary to manage + * available iocbs. + */ + struct iocb **freelist; /* free iocbs */ + unsigned int freelist_idx; + + /* Multiple requests are queued up before submitting them all in one go */ + struct iocb **queue; /* queued iocbs */ + unsigned int queue_idx; +} IOQueue; + +void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs); +void ioq_cleanup(IOQueue *ioq); +EventNotifier *ioq_get_notifier(IOQueue *ioq); +struct iocb *ioq_get_iocb(IOQueue *ioq); +void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb); +struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov, + unsigned int count, long long offset); +int ioq_submit(IOQueue *ioq); + +static inline unsigned int ioq_num_queued(IOQueue *ioq) +{ + return ioq->queue_idx; +} + +typedef void IOQueueCompletion(struct iocb *iocb, ssize_t ret, void *opaque); +int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion, + void *opaque); + +#endif /* IOQ_H */ From d02776350d9c76348988fc9e58a64a4f6b1a9f61 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Nov 2012 17:41:10 +0100 Subject: [PATCH 0058/1634] iov: add iov_discard_front/back() to remove data The iov_discard_front/back() functions remove data from the front or back of the vector. This is useful when peeling off header/footer structs. Signed-off-by: Stefan Hajnoczi --- include/qemu/iov.h | 13 ++++++++++++ iov.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/include/qemu/iov.h b/include/qemu/iov.h index d06f8b9ce3..68d25f29b7 100644 --- a/include/qemu/iov.h +++ b/include/qemu/iov.h @@ -99,4 +99,17 @@ unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt, const struct iovec *iov, unsigned int iov_cnt, size_t offset, size_t bytes); +/* + * Remove a given number of bytes from the front or back of a vector. + * This may update iov and/or iov_cnt to exclude iovec elements that are + * no longer required. + * + * The number of bytes actually discarded is returned. This number may be + * smaller than requested if the vector is too small. + */ +size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, + size_t bytes); +size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, + size_t bytes); + #endif diff --git a/iov.c b/iov.c index 419e419969..92ad77b162 100644 --- a/iov.c +++ b/iov.c @@ -354,3 +354,54 @@ size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset, { return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes); } + +size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, + size_t bytes) +{ + size_t total = 0; + struct iovec *cur; + + for (cur = *iov; *iov_cnt > 0; cur++) { + if (cur->iov_len > bytes) { + cur->iov_base += bytes; + cur->iov_len -= bytes; + total += bytes; + break; + } + + bytes -= cur->iov_len; + total += cur->iov_len; + *iov_cnt -= 1; + } + + *iov = cur; + return total; +} + +size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, + size_t bytes) +{ + size_t total = 0; + struct iovec *cur; + + if (*iov_cnt == 0) { + return 0; + } + + cur = iov + (*iov_cnt - 1); + + while (*iov_cnt > 0) { + if (cur->iov_len > bytes) { + cur->iov_len -= bytes; + total += bytes; + break; + } + + bytes -= cur->iov_len; + total += cur->iov_len; + cur--; + *iov_cnt -= 1; + } + + return total; +} From 8962e44fe438a051aff9f43209363f599be33624 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Nov 2012 19:18:26 +0100 Subject: [PATCH 0059/1634] test-iov: add iov_discard_front/back() testcases Signed-off-by: Stefan Hajnoczi --- tests/test-iov.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/tests/test-iov.c b/tests/test-iov.c index a480bc8725..46e4dddc55 100644 --- a/tests/test-iov.c +++ b/tests/test-iov.c @@ -250,11 +250,161 @@ static void test_io(void) #endif } +static void test_discard_front(void) +{ + struct iovec *iov; + struct iovec *iov_tmp; + unsigned int iov_cnt; + unsigned int iov_cnt_tmp; + void *old_base; + size_t size; + size_t ret; + + /* Discard zero bytes */ + iov_random(&iov, &iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0); + g_assert(ret == 0); + g_assert(iov_tmp == iov); + g_assert(iov_cnt_tmp == iov_cnt); + iov_free(iov, iov_cnt); + + /* Discard more bytes than vector size */ + iov_random(&iov, &iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1); + g_assert(ret == size); + g_assert(iov_cnt_tmp == 0); + iov_free(iov, iov_cnt); + + /* Discard entire vector */ + iov_random(&iov, &iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size); + g_assert(ret == size); + g_assert(iov_cnt_tmp == 0); + iov_free(iov, iov_cnt); + + /* Discard within first element */ + iov_random(&iov, &iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + old_base = iov->iov_base; + size = g_test_rand_int_range(1, iov->iov_len); + ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size); + g_assert(ret == size); + g_assert(iov_tmp == iov); + g_assert(iov_cnt_tmp == iov_cnt); + g_assert(iov_tmp->iov_base == old_base + size); + iov_tmp->iov_base = old_base; /* undo before g_free() */ + iov_free(iov, iov_cnt); + + /* Discard entire first element */ + iov_random(&iov, &iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len); + g_assert(ret == iov->iov_len); + g_assert(iov_tmp == iov + 1); + g_assert(iov_cnt_tmp == iov_cnt - 1); + iov_free(iov, iov_cnt); + + /* Discard within second element */ + iov_random(&iov, &iov_cnt); + iov_tmp = iov; + iov_cnt_tmp = iov_cnt; + old_base = iov[1].iov_base; + size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len); + ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size); + g_assert(ret == size); + g_assert(iov_tmp == iov + 1); + g_assert(iov_cnt_tmp == iov_cnt - 1); + g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len)); + iov_tmp->iov_base = old_base; /* undo before g_free() */ + iov_free(iov, iov_cnt); +} + +static void test_discard_back(void) +{ + struct iovec *iov; + unsigned int iov_cnt; + unsigned int iov_cnt_tmp; + void *old_base; + size_t size; + size_t ret; + + /* Discard zero bytes */ + iov_random(&iov, &iov_cnt); + iov_cnt_tmp = iov_cnt; + ret = iov_discard_back(iov, &iov_cnt_tmp, 0); + g_assert(ret == 0); + g_assert(iov_cnt_tmp == iov_cnt); + iov_free(iov, iov_cnt); + + /* Discard more bytes than vector size */ + iov_random(&iov, &iov_cnt); + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1); + g_assert(ret == size); + g_assert(iov_cnt_tmp == 0); + iov_free(iov, iov_cnt); + + /* Discard entire vector */ + iov_random(&iov, &iov_cnt); + iov_cnt_tmp = iov_cnt; + size = iov_size(iov, iov_cnt); + ret = iov_discard_back(iov, &iov_cnt_tmp, size); + g_assert(ret == size); + g_assert(iov_cnt_tmp == 0); + iov_free(iov, iov_cnt); + + /* Discard within last element */ + iov_random(&iov, &iov_cnt); + iov_cnt_tmp = iov_cnt; + old_base = iov[iov_cnt - 1].iov_base; + size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len); + ret = iov_discard_back(iov, &iov_cnt_tmp, size); + g_assert(ret == size); + g_assert(iov_cnt_tmp == iov_cnt); + g_assert(iov[iov_cnt - 1].iov_base == old_base); + iov_free(iov, iov_cnt); + + /* Discard entire last element */ + iov_random(&iov, &iov_cnt); + iov_cnt_tmp = iov_cnt; + old_base = iov[iov_cnt - 1].iov_base; + size = iov[iov_cnt - 1].iov_len; + ret = iov_discard_back(iov, &iov_cnt_tmp, size); + g_assert(ret == size); + g_assert(iov_cnt_tmp == iov_cnt - 1); + iov_free(iov, iov_cnt); + + /* Discard within second-to-last element */ + iov_random(&iov, &iov_cnt); + iov_cnt_tmp = iov_cnt; + old_base = iov[iov_cnt - 2].iov_base; + size = iov[iov_cnt - 1].iov_len + + g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len); + ret = iov_discard_back(iov, &iov_cnt_tmp, size); + g_assert(ret == size); + g_assert(iov_cnt_tmp == iov_cnt - 1); + g_assert(iov[iov_cnt - 2].iov_base == old_base); + iov_free(iov, iov_cnt); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); g_test_rand_int(); g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf); g_test_add_func("/basic/iov/io", test_io); + g_test_add_func("/basic/iov/discard-front", test_discard_front); + g_test_add_func("/basic/iov/discard-back", test_discard_back); return g_test_run(); } From 530c0bbd73e1b658c9266582072847de1fbdff10 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 22 Nov 2012 16:06:06 +0100 Subject: [PATCH 0060/1634] iov: add qemu_iovec_concat_iov() The qemu_iovec_concat() function copies a subset of a QEMUIOVector. The new qemu_iovec_concat_iov() function does the same for a iov/cnt pair. It is easy to define qemu_iovec_concat() in terms of qemu_iovec_concat_iov(). The existing code is mostly unchanged, except for the assertion src->size >= soffset, which cannot be efficiently checked upfront on a iov/cnt pair. Instead we assert upon hitting the end of src with an unsatisfied soffset. Signed-off-by: Stefan Hajnoczi --- include/qemu-common.h | 3 +++ iov.c | 47 ++++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/include/qemu-common.h b/include/qemu-common.h index 6871cab371..2b83de395c 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -329,6 +329,9 @@ void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t soffset, size_t sbytes); +void qemu_iovec_concat_iov(QEMUIOVector *dst, + struct iovec *src_iov, unsigned int src_cnt, + size_t soffset, size_t sbytes); void qemu_iovec_destroy(QEMUIOVector *qiov); void qemu_iovec_reset(QEMUIOVector *qiov); size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset, diff --git a/iov.c b/iov.c index 92ad77b162..c0f5c56618 100644 --- a/iov.c +++ b/iov.c @@ -288,6 +288,36 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len) ++qiov->niov; } +/* + * Concatenates (partial) iovecs from src_iov to the end of dst. + * It starts copying after skipping `soffset' bytes at the + * beginning of src and adds individual vectors from src to + * dst copies up to `sbytes' bytes total, or up to the end + * of src_iov if it comes first. This way, it is okay to specify + * very large value for `sbytes' to indicate "up to the end + * of src". + * Only vector pointers are processed, not the actual data buffers. + */ +void qemu_iovec_concat_iov(QEMUIOVector *dst, + struct iovec *src_iov, unsigned int src_cnt, + size_t soffset, size_t sbytes) +{ + int i; + size_t done; + assert(dst->nalloc != -1); + for (i = 0, done = 0; done < sbytes && i < src_cnt; i++) { + if (soffset < src_iov[i].iov_len) { + size_t len = MIN(src_iov[i].iov_len - soffset, sbytes - done); + qemu_iovec_add(dst, src_iov[i].iov_base + soffset, len); + done += len; + soffset = 0; + } else { + soffset -= src_iov[i].iov_len; + } + } + assert(soffset == 0); /* offset beyond end of src */ +} + /* * Concatenates (partial) iovecs from src to the end of dst. * It starts copying after skipping `soffset' bytes at the @@ -301,22 +331,7 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len) void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t soffset, size_t sbytes) { - int i; - size_t done; - struct iovec *siov = src->iov; - assert(dst->nalloc != -1); - assert(src->size >= soffset); - for (i = 0, done = 0; done < sbytes && i < src->niov; i++) { - if (soffset < siov[i].iov_len) { - size_t len = MIN(siov[i].iov_len - soffset, sbytes - done); - qemu_iovec_add(dst, siov[i].iov_base + soffset, len); - done += len; - soffset = 0; - } else { - soffset -= siov[i].iov_len; - } - } - /* return done; */ + qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes); } void qemu_iovec_destroy(QEMUIOVector *qiov) From 8a873ba78069ef81c4ef073a0bd703172c8b3312 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 10 Dec 2012 13:14:39 +0100 Subject: [PATCH 0061/1634] virtio-blk: restore VirtIOBlkConf->config_wce flag Two slightly different versions of a patch to conditionally set VIRTIO_BLK_F_CONFIG_WCE through the "config-wce" qdev property have been applied (ea776abca and eec7f96c2). David Gibson noticed that the "config-wce" property is broken as a result and fixed it recently. The fix sets the host_features VIRTIO_BLK_F_CONFIG_WCE bit from a qdev property. Unfortunately, the virtio device then has no chance to test for the presence of the feature bit during virtio_blk_init(). Therefore, reinstate the VirtIOBlkConf->config_wce flag. Drop the duplicate qdev property to set the host_features bit. The VirtIOBlkConf->config_wce flag will be used by virtio-blk-data-plane in a later patch. Signed-off-by: Stefan Hajnoczi --- hw/virtio-blk.c | 3 +++ hw/virtio-blk.h | 4 ++-- hw/virtio-pci.c | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 90cfa246db..f004148e3e 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -524,6 +524,9 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features) features |= (1 << VIRTIO_BLK_F_BLK_SIZE); features |= (1 << VIRTIO_BLK_F_SCSI); + if (s->blk->config_wce) { + features |= (1 << VIRTIO_BLK_F_CONFIG_WCE); + } if (bdrv_enable_write_cache(s->bs)) features |= (1 << VIRTIO_BLK_F_WCE); diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 651a000b9f..454f445d61 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -104,10 +104,10 @@ struct VirtIOBlkConf BlockConf conf; char *serial; uint32_t scsi; + uint32_t config_wce; }; #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ - DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \ - DEFINE_PROP_BIT("config-wce", _state, _field, VIRTIO_BLK_F_CONFIG_WCE, true) + DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) #endif diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index d2d2454493..3cab783804 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -894,6 +894,7 @@ static Property virtio_blk_properties[] = { #ifdef __linux__ DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true), #endif + DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true), DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), From e72f66a0a20f38d0c7576f6c0aec0ca644976e35 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 14 Nov 2012 15:39:30 +0100 Subject: [PATCH 0062/1634] dataplane: add virtio-blk data plane code virtio-blk-data-plane is a subset implementation of virtio-blk. It only handles read, write, and flush requests. It does this using a dedicated thread that executes an epoll(2)-based event loop and processes I/O using Linux AIO. This approach performs very well but can be used for raw image files only. The number of IOPS achieved has been reported to be several times higher than the existing virtio-blk implementation. Eventually it should be possible to unify virtio-blk-data-plane with the main body of QEMU code once the block layer and hardware emulation is able to run outside the global mutex. Signed-off-by: Stefan Hajnoczi --- hw/dataplane/Makefile.objs | 2 +- hw/dataplane/virtio-blk.c | 465 +++++++++++++++++++++++++++++++++++++ hw/dataplane/virtio-blk.h | 29 +++ hw/virtio-blk.h | 1 + trace-events | 6 + 5 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 hw/dataplane/virtio-blk.c create mode 100644 hw/dataplane/virtio-blk.h diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs index abd408f1da..682aa9e7ee 100644 --- a/hw/dataplane/Makefile.objs +++ b/hw/dataplane/Makefile.objs @@ -1,3 +1,3 @@ ifeq ($(CONFIG_VIRTIO), y) -common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o ioq.o +common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o ioq.o virtio-blk.o endif diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c new file mode 100644 index 0000000000..4c4ad8422a --- /dev/null +++ b/hw/dataplane/virtio-blk.c @@ -0,0 +1,465 @@ +/* + * Dedicated thread for virtio-blk I/O processing + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * 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 "trace.h" +#include "qemu/iov.h" +#include "event-poll.h" +#include "qemu/thread.h" +#include "vring.h" +#include "ioq.h" +#include "migration/migration.h" +#include "hw/virtio-blk.h" +#include "hw/dataplane/virtio-blk.h" + +enum { + SEG_MAX = 126, /* maximum number of I/O segments */ + VRING_MAX = SEG_MAX + 2, /* maximum number of vring descriptors */ + REQ_MAX = VRING_MAX, /* maximum number of requests in the vring, + * is VRING_MAX / 2 with traditional and + * VRING_MAX with indirect descriptors */ +}; + +typedef struct { + struct iocb iocb; /* Linux AIO control block */ + QEMUIOVector *inhdr; /* iovecs for virtio_blk_inhdr */ + unsigned int head; /* vring descriptor index */ +} VirtIOBlockRequest; + +struct VirtIOBlockDataPlane { + bool started; + QEMUBH *start_bh; + QemuThread thread; + + VirtIOBlkConf *blk; + int fd; /* image file descriptor */ + + VirtIODevice *vdev; + Vring vring; /* virtqueue vring */ + EventNotifier *guest_notifier; /* irq */ + + EventPoll event_poll; /* event poller */ + EventHandler io_handler; /* Linux AIO completion handler */ + EventHandler notify_handler; /* virtqueue notify handler */ + + IOQueue ioqueue; /* Linux AIO queue (should really be per + dataplane thread) */ + VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the + queue */ + + unsigned int num_reqs; + + Error *migration_blocker; +}; + +/* Raise an interrupt to signal guest, if necessary */ +static void notify_guest(VirtIOBlockDataPlane *s) +{ + if (!vring_should_notify(s->vdev, &s->vring)) { + return; + } + + event_notifier_set(s->guest_notifier); +} + +static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque) +{ + VirtIOBlockDataPlane *s = opaque; + VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); + struct virtio_blk_inhdr hdr; + int len; + + if (likely(ret >= 0)) { + hdr.status = VIRTIO_BLK_S_OK; + len = ret; + } else { + hdr.status = VIRTIO_BLK_S_IOERR; + len = 0; + } + + trace_virtio_blk_data_plane_complete_request(s, req->head, ret); + + qemu_iovec_from_buf(req->inhdr, 0, &hdr, sizeof(hdr)); + qemu_iovec_destroy(req->inhdr); + g_slice_free(QEMUIOVector, req->inhdr); + + /* According to the virtio specification len should be the number of bytes + * written to, but for virtio-blk it seems to be the number of bytes + * transferred plus the status bytes. + */ + vring_push(&s->vring, req->head, len + sizeof(hdr)); + + s->num_reqs--; +} + +static void complete_request_early(VirtIOBlockDataPlane *s, unsigned int head, + QEMUIOVector *inhdr, unsigned char status) +{ + struct virtio_blk_inhdr hdr = { + .status = status, + }; + + qemu_iovec_from_buf(inhdr, 0, &hdr, sizeof(hdr)); + qemu_iovec_destroy(inhdr); + g_slice_free(QEMUIOVector, inhdr); + + vring_push(&s->vring, head, sizeof(hdr)); + notify_guest(s); +} + +/* Get disk serial number */ +static void do_get_id_cmd(VirtIOBlockDataPlane *s, + struct iovec *iov, unsigned int iov_cnt, + unsigned int head, QEMUIOVector *inhdr) +{ + char id[VIRTIO_BLK_ID_BYTES]; + + /* Serial number not NUL-terminated when shorter than buffer */ + strncpy(id, s->blk->serial ? s->blk->serial : "", sizeof(id)); + iov_from_buf(iov, iov_cnt, 0, id, sizeof(id)); + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK); +} + +static int process_request(IOQueue *ioq, struct iovec iov[], + unsigned int out_num, unsigned int in_num, + unsigned int head) +{ + VirtIOBlockDataPlane *s = container_of(ioq, VirtIOBlockDataPlane, ioqueue); + struct iovec *in_iov = &iov[out_num]; + struct virtio_blk_outhdr outhdr; + QEMUIOVector *inhdr; + size_t in_size; + struct iocb *iocb; + + /* Copy in outhdr */ + if (unlikely(iov_to_buf(iov, out_num, 0, &outhdr, + sizeof(outhdr)) != sizeof(outhdr))) { + error_report("virtio-blk request outhdr too short"); + return -EFAULT; + } + iov_discard_front(&iov, &out_num, sizeof(outhdr)); + + /* Grab inhdr for later */ + in_size = iov_size(in_iov, in_num); + if (in_size < sizeof(struct virtio_blk_inhdr)) { + error_report("virtio_blk request inhdr too short"); + return -EFAULT; + } + inhdr = g_slice_new(QEMUIOVector); + qemu_iovec_init(inhdr, 1); + qemu_iovec_concat_iov(inhdr, in_iov, in_num, + in_size - sizeof(struct virtio_blk_inhdr), + sizeof(struct virtio_blk_inhdr)); + iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); + + /* TODO Linux sets the barrier bit even when not advertised! */ + outhdr.type &= ~VIRTIO_BLK_T_BARRIER; + + switch (outhdr.type) { + case VIRTIO_BLK_T_IN: + iocb = ioq_rdwr(ioq, true, in_iov, in_num, outhdr.sector * 512); + break; + + case VIRTIO_BLK_T_OUT: + iocb = ioq_rdwr(ioq, false, iov, out_num, outhdr.sector * 512); + break; + + case VIRTIO_BLK_T_SCSI_CMD: + /* TODO support SCSI commands */ + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_UNSUPP); + return 0; + + case VIRTIO_BLK_T_FLUSH: + /* TODO fdsync not supported by Linux AIO, do it synchronously here! */ + if (qemu_fdatasync(s->fd) < 0) { + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_IOERR); + } else { + complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK); + } + return 0; + + case VIRTIO_BLK_T_GET_ID: + do_get_id_cmd(s, in_iov, in_num, head, inhdr); + return 0; + + default: + error_report("virtio-blk unsupported request type %#x", outhdr.type); + qemu_iovec_destroy(inhdr); + g_slice_free(QEMUIOVector, inhdr); + return -EFAULT; + } + + /* Fill in virtio block metadata needed for completion */ + VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); + req->head = head; + req->inhdr = inhdr; + return 0; +} + +static void handle_notify(EventHandler *handler) +{ + VirtIOBlockDataPlane *s = container_of(handler, VirtIOBlockDataPlane, + notify_handler); + + /* There is one array of iovecs into which all new requests are extracted + * from the vring. Requests are read from the vring and the translated + * descriptors are written to the iovecs array. The iovecs do not have to + * persist across handle_notify() calls because the kernel copies the + * iovecs on io_submit(). + * + * Handling io_submit() EAGAIN may require storing the requests across + * handle_notify() calls until the kernel has sufficient resources to + * accept more I/O. This is not implemented yet. + */ + struct iovec iovec[VRING_MAX]; + struct iovec *end = &iovec[VRING_MAX]; + struct iovec *iov = iovec; + + /* When a request is read from the vring, the index of the first descriptor + * (aka head) is returned so that the completed request can be pushed onto + * the vring later. + * + * The number of hypervisor read-only iovecs is out_num. The number of + * hypervisor write-only iovecs is in_num. + */ + int head; + unsigned int out_num = 0, in_num = 0; + unsigned int num_queued; + + for (;;) { + /* Disable guest->host notifies to avoid unnecessary vmexits */ + vring_disable_notification(s->vdev, &s->vring); + + for (;;) { + head = vring_pop(s->vdev, &s->vring, iov, end, &out_num, &in_num); + if (head < 0) { + break; /* no more requests */ + } + + trace_virtio_blk_data_plane_process_request(s, out_num, in_num, + head); + + if (process_request(&s->ioqueue, iov, out_num, in_num, head) < 0) { + vring_set_broken(&s->vring); + break; + } + iov += out_num + in_num; + } + + if (likely(head == -EAGAIN)) { /* vring emptied */ + /* Re-enable guest->host notifies and stop processing the vring. + * But if the guest has snuck in more descriptors, keep processing. + */ + if (vring_enable_notification(s->vdev, &s->vring)) { + break; + } + } else { /* head == -ENOBUFS or fatal error, iovecs[] is depleted */ + /* Since there are no iovecs[] left, stop processing for now. Do + * not re-enable guest->host notifies since the I/O completion + * handler knows to check for more vring descriptors anyway. + */ + break; + } + } + + num_queued = ioq_num_queued(&s->ioqueue); + if (num_queued > 0) { + s->num_reqs += num_queued; + + int rc = ioq_submit(&s->ioqueue); + if (unlikely(rc < 0)) { + fprintf(stderr, "ioq_submit failed %d\n", rc); + exit(1); + } + } +} + +static void handle_io(EventHandler *handler) +{ + VirtIOBlockDataPlane *s = container_of(handler, VirtIOBlockDataPlane, + io_handler); + + if (ioq_run_completion(&s->ioqueue, complete_request, s) > 0) { + notify_guest(s); + } + + /* If there were more requests than iovecs, the vring will not be empty yet + * so check again. There should now be enough resources to process more + * requests. + */ + if (unlikely(vring_more_avail(&s->vring))) { + handle_notify(&s->notify_handler); + } +} + +static void *data_plane_thread(void *opaque) +{ + VirtIOBlockDataPlane *s = opaque; + + do { + event_poll(&s->event_poll); + } while (s->started || s->num_reqs > 0); + return NULL; +} + +static void start_data_plane_bh(void *opaque) +{ + VirtIOBlockDataPlane *s = opaque; + + qemu_bh_delete(s->start_bh); + s->start_bh = NULL; + qemu_thread_create(&s->thread, data_plane_thread, + s, QEMU_THREAD_JOINABLE); +} + +bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, + VirtIOBlockDataPlane **dataplane) +{ + VirtIOBlockDataPlane *s; + int fd; + + *dataplane = NULL; + + if (!blk->data_plane) { + return true; + } + + if (blk->scsi) { + error_report("device is incompatible with x-data-plane, use scsi=off"); + return false; + } + + if (blk->config_wce) { + error_report("device is incompatible with x-data-plane, " + "use config-wce=off"); + return false; + } + + fd = raw_get_aio_fd(blk->conf.bs); + if (fd < 0) { + error_report("drive is incompatible with x-data-plane, " + "use format=raw,cache=none,aio=native"); + return false; + } + + s = g_new0(VirtIOBlockDataPlane, 1); + s->vdev = vdev; + s->fd = fd; + s->blk = blk; + + /* Prevent block operations that conflict with data plane thread */ + bdrv_set_in_use(blk->conf.bs, 1); + + error_setg(&s->migration_blocker, + "x-data-plane does not support migration"); + migrate_add_blocker(s->migration_blocker); + + *dataplane = s; + return true; +} + +void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) +{ + if (!s) { + return; + } + + virtio_blk_data_plane_stop(s); + migrate_del_blocker(s->migration_blocker); + error_free(s->migration_blocker); + bdrv_set_in_use(s->blk->conf.bs, 0); + g_free(s); +} + +void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) +{ + VirtQueue *vq; + int i; + + if (s->started) { + return; + } + + vq = virtio_get_queue(s->vdev, 0); + if (!vring_setup(&s->vring, s->vdev, 0)) { + return; + } + + event_poll_init(&s->event_poll); + + /* Set up guest notifier (irq) */ + if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, + true) != 0) { + fprintf(stderr, "virtio-blk failed to set guest notifier, " + "ensure -enable-kvm is set\n"); + exit(1); + } + s->guest_notifier = virtio_queue_get_guest_notifier(vq); + + /* Set up virtqueue notify */ + if (s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, + 0, true) != 0) { + fprintf(stderr, "virtio-blk failed to set host notifier\n"); + exit(1); + } + event_poll_add(&s->event_poll, &s->notify_handler, + virtio_queue_get_host_notifier(vq), + handle_notify); + + /* Set up ioqueue */ + ioq_init(&s->ioqueue, s->fd, REQ_MAX); + for (i = 0; i < ARRAY_SIZE(s->requests); i++) { + ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb); + } + event_poll_add(&s->event_poll, &s->io_handler, + ioq_get_notifier(&s->ioqueue), handle_io); + + s->started = true; + trace_virtio_blk_data_plane_start(s); + + /* Kick right away to begin processing requests already in vring */ + event_notifier_set(virtio_queue_get_host_notifier(vq)); + + /* Spawn thread in BH so it inherits iothread cpusets */ + s->start_bh = qemu_bh_new(start_data_plane_bh, s); + qemu_bh_schedule(s->start_bh); +} + +void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) +{ + if (!s->started) { + return; + } + s->started = false; + trace_virtio_blk_data_plane_stop(s); + + /* Stop thread or cancel pending thread creation BH */ + if (s->start_bh) { + qemu_bh_delete(s->start_bh); + s->start_bh = NULL; + } else { + event_poll_notify(&s->event_poll); + qemu_thread_join(&s->thread); + } + + ioq_cleanup(&s->ioqueue); + + s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, 0, false); + + event_poll_cleanup(&s->event_poll); + + /* Clean up guest notifier (irq) */ + s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, false); + + vring_teardown(&s->vring); +} diff --git a/hw/dataplane/virtio-blk.h b/hw/dataplane/virtio-blk.h new file mode 100644 index 0000000000..1e8fdfe418 --- /dev/null +++ b/hw/dataplane/virtio-blk.h @@ -0,0 +1,29 @@ +/* + * Dedicated thread for virtio-blk I/O processing + * + * Copyright 2012 IBM, Corp. + * Copyright 2012 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef HW_DATAPLANE_VIRTIO_BLK_H +#define HW_DATAPLANE_VIRTIO_BLK_H + +#include "hw/virtio.h" + +typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane; + +bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, + VirtIOBlockDataPlane **dataplane); +void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s); + +#endif /* HW_DATAPLANE_VIRTIO_BLK_H */ diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 454f445d61..43ca492080 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -105,6 +105,7 @@ struct VirtIOBlkConf char *serial; uint32_t scsi; uint32_t config_wce; + uint32_t data_plane; }; #define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \ diff --git a/trace-events b/trace-events index 167d776eff..4023a4c094 100644 --- a/trace-events +++ b/trace-events @@ -98,6 +98,12 @@ virtio_blk_rw_complete(void *req, int ret) "req %p ret %d" virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" +# hw/dataplane/virtio-blk.c +virtio_blk_data_plane_start(void *s) "dataplane %p" +virtio_blk_data_plane_stop(void *s) "dataplane %p" +virtio_blk_data_plane_process_request(void *s, unsigned int out_num, unsigned int in_num, unsigned int head) "dataplane %p out_num %u in_num %u head %u" +virtio_blk_data_plane_complete_request(void *s, unsigned int head, int ret) "dataplane %p head %u ret %d" + # hw/dataplane/vring.c vring_setup(uint64_t physical, void *desc, void *avail, void *used) "vring physical %#"PRIx64" desc %p avail %p used %p" From 392808b49b6aee066d0c1d200e72fc3dc11c9d0f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 14 Nov 2012 15:45:38 +0100 Subject: [PATCH 0063/1634] virtio-blk: add x-data-plane=on|off performance feature The virtio-blk-data-plane feature is easy to integrate into hw/virtio-blk.c. The data plane can be started and stopped similar to vhost-net. Users can take advantage of the virtio-blk-data-plane feature using the new -device virtio-blk-pci,x-data-plane=on property. The x-data-plane name was chosen because at this stage the feature is experimental and likely to see changes in the future. If the VM configuration does not support virtio-blk-data-plane an error message is printed. Although we could fall back to regular virtio-blk, I prefer the explicit approach since it prompts the user to fix their configuration if they want the performance benefit of virtio-blk-data-plane. Limitations: * Only format=raw is supported * Live migration is not supported * Block jobs, hot unplug, and other operations fail with -EBUSY * I/O throttling limits are ignored * Only Linux hosts are supported due to Linux AIO usage Signed-off-by: Stefan Hajnoczi --- hw/virtio-blk.c | 44 +++++++++++++++++++++++++++++++++++++++++++- hw/virtio-pci.c | 3 +++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index f004148e3e..92c745a316 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -17,6 +17,9 @@ #include "hw/block-common.h" #include "sysemu/blockdev.h" #include "virtio-blk.h" +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE +#include "hw/dataplane/virtio-blk.h" +#endif #include "scsi-defs.h" #ifdef __linux__ # include @@ -33,6 +36,9 @@ typedef struct VirtIOBlock VirtIOBlkConf *blk; unsigned short sector_mask; DeviceState *qdev; +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + VirtIOBlockDataPlane *dataplane; +#endif } VirtIOBlock; static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) @@ -407,6 +413,16 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) .num_writes = 0, }; +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start + * dataplane here instead of waiting for .set_status(). + */ + if (s->dataplane) { + virtio_blk_data_plane_start(s->dataplane); + return; + } +#endif + while ((req = virtio_blk_get_request(s))) { virtio_blk_handle_request(req, &mrb); } @@ -446,8 +462,9 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, { VirtIOBlock *s = opaque; - if (!running) + if (!running) { return; + } if (!s->bh) { s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s); @@ -457,6 +474,14 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, static void virtio_blk_reset(VirtIODevice *vdev) { +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + VirtIOBlock *s = to_virtio_blk(vdev); + + if (s->dataplane) { + virtio_blk_data_plane_stop(s->dataplane); + } +#endif + /* * This should cancel pending requests, but can't do nicely until there * are per-device request lists. @@ -541,6 +566,12 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) VirtIOBlock *s = to_virtio_blk(vdev); uint32_t features; +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + if (s->dataplane && !(status & VIRTIO_CONFIG_S_DRIVER)) { + virtio_blk_data_plane_stop(s->dataplane); + } +#endif + if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { return; } @@ -638,6 +669,12 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1; s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output); +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + if (!virtio_blk_data_plane_create(&s->vdev, blk, &s->dataplane)) { + virtio_cleanup(&s->vdev); + return NULL; + } +#endif qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); s->qdev = dev; @@ -655,6 +692,11 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) void virtio_blk_exit(VirtIODevice *vdev) { VirtIOBlock *s = to_virtio_blk(vdev); + +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + virtio_blk_data_plane_destroy(s->dataplane); + s->dataplane = NULL; +#endif unregister_savevm(s->qdev, "virtio-blk", s); blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 3cab783804..82761cf7f7 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -896,6 +896,9 @@ static Property virtio_blk_properties[] = { #endif DEFINE_PROP_BIT("config-wce", VirtIOPCIProxy, blk.config_wce, 0, true), DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + DEFINE_PROP_BIT("x-data-plane", VirtIOPCIProxy, blk.data_plane, 0, false), +#endif DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_END_OF_LIST(), From 9e72c45033770b81b536ac6091e91807247cc25a Mon Sep 17 00:00:00 2001 From: Alexey Zaytsev Date: Thu, 13 Dec 2012 09:03:43 +0200 Subject: [PATCH 0064/1634] virtio-blk: Return UNSUPP for unknown request types Currently, all unknown requests are treated as VIRTIO_BLK_T_IN Signed-off-by: Alexey Zaytsev Signed-off-by: Stefan Hajnoczi --- hw/virtio-blk.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 92c745a316..df57b35f1b 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -398,10 +398,14 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req, qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1], req->elem.out_num - 1); virtio_blk_handle_write(req, mrb); - } else { + } else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) { + /* VIRTIO_BLK_T_IN is 0, so we can't just & it. */ qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0], req->elem.in_num - 1); virtio_blk_handle_read(req); + } else { + virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP); + g_free(req); } } From 37edbf7ea8067262a5c3d8bbe4786139348c8311 Mon Sep 17 00:00:00 2001 From: liguang Date: Mon, 17 Dec 2012 09:49:22 +0800 Subject: [PATCH 0065/1634] cutils: change strtosz_suffix_unit function if value to be translated is larger than INT64_MAX, this function will not be convenient for caller to be aware of it, so change a little for this. Signed-off-by: liguang Signed-off-by: Stefan Hajnoczi --- cutils.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cutils.c b/cutils.c index d06590b330..80bb1dcbf7 100644 --- a/cutils.c +++ b/cutils.c @@ -214,12 +214,13 @@ static int64_t suffix_mul(char suffix, int64_t unit) /* * Convert string to bytes, allowing either B/b for bytes, K/k for KB, * M/m for MB, G/g for GB or T/t for TB. End pointer will be returned - * in *end, if not NULL. Return -1 on error. + * in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on + * other error. */ int64_t strtosz_suffix_unit(const char *nptr, char **end, const char default_suffix, int64_t unit) { - int64_t retval = -1; + int64_t retval = -EINVAL; char *endptr; unsigned char c; int mul_required = 0; @@ -246,6 +247,7 @@ int64_t strtosz_suffix_unit(const char *nptr, char **end, goto fail; } if ((val * mul >= INT64_MAX) || val < 0) { + retval = -ERANGE; goto fail; } retval = val * mul; From 7944339726b4582b67fd94085c21c33636e8f973 Mon Sep 17 00:00:00 2001 From: liguang Date: Mon, 17 Dec 2012 09:49:23 +0800 Subject: [PATCH 0066/1634] qemu-img: report size overflow error message qemu-img will complain when qcow or qcow2 size overflow for 64 bits, report the right message in this condition. $./qemu-img create -f qcow2 /tmp/foo 0x10000000000000000 before change: qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for qemu-img: kilobytes, megabytes, gigabytes and terabytes. after change: qemu-img: Image size must be less than 8 EiB! [Resolved conflict with a9300911 goto removal -- Stefan] Signed-off-by: liguang Signed-off-by: Stefan Hajnoczi --- qemu-img.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 69cc02871b..85d3740b9c 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -348,9 +348,13 @@ static int img_create(int argc, char **argv) char *end; sval = strtosz_suffix(argv[optind++], &end, STRTOSZ_DEFSUFFIX_B); if (sval < 0 || *end) { - error_report("Invalid image size specified! You may use k, M, G or " - "T suffixes for "); - error_report("kilobytes, megabytes, gigabytes and terabytes."); + if (sval == -ERANGE) { + error_report("Image size must be less than 8 EiB!"); + } else { + error_report("Invalid image size specified! You may use k, M, " + "G or T suffixes for "); + error_report("kilobytes, megabytes, gigabytes and terabytes."); + } return 1; } img_size = (uint64_t)sval; From fccedc624c425e3acb1557f9f9b13104427ec5ce Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 17 Dec 2012 20:40:01 +0100 Subject: [PATCH 0067/1634] block/raw-win32: Fix compiler warnings (wrong format specifiers) Commit fbcad04d6bfdff937536eb23088a01a280a1a3af added fprintf statements with wrong format specifiers. GetLastError() returns a DWORD which is unsigned long, so %lu must be used. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- block/raw-win32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/raw-win32.c b/block/raw-win32.c index f58334be08..b89ac19ffa 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -314,11 +314,11 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset) */ dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN); if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { - fprintf(stderr, "SetFilePointer error: %d\n", GetLastError()); + fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError()); return -EIO; } if (SetEndOfFile(s->hfile) == 0) { - fprintf(stderr, "SetEndOfFile error: %d\n", GetLastError()); + fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError()); return -EIO; } return 0; From bd751f2204a03d6fcd47a4b4b12ac534d2ecbea7 Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Mon, 17 Dec 2012 14:17:26 +0800 Subject: [PATCH 0068/1634] sheepdog: don't update inode when create_and_write fails For the error case such as SD_RES_NO_SPACE, we shouldn't update the inode bitmap to avoid the scenario that the object is allocated but wasn't created at the server side. This will result in VM's IO error on the failed object. Cc: MORITA Kazutaka Cc: Kevin Wolf Signed-off-by: Liu Yuan Reviewed-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 13dc023fdb..b9186fb92b 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -714,10 +714,11 @@ static void coroutine_fn aio_read_response(void *opaque) * and max_dirty_data_idx are changed to include updated * index between them. */ - s->inode.data_vdi_id[idx] = s->inode.vdi_id; - s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx); - s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx); - + if (rsp.result == SD_RES_SUCCESS) { + s->inode.data_vdi_id[idx] = s->inode.vdi_id; + s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx); + s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx); + } /* * Some requests may be blocked because simultaneous * create requests are not allowed, so we search the From d6b1ef89a1ede41334e4d0fa27e600e0b4d4f209 Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Mon, 17 Dec 2012 14:17:27 +0800 Subject: [PATCH 0069/1634] sheepdog: pass oid directly to send_pending_req() Cc: MORITA Kazutaka Cc: Kevin Wolf Signed-off-by: Liu Yuan Reviewed-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index b9186fb92b..e821746116 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -724,7 +724,7 @@ static void coroutine_fn aio_read_response(void *opaque) * create requests are not allowed, so we search the * pending requests here. */ - send_pending_req(s, vid_to_data_oid(s->inode.vdi_id, idx)); + send_pending_req(s, aio_req->oid); } break; case AIOCB_READ_UDATA: From 9a8a5ae69d3a436e51a7eb2edafe254572f60823 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 30 Dec 2012 08:20:13 +0100 Subject: [PATCH 0070/1634] tcg: Remove unneeded assertion Commit 7f6f0ae5b95adfa76e10eabe2c34424a955fd10c added two assertions. One of these assertions is not needed: The pointer ts is never NULL because it is initialized with the address of an array element. Reviewed-by: Richard Henderson Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- tcg/tcg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index ede51a3960..9275e372ff 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -800,7 +800,6 @@ static char *tcg_get_arg_str_idx(TCGContext *s, char *buf, int buf_size, assert(idx >= 0 && idx < s->nb_temps); ts = &s->temps[idx]; - assert(ts); if (idx < s->nb_globals) { pstrcpy(buf, buf_size, ts->name); } else { From ab51b1d568e02c80b1abf9016bda3a86dc1db389 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sun, 30 Dec 2012 12:48:14 +0400 Subject: [PATCH 0071/1634] disallow -daemonize usage of stdio (curses display, -nographic, -serial stdio etc) Curses display requires stdin/out to stay on the terminal, so -daemonize makes no sense in this case. Instead of leaving display uninitialized like is done since 995ee2bf469de6bb, explicitly detect this case earlier and error out. -nographic can actually be used with -daemonize, by redirecting everything to a null device, but the problem is that according to documentation and historical behavour, -nographic redirects guest ports to stdin/out, which, again, makes no sense in case of -daemonize. Since -nographic is a legacy option, don't bother fixing this case (to allow -nographic and -daemonize by redirecting guest ports to null instead of stdin/out in this case), but disallow it completely instead, to stop garbling host terminal. If no display display needed and user wants to use -nographic, the right way to go is to use -serial null -parallel null -monitor none -display none -vga none instead of -nographic. Also prevent the same issue -- it was possible to get garbled host tty after -nographic -daemonize and it is still possible to have it by using -serial stdio -daemonize Fix this by disallowing opening stdio chardev when -daemonize is specified. Signed-off-by: Michael Tokarev Signed-off-by: Anthony Liguori --- qemu-char.c | 4 ++++ vl.c | 28 +++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index c6382a93f5..331ad5c087 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -772,6 +772,10 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) if (stdio_nb_clients >= STDIO_MAX_CLIENTS) { return NULL; } + if (is_daemonized()) { + error_report("cannot use stdio with -daemonize"); + return NULL; + } if (stdio_nb_clients == 0) { old_fd0_flags = fcntl(0, F_GETFL); tcgetattr (0, &oldtty); diff --git a/vl.c b/vl.c index e6a8d89acc..f056c95807 100644 --- a/vl.c +++ b/vl.c @@ -3637,6 +3637,30 @@ int main(int argc, char **argv, char **envp) default_sdcard = 0; } + if (is_daemonized()) { + /* According to documentation and historically, -nographic redirects + * serial port, parallel port and monitor to stdio, which does not work + * with -daemonize. We can redirect these to null instead, but since + * -nographic is legacy, let's just error out. + * We disallow -nographic only if all other ports are not redirected + * explicitly, to not break existing legacy setups which uses + * -nographic _and_ redirects all ports explicitly - this is valid + * usage, -nographic is just a no-op in this case. + */ + if (display_type == DT_NOGRAPHIC + && (default_parallel || default_serial + || default_monitor || default_virtcon)) { + fprintf(stderr, "-nographic can not be used with -daemonize\n"); + exit(1); + } +#ifdef CONFIG_CURSES + if (display_type == DT_CURSES) { + fprintf(stderr, "curses display can not be used with -daemonize\n"); + exit(1); + } +#endif + } + if (display_type == DT_NOGRAPHIC) { if (default_parallel) add_device_config(DEV_PARALLEL, "null"); @@ -3903,9 +3927,7 @@ int main(int argc, char **argv, char **envp) break; #if defined(CONFIG_CURSES) case DT_CURSES: - if (!is_daemonized()) { - curses_display_init(ds, full_screen); - } + curses_display_init(ds, full_screen); break; #endif #if defined(CONFIG_SDL) From 74e91370beb3fabda515623b4491a8b7a024304a Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Mon, 31 Dec 2012 15:30:31 +0400 Subject: [PATCH 0072/1634] savevm.c: cleanup system includes savevm.c suffers from the same problem as some other files. Some years ago savevm.c was created from vl.c, moving some code from there into a separate file. At that time, all includes were just copied from vl.c to savevm.c, without checking which ones are needed and which are not. But actually most of that stuff is _not_ needed. More, some stuff is wrong, for example, *BSD #ifdef'ery around vs - for one, it fails to build on Debian/kFreebsd. Just remove all this. Maybe there's a possibility to clean it up further - like removing (and maybe including winsock.h for htons etc), and maybe it's possible to remove some internal #includes too, but I didn't check this. While at it, remove duplicate #include of qemu/timer.h. Signed-off-by: Michael Tokarev Signed-off-by: Anthony Liguori --- savevm.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/savevm.c b/savevm.c index bcdb92ee81..529d60ec1f 100644 --- a/savevm.c +++ b/savevm.c @@ -21,52 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -/* Needed early for CONFIG_BSD etc. */ #include "config-host.h" #ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#ifdef CONFIG_BSD -#include -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#include -#else -#include -#endif -#ifdef __linux__ -#include -#include -#include -#endif -#endif #endif #ifdef _WIN32 #include -#include -#include -#include -#define getopt_long_only getopt_long -#define memalign(align, size) malloc(size) #endif #include "qemu-common.h" @@ -80,7 +43,6 @@ #include "migration/migration.h" #include "qemu/sockets.h" #include "qemu/queue.h" -#include "qemu/timer.h" #include "sysemu/cpus.h" #include "exec/memory.h" #include "qmp-commands.h" From 503483336039a8b2b182535f87f4820d259fca82 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 1 Jan 2013 18:43:56 +0100 Subject: [PATCH 0073/1634] tci: Fix broken builds with TCG interpreter TCI no longer compiled after commit 76cad71136b7eb371cf2a2a4e1621cfe8d9c769a. The TCI disassembler depends on data structures which are different for each QEMU target, so it cannot be compiled as a universal-obj today. Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- Makefile.target | 3 +-- disas/Makefile.objs | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile.target b/Makefile.target index be8b8b86a5..5bfa496080 100644 --- a/Makefile.target +++ b/Makefile.target @@ -69,13 +69,12 @@ all: $(PROGS) stap obj-y = exec.o translate-all.o cpu-exec.o obj-y += tcg/tcg.o tcg/optimize.o obj-$(CONFIG_TCG_INTERPRETER) += tci.o +obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o obj-y += fpu/softfloat.o obj-y += target-$(TARGET_BASE_ARCH)/ obj-y += disas.o obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o -tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci - ######################################################### # Linux user emulator target diff --git a/disas/Makefile.objs b/disas/Makefile.objs index 9134429845..3f5c5b9a21 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -13,4 +13,6 @@ universal-obj-$(CONFIG_SH4_DIS) += sh4.o universal-obj-$(CONFIG_SPARC_DIS) += sparc.o universal-obj-$(CONFIG_LM32_DIS) += lm32.o -universal-obj-$(CONFIG_TCI_DIS) += tci.o +# TODO: As long as the TCG interpreter and its generated code depend +# on the QEMU target, we cannot compile the disassembler here. +#universal-obj-$(CONFIG_TCI_DIS) += tci.o From dbd99ae302be8f51b547fb6283c91d0c9859b7d5 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 1 Jan 2013 18:33:44 +0100 Subject: [PATCH 0074/1634] configure: Write new file "config-all-disas.mak" when running configure Incremental builds added new lines to that file each time when configure was run. Now a new file with a comment line is written. Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index cc1e20ac54..9538041d05 100755 --- a/configure +++ b/configure @@ -3314,6 +3314,8 @@ fi config_host_mak="config-host.mak" config_host_ld="config-host.ld" +echo "# Automatically generated by configure - do not modify" >config-all-disas.mak + echo "# Automatically generated by configure - do not modify" > $config_host_mak printf "# Configured with:" >> $config_host_mak printf " '%s'" "$0" "$@" >> $config_host_mak From ef4929fb3c25e03deca76c7f5d22fba08edf864f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 3 Jan 2013 11:56:16 +0100 Subject: [PATCH 0075/1634] dataplane: use linux-headers/ for virtio includes The hw/dataplane/vring.c code includes linux/virtio_ring.h. Ensure that we use linux-headers/ instead of the system-wide headers, which may be out-of-date on older distros. This resolves the following build error on Debian 6: CC hw/dataplane/vring.o cc1: warnings being treated as errors hw/dataplane/vring.c: In function 'vring_enable_notification': hw/dataplane/vring.c:71: error: implicit declaration of function 'vring_avail_event' hw/dataplane/vring.c:71: error: nested extern declaration of 'vring_avail_event' hw/dataplane/vring.c:71: error: lvalue required as left operand of assignment Note that we now build dataplane/ for each target instead of only once. There is no way around this since linux-headers/ is only available for per-target objects - and it's how virtio, vfio, kvm, and friends are built. Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- hw/Makefile.objs | 3 ++- hw/dataplane/Makefile.objs | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 5ac49134bd..b8bbed39c1 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y = usb/ ide/ pci/ dataplane/ +common-obj-y = usb/ ide/ pci/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o common-obj-$(CONFIG_VIRTIO) += virtio-rng.o @@ -191,6 +191,7 @@ common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o # Per-target files # virtio has to be here due to weird dependency between PCI and virtio-net. # need to fix this properly +obj-$(CONFIG_VIRTIO) += dataplane/ obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o virtio-scsi.o obj-$(CONFIG_SOFTMMU) += vhost_net.o diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs index 682aa9e7ee..3e47d0537e 100644 --- a/hw/dataplane/Makefile.objs +++ b/hw/dataplane/Makefile.objs @@ -1,3 +1 @@ -ifeq ($(CONFIG_VIRTIO), y) -common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o ioq.o virtio-blk.o -endif +obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o ioq.o virtio-blk.o From 25bbf61e4bacd1e4fa4115ffcf151051b9d6608e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 3 Jan 2013 14:23:03 +0100 Subject: [PATCH 0076/1634] pty: unbreak libvirt Commit 586502189edf9fd0f89a83de96717a2ea826fdb0 breaks libvirt pty support because it tried to figure the pts name from stderr output. Fix this by moving the label to the end of the line, this way the libvirt parser does still recognise the message. libvirt looks for "char device redirected to ${ptsname}". Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- qemu-char.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 331ad5c087..f41788c9ef 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1012,10 +1012,11 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) qemu_opt_set(opts, "path", q_ptsname(master_fd)); label = qemu_opts_id(opts); - fprintf(stderr, "char device%s%s redirected to %s\n", - label ? " " : "", - label ?: "", - q_ptsname(master_fd)); + fprintf(stderr, "char device redirected to %s%s%s%s\n", + q_ptsname(master_fd), + label ? " (label " : "", + label ? label : "", + label ? ")" : ""); s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; From 5acc2ec041b2fd5c9a85d9d12362c08d3b3bf339 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 Dec 2012 10:45:49 +0100 Subject: [PATCH 0077/1634] configure: also symlink *.aml files Signed-off-by: Gerd Hoffmann --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 9538041d05..1e9fd868af 100755 --- a/configure +++ b/configure @@ -4240,6 +4240,7 @@ FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" for bios_file in \ $source_path/pc-bios/*.bin \ + $source_path/pc-bios/*.aml \ $source_path/pc-bios/*.rom \ $source_path/pc-bios/*.dtb \ $source_path/pc-bios/openbios-* \ From f7e4dd6c18ccfbaf6cd2f5eaaed2b77cabc8a406 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 Dec 2012 10:47:27 +0100 Subject: [PATCH 0078/1634] acpi: autoload dsdt Signed-off-by: Gerd Hoffmann --- hw/pc.c | 23 +++++++++++++++++++++++ hw/pc.h | 1 + hw/pc_piix.c | 1 + hw/pc_q35.c | 1 + 4 files changed, 26 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index 71902e210b..5ec3bd5aff 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -886,6 +886,29 @@ void pc_cpus_init(const char *cpu_model) } } +void pc_acpi_init(const char *default_dsdt) +{ + char *filename = NULL, *arg = NULL; + + if (acpi_tables != NULL) { + /* manually set via -acpitable, leave it alone */ + return; + } + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt); + if (filename == NULL) { + fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt); + return; + } + + arg = g_strdup_printf("file=%s", filename); + if (acpi_table_add(arg) != 0) { + fprintf(stderr, "WARNING: failed to load %s\n", filename); + } + g_free(arg); + g_free(filename); +} + void *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline, diff --git a/hw/pc.h b/hw/pc.h index a73e3e7b5b..4134aa94e5 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -79,6 +79,7 @@ void pc_register_ferr_irq(qemu_irq irq); void pc_acpi_smi_interrupt(void *opaque, int irq, int level); void pc_cpus_init(const char *cpu_model); +void pc_acpi_init(const char *default_dsdt); void *pc_memory_init(MemoryRegion *system_memory, const char *kernel_filename, const char *kernel_cmdline, diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 99747a774c..2b3d58b852 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -87,6 +87,7 @@ static void pc_init1(MemoryRegion *system_memory, void *fw_cfg = NULL; pc_cpus_init(cpu_model); + pc_acpi_init("acpi-dsdt.aml"); if (kvmclock_enabled) { kvmclock_create(); diff --git a/hw/pc_q35.c b/hw/pc_q35.c index c7262d6315..ef540b6a71 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -87,6 +87,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) qemu_irq *cmos_s3; pc_cpus_init(cpu_model); + pc_acpi_init("q35-acpi-dsdt.aml"); kvmclock_create(); From 56e5b2a1a655b9158c0d274a6f630927c9a5fb4b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 11 Dec 2012 09:40:45 +0100 Subject: [PATCH 0079/1634] apci: assign memory regions to piix4 acpi device Get rid of get_system_io() usage. Signed-off-by: Gerd Hoffmann --- hw/acpi_piix4.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index f53b969aa6..06a8aca9cb 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -57,6 +57,7 @@ struct pci_status { typedef struct PIIX4PMState { PCIDevice dev; + MemoryRegion io; MemoryRegion io_gpe; MemoryRegion io_pci; @@ -83,7 +84,8 @@ typedef struct PIIX4PMState { uint8_t s4_val; } PIIX4PMState; -static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); +static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, + PCIBus *bus, PIIX4PMState *s); #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 @@ -406,11 +408,13 @@ static int piix4_pm_initfn(PCIDevice *dev) pci_conf[0xd2] = 0x09; pm_smbus_init(&s->dev.qdev, &s->smb); memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1); - memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io); + memory_region_add_subregion(pci_address_space_io(dev), + s->smb_io_base, &s->smb.io); memory_region_init(&s->io, "piix4-pm", 64); memory_region_set_enabled(&s->io, false); - memory_region_add_subregion(get_system_io(), 0, &s->io); + memory_region_add_subregion(pci_address_space_io(dev), + 0, &s->io); acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); @@ -423,7 +427,8 @@ static int piix4_pm_initfn(PCIDevice *dev) s->machine_ready.notify = piix4_pm_machine_ready; qemu_add_machine_init_done_notifier(&s->machine_ready); qemu_register_reset(piix4_reset, s); - piix4_acpi_system_hot_add_init(dev->bus, s); + + piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s); return 0; } @@ -593,15 +598,16 @@ static const MemoryRegionOps piix4_pci_ops = { static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, PCIHotplugState state); -static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) +static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, + PCIBus *bus, PIIX4PMState *s) { memory_region_init_io(&s->io_gpe, &piix4_gpe_ops, s, "apci-gpe0", GPE_LEN); - memory_region_add_subregion(get_system_io(), GPE_BASE, &s->io_gpe); + memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe); memory_region_init_io(&s->io_pci, &piix4_pci_ops, s, "apci-pci-hotplug", PCI_HOTPLUG_SIZE); - memory_region_add_subregion(get_system_io(), PCI_HOTPLUG_ADDR, + memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR, &s->io_pci); pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); } From 503b19fc5d018f4edc60fb771cf97f47cea71be2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 11 Dec 2012 09:42:18 +0100 Subject: [PATCH 0080/1634] apci: assign memory regions to ich9 lpc device Get rid of get_system_io() usage. Signed-off-by: Gerd Hoffmann --- hw/acpi_ich9.c | 6 ++++-- hw/acpi_ich9.h | 4 +++- hw/lpc_ich9.c | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c index 37a50e6d7b..d2f9808242 100644 --- a/hw/acpi_ich9.c +++ b/hw/acpi_ich9.c @@ -202,11 +202,13 @@ static void pm_powerdown_req(Notifier *n, void *opaque) acpi_pm1_evt_power_down(&pm->acpi_regs); } -void ich9_pm_init(ICH9LPCPMRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3) +void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, + qemu_irq sci_irq, qemu_irq cmos_s3) { memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE); memory_region_set_enabled(&pm->io, false); - memory_region_add_subregion(get_system_io(), 0, &pm->io); + memory_region_add_subregion(pci_address_space_io(lpc_pci), + 0, &pm->io); acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h index bc221d3cbc..ecb82abc65 100644 --- a/hw/acpi_ich9.h +++ b/hw/acpi_ich9.h @@ -30,9 +30,11 @@ typedef struct ICH9LPCPMRegs { * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t. */ ACPIREGS acpi_regs; + MemoryRegion io; MemoryRegion io_gpe; MemoryRegion io_smi; + uint32_t smi_en; uint32_t smi_sts; @@ -42,7 +44,7 @@ typedef struct ICH9LPCPMRegs { Notifier powerdown_notifier; } ICH9LPCPMRegs; -void ich9_pm_init(ICH9LPCPMRegs *pm, +void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3_resume); void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base); extern const VMStateDescription vmstate_ich9_pm; diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index a068715c04..16843d76bc 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -336,7 +336,7 @@ void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3) qemu_irq *sci_irq; sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1); - ich9_pm_init(&lpc->pm, sci_irq[0], cmos_s3); + ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], cmos_s3); ich9_lpc_reset(&lpc->d.qdev); } From e8ba1ce92d8cbc4e77efcaf040077d3901098e5f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Dec 2012 15:43:35 +0100 Subject: [PATCH 0081/1634] switch debugcon to memory api Also some QOM glue while being at it. Signed-off-by: Gerd Hoffmann --- hw/debugcon.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/hw/debugcon.c b/hw/debugcon.c index 14f83f1962..e8a855e33a 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -29,20 +29,27 @@ #include "isa.h" #include "pc.h" +#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" +#define ISA_DEBUGCON_DEVICE(obj) \ + OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE) + //#define DEBUG_DEBUGCON typedef struct DebugconState { + MemoryRegion io; CharDriverState *chr; uint32_t readback; } DebugconState; typedef struct ISADebugconState { - ISADevice dev; + ISADevice parent_obj; + uint32_t iobase; DebugconState state; } ISADebugconState; -static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { DebugconState *s = opaque; unsigned char ch = val; @@ -55,7 +62,7 @@ static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val) } -static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr) +static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width) { DebugconState *s = opaque; @@ -66,6 +73,14 @@ static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr) return s->readback; } +static const MemoryRegionOps debugcon_ops = { + .read = debugcon_ioport_read, + .write = debugcon_ioport_write, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static void debugcon_init_core(DebugconState *s) { if (!s->chr) { @@ -78,12 +93,14 @@ static void debugcon_init_core(DebugconState *s) static int debugcon_isa_initfn(ISADevice *dev) { - ISADebugconState *isa = DO_UPCAST(ISADebugconState, dev, dev); + ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev); DebugconState *s = &isa->state; debugcon_init_core(s); - register_ioport_write(isa->iobase, 1, 1, debugcon_ioport_write, s); - register_ioport_read(isa->iobase, 1, 1, debugcon_ioport_read, s); + memory_region_init_io(&s->io, &debugcon_ops, s, + TYPE_ISA_DEBUGCON_DEVICE, 1); + memory_region_add_subregion(isa_address_space_io(dev), + isa->iobase, &s->io); return 0; } @@ -103,7 +120,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) } static TypeInfo debugcon_isa_info = { - .name = "isa-debugcon", + .name = TYPE_ISA_DEBUGCON_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISADebugconState), .class_init = debugcon_isa_class_initfn, From bb355b1859dde19fbb4f856c6d0b8f46733142d7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Dec 2012 15:54:59 +0100 Subject: [PATCH 0082/1634] add isa-debug-exit device. When present it makes qemu exit on any write. Mapped to port 0x501 by default. Without this patch Anthony doesn't allow me to remove the bochs bios debug ports because his test suite uses this. Signed-off-by: Gerd Hoffmann --- hw/debugexit.c | 75 +++++++++++++++++++++++++++++++++++++++++++ hw/i386/Makefile.objs | 2 +- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 hw/debugexit.c diff --git a/hw/debugexit.c b/hw/debugexit.c new file mode 100644 index 0000000000..90642eb37f --- /dev/null +++ b/hw/debugexit.c @@ -0,0 +1,75 @@ +/* + * debug exit port emulation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + */ + +#include "hw.h" +#include "isa.h" + +#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit" +#define ISA_DEBUG_EXIT_DEVICE(obj) \ + OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE) + +typedef struct ISADebugExitState { + ISADevice parent_obj; + + uint32_t iobase; + uint32_t iosize; + MemoryRegion io; +} ISADebugExitState; + +static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + exit((val << 1) | 1); +} + +static const MemoryRegionOps debug_exit_ops = { + .write = debug_exit_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int debug_exit_initfn(ISADevice *dev) +{ + ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(dev); + + memory_region_init_io(&isa->io, &debug_exit_ops, isa, + TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize); + memory_region_add_subregion(isa_address_space_io(dev), + isa->iobase, &isa->io); + return 0; +} + +static Property debug_exit_properties[] = { + DEFINE_PROP_HEX32("iobase", ISADebugExitState, iobase, 0x501), + DEFINE_PROP_HEX32("iosize", ISADebugExitState, iosize, 0x02), + DEFINE_PROP_END_OF_LIST(), +}; + +static void debug_exit_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = debug_exit_initfn; + dc->props = debug_exit_properties; +} + +static TypeInfo debug_exit_info = { + .name = TYPE_ISA_DEBUG_EXIT_DEVICE, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISADebugExitState), + .class_init = debug_exit_class_initfn, +}; + +static void debug_exit_register_types(void) +{ + type_register_static(&debug_exit_info); +} + +type_init(debug_exit_register_types) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 257f3c1a91..2ba04db0a8 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,7 +3,7 @@ obj-y += apic_common.o apic.o kvmvapic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o -obj-y += debugcon.o multiboot.o +obj-y += debugcon.o debugexit.o multiboot.o obj-y += pc_piix.o obj-y += pc_sysfw.o obj-y += lpc_ich9.o q35.o pc_q35.o From ee0cc5415e6edc043bd84e855f7d0bf85bd97547 Mon Sep 17 00:00:00 2001 From: Lucas Meneghel Rodrigues Date: Thu, 13 Dec 2012 12:48:53 -0200 Subject: [PATCH 0083/1634] hw: Add test device for unittests execution Add a test device which supports the kvmctl ioports, so one can run the KVM unittest suite. Intended Usage: qemu-system-x86_64 -nographic \ -device pc-testdev \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ -kernel /path/to/kvm/unittests/msr.flat Where msr.flat is one of the KVM unittests, present on a separate repo, git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git [ kraxel: more memory api + qom fixes ] CC: Paolo Bonzini Signed-off-by: Alexander Graf Signed-off-by: Marcelo Tosatti Signed-off-by: Lucas Meneghel Rodrigues Signed-off-by: Gerd Hoffmann --- hw/i386/Makefile.objs | 1 + hw/pc-testdev.c | 182 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 hw/pc-testdev.c diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 2ba04db0a8..025803aa66 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -12,5 +12,6 @@ obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o obj-y += kvm/ obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o +obj-y += pc-testdev.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c new file mode 100644 index 0000000000..620c86c92a --- /dev/null +++ b/hw/pc-testdev.c @@ -0,0 +1,182 @@ +/* + * QEMU x86 ISA testdev + * + * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti + * + * 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. + */ + +/* + * This device is used to test KVM features specific to the x86 port, such + * as emulation, power management, interrupt routing, among others. It's meant + * to be used like: + * + * qemu-system-x86_64 -device pc-testdev -serial stdio \ + * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \ + * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat + * + * Where msr.flat is one of the KVM unittests, present on a separate repo, + * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git +*/ + +#include +#include "hw.h" +#include "qdev.h" +#include "isa.h" + +#define IOMEM_LEN 0x10000 + +typedef struct PCTestdev { + ISADevice parent_obj; + + MemoryRegion ioport; + MemoryRegion flush; + MemoryRegion irq; + MemoryRegion iomem; + uint32_t ioport_data; + char iomem_buf[IOMEM_LEN]; +} PCTestdev; + +#define TYPE_TESTDEV "pc-testdev" +#define TESTDEV(obj) \ + OBJECT_CHECK(struct PCTestdev, (obj), TYPE_TESTDEV) + +static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + struct PCTestdev *dev = opaque; + struct ISADevice *isa = ISA_DEVICE(dev); + + qemu_set_irq(isa_get_irq(isa, addr), !!data); +} + +static const MemoryRegionOps test_irq_ops = { + .write = test_irq_line, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + struct PCTestdev *dev = opaque; + dev->ioport_data = data; +} + +static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len) +{ + struct PCTestdev *dev = opaque; + return dev->ioport_data; +} + +static const MemoryRegionOps test_ioport_ops = { + .read = test_ioport_read, + .write = test_ioport_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + hwaddr page = 4096; + void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0); + + /* We might not be able to get the full page, only mprotect what we actually + have mapped */ + mprotect(a, page, PROT_NONE); + mprotect(a, page, PROT_READ|PROT_WRITE); + cpu_physical_memory_unmap(a, page, 0, 0); +} + +static const MemoryRegionOps test_flush_ops = { + .write = test_flush_page, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) +{ + struct PCTestdev *dev = opaque; + uint64_t ret = 0; + memcpy(&ret, &dev->iomem_buf[addr], len); + ret = le64_to_cpu(ret); + + return ret; +} + +static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) +{ + struct PCTestdev *dev = opaque; + val = cpu_to_le64(val); + memcpy(&dev->iomem_buf[addr], &val, len); + dev->iomem_buf[addr] = val; +} + +static const MemoryRegionOps test_iomem_ops = { + .read = test_iomem_read, + .write = test_iomem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int init_test_device(ISADevice *isa) +{ + struct PCTestdev *dev = TESTDEV(isa); + MemoryRegion *mem = isa_address_space(isa); + MemoryRegion *io = isa_address_space_io(isa); + + memory_region_init_io(&dev->ioport, &test_ioport_ops, dev, + "pc-testdev-ioport", 4); + memory_region_init_io(&dev->flush, &test_flush_ops, dev, + "pc-testdev-flush-page", 4); + memory_region_init_io(&dev->irq, &test_irq_ops, dev, + "pc-testdev-irq-line", 24); + memory_region_init_io(&dev->iomem, &test_iomem_ops, dev, + "pc-testdev-iomem", IOMEM_LEN); + + memory_region_add_subregion(io, 0xe0, &dev->ioport); + memory_region_add_subregion(io, 0xe4, &dev->flush); + memory_region_add_subregion(io, 0x2000, &dev->irq); + memory_region_add_subregion(mem, 0xff000000, &dev->iomem); + + return 0; +} + +static void testdev_class_init(ObjectClass *klass, void *data) +{ + ISADeviceClass *k = ISA_DEVICE_CLASS(klass); + + k->init = init_test_device; +} + +static TypeInfo testdev_info = { + .name = TYPE_TESTDEV, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(struct PCTestdev), + .class_init = testdev_class_init, +}; + +static void testdev_register_types(void) +{ + type_register_static(&testdev_info); +} + +type_init(testdev_register_types) From 9ee59f341f9d7a95b3a87b7cac3f74bcdda395fb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 11 Dec 2012 09:59:55 +0100 Subject: [PATCH 0084/1634] pc: remove bochs bios debug ports Prehistoric leftover, zap it. We poweroff via acpi these days. And having a port (0x501,0x502) where any random guest write will make qemu exit -- with no way to turn it off -- is a bad joke anyway. Signed-off-by: Gerd Hoffmann --- hw/pc.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 71902e210b..4879e4f4fb 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -524,34 +524,6 @@ static void handle_a20_line_change(void *opaque, int irq, int level) cpu_x86_set_a20(cpu, level); } -/***********************************************************/ -/* Bochs BIOS debug ports */ - -static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) -{ - static const char shutdown_str[8] = "Shutdown"; - static int shutdown_index = 0; - - switch(addr) { - case 0x8900: - /* same as Bochs power off */ - if (val == shutdown_str[shutdown_index]) { - shutdown_index++; - if (shutdown_index == 8) { - shutdown_index = 0; - qemu_system_shutdown_request(); - } - } else { - shutdown_index = 0; - } - break; - - case 0x501: - case 0x502: - exit((val << 1) | 1); - } -} - int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) { int index = le32_to_cpu(e820_table.count); @@ -569,14 +541,6 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return index; } -static const MemoryRegionPortio bochs_bios_portio_list[] = { - { 0x500, 1, 1, .write = bochs_bios_write, }, /* 0x500 */ - { 0x501, 1, 1, .write = bochs_bios_write, }, /* 0x501 */ - { 0x501, 2, 2, .write = bochs_bios_write, }, /* 0x501 */ - { 0x8900, 1, 1, .write = bochs_bios_write, }, /* 0x8900 */ - PORTIO_END_OF_LIST(), -}; - static void *bochs_bios_init(void) { void *fw_cfg; @@ -584,11 +548,6 @@ static void *bochs_bios_init(void) size_t smbios_len; uint64_t *numa_fw_cfg; int i, j; - PortioList *bochs_bios_port_list = g_new(PortioList, 1); - - portio_list_init(bochs_bios_port_list, bochs_bios_portio_list, - NULL, "bochs-bios"); - portio_list_add(bochs_bios_port_list, get_system_io(), 0x0); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); From e7b1d0ea950fc760371c9580ba6b34c912369a38 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 5 Dec 2012 15:28:05 +0100 Subject: [PATCH 0085/1634] pc_sysfw: Check for qemu_find_file() failure pc_fw_add_pflash_drv() ignores qemu_find_file() failure, and happily creates a drive without a medium. When pc_system_flash_init() asks for its size, bdrv_getlength() fails with -ENOMEDIUM, which isn't checked either. It fails relatively cleanly only because -ENOMEDIUM isn't a multiple of 4096: $ qemu-system-x86_64 -S -vnc :0 -bios nonexistant qemu: PC system firmware (pflash) must be a multiple of 0x1000 [Exit 1 ] Fix by handling the qemu_find_file() failure. Signed-off-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- hw/pc_sysfw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index 87e1fa961b..7567593a63 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -84,6 +84,10 @@ static void pc_fw_add_pflash_drv(void) bios_name = BIOS_FILENAME; } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (!filename) { + error_report("Can't open BIOS image %s", bios_name); + exit(1); + } opts = drive_add(IF_PFLASH, -1, filename, "readonly=on"); From e2af7a4dc8d218c5fb5b41dd1d008fa111d0636e Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 20 Dec 2012 07:50:41 +0100 Subject: [PATCH 0086/1634] pseries: Remove unneeded include statement (fixes MinGW builds) sys/mman.h is not needed (tested on Linux) and unavailable for MinGW, so remove it. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- hw/spapr_nvram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/spapr_nvram.c b/hw/spapr_nvram.c index f20f6b4fdd..680cdba928 100644 --- a/hw/spapr_nvram.c +++ b/hw/spapr_nvram.c @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include + #include #include "sysemu/device_tree.h" From c242222c978d2c09411f2560915708c364ca2ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E9=9F=8B=E4=BB=BB=20=28Wei-Ren=20Chen=29?= Date: Thu, 20 Dec 2012 16:41:34 +0800 Subject: [PATCH 0087/1634] Remove --sparc_cpu option from the configure list commit 9b9c37c36439ee0452632253dac7a31897f27f70 always assume sparcv9, the others are no longer supported. Remove --sparc_cpu option from the configure list. Signed-off-by: Chen Wei-Ren Signed-off-by: Stefan Hajnoczi --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 9538041d05..db11e511f0 100755 --- a/configure +++ b/configure @@ -1096,7 +1096,6 @@ echo " --fmod-inc path to FMOD includes" echo " --oss-lib path to OSS library" echo " --enable-uname-release=R Return R for uname -r in usermode emulation" echo " --cpu=CPU Build for host CPU [$cpu]" -echo " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9" echo " --disable-uuid disable uuid support" echo " --enable-uuid enable uuid support" echo " --disable-vde disable support for vde network" From 715857cbbabc8740792b608f9bc4cd9fad6ecb1d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 22 Dec 2012 13:59:22 +0100 Subject: [PATCH 0088/1634] hw/mcf5206: Reduce size of lookup table This typically reduces the size from 512 bytes to 128 bytes. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- hw/mcf5206.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mcf5206.c b/hw/mcf5206.c index fe7a48864f..d8c0059ed6 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -359,7 +359,7 @@ static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, /* Internal peripherals use a variety of register widths. This lookup table allows a single routine to handle all of them. */ -static const int m5206_mbar_width[] = +static const uint8_t m5206_mbar_width[] = { /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, From 586b0bef84c202bb2256a35eb71bfd6670262bd7 Mon Sep 17 00:00:00 2001 From: John Spencer Date: Wed, 26 Dec 2012 00:49:49 +0100 Subject: [PATCH 0089/1634] linux-user/syscall.c: remove forward declarations instead use the correct headers that define these functions. Requested-by: Stefan Weil Signed-off-by: John Spencer Reviewed-by: Amos Kong Reviewed-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- linux-user/syscall.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e99adab492..3167a87549 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -581,11 +584,6 @@ _syscall4(int, sys_prlimit64, pid_t, pid, int, resource, struct host_rlimit64 *, old_limit) #endif -extern int personality(int); -extern int flock(int, int); -extern int setfsuid(int); -extern int setfsgid(int); - /* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */ #ifdef TARGET_ARM static inline int regpairs_aligned(void *cpu_env) { From bfb82a28752d29291adf932c3a9941e8383203af Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 19 Dec 2012 14:07:16 +0100 Subject: [PATCH 0090/1634] spice: drop incorrect vm_change_state_handler() opaque The spice_server pointer is a global variable and vm_change_state_handler() therefore does not use its opaque parameter. The vm change state handler is added with a pointer to the spice_server pointer. This is useless and we probably would not want 2 levels of pointers. Signed-off-by: Stefan Hajnoczi Reviewed-by: Uri Lublin --- ui/spice-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 3e44779107..d83de2a46e 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -709,7 +709,7 @@ void qemu_spice_init(void) qemu_spice_input_init(); qemu_spice_audio_init(); - qemu_add_vm_change_state_handler(vm_change_state_handler, &spice_server); + qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); g_free(x509_key_file); g_free(x509_cert_file); @@ -736,8 +736,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) */ spice_server = spice_server_new(); spice_server_init(spice_server, &core_interface); - qemu_add_vm_change_state_handler(vm_change_state_handler, - &spice_server); + qemu_add_vm_change_state_handler(vm_change_state_handler, NULL); } return spice_server_add_interface(spice_server, sin); From 17ed229379d971ae117245b353324115a62b0014 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Dec 2012 10:09:03 -0800 Subject: [PATCH 0091/1634] softfloat: Fix uint64_to_float64 The interface to normalizeRoundAndPackFloat64 requires that the high bit be clear. Perform one shift-right-and-jam if needed. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- fpu/softfloat.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 0cfa6b4831..20b05d4392 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1271,11 +1271,18 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) } -float64 uint64_to_float64( uint64 a STATUS_PARAM ) +float64 uint64_to_float64(uint64 a STATUS_PARAM) { - if ( a == 0 ) return float64_zero; - return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR ); + int exp = 0x43C; + if (a == 0) { + return float64_zero; + } + if ((int64_t)a < 0) { + shift64RightJamming(a, 1, &a); + exp += 1; + } + return normalizeRoundAndPackFloat64(0, exp, a STATUS_VAR); } /*---------------------------------------------------------------------------- From 1e397eadf1cf54920c45a2fdc204b1ade1b72d38 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 31 Dec 2012 10:09:04 -0800 Subject: [PATCH 0092/1634] softfloat: Implement uint64_to_float128 Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- fpu/softfloat.c | 8 ++++++++ include/fpu/softfloat.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 20b05d4392..ac3d150015 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1339,6 +1339,14 @@ float128 int64_to_float128( int64 a STATUS_PARAM ) } +float128 uint64_to_float128(uint64 a STATUS_PARAM) +{ + if (a == 0) { + return float128_zero; + } + return normalizeRoundAndPackFloat128(0, 0x406E, a, 0 STATUS_VAR); +} + /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the 32-bit two's complement integer format. The conversion is diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 0946f0739d..f3927e2419 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -237,6 +237,7 @@ float64 int64_to_float64( int64 STATUS_PARAM ); float64 uint64_to_float64( uint64 STATUS_PARAM ); floatx80 int64_to_floatx80( int64 STATUS_PARAM ); float128 int64_to_float128( int64 STATUS_PARAM ); +float128 uint64_to_float128( uint64 STATUS_PARAM ); /*---------------------------------------------------------------------------- | Software half-precision conversion routines. @@ -630,6 +631,8 @@ INLINE int float128_is_any_nan(float128 a) ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0)); } +#define float128_zero make_float128(0, 0) + /*---------------------------------------------------------------------------- | The pattern for a default generated quadruple-precision NaN. *----------------------------------------------------------------------------*/ From 549db5c32bb025501e2eeb23d2e5cc669061eb71 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 5 Jan 2013 09:33:43 +0100 Subject: [PATCH 0093/1634] hw/i386: Fix broken build for non POSIX hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pc-testdev.c cannot be compiled with MinGW (and other non POSIX hosts): CC i386-softmmu/hw/i386/../pc-testdev.o qemu/hw/i386/../pc-testdev.c:38:22: warning: sys/mman.h: file not found qemu/hw/i386/../pc-testdev.c: In function ‘test_flush_page’: qemu/hw/i386/../pc-testdev.c:103: warning: implicit declaration of function ‘mprotect’ ... Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- hw/pc-testdev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c index 620c86c92a..192848998c 100644 --- a/hw/pc-testdev.c +++ b/hw/pc-testdev.c @@ -35,7 +35,10 @@ * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git */ +#include "config-host.h" +#if defined(CONFIG_POSIX) #include +#endif #include "hw.h" #include "qdev.h" #include "isa.h" @@ -100,8 +103,10 @@ static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, /* We might not be able to get the full page, only mprotect what we actually have mapped */ +#if defined(CONFIG_POSIX) mprotect(a, page, PROT_NONE); mprotect(a, page, PROT_READ|PROT_WRITE); +#endif cpu_physical_memory_unmap(a, page, 0, 0); } From 0fd81617fad2cae099348877099f6cf4c3bbc5bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 12:49:47 -0700 Subject: [PATCH 0094/1634] target-s390: Disassemble more z10 and z196 opcodes Also fix disassembly for COMPARE AND BRANCH. The table must be sorted by primary opcode, and several were out of place. Signed-off-by: Richard Henderson --- disas/s390.c | 169 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 151 insertions(+), 18 deletions(-) diff --git a/disas/s390.c b/disas/s390.c index 0859dfa19f..73c4193202 100644 --- a/disas/s390.c +++ b/disas/s390.c @@ -589,6 +589,16 @@ static const struct s390_operand s390_operands[] = { 4, 32, S390_OPERAND_CCODE }, #define I8_32 46 /* 8 bit signed value starting at 32 */ { 8, 32, S390_OPERAND_SIGNED }, +#define U8_24 47 /* 8 bit unsigned value starting at 24 */ + { 8, 24, 0 }, +#define U8_32 48 /* 8 bit unsigned value starting at 32 */ + { 8, 32, 0 }, +#define I16_32 49 + { 16, 32, S390_OPERAND_SIGNED }, +#define M4_16 50 /* 4-bit condition-code starting at 12 */ + { 4, 16, S390_OPERAND_CCODE }, +#define I8_16 51 + { 8, 16, S390_OPERAND_SIGNED }, /* QEMU-END */ }; @@ -801,11 +811,35 @@ static const struct s390_operand s390_operands[] = #define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 } /* QEMU-ADD: */ -#define INSTR_RIE_MRRP 6, { M4_32,R_8,R_12,J16_16,0,0 } /* e.g. crj */ +#define INSTR_RIE_MRRP 6, { M4_32, R_8, R_12, J16_16, 0, 0 } /* e.g. crj */ #define MASK_RIE_MRRP { 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff } -#define INSTR_RIE_MRIP 6, { M4_12,R_8,I8_32,J16_16,0,0 } /* e.g. cij */ +#define INSTR_RIE_MRIP 6, { M4_12, R_8, I8_32, J16_16, 0, 0 } /* e.g. cij */ #define MASK_RIE_MRIP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RIE_RRIII 6, { R_8, R_12, U8_16, U8_24, U8_32, 0 } /* risbg */ +#define MASK_RIE_RRIII { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_MRI 6, { M4_32, R_8, I16_16, 0, 0, 0 } /* e.g. cit */ +#define MASK_RIE_MRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_MRU 6, { M4_32, R_8, U16_16, 0, 0, 0 } /* e.g. clfit */ +#define MASK_RIE_MRU { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } +#define INSTR_RIE_RRI 6, { R_8, R_12, I16_16, 0, 0, 0 } +#define MASK_RIE_RRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RXY_URRD 6, { U8_8, D20_20, X_12, B_16, 0, 0 } +#define MASK_RXY_URRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_SIL_DRI 6, { D_20, B_16, I16_32, 0, 0, 0 } +#define MASK_SIL_DRI { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } + +#define INSTR_RSY_MRRD 6, { M4_12, R_8, D20_20, B_16, 0, 0 } +#define MASK_SRY_MRRD { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } + +#define INSTR_RRF_MRR 6, { M4_16, R_24, R_28, 0, 0, 0 } +#define MASK_RRF_MRR { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } + +#define INSTR_SIY_DRI 6, { D20_20, B_16, I8_16, 0, 0, 0 } +#define MASK_SIY_DRI { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff } /* QEMU-END */ /* The opcode formats table (blueprints for .insn pseudo mnemonic). */ @@ -926,6 +960,30 @@ static const struct s390_opcode s390_opcodes[] = { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0}, { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2}, +/* QEMU-ADD: */ + { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, + { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, + { "risbg", OP48(0xec0000000055LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "risbhg", OP48(0xec000000005dLL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "risblg", OP48(0xec0000000051LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rnsbg", OP48(0xec0000000054LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rosbg", OP48(0xec0000000056LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "rxsbg", OP48(0xec0000000057LL), MASK_RIE_RRIII, INSTR_RIE_RRIII, 3, 6}, + { "cit", OP48(0xec0000000072LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, + { "cgit", OP48(0xec0000000070LL), MASK_RIE_MRI, INSTR_RIE_MRI, 3, 6}, + { "clfit", OP48(0xec0000000073LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, + { "clgit", OP48(0xec0000000071LL), MASK_RIE_MRU, INSTR_RIE_MRU, 3, 6}, + { "ahik", OP48(0xec00000000d8LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "aghik", OP48(0xec00000000d9LL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "alhsik", OP48(0xec00000000daLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, + { "alghsik", OP48(0xec00000000dbLL), MASK_RIE_RRI, INSTR_RIE_RRI, 3, 6}, +/* QEMU-END */ { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0}, { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3}, @@ -985,6 +1043,20 @@ static const struct s390_opcode s390_opcodes[] = { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3}, { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2}, +/* QEMU-ADD: */ + { "loc", OP48(0xeb00000000f2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "locg", OP48(0xeb00000000e2LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "stoc", OP48(0xeb00000000f3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "stocg", OP48(0xeb00000000e3LL), MASK_SRY_MRRD, INSTR_RSY_MRRD, 3, 6}, + { "srak", OP48(0xeb00000000dcLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "slak", OP48(0xeb00000000ddLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "srlk", OP48(0xeb00000000deLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "sllk", OP48(0xeb00000000dfLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 6}, + { "asi", OP48(0xeb000000006aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "alsi", OP48(0xeb000000006eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "agsi", OP48(0xeb000000007aLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, + { "algsi", OP48(0xeb000000007eLL), MASK_SIY_DRI, INSTR_SIY_DRI, 3, 6}, +/* QEMU-END */ { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0}, { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, @@ -993,6 +1065,17 @@ static const struct s390_opcode s390_opcodes[] = { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2}, { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0}, +/* QEMU-ADD: */ + { "mvhhi", OP16(0xe544LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "mvghi", OP16(0xe548LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "mvhi", OP16(0xe54cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "chhsi", OP16(0xe554LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clhhsi", OP16(0xe555LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "cghsi", OP16(0xe558LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clghsi", OP16(0xe559LL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "chsi", OP16(0xe55cLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, + { "clfhsi", OP16(0xe55dLL), MASK_SIL_DRI, INSTR_SIL_DRI, 3, 6}, +/* QEMU-END */ { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2}, { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3}, @@ -1116,6 +1199,9 @@ static const struct s390_opcode s390_opcodes[] = { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3}, { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2}, { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4}, +/* QEMU-ADD: */ + { "pfd", OP48(0xe30000000036LL), MASK_RXY_URRD, INSTR_RXY_URRD, 3, 6}, +/* QEMU-END */ { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0}, @@ -1135,6 +1221,32 @@ static const struct s390_opcode s390_opcodes[] = { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5}, { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4}, +/* QEMU-ADD: */ + { "exrl", OP16(0xc600ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "pfdrl", OP16(0xc602ll), MASK_RIL_UP, INSTR_RIL_UP, 3, 6}, + { "cghrl", OP16(0xc604ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "chrl", OP16(0xc605ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clghrl", OP16(0xc606ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clhrl", OP16(0xc607ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "cgrl", OP16(0xc608ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clgrl", OP16(0xc60all), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "cgfrl", OP16(0xc60cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "crl", OP16(0xc60dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clgfrl", OP16(0xc60ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "clrl", OP16(0xc60fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + + { "llhrl", OP16(0xc400ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lghrl", OP16(0xc404ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lhrl", OP16(0xc405ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "llghrl", OP16(0xc406ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "sthrl", OP16(0xc407ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "stgrl", OP16(0xc40bll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "llgfrl", OP16(0xc40ell), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, + { "strl", OP16(0xc40fll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, +/* QEMU-END */ { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4}, { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4}, @@ -1265,6 +1377,29 @@ static const struct s390_opcode s390_opcodes[] = { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2}, +/* QEMU-ADD: */ + { "crt", OP16(0xb972LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "cgrt", OP16(0xb960LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "clrt", OP16(0xb973LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "clgrt", OP16(0xb961LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 6}, + { "locr", OP16(0xb9f2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, + { "locgr", OP16(0xb9e2LL), MASK_RRF_MRR, INSTR_RRF_MRR, 3, 6}, + { "popcnt", OP16(0xb9e1LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 6}, + { "ngrk", OP16(0xb9e4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ogrk", OP16(0xb9e6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "xgrk", OP16(0xb9e7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "agrk", OP16(0xb9e8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "sgrk", OP16(0xb9e9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "algrk", OP16(0xb9eaLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "slgrk", OP16(0xb9ebLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "nrk", OP16(0xb9f4LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ork", OP16(0xb9f6LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "xrk", OP16(0xb9f7LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "ark", OP16(0xb9f8LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "srk", OP16(0xb9f9LL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "alrk", OP16(0xb9faLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, + { "slrk", OP16(0xb9fbLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 3, 6}, +/* QEMU-END */ { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0}, { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5}, @@ -1426,6 +1561,20 @@ static const struct s390_opcode s390_opcodes[] = { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0}, +/* QEMU-ADD: */ + { "clfebr", OP16(0xb39cLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clfdbr", OP16(0xb39dLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clfxbr", OP16(0xb39eLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgebr", OP16(0xb3acLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgdbr", OP16(0xb3adLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "clgxbr", OP16(0xb3aeLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "celfbr", OP16(0xb390LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cdlfbr", OP16(0xb391LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cxlfbr", OP16(0xb392LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "celgbr", OP16(0xb3a0LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cdlgbr", OP16(0xb3a1LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, + { "cxlgbr", OP16(0xb3a2LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 3, 6}, +/* QEMU-END */ { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0}, { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5}, { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5}, @@ -1774,22 +1923,6 @@ static const struct s390_opcode s390_opcodes[] = { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0}, { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0}, { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0}, - -/* QEMU-ADD: */ - { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6}, - - { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6}, - - { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, - { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6}, -/* QEMU-END */ }; static const int s390_num_opcodes = From 79be7c7b603f89da209098a03a5459beb09a579b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 14:13:12 -0700 Subject: [PATCH 0095/1634] target-s390: Fix disassembly of cpsdr Signed-off-by: Richard Henderson --- disas/s390.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/disas/s390.c b/disas/s390.c index 73c4193202..25499ba419 100644 --- a/disas/s390.c +++ b/disas/s390.c @@ -673,7 +673,9 @@ static const struct s390_operand s390_operands[] = This is just a workaround for existing code e.g. glibc. */ #define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 } /* efpc, sfpc */ #define INSTR_RRF_F0FF 4, { F_16,F_24,F_28,0,0,0 } /* e.g. madbr */ -#define INSTR_RRF_F0FF2 4, { F_24,F_16,F_28,0,0,0 } /* e.g. cpsdr */ +/* QEMU-MOD */ +#define INSTR_RRF_F0FF2 4, { F_24,F_28,F_16,0,0,0 } /* e.g. cpsdr */ +/* QEMU-END */ #define INSTR_RRF_F0FR 4, { F_24,F_16,R_28,0,0,0 } /* e.g. iedtr */ #define INSTR_RRF_FUFF 4, { F_24,F_16,F_28,U4_20,0,0 } /* e.g. didbr */ #define INSTR_RRF_RURR 4, { R_24,R_28,R_16,U4_20,0,0 } /* e.g. .insn */ From 6ee77b16630bc86c1a44f9df61b072c7974ba503 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 10:44:45 -0700 Subject: [PATCH 0096/1634] target-s390: Fix gdbstub The real gdb protocol doesn't split out pc or cc as real registers. Those are pseudos that are extracted as needed from the PSW. Don't modify env->cc_op during read -- that way lies heisenbugs. Fill in the XXX for the fp registers. Remove duplicated defines in cpu.h. Signed-off-by: Richard Henderson --- gdbstub.c | 78 ++++++++++++++++++++++++++++------------------ target-s390x/cpu.h | 73 ------------------------------------------- 2 files changed, 48 insertions(+), 103 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index a8dd437ec0..e62dc798c3 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -40,6 +40,7 @@ #include "cpu.h" #include "qemu/sockets.h" #include "sysemu/kvm.h" +#include "qemu/bitops.h" #ifndef TARGET_CPU_MEMORY_RW_DEBUG static inline int target_memory_rw_debug(CPUArchState *env, target_ulong addr, @@ -1535,27 +1536,34 @@ static int cpu_gdb_write_register(CPUAlphaState *env, uint8_t *mem_buf, int n) } #elif defined (TARGET_S390X) -#define NUM_CORE_REGS S390_NUM_TOTAL_REGS +#define NUM_CORE_REGS S390_NUM_REGS static int cpu_gdb_read_register(CPUS390XState *env, uint8_t *mem_buf, int n) { + uint64_t val; + int cc_op; + switch (n) { - case S390_PSWM_REGNUM: GET_REGL(env->psw.mask); break; - case S390_PSWA_REGNUM: GET_REGL(env->psw.addr); break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - GET_REGL(env->regs[n-S390_R0_REGNUM]); break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - GET_REG32(env->aregs[n-S390_A0_REGNUM]); break; - case S390_FPC_REGNUM: GET_REG32(env->fpc); break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - /* XXX */ - break; - case S390_PC_REGNUM: GET_REGL(env->psw.addr); break; - case S390_CC_REGNUM: - env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, - env->cc_vr); - GET_REG32(env->cc_op); - break; + case S390_PSWM_REGNUM: + cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); + val = deposit64(env->psw.mask, 44, 2, cc_op); + GET_REGL(val); + break; + case S390_PSWA_REGNUM: + GET_REGL(env->psw.addr); + break; + case S390_R0_REGNUM ... S390_R15_REGNUM: + GET_REGL(env->regs[n-S390_R0_REGNUM]); + break; + case S390_A0_REGNUM ... S390_A15_REGNUM: + GET_REG32(env->aregs[n-S390_A0_REGNUM]); + break; + case S390_FPC_REGNUM: + GET_REG32(env->fpc); + break; + case S390_F0_REGNUM ... S390_F15_REGNUM: + GET_REG64(env->fregs[n-S390_F0_REGNUM].ll); + break; } return 0; @@ -1570,20 +1578,30 @@ static int cpu_gdb_write_register(CPUS390XState *env, uint8_t *mem_buf, int n) tmp32 = ldl_p(mem_buf); switch (n) { - case S390_PSWM_REGNUM: env->psw.mask = tmpl; break; - case S390_PSWA_REGNUM: env->psw.addr = tmpl; break; - case S390_R0_REGNUM ... S390_R15_REGNUM: - env->regs[n-S390_R0_REGNUM] = tmpl; break; - case S390_A0_REGNUM ... S390_A15_REGNUM: - env->aregs[n-S390_A0_REGNUM] = tmp32; r=4; break; - case S390_FPC_REGNUM: env->fpc = tmp32; r=4; break; - case S390_F0_REGNUM ... S390_F15_REGNUM: - /* XXX */ - break; - case S390_PC_REGNUM: env->psw.addr = tmpl; break; - case S390_CC_REGNUM: env->cc_op = tmp32; r=4; break; + case S390_PSWM_REGNUM: + env->psw.mask = tmpl; + env->cc_op = extract64(tmpl, 44, 2); + break; + case S390_PSWA_REGNUM: + env->psw.addr = tmpl; + break; + case S390_R0_REGNUM ... S390_R15_REGNUM: + env->regs[n-S390_R0_REGNUM] = tmpl; + break; + case S390_A0_REGNUM ... S390_A15_REGNUM: + env->aregs[n-S390_A0_REGNUM] = tmp32; + r = 4; + break; + case S390_FPC_REGNUM: + env->fpc = tmp32; + r = 4; + break; + case S390_F0_REGNUM ... S390_F15_REGNUM: + env->fregs[n-S390_F0_REGNUM].ll = tmpl; + break; + default: + return 0; } - return r; } #elif defined (TARGET_LM32) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index cd565c91de..529716de47 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -430,79 +430,6 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) /* Total. */ #define S390_NUM_REGS 51 -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) - - - -/* Program Status Word. */ -#define S390_PSWM_REGNUM 0 -#define S390_PSWA_REGNUM 1 -/* General Purpose Registers. */ -#define S390_R0_REGNUM 2 -#define S390_R1_REGNUM 3 -#define S390_R2_REGNUM 4 -#define S390_R3_REGNUM 5 -#define S390_R4_REGNUM 6 -#define S390_R5_REGNUM 7 -#define S390_R6_REGNUM 8 -#define S390_R7_REGNUM 9 -#define S390_R8_REGNUM 10 -#define S390_R9_REGNUM 11 -#define S390_R10_REGNUM 12 -#define S390_R11_REGNUM 13 -#define S390_R12_REGNUM 14 -#define S390_R13_REGNUM 15 -#define S390_R14_REGNUM 16 -#define S390_R15_REGNUM 17 -/* Access Registers. */ -#define S390_A0_REGNUM 18 -#define S390_A1_REGNUM 19 -#define S390_A2_REGNUM 20 -#define S390_A3_REGNUM 21 -#define S390_A4_REGNUM 22 -#define S390_A5_REGNUM 23 -#define S390_A6_REGNUM 24 -#define S390_A7_REGNUM 25 -#define S390_A8_REGNUM 26 -#define S390_A9_REGNUM 27 -#define S390_A10_REGNUM 28 -#define S390_A11_REGNUM 29 -#define S390_A12_REGNUM 30 -#define S390_A13_REGNUM 31 -#define S390_A14_REGNUM 32 -#define S390_A15_REGNUM 33 -/* Floating Point Control Word. */ -#define S390_FPC_REGNUM 34 -/* Floating Point Registers. */ -#define S390_F0_REGNUM 35 -#define S390_F1_REGNUM 36 -#define S390_F2_REGNUM 37 -#define S390_F3_REGNUM 38 -#define S390_F4_REGNUM 39 -#define S390_F5_REGNUM 40 -#define S390_F6_REGNUM 41 -#define S390_F7_REGNUM 42 -#define S390_F8_REGNUM 43 -#define S390_F9_REGNUM 44 -#define S390_F10_REGNUM 45 -#define S390_F11_REGNUM 46 -#define S390_F12_REGNUM 47 -#define S390_F13_REGNUM 48 -#define S390_F14_REGNUM 49 -#define S390_F15_REGNUM 50 -/* Total. */ -#define S390_NUM_REGS 51 - -/* Pseudo registers -- PC and condition code. */ -#define S390_PC_REGNUM S390_NUM_REGS -#define S390_CC_REGNUM (S390_NUM_REGS+1) -#define S390_NUM_PSEUDO_REGS 2 -#define S390_NUM_TOTAL_REGS (S390_NUM_REGS+2) - /* CC optimization */ enum cc_op { From 063eb0f3038434ab4cf9ad4bcc19a8789e15d237 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 08:15:42 -0700 Subject: [PATCH 0097/1634] target-s390: Add missing temp_free in gen_op_calc_cc Signed-off-by: Richard Henderson --- target-s390x/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9e34741311..f1e754f76a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -757,6 +757,7 @@ static void gen_op_calc_cc(DisasContext *s) } tcg_temp_free_i32(local_cc_op); + tcg_temp_free_i64(dummy); /* We now have cc in cc_op as constant */ set_cc_static(s); From 431253c28f9177a3f4783dc47b952c8fffcf3177 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 06:57:35 -0700 Subject: [PATCH 0098/1634] target-s390: Use TCG registers for FPR At the same time, tidy other usages of tcg_gen_deposit_i64. In some cases we can "type cast" rather than extend, and in others we can allow tcg_gen_deposit_i64 itself to optimize the HOST_LONG_BITS==32 case. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 68 +++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f1e754f76a..27450656f5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -97,7 +97,7 @@ void cpu_dump_state(CPUS390XState *env, FILE *f, fprintf_function cpu_fprintf, } for (i = 0; i < 16; i++) { - cpu_fprintf(f, "F%02d=%016" PRIx64, i, *(uint64_t *)&env->fregs[i]); + cpu_fprintf(f, "F%02d=%016" PRIx64, i, env->fregs[i].ll); if ((i % 4) == 3) { cpu_fprintf(f, "\n"); } else { @@ -134,21 +134,22 @@ static TCGv_i64 cc_src; static TCGv_i64 cc_dst; static TCGv_i64 cc_vr; -static char cpu_reg_names[10*3 + 6*4]; +static char cpu_reg_names[32][4]; static TCGv_i64 regs[16]; +static TCGv_i64 fregs[16]; static uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; void s390x_translate_init(void) { int i; - size_t cpu_reg_names_size = sizeof(cpu_reg_names); - char *p; cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); - psw_addr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, psw.addr), + psw_addr = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUS390XState, psw.addr), "psw_addr"); - psw_mask = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, psw.mask), + psw_mask = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUS390XState, psw.mask), "psw_mask"); cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op), @@ -160,13 +161,18 @@ void s390x_translate_init(void) cc_vr = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, cc_vr), "cc_vr"); - p = cpu_reg_names; for (i = 0; i < 16; i++) { - snprintf(p, cpu_reg_names_size, "r%d", i); + snprintf(cpu_reg_names[i], sizeof(cpu_reg_names[0]), "r%d", i); regs[i] = tcg_global_mem_new(TCG_AREG0, - offsetof(CPUS390XState, regs[i]), p); - p += (i < 10) ? 3 : 4; - cpu_reg_names_size -= (i < 10) ? 3 : 4; + offsetof(CPUS390XState, regs[i]), + cpu_reg_names[i]); + } + + for (i = 0; i < 16; i++) { + snprintf(cpu_reg_names[i + 16], sizeof(cpu_reg_names[0]), "f%d", i); + fregs[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUS390XState, fregs[i].d), + cpu_reg_names[i + 16]); } } @@ -180,14 +186,18 @@ static inline TCGv_i64 load_reg(int reg) static inline TCGv_i64 load_freg(int reg) { TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ld_i64(r, cpu_env, offsetof(CPUS390XState, fregs[reg].d)); + tcg_gen_mov_i64(r, fregs[reg]); return r; } static inline TCGv_i32 load_freg32(int reg) { TCGv_i32 r = tcg_temp_new_i32(); - tcg_gen_ld_i32(r, cpu_env, offsetof(CPUS390XState, fregs[reg].l.upper)); +#if HOST_LONG_BITS == 32 + tcg_gen_mov_i32(r, TCGV_HIGH(fregs[reg])); +#else + tcg_gen_shri_i64(MAKE_TCGV_I64(GET_TCGV_I32(r)), fregs[reg], 32); +#endif return r; } @@ -212,39 +222,35 @@ static inline void store_reg(int reg, TCGv_i64 v) static inline void store_freg(int reg, TCGv_i64 v) { - tcg_gen_st_i64(v, cpu_env, offsetof(CPUS390XState, fregs[reg].d)); + tcg_gen_mov_i64(fregs[reg], v); } static inline void store_reg32(int reg, TCGv_i32 v) { + /* 32 bit register writes keep the upper half */ #if HOST_LONG_BITS == 32 tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v); #else - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, v); - /* 32 bit register writes keep the upper half */ - tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 32); - tcg_temp_free_i64(tmp); + tcg_gen_deposit_i64(regs[reg], regs[reg], + MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 32); #endif } static inline void store_reg32_i64(int reg, TCGv_i64 v) { /* 32 bit register writes keep the upper half */ -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_LOW(regs[reg]), TCGV_LOW(v)); -#else tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); -#endif } static inline void store_reg16(int reg, TCGv_i32 v) { - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, v); /* 16 bit register writes keep the upper bytes */ - tcg_gen_deposit_i64(regs[reg], regs[reg], tmp, 0, 16); - tcg_temp_free_i64(tmp); +#if HOST_LONG_BITS == 32 + tcg_gen_deposit_i32(TCGV_LOW(regs[reg]), TCGV_LOW(regs[reg]), v, 0, 16); +#else + tcg_gen_deposit_i64(regs[reg], regs[reg], + MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 16); +#endif } static inline void store_reg8(int reg, TCGv_i64 v) @@ -255,7 +261,13 @@ static inline void store_reg8(int reg, TCGv_i64 v) static inline void store_freg32(int reg, TCGv_i32 v) { - tcg_gen_st_i32(v, cpu_env, offsetof(CPUS390XState, fregs[reg].l.upper)); + /* 32 bit register writes keep the lower half */ +#if HOST_LONG_BITS == 32 + tcg_gen_mov_i32(TCGV_HIGH(fregs[reg]), v); +#else + tcg_gen_deposit_i64(fregs[reg], fregs[reg], + MAKE_TCGV_I64(GET_TCGV_I32(v)), 32, 32); +#endif } static inline void update_psw_addr(DisasContext *s) From 7e68da2a9dd112a1a4ef16e8ef3dc1916529ae6b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Sep 2012 09:14:33 -0700 Subject: [PATCH 0099/1634] target-s390: Register helpers Which highlights a lot of cc helpers that no longer exist. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 21 ++++----------------- target-s390x/translate.c | 4 ++++ 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c4926c52ad..2498f83be7 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -7,21 +7,10 @@ DEF_HELPER_4(xc, i32, env, i32, i64, i64) DEF_HELPER_4(mvc, void, env, i32, i64, i64) DEF_HELPER_4(clc, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) -DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_NO_RWG_SE, i32, s32) -DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_NO_RWG_SE, i32, s64) -DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_3(mlg, void, env, i32, i64) DEF_HELPER_3(dlg, void, env, i32, i64) -DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_addu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_NO_RWG_SE, i32, s64, s64, s64) -DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_NO_RWG_SE, i32, s32, s32, s32) -DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) @@ -38,7 +27,6 @@ DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) @@ -112,11 +100,13 @@ DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) +DEF_HELPER_3(cksm, void, env, i32, i32) +DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) +#ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) -DEF_HELPER_1(program_interrupt, void, i32) DEF_HELPER_FLAGS_2(stidp, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) @@ -144,9 +134,6 @@ DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_3(lra, i32, env, i64, i32) DEF_HELPER_3(stura, void, env, i64, i32) -DEF_HELPER_3(cksm, void, env, i32, i32) - -DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, - i32, env, i32, i64, i64, i64) +#endif #include "exec/def-helper.h" diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 27450656f5..1df3c538e5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -174,6 +174,10 @@ void s390x_translate_init(void) offsetof(CPUS390XState, fregs[i].d), cpu_reg_names[i + 16]); } + + /* register helpers */ +#define GEN_HELPER 2 +#include "helper.h" } static inline TCGv_i64 load_reg(int reg) From afd43fecfe7f6e863884b850f53fac4a75c28d84 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Sep 2012 05:22:18 -0700 Subject: [PATCH 0100/1634] target-s390: Fix SACF exit DISAS_EXCP is exit via exception; we wanted DISAS_JUMP. This matters when we start cleaning up the TB exit paths. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1df3c538e5..4898c7b8ad 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2933,7 +2933,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i64(tmp); break; case 0x79: /* SACF D2(B2) [S] */ - /* Store Clock Extended */ + /* Set Address Space Control Fast */ check_privileged(env, s, ilc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -2943,7 +2943,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, /* addressing mode has changed, so end the block */ s->pc += ilc * 2; update_psw_addr(s); - s->is_jmp = DISAS_EXCP; + s->is_jmp = DISAS_JUMP; break; case 0x7d: /* STSI D2,(B2) [S] */ check_privileged(env, s, ilc); From 9d126faf4279b324d5c4cdf09a3570d4a2041626 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Sep 2012 05:25:09 -0700 Subject: [PATCH 0101/1634] target-s390: Fix BCR There were are two exit paths for which we forgot to copy s->cc_op back to the tcg register. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 4898c7b8ad..79ab3e5344 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1212,6 +1212,7 @@ static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, if (mask == 0xf) { /* unconditional */ + gen_update_cc_op(s); tcg_gen_mov_i64(psw_addr, target); tcg_gen_exit_tb(0); } else if (mask == 0) { @@ -1223,6 +1224,7 @@ static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, tcg_gen_mov_i64(new_addr, target); skip = gen_new_label(); gen_jcc(s, mask, skip); + gen_update_cc_op(s); tcg_gen_mov_i64(psw_addr, new_addr); tcg_temp_free_i64(new_addr); tcg_gen_exit_tb(0); From 2f22e2ec79c07de03016adefb166cf01745fc852 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Sep 2012 05:28:43 -0700 Subject: [PATCH 0102/1634] target-s390: Tidy unconditional BRCL Yes, we're about to rewrite all of this, but having this unconditional jump recompute cc_op is a large source of "false diff errors" when trying to examine before and after dumps. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 79ab3e5344..b8f2ca8678 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3706,6 +3706,11 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 tcg_temp_free_i64(tmp); break; case 0x4: /* BRCL M1,I2 [RIL] */ + if (r1 == 15) { /* m1 == r1 */ + gen_goto_tb(s, 0, target); + s->is_jmp = DISAS_TB_JUMP; + break; + } /* m1 & (1 << (3 - cc)) */ tmp32_1 = tcg_const_i32(3); tmp32_2 = tcg_const_i32(1); From 51855ecf1a9d5a8388778571b8ab32134e83f378 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 24 Sep 2012 12:06:15 -0700 Subject: [PATCH 0103/1634] target-s390: Fix PSW_MASK handling We were treating psw.mask as the 32-bit quantity it is in ESA mode. In particular, the CC field was at the wrong place. Signed-off-by: Richard Henderson --- target-s390x/helper.c | 9 +++++---- target-s390x/translate.c | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 42e06eb85e..7dc4d46eac 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -454,18 +454,19 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) env->psw.addr = addr; env->psw.mask = mask; - env->cc_op = (mask >> 13) & 3; + env->cc_op = (mask >> 44) & 3; } static uint64_t get_psw_mask(CPUS390XState *env) { - uint64_t r = env->psw.mask; + uint64_t r; env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr); - r &= ~(3ULL << 13); + r = env->psw.mask; + r &= ~PSW_MASK_CC; assert(!(env->cc_op & ~3)); - r |= env->cc_op << 13; + r |= (uint64_t)env->cc_op << 44; return r; } diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b8f2ca8678..dc0f9cc8b9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -4559,6 +4559,8 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); tcg_gen_addi_i64(tmp, tmp, 4); tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); + /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ + tcg_gen_shli_i64(tmp2, tmp2, 32); gen_helper_load_psw(cpu_env, tmp2, tmp3); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); From ad044d09de62c10c361003765d5039396c057abe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Aug 2012 17:16:22 -0700 Subject: [PATCH 0104/1634] target-s390: Add format based disassassmbly infrastructure Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 54 ++ target-s390x/insn-format.def | 55 ++ target-s390x/translate.c | 1113 +++++++++++++++++++++++----------- 3 files changed, 858 insertions(+), 364 deletions(-) create mode 100644 target-s390x/insn-data.def create mode 100644 target-s390x/insn-format.def diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def new file mode 100644 index 0000000000..7d81928350 --- /dev/null +++ b/target-s390x/insn-data.def @@ -0,0 +1,54 @@ +/* ADD */ + C(0x1a00, AR, RR_a, Z, r1, r2, new, r1_32, add, adds32) + C(0xb9f8, ARK, RRF_a, DO, r2, r3, new, r1_32, add, adds32) + C(0x5a00, A, RX_a, Z, r1, m2_32s, new, r1_32, add, adds32) + C(0xe35a, AY, RXY_a, LD, r1, m2_32s, new, r1_32, add, adds32) + C(0xb908, AGR, RRE, Z, r1, r2, r1, 0, add, adds64) + C(0xb918, AGFR, RRE, Z, r1, r2_32s, r1, 0, add, adds64) + C(0xb9e8, AGRK, RRF_a, DO, r2, r3, r1, 0, add, adds64) + C(0xe308, AG, RXY_a, Z, r1, m2_64, r1, 0, add, adds64) + C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) +/* ADD IMMEDIATE */ + C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) + C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32) + C(0xecd8, AHIK, RIE_d, DO, r3, i2, new, r1_32, add, adds32) + C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) + C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64) + C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) +/* ADD LOGICAL */ + C(0x1e00, ALR, RR_a, Z, r1, r2, new, r1_32, add, addu32) + C(0xb9fa, ALRK, RRF_a, DO, r2, r3, new, r1_32, add, addu32) + C(0x5e00, AL, RX_a, Z, r1, m2_32u, new, r1_32, add, addu32) + C(0xe35e, ALY, RXY_a, LD, r1, m2_32u, new, r1_32, add, addu32) + C(0xb90a, ALGR, RRE, Z, r1, r2, r1, 0, add, addu64) + C(0xb91a, ALGFR, RRE, Z, r1, r2_32u, r1, 0, add, addu64) + C(0xb9ea, ALGRK, RRF_a, DO, r2, r3, r1, 0, add, addu64) + C(0xe30a, ALG, RXY_a, Z, r1, m2_64, r1, 0, add, addu64) + C(0xe31a, ALGF, RXY_a, Z, r1, m2_32u, r1, 0, add, addu64) +/* ADD LOGICAL IMMEDIATE */ + C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32) + C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64) + +/* SUBTRACT */ + C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) + C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) + C(0x5b00, S, RX_a, Z, r1, m2_32s, new, r1_32, sub, subs32) + C(0xe35b, SY, RXY_a, LD, r1, m2_32s, new, r1_32, sub, subs32) + C(0xb909, SGR, RRE, Z, r1, r2, r1, 0, sub, subs64) + C(0xb919, SGFR, RRE, Z, r1, r2_32s, r1, 0, sub, subs64) + C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) + C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) + C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) +/* SUBTRACT LOGICAL */ + C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32) + C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32) + C(0x5f00, SL, RX_a, Z, r1, m2_32u, new, r1_32, sub, subu32) + C(0xe35f, SLY, RXY_a, LD, r1, m2_32u, new, r1_32, sub, subu32) + C(0xb90b, SLGR, RRE, Z, r1, r2, r1, 0, sub, subu64) + C(0xb91b, SLGFR, RRE, Z, r1, r2_32u, r1, 0, sub, subu64) + C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, sub, subu64) + C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, sub, subu64) + C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, sub, subu64) +/* SUBTRACT LOGICAL IMMEDIATE */ + C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32) + C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64) diff --git a/target-s390x/insn-format.def b/target-s390x/insn-format.def new file mode 100644 index 0000000000..0e898b90bd --- /dev/null +++ b/target-s390x/insn-format.def @@ -0,0 +1,55 @@ +/* Description of s390 insn formats. */ +/* NAME F1, F2... */ +F0(E) +F1(I, I(1, 8, 8)) +F2(RI_a, R(1, 8), I(2,16,16)) +F2(RI_b, R(1, 8), I(2,16,16)) +F2(RI_c, M(1, 8), I(2,16,16)) +F3(RIE_a, R(1, 8), I(2,16,16), M(3,32)) +F4(RIE_b, R(1, 8), R(2,12), M(3,32), I(4,16,16)) +F4(RIE_c, R(1, 8), I(2,32, 8), M(3,12), I(4,16,16)) +F3(RIE_d, R(1, 8), I(2,16,16), R(3,12)) +F3(RIE_e, R(1, 8), I(2,16,16), R(3,12)) +F5(RIE_f, R(1, 8), R(2,12), I(3,16,8), I(4,24,8), I(5,32,8)) +F2(RIL_a, R(1, 8), I(2,16,32)) +F2(RIL_b, R(1, 8), I(2,16,32)) +F2(RIL_c, M(1, 8), I(2,16,32)) +F4(RIS, R(1, 8), I(2,32, 8), M(3,12), BD(4,16,20)) +/* ??? The PoO does not call out subtypes _a and _b for RR, as it does + for e.g. RX. Our checking requires this for e.g. BCR. */ +F2(RR_a, R(1, 8), R(2,12)) +F2(RR_b, M(1, 8), R(2,12)) +F2(RRE, R(1,24), R(2,28)) +F3(RRD, R(1,16), R(2,28), R(3,24)) +F4(RRF_a, R(1,24), R(2,28), R(3,16), M(4,20)) +F4(RRF_b, R(1,24), R(2,28), R(3,16), M(4,20)) +F4(RRF_c, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRF_d, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRF_e, R(1,24), R(2,28), M(3,16), M(4,20)) +F4(RRS, R(1, 8), R(2,12), M(3,32), BD(4,16,20)) +F3(RS_a, R(1, 8), BD(2,16,20), R(3,12)) +F3(RS_b, R(1, 8), BD(2,16,20), M(3,12)) +F3(RSI, R(1, 8), I(2,16,16), R(3,12)) +F2(RSL, L(1, 8, 4), BD(1,16,20)) +F3(RSY_a, R(1, 8), BDL(2), R(3,12)) +F3(RSY_b, R(1, 8), BDL(2), M(3,12)) +F2(RX_a, R(1, 8), BXD(2)) +F2(RX_b, M(1, 8), BXD(2)) +F2(RXE, R(1, 8), BXD(2)) +F3(RXF, R(1,32), BXD(2), R(3, 8)) +F2(RXY_a, R(1, 8), BXDL(2)) +F2(RXY_b, M(1, 8), BXDL(2)) +F1(S, BD(2,16,20)) +F2(SI, BD(1,16,20), I(2,8,8)) +F2(SIL, BD(1,16,20), I(2,32,16)) +F2(SIY, BDL(1), I(2, 8, 8)) +F3(SS_a, L(1, 8, 8), BD(1,16,20), BD(2,32,36)) +F4(SS_b, L(1, 8, 4), BD(1,16,20), L(2,12,4), BD(2,32,36)) +F4(SS_c, L(1, 8, 4), BD(1,16,20), BD(2,32,36), I(3,12, 4)) +/* ??? Odd man out. The L1 field here is really a register, but the + easy way to compress the fields has R1 and B1 overlap. */ +F4(SS_d, L(1, 8, 4), BD(1,16,20), BD(2,32,36), R(3,12)) +F4(SS_e, R(1, 8), BD(2,16,20), R(3,12), BD(4,32,36)) +F3(SS_f, BD(1,16,20), L(2,8,8), BD(2,32,36)) +F2(SSE, BD(1,16,20), BD(2,32,36)) +F3(SSF, BD(1,16,20), BD(2,32,36), R(3,8)) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dc0f9cc8b9..92d49e1c6f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -42,12 +42,20 @@ static TCGv_ptr cpu_env; #define GEN_HELPER 1 #include "helper.h" + +/* Information that (most) every instruction needs to manipulate. */ typedef struct DisasContext DisasContext; +typedef struct DisasInsn DisasInsn; +typedef struct DisasFields DisasFields; + struct DisasContext { - uint64_t pc; - int is_jmp; - enum cc_op cc_op; struct TranslationBlock *tb; + const DisasInsn *insn; + DisasFields *fields; + uint64_t pc, next_pc; + enum cc_op cc_op; + bool singlestep_enabled; + int is_jmp; }; #define DISAS_EXCP 4 @@ -295,15 +303,12 @@ static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc) { - return (uint64_t)cpu_ldl_code(env, pc); + return (uint64_t)(uint32_t)cpu_ldl_code(env, pc); } static inline uint64_t ld_code6(CPUS390XState *env, uint64_t pc) { - uint64_t opc; - opc = (uint64_t)cpu_lduw_code(env, pc) << 32; - opc |= (uint64_t)(uint32_t)cpu_ldl_code(env, pc + 2); - return opc; + return (ld_code2(env, pc) << 32) | ld_code4(env, pc + 2); } static inline int get_mem_index(DisasContext *s) @@ -607,17 +612,6 @@ static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr); } -static void set_cc_sub64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_SUB_64, v1, v2, vr); -} - -static void set_cc_subu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_SUBU_64, v1, v2, vr); -} - static void set_cc_abs64(DisasContext *s, TCGv_i64 v1) { gen_op_update1_cc_i64(s, CC_OP_ABS_64, v1); @@ -644,12 +638,6 @@ static void set_cc_sub32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) gen_op_update3_cc_i32(s, CC_OP_SUB_32, v1, v2, vr); } -static void set_cc_subu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_SUBU_32, v1, v2, vr); -} - static void set_cc_abs32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1); @@ -1535,72 +1523,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp3); tcg_temp_free_i64(tmp4); break; - case 0x8: /* AG R1,D2(X2,B2) [RXY] */ - case 0xa: /* ALG R1,D2(X2,B2) [RXY] */ - case 0x18: /* AGF R1,D2(X2,B2) [RXY] */ - case 0x1a: /* ALGF R1,D2(X2,B2) [RXY] */ - if (op == 0x1a) { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - } else if (op == 0x18) { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else { - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x8: - case 0x18: - set_cc_add64(s, tmp4, tmp2, tmp3); - break; - case 0xa: - case 0x1a: - set_cc_addu64(s, tmp4, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; - case 0x9: /* SG R1,D2(X2,B2) [RXY] */ - case 0xb: /* SLG R1,D2(X2,B2) [RXY] */ - case 0x19: /* SGF R1,D2(X2,B2) [RXY] */ - case 0x1b: /* SLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0x19) { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else if (op == 0x1b) { - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_sub_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x9: - case 0x19: - set_cc_sub64(s, tmp4, tmp2, tmp3); - break; - case 0xb: - case 0x1b: - set_cc_subu64(s, tmp4, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0xf: /* LRVG R1,D2(X2,B2) [RXE] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); @@ -1723,40 +1645,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg32_i64(r1, tmp3); tcg_temp_free_i64(tmp3); break; - case 0x5a: /* AY R1,D2(X2,B2) [RXY] */ - case 0x5b: /* SY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_temp_free_i64(tmp2); - switch (op) { - case 0x5a: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - break; - case 0x5b: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - switch (op) { - case 0x5a: - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5b: - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ store_reg(r1, addr); break; @@ -3350,68 +3238,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x8: /* AGR R1,R2 [RRE] */ - case 0xa: /* ALGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x8: - set_cc_add64(s, tmp, tmp2, tmp3); - break; - case 0xa: - set_cc_addu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x9: /* SGR R1,R2 [RRE] */ - case 0xb: /* SLGR R1,R2 [RRE] */ - case 0x1b: /* SLGFR R1,R2 [RRE] */ - case 0x19: /* SGFR R1,R2 [RRE] */ - tmp = load_reg(r1); - switch (op) { - case 0x1b: - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x19: - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - default: - tmp2 = load_reg(r2); - break; - } - tmp3 = tcg_temp_new_i64(); - tcg_gen_sub_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - switch (op) { - case 0x9: - case 0x19: - set_cc_sub64(s, tmp, tmp2, tmp3); - break; - case 0xb: - case 0x1b: - set_cc_subu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0xc: /* MSGR R1,R2 [RRE] */ case 0x1c: /* MSGFR R1,R2 [RRE] */ tmp = load_reg(r1); @@ -3469,29 +3295,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x18: /* AGFR R1,R2 [RRE] */ - case 0x1a: /* ALGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - if (op == 0x18) { - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - } else { - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - } - tcg_temp_free_i32(tmp32_1); - tmp = load_reg(r1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_add_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - if (op == 0x18) { - set_cc_add64(s, tmp, tmp2, tmp3); - } else { - set_cc_addu64(s, tmp, tmp2, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x0f: /* LRVGR R1,R2 [RRE] */ tcg_gen_bswap64_i64(regs[r1], regs[r2]); break; @@ -3794,54 +3597,10 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { - TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i64 tmp; + TCGv_i32 tmp32_1; switch (op) { - case 0x4: /* SLGFI R1,I2 [RIL] */ - case 0xa: /* ALGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64((uint64_t)(uint32_t)i2); - tmp3 = tcg_temp_new_i64(); - switch (op) { - case 0x4: - tcg_gen_sub_i64(tmp3, tmp, tmp2); - set_cc_subu64(s, tmp, tmp2, tmp3); - break; - case 0xa: - tcg_gen_add_i64(tmp3, tmp, tmp2); - set_cc_addu64(s, tmp, tmp2, tmp3); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x5: /* SLFI R1,I2 [RIL] */ - case 0xb: /* ALFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(i2); - tmp32_3 = tcg_temp_new_i32(); - switch (op) { - case 0x5: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0xb: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0xc: /* CGFI R1,I2 [RIL] */ tmp = load_reg(r1); cmp_s64c(s, tmp, (int64_t)i2); @@ -4059,42 +3818,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x1a: /* AR R1,R2 [RR] */ - case 0x1e: /* ALR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_3); - if (opc == 0x1a) { - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - } else { - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x1b: /* SR R1,R2 [RR] */ - case 0x1f: /* SLR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_3); - if (opc == 0x1b) { - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - } else { - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x1c: /* MR R1,R2 [RR] */ /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ insn = ld_code2(env, s->pc); @@ -4380,51 +4103,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5a: /* A R1,D2(X2,B2) [RX] */ - case 0x5b: /* S R1,D2(X2,B2) [RX] */ - case 0x5e: /* AL R1,D2(X2,B2) [RX] */ - case 0x5f: /* SL R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp); - switch (opc) { - case 0x5a: - case 0x5e: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - break; - case 0x5b: - case 0x5f: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - switch (opc) { - case 0x5a: - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5e: - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5b: - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x5f: - set_cc_subu32(s, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x5c: /* M R1,D2(X2,B2) [RX] */ /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */ insn = ld_code4(env, s->pc); @@ -5131,9 +4809,699 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) gen_illegal_opcode(env, s, ilc); break; } +} + +/* ====================================================================== */ +/* Define the insn format enumeration. */ +#define F0(N) FMT_##N, +#define F1(N, X1) F0(N) +#define F2(N, X1, X2) F0(N) +#define F3(N, X1, X2, X3) F0(N) +#define F4(N, X1, X2, X3, X4) F0(N) +#define F5(N, X1, X2, X3, X4, X5) F0(N) + +typedef enum { +#include "insn-format.def" +} DisasFormat; + +#undef F0 +#undef F1 +#undef F2 +#undef F3 +#undef F4 +#undef F5 + +/* Define a structure to hold the decoded fields. We'll store each inside + an array indexed by an enum. In order to conserve memory, we'll arrange + for fields that do not exist at the same time to overlap, thus the "C" + for compact. For checking purposes there is an "O" for original index + as well that will be applied to availability bitmaps. */ + +enum DisasFieldIndexO { + FLD_O_r1, + FLD_O_r2, + FLD_O_r3, + FLD_O_m1, + FLD_O_m3, + FLD_O_m4, + FLD_O_b1, + FLD_O_b2, + FLD_O_b4, + FLD_O_d1, + FLD_O_d2, + FLD_O_d4, + FLD_O_x2, + FLD_O_l1, + FLD_O_l2, + FLD_O_i1, + FLD_O_i2, + FLD_O_i3, + FLD_O_i4, + FLD_O_i5 +}; + +enum DisasFieldIndexC { + FLD_C_r1 = 0, + FLD_C_m1 = 0, + FLD_C_b1 = 0, + FLD_C_i1 = 0, + + FLD_C_r2 = 1, + FLD_C_b2 = 1, + FLD_C_i2 = 1, + + FLD_C_r3 = 2, + FLD_C_m3 = 2, + FLD_C_i3 = 2, + + FLD_C_m4 = 3, + FLD_C_b4 = 3, + FLD_C_i4 = 3, + FLD_C_l1 = 3, + + FLD_C_i5 = 4, + FLD_C_d1 = 4, + + FLD_C_d2 = 5, + + FLD_C_d4 = 6, + FLD_C_x2 = 6, + FLD_C_l2 = 6, + + NUM_C_FIELD = 7 +}; + +struct DisasFields { + unsigned op:8; + unsigned op2:8; + unsigned presentC:16; + unsigned int presentO; + int c[NUM_C_FIELD]; +}; + +/* This is the way fields are to be accessed out of DisasFields. */ +#define have_field(S, F) have_field1((S), FLD_O_##F) +#define get_field(S, F) get_field1((S), FLD_O_##F, FLD_C_##F) + +static bool have_field1(const DisasFields *f, enum DisasFieldIndexO c) +{ + return (f->presentO >> c) & 1; +} + +static int get_field1(const DisasFields *f, enum DisasFieldIndexO o, + enum DisasFieldIndexC c) +{ + assert(have_field1(f, o)); + return f->c[c]; +} + +/* Describe the layout of each field in each format. */ +typedef struct DisasField { + unsigned int beg:8; + unsigned int size:8; + unsigned int type:2; + unsigned int indexC:6; + enum DisasFieldIndexO indexO:8; +} DisasField; + +typedef struct DisasFormatInfo { + DisasField op[NUM_C_FIELD]; +} DisasFormatInfo; + +#define R(N, B) { B, 4, 0, FLD_C_r##N, FLD_O_r##N } +#define M(N, B) { B, 4, 0, FLD_C_m##N, FLD_O_m##N } +#define BD(N, BB, BD) { BB, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { BD, 12, 0, FLD_C_d##N, FLD_O_d##N } +#define BXD(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 12, 4, 0, FLD_C_x##N, FLD_O_x##N }, \ + { 20, 12, 0, FLD_C_d##N, FLD_O_d##N } +#define BDL(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 20, 20, 2, FLD_C_d##N, FLD_O_d##N } +#define BXDL(N) { 16, 4, 0, FLD_C_b##N, FLD_O_b##N }, \ + { 12, 4, 0, FLD_C_x##N, FLD_O_x##N }, \ + { 20, 20, 2, FLD_C_d##N, FLD_O_d##N } +#define I(N, B, S) { B, S, 1, FLD_C_i##N, FLD_O_i##N } +#define L(N, B, S) { B, S, 0, FLD_C_l##N, FLD_O_l##N } + +#define F0(N) { { } }, +#define F1(N, X1) { { X1 } }, +#define F2(N, X1, X2) { { X1, X2 } }, +#define F3(N, X1, X2, X3) { { X1, X2, X3 } }, +#define F4(N, X1, X2, X3, X4) { { X1, X2, X3, X4 } }, +#define F5(N, X1, X2, X3, X4, X5) { { X1, X2, X3, X4, X5 } }, + +static const DisasFormatInfo format_info[] = { +#include "insn-format.def" +}; + +#undef F0 +#undef F1 +#undef F2 +#undef F3 +#undef F4 +#undef F5 +#undef R +#undef M +#undef BD +#undef BXD +#undef BDL +#undef BXDL +#undef I +#undef L + +/* Generally, we'll extract operands into this structures, operate upon + them, and store them back. See the "in1", "in2", "prep", "wout" sets + of routines below for more details. */ +typedef struct { + bool g_out, g_out2, g_in1, g_in2; + TCGv_i64 out, out2, in1, in2; + TCGv_i64 addr1; +} DisasOps; + +/* Return values from translate_one, indicating the state of the TB. */ +typedef enum { + /* Continue the TB. */ + NO_EXIT, + /* We have emitted one or more goto_tb. No fixup required. */ + EXIT_GOTO_TB, + /* We are not using a goto_tb (for whatever reason), but have updated + the PC (for whatever reason), so there's no need to do it again on + exiting the TB. */ + EXIT_PC_UPDATED, + /* We are exiting the TB, but have neither emitted a goto_tb, nor + updated the PC for the next instruction to be executed. */ + EXIT_PC_STALE, + /* We are ending the TB with a noreturn function call, e.g. longjmp. + No following code will be executed. */ + EXIT_NORETURN, +} ExitStatus; + +typedef enum DisasFacility { + FAC_Z, /* zarch (default) */ + FAC_CASS, /* compare and swap and store */ + FAC_CASS2, /* compare and swap and store 2*/ + FAC_DFP, /* decimal floating point */ + FAC_DFPR, /* decimal floating point rounding */ + FAC_DO, /* distinct operands */ + FAC_EE, /* execute extensions */ + FAC_EI, /* extended immediate */ + FAC_FPE, /* floating point extension */ + FAC_FPSSH, /* floating point support sign handling */ + FAC_FPRGR, /* FPR-GR transfer */ + FAC_GIE, /* general instructions extension */ + FAC_HFP_MA, /* HFP multiply-and-add/subtract */ + FAC_HW, /* high-word */ + FAC_IEEEE_SIM, /* IEEE exception sumilation */ + FAC_LOC, /* load/store on condition */ + FAC_LD, /* long displacement */ + FAC_PC, /* population count */ + FAC_SCF, /* store clock fast */ + FAC_SFLE, /* store facility list extended */ +} DisasFacility; + +struct DisasInsn { + unsigned opc:16; + DisasFormat fmt:6; + DisasFacility fac:6; + + const char *name; + + void (*help_in1)(DisasContext *, DisasFields *, DisasOps *); + void (*help_in2)(DisasContext *, DisasFields *, DisasOps *); + void (*help_prep)(DisasContext *, DisasFields *, DisasOps *); + void (*help_wout)(DisasContext *, DisasFields *, DisasOps *); + void (*help_cout)(DisasContext *, DisasOps *); + ExitStatus (*help_op)(DisasContext *, DisasOps *); + + uint64_t data; +}; + +/* ====================================================================== */ +/* The operations. These perform the bulk of the work for any insn, + usually after the operands have been loaded and output initialized. */ + +static ExitStatus op_add(DisasContext *s, DisasOps *o) +{ + tcg_gen_add_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sub(DisasContext *s, DisasOps *o) +{ + tcg_gen_sub_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +/* ====================================================================== */ +/* The "Cc OUTput" generators. Given the generated output (and in some cases + the original inputs), update the various cc data structures in order to + be able to compute the new condition code. */ + +static void cout_adds32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADD_32, o->in1, o->in2, o->out); +} + +static void cout_adds64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADD_64, o->in1, o->in2, o->out); +} + +static void cout_addu32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDU_32, o->in1, o->in2, o->out); +} + +static void cout_addu64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); +} + +static void cout_subs32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out); +} + +static void cout_subs64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUB_64, o->in1, o->in2, o->out); +} + +static void cout_subu32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBU_32, o->in1, o->in2, o->out); +} + +static void cout_subu64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out); +} + +/* ====================================================================== */ +/* The "PREPeration" generators. These initialize the DisasOps.OUT fields + with the TCG register to which we will write. Used in combination with + the "wout" generators, in some cases we need a new temporary, and in + some cases we can write to a TCG global. */ + +static void prep_new(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = tcg_temp_new_i64(); +} + +static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = regs[get_field(f, r1)]; + o->g_out = true; +} + +/* ====================================================================== */ +/* The "Write OUTput" generators. These generally perform some non-trivial + copy of data to TCG globals, or to main memory. The trivial cases are + generally handled by having a "prep" generator install the TCG global + as the destination of the operation. */ + +static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg32_i64(get_field(f, r1), o->out); +} + +static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); +} + +static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s)); +} + +/* ====================================================================== */ +/* The "INput 1" generators. These load the first operand to an insn. */ + +static void in1_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r1)); +} + +static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r2)); +} + +static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_reg(get_field(f, r3)); +} + +static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); +} + +static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s)); +} + +static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s)); +} + +/* ====================================================================== */ +/* The "INput 2" generators. These load the second operand to an insn. */ + +static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_reg(get_field(f, r2)); +} + +static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_reg(get_field(f, r3)); +} + +static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int x2 = have_field(f, x2) ? get_field(f, x2) : 0; + o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); +} + +static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_m2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64(get_field(f, i2)); +} + +static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); +} + +/* ====================================================================== */ + +/* Find opc within the table of insns. This is formulated as a switch + statement so that (1) we get compile-time notice of cut-paste errors + for duplicated opcodes, and (2) the compiler generates the binary + search tree, rather than us having to post-process the table. */ + +#define C(OPC, NM, FT, FC, I1, I2, P, W, OP, CC) \ + D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, 0) + +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) insn_ ## NM, + +enum DisasInsnEnum { +#include "insn-data.def" +}; + +#undef D +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \ + .opc = OPC, \ + .fmt = FMT_##FT, \ + .fac = FAC_##FC, \ + .name = #NM, \ + .help_in1 = in1_##I1, \ + .help_in2 = in2_##I2, \ + .help_prep = prep_##P, \ + .help_wout = wout_##W, \ + .help_cout = cout_##CC, \ + .help_op = op_##OP, \ + .data = D \ + }, + +/* Allow 0 to be used for NULL in the table below. */ +#define in1_0 NULL +#define in2_0 NULL +#define prep_0 NULL +#define wout_0 NULL +#define cout_0 NULL +#define op_0 NULL + +static const DisasInsn insn_info[] = { +#include "insn-data.def" +}; + +#undef D +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) \ + case OPC: return &insn_info[insn_ ## NM]; + +static const DisasInsn *lookup_opc(uint16_t opc) +{ + switch (opc) { +#include "insn-data.def" + default: + return NULL; + } +} + +#undef D +#undef C + +/* Extract a field from the insn. The INSN should be left-aligned in + the uint64_t so that we can more easily utilize the big-bit-endian + definitions we extract from the Principals of Operation. */ + +static void extract_field(DisasFields *o, const DisasField *f, uint64_t insn) +{ + uint32_t r, m; + + if (f->size == 0) { + return; + } + + /* Zero extract the field from the insn. */ + r = (insn << f->beg) >> (64 - f->size); + + /* Sign-extend, or un-swap the field as necessary. */ + switch (f->type) { + case 0: /* unsigned */ + break; + case 1: /* signed */ + assert(f->size <= 32); + m = 1u << (f->size - 1); + r = (r ^ m) - m; + break; + case 2: /* dl+dh split, signed 20 bit. */ + r = ((int8_t)r << 12) | (r >> 8); + break; + default: + abort(); + } + + /* Validate that the "compressed" encoding we selected above is valid. + I.e. we havn't make two different original fields overlap. */ + assert(((o->presentC >> f->indexC) & 1) == 0); + o->presentC |= 1 << f->indexC; + o->presentO |= 1 << f->indexO; + + o->c[f->indexC] = r; +} + +/* Lookup the insn at the current PC, extracting the operands into O and + returning the info struct for the insn. Returns NULL for invalid insn. */ + +static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, + DisasFields *f) +{ + uint64_t insn, pc = s->pc; + int op, op2; + const DisasInsn *info; + + insn = ld_code2(env, pc); + op = (insn >> 8) & 0xff; + switch (get_ilc(op)) { + case 1: + insn = insn << 48; + break; + case 2: + insn = ld_code4(env, pc) << 32; + break; + case 3: + insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); + break; + default: + abort(); + } + + /* We can't actually determine the insn format until we've looked up + the full insn opcode. Which we can't do without locating the + secondary opcode. Assume by default that OP2 is at bit 40; for + those smaller insns that don't actually have a secondary opcode + this will correctly result in OP2 = 0. */ + switch (op) { + case 0x01: /* E */ + case 0x80: /* S */ + case 0x82: /* S */ + case 0x93: /* S */ + case 0xb2: /* S, RRF, RRE */ + case 0xb3: /* RRE, RRD, RRF */ + case 0xb9: /* RRE, RRF */ + case 0xe5: /* SSE, SIL */ + op2 = (insn << 8) >> 56; + break; + case 0xa5: /* RI */ + case 0xa7: /* RI */ + case 0xc0: /* RIL */ + case 0xc2: /* RIL */ + case 0xc4: /* RIL */ + case 0xc6: /* RIL */ + case 0xc8: /* SSF */ + case 0xcc: /* RIL */ + op2 = (insn << 12) >> 60; + break; + case 0xd0 ... 0xdf: /* SS */ + case 0xe1: /* SS */ + case 0xe2: /* SS */ + case 0xe8: /* SS */ + case 0xe9: /* SS */ + case 0xea: /* SS */ + case 0xee ... 0xf3: /* SS */ + case 0xf8 ... 0xfd: /* SS */ + op2 = 0; + break; + default: + op2 = (insn << 40) >> 56; + break; + } + + memset(f, 0, sizeof(*f)); + f->op = op; + f->op2 = op2; + + /* Lookup the instruction. */ + info = lookup_opc(op << 8 | op2); + + /* If we found it, extract the operands. */ + if (info != NULL) { + DisasFormat fmt = info->fmt; + int i; + + for (i = 0; i < NUM_C_FIELD; ++i) { + extract_field(f, &format_info[fmt].op[i], insn); + } + } + return info; +} + +static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) +{ + const DisasInsn *insn; + ExitStatus ret = NO_EXIT; + DisasFields f; + DisasOps o; + + insn = extract_insn(env, s, &f); /* Instruction length is encoded in the opcode */ - s->pc += (ilc * 2); + s->next_pc = s->pc + get_ilc(f.op) * 2; + + /* If not found, try the old interpreter. This includes ILLOPC. */ + if (insn == NULL) { + disas_s390_insn(env, s); + switch (s->is_jmp) { + case DISAS_NEXT: + ret = NO_EXIT; + break; + case DISAS_TB_JUMP: + ret = EXIT_GOTO_TB; + break; + case DISAS_JUMP: + ret = EXIT_PC_UPDATED; + break; + case DISAS_EXCP: + ret = EXIT_NORETURN; + break; + default: + abort(); + } + + s->pc = s->next_pc; + return ret; + } + + /* Set up the strutures we use to communicate with the helpers. */ + s->insn = insn; + s->fields = &f; + o.g_out = o.g_out2 = o.g_in1 = o.g_in2 = false; + TCGV_UNUSED_I64(o.out); + TCGV_UNUSED_I64(o.out2); + TCGV_UNUSED_I64(o.in1); + TCGV_UNUSED_I64(o.in2); + TCGV_UNUSED_I64(o.addr1); + + /* Implement the instruction. */ + if (insn->help_in1) { + insn->help_in1(s, &f, &o); + } + if (insn->help_in2) { + insn->help_in2(s, &f, &o); + } + if (insn->help_prep) { + insn->help_prep(s, &f, &o); + } + if (insn->help_op) { + ret = insn->help_op(s, &o); + } + if (insn->help_wout) { + insn->help_wout(s, &f, &o); + } + if (insn->help_cout) { + insn->help_cout(s, &o); + } + + /* Free any temporaries created by the helpers. */ + if (!TCGV_IS_UNUSED_I64(o.out) && !o.g_out) { + tcg_temp_free_i64(o.out); + } + if (!TCGV_IS_UNUSED_I64(o.out2) && !o.g_out2) { + tcg_temp_free_i64(o.out2); + } + if (!TCGV_IS_UNUSED_I64(o.in1) && !o.g_in1) { + tcg_temp_free_i64(o.in1); + } + if (!TCGV_IS_UNUSED_I64(o.in2) && !o.g_in2) { + tcg_temp_free_i64(o.in2); + } + if (!TCGV_IS_UNUSED_I64(o.addr1)) { + tcg_temp_free_i64(o.addr1); + } + + /* Advance to the next instruction. */ + s->pc = s->next_pc; + return ret; } static inline void gen_intermediate_code_internal(CPUS390XState *env, @@ -5147,6 +5515,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, int j, lj = -1; int num_insns, max_insns; CPUBreakpoint *bp; + ExitStatus status; pc_start = tb->pc; @@ -5155,10 +5524,11 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, pc_start &= 0x7fffffff; } - dc.pc = pc_start; - dc.is_jmp = DISAS_NEXT; dc.tb = tb; + dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; + dc.singlestep_enabled = env->singlestep_enabled; + dc.is_jmp = DISAS_NEXT; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -5194,7 +5564,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_ctx.gen_opc_instr_start[lj] = 1; tcg_ctx.gen_opc_icount[lj] = num_insns; } - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + if (++num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); } @@ -5202,36 +5572,50 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_gen_debug_insn_start(dc.pc); } - disas_s390_insn(env, &dc); + status = translate_one(env, &dc); - num_insns++; - if (env->singlestep_enabled) { - gen_debug(&dc); + /* If we reach a page boundary, are single stepping, + or exhaust instruction count, stop generation. */ + if (status == NO_EXIT + && (dc.pc >= next_page_start + || tcg_ctx.gen_opc_ptr >= gen_opc_end + || num_insns >= max_insns + || singlestep + || env->singlestep_enabled)) { + status = EXIT_PC_STALE; } - } while (!dc.is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end - && dc.pc < next_page_start - && num_insns < max_insns && !env->singlestep_enabled - && !singlestep); - - if (!dc.is_jmp) { - update_psw_addr(&dc); - } - - if (singlestep && dc.cc_op != CC_OP_DYNAMIC) { - gen_op_calc_cc(&dc); - } else { - /* next TB starts off with CC_OP_DYNAMIC, so make sure the cc op type - is in env */ - gen_op_set_cc_op(&dc); - } + } while (status == NO_EXIT); if (tb->cflags & CF_LAST_IO) { gen_io_end(); } - /* Generate the return instruction */ - if (dc.is_jmp != DISAS_TB_JUMP) { - tcg_gen_exit_tb(0); + + switch (status) { + case EXIT_GOTO_TB: + case EXIT_NORETURN: + break; + case EXIT_PC_STALE: + update_psw_addr(&dc); + /* FALLTHRU */ + case EXIT_PC_UPDATED: + if (singlestep && dc.cc_op != CC_OP_DYNAMIC) { + gen_op_calc_cc(&dc); + } else { + /* Next TB starts off with CC_OP_DYNAMIC, + so make sure the cc op type is in env */ + gen_op_set_cc_op(&dc); + } + if (env->singlestep_enabled) { + gen_debug(&dc); + } else { + /* Generate the return instruction */ + tcg_gen_exit_tb(0); + } + break; + default: + abort(); } + gen_icount_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { @@ -5244,6 +5628,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tb->size = dc.pc - pc_start; tb->icount = num_insns; } + #if defined(S390X_DEBUG_DISAS) if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log("IN: %s\n", lookup_symbol(pc_start)); From 3fde06f5fb67dd9e5373b8105318e74e18eec895 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 13:31:01 -0700 Subject: [PATCH 0105/1634] target-s390: Split out disas_jcc Lots of duplicated code replaced with a couple of tables. We no longer attempt to manually invert the logic operation: the comments now match the code. In the fully general test, constant propagate (1 << (3 - cc)) into (8 >> cc). The new function will be usable by non-branch insns as well. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 618 ++++++++++++++++++--------------------- 1 file changed, 277 insertions(+), 341 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 92d49e1c6f..6761889e1f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -58,6 +58,18 @@ struct DisasContext { int is_jmp; }; +/* Information carried about a condition to be evaluated. */ +typedef struct { + TCGCond cond:8; + bool is_64; + bool g1; + bool g2; + union { + struct { TCGv_i64 a, b; } s64; + struct { TCGv_i32 a, b; } s32; + } u; +} DisasCompare; + #define DISAS_EXCP 4 static void gen_op_calc_cc(DisasContext *s); @@ -840,357 +852,281 @@ static inline void account_noninline_branch(DisasContext *s, int cc_op) #endif } -static inline void account_inline_branch(DisasContext *s) +static inline void account_inline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES - inline_branch_hit[s->cc_op]++; + inline_branch_hit[cc_op]++; #endif } +/* Table of mask values to comparison codes, given a comparison as input. + For a true comparison CC=3 will never be set, but we treat this + conservatively for possible use when CC=3 indicates overflow. */ +static const TCGCond ltgt_cond[16] = { + TCG_COND_NEVER, TCG_COND_NEVER, /* | | | x */ + TCG_COND_GT, TCG_COND_NEVER, /* | | GT | x */ + TCG_COND_LT, TCG_COND_NEVER, /* | LT | | x */ + TCG_COND_NE, TCG_COND_NEVER, /* | LT | GT | x */ + TCG_COND_EQ, TCG_COND_NEVER, /* EQ | | | x */ + TCG_COND_GE, TCG_COND_NEVER, /* EQ | | GT | x */ + TCG_COND_LE, TCG_COND_NEVER, /* EQ | LT | | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | LT | GT | x */ +}; + +/* Table of mask values to comparison codes, given a logic op as input. + For such, only CC=0 and CC=1 should be possible. */ +static const TCGCond nz_cond[16] = { + /* | | x | x */ + TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, + /* | NE | x | x */ + TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, + /* EQ | | x | x */ + TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, + /* EQ | NE | x | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, +}; + +/* Interpret MASK in terms of S->CC_OP, and fill in C with all the + details required to generate a TCG comparison. */ +static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) +{ + TCGCond cond; + enum cc_op old_cc_op = s->cc_op; + + if (mask == 15 || mask == 0) { + c->cond = (mask ? TCG_COND_ALWAYS : TCG_COND_NEVER); + c->u.s32.a = cc_op; + c->u.s32.b = cc_op; + c->g1 = c->g2 = true; + c->is_64 = false; + return; + } + + /* Find the TCG condition for the mask + cc op. */ + switch (old_cc_op) { + case CC_OP_LTGT0_32: + case CC_OP_LTGT0_64: + case CC_OP_LTGT_32: + case CC_OP_LTGT_64: + cond = ltgt_cond[mask]; + if (cond == TCG_COND_NEVER) { + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_LTUGTU_32: + case CC_OP_LTUGTU_64: + cond = tcg_unsigned_cond(ltgt_cond[mask]); + if (cond == TCG_COND_NEVER) { + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_NZ: + cond = nz_cond[mask]; + if (cond == TCG_COND_NEVER) { + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_TM_32: + case CC_OP_TM_64: + switch (mask) { + case 8: + cond = TCG_COND_EQ; + break; + case 4 | 2 | 1: + cond = TCG_COND_NE; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_ICM: + switch (mask) { + case 8: + cond = TCG_COND_EQ; + break; + case 4 | 2 | 1: + case 4 | 2: + cond = TCG_COND_NE; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + default: + do_dynamic: + /* Calculate cc value. */ + gen_op_calc_cc(s); + /* FALLTHRU */ + + case CC_OP_STATIC: + /* Jump based on CC. We'll load up the real cond below; + the assignment here merely avoids a compiler warning. */ + account_noninline_branch(s, old_cc_op); + old_cc_op = CC_OP_STATIC; + cond = TCG_COND_NEVER; + break; + } + + /* Load up the arguments of the comparison. */ + c->is_64 = true; + c->g1 = c->g2 = false; + switch (old_cc_op) { + case CC_OP_LTGT0_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_dst); + c->u.s32.b = tcg_const_i32(0); + break; + case CC_OP_LTGT_32: + case CC_OP_LTUGTU_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_src); + c->u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.b, cc_dst); + break; + + case CC_OP_LTGT0_64: + case CC_OP_NZ: + case CC_OP_ICM: + c->u.s64.a = cc_dst; + c->u.s64.b = tcg_const_i64(0); + c->g1 = true; + break; + case CC_OP_LTGT_64: + case CC_OP_LTUGTU_64: + c->u.s64.a = cc_src; + c->u.s64.b = cc_dst; + c->g1 = c->g2 = true; + break; + + case CC_OP_TM_32: + case CC_OP_TM_64: + c->u.s64.a = tcg_temp_new_i64(); + c->u.s64.b = tcg_const_i64(0); + tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); + break; + + case CC_OP_STATIC: + c->is_64 = false; + c->u.s32.a = cc_op; + c->g1 = true; + switch (mask) { + case 0x8 | 0x4 | 0x2: /* cc != 3 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(3); + break; + case 0x8 | 0x4 | 0x1: /* cc != 2 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(2); + break; + case 0x8 | 0x2 | 0x1: /* cc != 1 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(1); + break; + case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */ + cond = TCG_COND_EQ; + c->g1 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_andi_i32(c->u.s32.a, cc_op, 1); + break; + case 0x8 | 0x4: /* cc < 2 */ + cond = TCG_COND_LTU; + c->u.s32.b = tcg_const_i32(2); + break; + case 0x8: /* cc == 0 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(0); + break; + case 0x4 | 0x2 | 0x1: /* cc != 0 */ + cond = TCG_COND_NE; + c->u.s32.b = tcg_const_i32(0); + break; + case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */ + cond = TCG_COND_NE; + c->g1 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_andi_i32(c->u.s32.a, cc_op, 1); + break; + case 0x4: /* cc == 1 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(1); + break; + case 0x2 | 0x1: /* cc > 1 */ + cond = TCG_COND_GTU; + c->u.s32.b = tcg_const_i32(1); + break; + case 0x2: /* cc == 2 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(2); + break; + case 0x1: /* cc == 3 */ + cond = TCG_COND_EQ; + c->u.s32.b = tcg_const_i32(3); + break; + default: + /* CC is masked by something else: (8 >> cc) & mask. */ + cond = TCG_COND_NE; + c->g1 = false; + c->u.s32.a = tcg_const_i32(8); + c->u.s32.b = tcg_const_i32(0); + tcg_gen_shr_i32(c->u.s32.a, c->u.s32.a, cc_op); + tcg_gen_andi_i32(c->u.s32.a, c->u.s32.a, mask); + break; + } + break; + + default: + abort(); + } + c->cond = cond; +} + +static void free_compare(DisasCompare *c) +{ + if (!c->g1) { + if (c->is_64) { + tcg_temp_free_i64(c->u.s64.a); + } else { + tcg_temp_free_i32(c->u.s32.a); + } + } + if (!c->g2) { + if (c->is_64) { + tcg_temp_free_i64(c->u.s64.b); + } else { + tcg_temp_free_i32(c->u.s32.b); + } + } +} + static void gen_jcc(DisasContext *s, uint32_t mask, int skip) { - TCGv_i32 tmp, tmp2, r; - TCGv_i64 tmp64; - int old_cc_op; + DisasCompare c; + TCGCond cond; - switch (s->cc_op) { - case CC_OP_LTGT0_32: - tmp = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* dst <= 0 */ - tcg_gen_brcondi_i32(TCG_COND_GT, tmp, 0, skip); - break; - case 0x8 | 0x2: /* dst >= 0 */ - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, skip); - break; - case 0x8: /* dst == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - break; - case 0x7: /* dst != 0 */ - case 0x6: /* dst != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - break; - case 0x4: /* dst < 0 */ - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, skip); - break; - case 0x2: /* dst > 0 */ - tcg_gen_brcondi_i32(TCG_COND_LE, tmp, 0, skip); - break; - default: - tcg_temp_free_i32(tmp); - goto do_dynamic; - } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - break; - case CC_OP_LTGT0_64: - switch (mask) { - case 0x8 | 0x4: /* dst <= 0 */ - tcg_gen_brcondi_i64(TCG_COND_GT, cc_dst, 0, skip); - break; - case 0x8 | 0x2: /* dst >= 0 */ - tcg_gen_brcondi_i64(TCG_COND_LT, cc_dst, 0, skip); - break; - case 0x8: /* dst == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); - break; - case 0x7: /* dst != 0 */ - case 0x6: /* dst != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); - break; - case 0x4: /* dst < 0 */ - tcg_gen_brcondi_i64(TCG_COND_GE, cc_dst, 0, skip); - break; - case 0x2: /* dst > 0 */ - tcg_gen_brcondi_i64(TCG_COND_LE, cc_dst, 0, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_LTGT_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i32(TCG_COND_GT, tmp, tmp2, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i32(TCG_COND_LT, tmp, tmp2, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i32(TCG_COND_GE, tmp, tmp2, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i32(TCG_COND_LE, tmp, tmp2, skip); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto do_dynamic; - } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - break; - case CC_OP_LTGT_64: - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i64(TCG_COND_GT, cc_src, cc_dst, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i64(TCG_COND_LT, cc_src, cc_dst, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i64(TCG_COND_GE, cc_src, cc_dst, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i64(TCG_COND_LE, cc_src, cc_dst, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_LTUGTU_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i32(TCG_COND_GTU, tmp, tmp2, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i32(TCG_COND_LTU, tmp, tmp2, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i32(TCG_COND_GEU, tmp, tmp2, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i32(TCG_COND_LEU, tmp, tmp2, skip); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto do_dynamic; - } - account_inline_branch(s); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - break; - case CC_OP_LTUGTU_64: - switch (mask) { - case 0x8 | 0x4: /* src <= dst */ - tcg_gen_brcond_i64(TCG_COND_GTU, cc_src, cc_dst, skip); - break; - case 0x8 | 0x2: /* src >= dst */ - tcg_gen_brcond_i64(TCG_COND_LTU, cc_src, cc_dst, skip); - break; - case 0x8: /* src == dst */ - tcg_gen_brcond_i64(TCG_COND_NE, cc_src, cc_dst, skip); - break; - case 0x7: /* src != dst */ - case 0x6: /* src != dst */ - tcg_gen_brcond_i64(TCG_COND_EQ, cc_src, cc_dst, skip); - break; - case 0x4: /* src < dst */ - tcg_gen_brcond_i64(TCG_COND_GEU, cc_src, cc_dst, skip); - break; - case 0x2: /* src > dst */ - tcg_gen_brcond_i64(TCG_COND_LEU, cc_src, cc_dst, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_NZ: - switch (mask) { - /* dst == 0 || dst != 0 */ - case 0x8 | 0x4: - case 0x8 | 0x4 | 0x2: - case 0x8 | 0x4 | 0x2 | 0x1: - case 0x8 | 0x4 | 0x1: - break; - /* dst == 0 */ - case 0x8: - case 0x8 | 0x2: - case 0x8 | 0x2 | 0x1: - case 0x8 | 0x1: - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); - break; - /* dst != 0 */ - case 0x4: - case 0x4 | 0x2: - case 0x4 | 0x2 | 0x1: - case 0x4 | 0x1: - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_TM_32: - tmp = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i32(); + disas_jcc(s, &c, mask); + cond = tcg_invert_cond(c.cond); - tcg_gen_trunc_i64_i32(tmp, cc_src); - tcg_gen_trunc_i64_i32(tmp2, cc_dst); - tcg_gen_and_i32(tmp, tmp, tmp2); - switch (mask) { - case 0x8: /* val & mask == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* val & mask != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - break; - default: - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - goto do_dynamic; - } - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - account_inline_branch(s); - break; - case CC_OP_TM_64: - tmp64 = tcg_temp_new_i64(); - - tcg_gen_and_i64(tmp64, cc_src, cc_dst); - switch (mask) { - case 0x8: /* val & mask == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, tmp64, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* val & mask != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, tmp64, 0, skip); - break; - default: - tcg_temp_free_i64(tmp64); - goto do_dynamic; - } - tcg_temp_free_i64(tmp64); - account_inline_branch(s); - break; - case CC_OP_ICM: - switch (mask) { - case 0x8: /* val == 0 */ - tcg_gen_brcondi_i64(TCG_COND_NE, cc_dst, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* val != 0 */ - case 0x4 | 0x2: /* val != 0 */ - tcg_gen_brcondi_i64(TCG_COND_EQ, cc_dst, 0, skip); - break; - default: - goto do_dynamic; - } - account_inline_branch(s); - break; - case CC_OP_STATIC: - old_cc_op = s->cc_op; - goto do_dynamic_nocccalc; - case CC_OP_DYNAMIC: - default: -do_dynamic: - old_cc_op = s->cc_op; - /* calculate cc value */ - gen_op_calc_cc(s); - -do_dynamic_nocccalc: - /* jump based on cc */ - account_noninline_branch(s, old_cc_op); - - switch (mask) { - case 0x8 | 0x4 | 0x2 | 0x1: - /* always true */ - break; - case 0x8 | 0x4 | 0x2: /* cc != 3 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 3, skip); - break; - case 0x8 | 0x4 | 0x1: /* cc != 2 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 2, skip); - break; - case 0x8 | 0x2 | 0x1: /* cc != 1 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 1, skip); - break; - case 0x8 | 0x2: /* cc == 0 || cc == 2 */ - tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cc_op, 1); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, skip); - tcg_temp_free_i32(tmp); - break; - case 0x8 | 0x4: /* cc < 2 */ - tcg_gen_brcondi_i32(TCG_COND_GEU, cc_op, 2, skip); - break; - case 0x8: /* cc == 0 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 0, skip); - break; - case 0x4 | 0x2 | 0x1: /* cc != 0 */ - tcg_gen_brcondi_i32(TCG_COND_EQ, cc_op, 0, skip); - break; - case 0x4 | 0x1: /* cc == 1 || cc == 3 */ - tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cc_op, 1); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip); - tcg_temp_free_i32(tmp); - break; - case 0x4: /* cc == 1 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 1, skip); - break; - case 0x2 | 0x1: /* cc > 1 */ - tcg_gen_brcondi_i32(TCG_COND_LEU, cc_op, 1, skip); - break; - case 0x2: /* cc == 2 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 2, skip); - break; - case 0x1: /* cc == 3 */ - tcg_gen_brcondi_i32(TCG_COND_NE, cc_op, 3, skip); - break; - default: /* cc is masked by something else */ - tmp = tcg_const_i32(3); - /* 3 - cc */ - tcg_gen_sub_i32(tmp, tmp, cc_op); - tmp2 = tcg_const_i32(1); - /* 1 << (3 - cc) */ - tcg_gen_shl_i32(tmp2, tmp2, tmp); - r = tcg_const_i32(mask); - /* mask & (1 << (3 - cc)) */ - tcg_gen_and_i32(r, r, tmp2); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(tmp2); - - tcg_gen_brcondi_i32(TCG_COND_EQ, r, 0, skip); - tcg_temp_free_i32(r); - break; - } - break; + if (c.is_64) { + tcg_gen_brcond_i64(cond, c.u.s64.a, c.u.s64.b, skip); + } else { + tcg_gen_brcond_i32(cond, c.u.s32.a, c.u.s32.b, skip); } + + free_compare(&c); } static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, From d5a103cd6eb3b407feb4e007cb778a89b1b20c5f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Sep 2012 19:31:57 -0700 Subject: [PATCH 0106/1634] target-s390: Reorg exception handling Make the user path more like the system path. Prepare for more kinds of runtime exceptions. Rename ILC to ILEN to make it clear that we want to pass around a full instruction length, rather than a "code" that happens to be stored one bit left in a larger field. Signed-off-by: Richard Henderson --- linux-user/main.c | 142 ++++++++++++++-------- linux-user/s390x/syscall.h | 2 +- target-s390x/cpu.h | 49 ++++---- target-s390x/helper.c | 58 +++++---- target-s390x/mem_helper.c | 2 +- target-s390x/misc_helper.c | 8 +- target-s390x/translate.c | 242 ++++++++++++++----------------------- 7 files changed, 242 insertions(+), 261 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index f6c4c8d7a3..15bacb9a30 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2933,71 +2933,115 @@ void cpu_loop(CPUAlphaState *env) #ifdef TARGET_S390X void cpu_loop(CPUS390XState *env) { - int trapnr; + int trapnr, n, sig; target_siginfo_t info; + target_ulong addr; while (1) { - trapnr = cpu_s390x_exec (env); - + trapnr = cpu_s390x_exec(env); switch (trapnr) { case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ + /* Just indicate that signals should be handled asap. */ break; - case EXCP_DEBUG: - { - int sig; - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } - } - break; case EXCP_SVC: - { - int n = env->int_svc_code; - if (!n) { - /* syscalls > 255 */ - n = env->regs[1]; - } - env->psw.addr += env->int_svc_ilc; - env->regs[2] = do_syscall(env, n, - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5], - env->regs[6], - env->regs[7], - 0, 0); + n = env->int_svc_code; + if (!n) { + /* syscalls > 255 */ + n = env->regs[1]; + } + env->psw.addr += env->int_svc_ilen; + env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3], + env->regs[4], env->regs[5], + env->regs[6], env->regs[7], 0, 0); + break; + + case EXCP_DEBUG: + sig = gdb_handlesig(env, TARGET_SIGTRAP); + if (sig) { + n = TARGET_TRAP_BRKPT; + goto do_signal_pc; } break; - case EXCP_ADDR: - { - info.si_signo = SIGSEGV; - info.si_errno = 0; + case EXCP_PGM: + n = env->int_pgm_code; + switch (n) { + case PGM_OPERATION: + case PGM_PRIVILEGED: + sig = SIGILL; + n = TARGET_ILL_ILLOPC; + goto do_signal_pc; + case PGM_PROTECTION: + case PGM_ADDRESSING: + sig = SIGSEGV; /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); + n = TARGET_SEGV_MAPERR; + addr = env->__excp_addr; + goto do_signal; + case PGM_EXECUTE: + case PGM_SPECIFICATION: + case PGM_SPECIAL_OP: + case PGM_OPERAND: + do_sigill_opn: + sig = SIGILL; + n = TARGET_ILL_ILLOPN; + goto do_signal_pc; + + case PGM_FIXPT_OVERFLOW: + sig = SIGFPE; + n = TARGET_FPE_INTOVF; + goto do_signal_pc; + case PGM_FIXPT_DIVIDE: + sig = SIGFPE; + n = TARGET_FPE_INTDIV; + goto do_signal_pc; + + case PGM_DATA: + n = (env->fpc >> 8) & 0xff; + if (n == 0xff) { + /* compare-and-trap */ + goto do_sigill_opn; + } else { + /* An IEEE exception, simulated or otherwise. */ + if (n & 0x80) { + n = TARGET_FPE_FLTINV; + } else if (n & 0x40) { + n = TARGET_FPE_FLTDIV; + } else if (n & 0x20) { + n = TARGET_FPE_FLTOVF; + } else if (n & 0x10) { + n = TARGET_FPE_FLTUND; + } else if (n & 0x08) { + n = TARGET_FPE_FLTRES; + } else { + /* ??? Quantum exception; BFP, DFP error. */ + goto do_sigill_opn; + } + sig = SIGFPE; + goto do_signal_pc; + } + + default: + fprintf(stderr, "Unhandled program exception: %#x\n", n); + cpu_dump_state(env, stderr, fprintf, 0); + exit(1); } break; - case EXCP_SPEC: - { - fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPC; - info._sifields._sigfault._addr = env->__excp_addr; - queue_signal(env, info.si_signo, &info); - } + + do_signal_pc: + addr = env->psw.addr; + do_signal: + info.si_signo = sig; + info.si_errno = 0; + info.si_code = n; + info._sifields._sigfault._addr = addr; + queue_signal(env, info.si_signo, &info); break; + default: - printf ("Unhandled trap: 0x%x\n", trapnr); + fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); - exit (1); + exit(1); } process_pending_signals (env); } diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index c2ea151ea5..e4603b79c3 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -16,7 +16,7 @@ struct target_pt_regs { target_psw_t psw; abi_ulong gprs[TARGET_NUM_GPRS]; abi_ulong orig_gpr2; - unsigned short ilc; + unsigned short ilen; unsigned short trap; }; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 529716de47..83e618ab0e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -79,10 +79,10 @@ typedef struct CPUS390XState { uint64_t psa; uint32_t int_pgm_code; - uint32_t int_pgm_ilc; + uint32_t int_pgm_ilen; uint32_t int_svc_code; - uint32_t int_svc_ilc; + uint32_t int_svc_ilen; uint64_t cregs[16]; /* control registers */ @@ -253,25 +253,31 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); } -static inline int get_ilc(uint8_t opc) +/* While the PoO talks about ILC (a number between 1-3) what is actually + stored in LowCore is shifted left one bit (an even between 2-6). As + this is the actual length of the insn and therefore more useful, that + is what we want to pass around and manipulate. To make sure that we + have applied this distinction universally, rename the "ILC" to "ILEN". */ +static inline int get_ilen(uint8_t opc) { switch (opc >> 6) { case 0: - return 1; + return 2; case 1: case 2: - return 2; - case 3: - return 3; + return 4; + default: + return 6; } - - return 0; } -#define ILC_LATER 0x20 -#define ILC_LATER_INC 0x21 -#define ILC_LATER_INC_2 0x22 - +#ifndef CONFIG_USER_ONLY +/* In several cases of runtime exceptions, we havn't recorded the true + instruction length. Use these codes when raising exceptions in order + to re-compute the length by examining the insn in memory. */ +#define ILEN_LATER 0x20 +#define ILEN_LATER_INC 0x21 +#endif S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); @@ -352,21 +358,10 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) #include "exec/exec-all.h" -#ifdef CONFIG_USER_ONLY - -#define EXCP_OPEX 1 /* operation exception (sigill) */ -#define EXCP_SVC 2 /* supervisor call (syscall) */ -#define EXCP_ADDR 5 /* addressing exception */ -#define EXCP_SPEC 6 /* specification exception */ - -#else - #define EXCP_EXT 1 /* external interrupt */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_PGM 3 /* program interruption */ -#endif /* CONFIG_USER_ONLY */ - #define INTERRUPT_EXT (1 << 0) #define INTERRUPT_TOD (1 << 1) #define INTERRUPT_CPUTIMER (1 << 2) @@ -532,9 +527,9 @@ typedef struct LowCore uint32_t ext_params; /* 0x080 */ uint16_t cpu_addr; /* 0x084 */ uint16_t ext_int_code; /* 0x086 */ - uint16_t svc_ilc; /* 0x088 */ + uint16_t svc_ilen; /* 0x088 */ uint16_t svc_code; /* 0x08a */ - uint16_t pgm_ilc; /* 0x08c */ + uint16_t pgm_ilen; /* 0x08c */ uint16_t pgm_code; /* 0x08e */ uint32_t data_exc_code; /* 0x090 */ uint16_t mon_class_num; /* 0x094 */ @@ -924,6 +919,6 @@ uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); /* misc_helper.c */ -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); #endif diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 7dc4d46eac..9a132e6d2c 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -99,10 +99,10 @@ void do_interrupt(CPUS390XState *env) int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, int rw, int mmu_idx) { - /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", - __func__, address, rw, mmu_idx); */ - env->exception_index = EXCP_ADDR; - /* FIXME: find out how this works on a real machine */ + env->exception_index = EXCP_PGM; + env->int_pgm_code = PGM_ADDRESSING; + /* On real machines this value is dropped into LowMem. Since this + is userland, simply put this someplace that cpu_loop can find it. */ env->__excp_addr = address; return 1; } @@ -111,11 +111,11 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, /* Ensure to exit the TB after this call! */ static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, - uint32_t ilc) + uint32_t ilen) { env->exception_index = EXCP_PGM; env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; } static int trans_bits(CPUS390XState *env, uint64_t mode) @@ -143,30 +143,30 @@ static int trans_bits(CPUS390XState *env, uint64_t mode) static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode) { - int ilc = ILC_LATER_INC_2; + int ilen = ILEN_LATER_INC; int bits = trans_bits(env, mode) | 4; DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, PGM_PROTECTION, ilc); + trigger_pgm_exception(env, PGM_PROTECTION, ilen); } static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, uint64_t asc, int rw) { - int ilc = ILC_LATER; + int ilen = ILEN_LATER; int bits = trans_bits(env, asc); + /* Code accesses have an undefined ilc. */ if (rw == 2) { - /* code has is undefined ilc */ - ilc = 2; + ilen = 2; } DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); - trigger_pgm_exception(env, type, ilc); + trigger_pgm_exception(env, type, ilen); } static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, @@ -406,7 +406,7 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, if (raddr > (ram_size + virtio_size)) { DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)aaddr, (uint64_t)ram_size); - trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER); + trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); return 1; } @@ -480,9 +480,9 @@ static void do_svc_interrupt(CPUS390XState *env) lowcore = cpu_physical_memory_map(env->psa, &len, 1); lowcore->svc_code = cpu_to_be16(env->int_svc_code); - lowcore->svc_ilc = cpu_to_be16(env->int_svc_ilc); + lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); - lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + (env->int_svc_ilc)); + lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); mask = be64_to_cpu(lowcore->svc_new_psw.mask); addr = be64_to_cpu(lowcore->svc_new_psw.addr); @@ -496,28 +496,26 @@ static void do_program_interrupt(CPUS390XState *env) uint64_t mask, addr; LowCore *lowcore; hwaddr len = TARGET_PAGE_SIZE; - int ilc = env->int_pgm_ilc; + int ilen = env->int_pgm_ilen; - switch (ilc) { - case ILC_LATER: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); + switch (ilen) { + case ILEN_LATER: + ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); break; - case ILC_LATER_INC: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); - env->psw.addr += ilc * 2; - break; - case ILC_LATER_INC_2: - ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2; - env->psw.addr += ilc; + case ILEN_LATER_INC: + ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); + env->psw.addr += ilen; break; + default: + assert(ilen == 2 || ilen == 4 || ilen == 6); } - qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilc=%d\n", - __func__, env->int_pgm_code, ilc); + qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", + __func__, env->int_pgm_code, ilen); lowcore = cpu_physical_memory_map(env->psa, &len, 1); - lowcore->pgm_ilc = cpu_to_be16(ilc); + lowcore->pgm_ilen = cpu_to_be16(ilen); lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); @@ -527,7 +525,7 @@ static void do_program_interrupt(CPUS390XState *env) cpu_physical_memory_unmap(lowcore, len, 1, len); DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, - env->int_pgm_code, ilc, env->psw.mask, + env->int_pgm_code, ilen, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index bed21e6e1c..7eb3790b40 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -594,7 +594,7 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); env->psw.addr = ret - 4; env->int_svc_code = (insn | v1) & 0xff; - env->int_svc_ilc = 4; + env->int_svc_ilen = 4; helper_exception(env, EXCP_SVC); } else if ((insn & 0xff00) == 0xbf00) { uint32_t insn2, r1, r3, b2, d2; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 70f9739685..2aa1ed0b5e 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -41,7 +41,7 @@ #define HELPER_LOG(x...) #endif -/* raise an exception */ +/* Raise an exception statically from a TB. */ void HELPER(exception)(CPUS390XState *env, uint32_t excp) { HELPER_LOG("%s: exception %d\n", __func__, excp); @@ -50,7 +50,7 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) } #ifndef CONFIG_USER_ONLY -void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) { qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", env->psw.addr); @@ -61,7 +61,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) #endif } else { env->int_pgm_code = code; - env->int_pgm_ilc = ilc; + env->int_pgm_ilen = ilen; env->exception_index = EXCP_PGM; cpu_loop_exit(env); } @@ -105,7 +105,7 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, } if (r) { - program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); + program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC); } return r; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6761889e1f..076bb7f5fe 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -18,7 +18,6 @@ * License along with this library; if not, see . */ -/* #define DEBUG_ILLEGAL_INSTRUCTIONS */ /* #define DEBUG_INLINE_BRANCHES */ #define S390X_DEBUG_DISAS /* #define S390X_DEBUG_DISAS_VERBOSE */ @@ -338,105 +337,52 @@ static inline int get_mem_index(DisasContext *s) } } -static inline void gen_debug(DisasContext *s) +static void gen_exception(int excp) { - TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); - update_psw_addr(s); - gen_op_calc_cc(s); + TCGv_i32 tmp = tcg_const_i32(excp); gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; } -#ifdef CONFIG_USER_ONLY - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) -{ - TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); - s->is_jmp = DISAS_EXCP; -} - -#else /* CONFIG_USER_ONLY */ - -static void debug_print_inst(CPUS390XState *env, DisasContext *s, int ilc) -{ -#ifdef DEBUG_ILLEGAL_INSTRUCTIONS - uint64_t inst = 0; - - switch (ilc & 3) { - case 1: - inst = ld_code2(env, s->pc); - break; - case 2: - inst = ld_code4(env, s->pc); - break; - case 3: - inst = ld_code6(env, s->pc); - break; - } - - fprintf(stderr, "Illegal instruction [%d at %016" PRIx64 "]: 0x%016" - PRIx64 "\n", ilc, s->pc, inst); -#endif -} - -static void gen_program_exception(CPUS390XState *env, DisasContext *s, int ilc, - int code) +static void gen_program_exception(DisasContext *s, int code) { TCGv_i32 tmp; - debug_print_inst(env, s, ilc); - - /* remember what pgm exeption this was */ + /* Remember what pgm exeption this was. */ tmp = tcg_const_i32(code); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_temp_free_i32(tmp); - tmp = tcg_const_i32(ilc); - tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilc)); + tmp = tcg_const_i32(s->next_pc - s->pc); + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen)); tcg_temp_free_i32(tmp); - /* advance past instruction */ - s->pc += (ilc * 2); + /* Advance past instruction. */ + s->pc = s->next_pc; update_psw_addr(s); - /* save off cc */ + /* Save off cc. */ gen_op_calc_cc(s); - /* trigger exception */ - tmp = tcg_const_i32(EXCP_PGM); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + /* Trigger exception. */ + gen_exception(EXCP_PGM); - /* end TB here */ + /* End TB here. */ s->is_jmp = DISAS_EXCP; } - -static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) +static inline void gen_illegal_opcode(DisasContext *s) { - gen_program_exception(env, s, ilc, PGM_SPECIFICATION); + gen_program_exception(s, PGM_SPECIFICATION); } -static void gen_privileged_exception(CPUS390XState *env, DisasContext *s, - int ilc) -{ - gen_program_exception(env, s, ilc, PGM_PRIVILEGED); -} - -static void check_privileged(CPUS390XState *env, DisasContext *s, int ilc) +static inline void check_privileged(DisasContext *s) { if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) { - gen_privileged_exception(env, s, ilc); + gen_program_exception(s, PGM_PRIVILEGED); } } -#endif /* CONFIG_USER_ONLY */ - static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { TCGv_i64 tmp; @@ -1769,7 +1715,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } tcg_temp_free_i64(addr); @@ -1794,7 +1740,7 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) break; default: LOG_DISAS("illegal e5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } @@ -1809,7 +1755,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, TCGv_i64 tmp, tmp2, tmp3, tmp4; TCGv_i32 tmp32_1, tmp32_2; int i, stm_len; - int ilc = 3; LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); @@ -1947,7 +1892,7 @@ do_mh: #ifndef CONFIG_USER_ONLY case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ /* Load Control */ - check_privileged(env, s, ilc); + check_privileged(s); tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); @@ -1959,7 +1904,7 @@ do_mh: break; case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ /* Store Control */ - check_privileged(env, s, ilc); + check_privileged(s); tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); @@ -2036,7 +1981,7 @@ do_mh: break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -2156,7 +2101,7 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal ed operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); return; } tcg_temp_free_i32(tmp_r1); @@ -2313,7 +2258,7 @@ static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal a5 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); return; } } @@ -2451,7 +2396,7 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); return; } } @@ -2462,7 +2407,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, TCGv_i64 tmp, tmp2, tmp3; TCGv_i32 tmp32_1, tmp32_2, tmp32_3; int r1, r2; - int ilc = 2; #ifndef CONFIG_USER_ONLY int r3, d2, b2; #endif @@ -2556,7 +2500,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, #ifndef CONFIG_USER_ONLY case 0x02: /* STIDP D2(B2) [S] */ /* Store CPU ID */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2565,7 +2509,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x04: /* SCK D2(B2) [S] */ /* Set Clock */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2584,7 +2528,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x06: /* SCKC D2(B2) [S] */ /* Set Clock Comparator */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2593,7 +2537,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x07: /* STCKC D2(B2) [S] */ /* Store Clock Comparator */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2602,7 +2546,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x08: /* SPT D2(B2) [S] */ /* Set CPU Timer */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2611,7 +2555,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x09: /* STPT D2(B2) [S] */ /* Store CPU Timer */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2620,7 +2564,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x0a: /* SPKA D2(B2) [S] */ /* Set PSW Key from Address */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2632,12 +2576,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x0d: /* PTLB [S] */ /* Purge TLB */ - check_privileged(env, s, ilc); + check_privileged(s); gen_helper_ptlb(cpu_env); break; case 0x10: /* SPX D2(B2) [S] */ /* Set Prefix Register */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); @@ -2646,7 +2590,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x11: /* STPX D2(B2) [S] */ /* Store Prefix */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2657,7 +2601,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x12: /* STAP D2(B2) [S] */ /* Store CPU Address */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2671,7 +2615,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x21: /* IPTE R1,R2 [RRE] */ /* Invalidate PTE */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp = load_reg(r1); @@ -2682,7 +2626,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x29: /* ISKE R1,R2 [RRE] */ /* Insert Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp = load_reg(r2); @@ -2694,7 +2638,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x2a: /* RRBE R1,R2 [RRE] */ /* Set Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2706,7 +2650,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x2b: /* SSKE R1,R2 [RRE] */ /* Set Storage Key Extended */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2717,12 +2661,12 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x34: /* STCH ? */ /* Store Subchannel */ - check_privileged(env, s, ilc); + check_privileged(s); gen_op_movi_cc(s, 3); break; case 0x46: /* STURA R1,R2 [RRE] */ /* Store Using Real Address */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = load_reg32(r1); @@ -2734,7 +2678,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x50: /* CSP R1,R2 [RRE] */ /* Compare And Swap And Purge */ - check_privileged(env, s, ilc); + check_privileged(s); r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; tmp32_1 = tcg_const_i32(r1); @@ -2746,7 +2690,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x5f: /* CHSC ? */ /* Channel Subsystem Call */ - check_privileged(env, s, ilc); + check_privileged(s); gen_op_movi_cc(s, 3); break; case 0x78: /* STCKE D2(B2) [S] */ @@ -2760,19 +2704,19 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x79: /* SACF D2(B2) [S] */ /* Set Address Space Control Fast */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); gen_helper_sacf(cpu_env, tmp); tcg_temp_free_i64(tmp); /* addressing mode has changed, so end the block */ - s->pc += ilc * 2; + s->pc = s->next_pc; update_psw_addr(s); s->is_jmp = DISAS_JUMP; break; case 0x7d: /* STSI D2,(B2) [S] */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp32_1 = load_reg32(0); @@ -2798,7 +2742,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0xb1: /* STFL D2(B2) [S] */ /* Store Facility List (CPU features) at 200 */ - check_privileged(env, s, ilc); + check_privileged(s); tmp2 = tcg_const_i64(0xc0000000); tmp = tcg_const_i64(200); tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); @@ -2807,7 +2751,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0xb2: /* LPSWE D2(B2) [S] */ /* Load PSW Extended */ - check_privileged(env, s, ilc); + check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); tmp2 = tcg_temp_new_i64(); @@ -2824,7 +2768,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, break; case 0x20: /* SERVC R1,R2 [RRE] */ /* SCLP Service call (PV hypercall) */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); tmp32_1 = load_reg32(r2); tmp = load_reg(r1); @@ -2836,7 +2780,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, #endif default: LOG_DISAS("illegal b2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -3112,7 +3056,7 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, break; default: LOG_DISAS("illegal b3 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); break; } @@ -3419,7 +3363,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal b9 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 2); + gen_illegal_opcode(s); break; } } @@ -3525,7 +3469,7 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } } @@ -3559,7 +3503,7 @@ static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, break; default: LOG_DISAS("illegal c2 operation 0x%x\n", op); - gen_illegal_opcode(env, s, 3); + gen_illegal_opcode(s); break; } } @@ -3589,14 +3533,11 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; TCGv_i32 vl; - int ilc; int l1; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); - ilc = get_ilc(opc); - switch (opc) { #ifndef CONFIG_USER_ONLY case 0x01: /* SAM */ @@ -3649,15 +3590,13 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) update_psw_addr(s); gen_op_calc_cc(s); tmp32_1 = tcg_const_i32(i); - tmp32_2 = tcg_const_i32(ilc * 2); - tmp32_3 = tcg_const_i32(EXCP_SVC); + tmp32_2 = tcg_const_i32(s->next_pc - s->pc); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); - tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc)); - gen_helper_exception(cpu_env, tmp32_3); + tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); + gen_exception(EXCP_SVC); s->is_jmp = DISAS_EXCP; tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); break; case 0xd: /* BASR R1,R2 [RR] */ insn = ld_code2(env, s->pc); @@ -4148,7 +4087,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4164,7 +4103,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0x82: /* LPSW D2(B2) [S] */ /* Load PSW */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4184,7 +4123,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0x83: /* DIAG R1,R3,D2 [RS] */ /* Diagnose call (KVM hypercall) */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -4402,7 +4341,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xac: /* STNSM D1(B1),I2 [SI] */ case 0xad: /* STOSM D1(B1),I2 [SI] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); tmp = decode_si(s, insn, &i2, &b1, &d1); tmp2 = tcg_temp_new_i64(); @@ -4418,7 +4357,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); break; case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4432,7 +4371,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); break; case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); tmp32_1 = tcg_const_i32(r1); @@ -4476,7 +4415,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ /* Store Control */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4490,7 +4429,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ /* Load Control */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); @@ -4674,7 +4613,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ - check_privileged(env, s, ilc); + check_privileged(s); potential_page_fault(s); insn = ld_code6(env, s->pc); r1 = (insn >> 36) & 0xf; @@ -4712,7 +4651,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY case 0xe5: /* Test Protection */ - check_privileged(env, s, ilc); + check_privileged(s); insn = ld_code6(env, s->pc); debug_insn(insn); disas_e5(env, s, insn); @@ -4742,7 +4681,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); - gen_illegal_opcode(env, s, ilc); + gen_illegal_opcode(s); break; } } @@ -5273,19 +5212,22 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, DisasFields *f) { uint64_t insn, pc = s->pc; - int op, op2; + int op, op2, ilen; const DisasInsn *info; insn = ld_code2(env, pc); op = (insn >> 8) & 0xff; - switch (get_ilc(op)) { - case 1: + ilen = get_ilen(op); + s->next_pc = s->pc + ilen; + + switch (ilen) { + case 2: insn = insn << 48; break; - case 2: + case 4: insn = ld_code4(env, pc) << 32; break; - case 3: + case 6: insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); break; default: @@ -5361,9 +5303,6 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) insn = extract_insn(env, s, &f); - /* Instruction length is encoded in the opcode */ - s->next_pc = s->pc + get_ilc(f.op) * 2; - /* If not found, try the old interpreter. This includes ILLOPC. */ if (insn == NULL) { disas_s390_insn(env, s); @@ -5452,6 +5391,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, int num_insns, max_insns; CPUBreakpoint *bp; ExitStatus status; + bool do_debug; pc_start = tb->pc; @@ -5463,7 +5403,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, dc.tb = tb; dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; - dc.singlestep_enabled = env->singlestep_enabled; + do_debug = dc.singlestep_enabled = env->singlestep_enabled; dc.is_jmp = DISAS_NEXT; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -5479,14 +5419,6 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, gen_icount_start(); do { - if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { - QTAILQ_FOREACH(bp, &env->breakpoints, entry) { - if (bp->pc == dc.pc) { - gen_debug(&dc); - break; - } - } - } if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; if (lj < j) { @@ -5508,7 +5440,19 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, tcg_gen_debug_insn_start(dc.pc); } - status = translate_one(env, &dc); + status = NO_EXIT; + if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { + QTAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc.pc) { + status = EXIT_PC_STALE; + do_debug = true; + break; + } + } + } + if (status == NO_EXIT) { + status = translate_one(env, &dc); + } /* If we reach a page boundary, are single stepping, or exhaust instruction count, stop generation. */ @@ -5541,8 +5485,8 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, so make sure the cc op type is in env */ gen_op_set_cc_op(&dc); } - if (env->singlestep_enabled) { - gen_debug(&dc); + if (do_debug) { + gen_exception(EXCP_DEBUG); } else { /* Generate the return instruction */ tcg_gen_exit_tb(0); From d82287dee9d8bfe2c4cb520e30c76244fcbb705c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 16 Aug 2012 14:09:45 -0700 Subject: [PATCH 0107/1634] target-s390: Convert ADD HALFWORD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 43 +++++++------------------------------- 2 files changed, 14 insertions(+), 36 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7d81928350..2acc8f0539 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -15,6 +15,13 @@ C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64) C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) +/* ADD HALFWORD */ + C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32) + C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32) +/* ADD HALFWORD IMMEDIATE */ + C(0xa70a, AHI, RI_a, Z, r1, i2, new, r1_32, add, adds32) + C(0xa70b, AGHI, RI_a, Z, r1, i2, r1, 0, add, adds64) + /* ADD LOGICAL */ C(0x1e00, ALR, RR_a, Z, r1, r2, new, r1_32, add, addu32) C(0xb9fa, ALRK, RRF_a, DO, r2, r3, new, r1_32, add, addu32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 076bb7f5fe..0a916b1a3f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -559,11 +559,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_add64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_ADD_64, v1, v2, vr); -} - static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, TCGv_i64 vr) { @@ -2267,7 +2262,7 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1; int l1; LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); @@ -2342,36 +2337,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0xa: /* AHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_const_i32(i2); - - if (i2 < 0) { - tcg_gen_subi_i32(tmp32_2, tmp32_1, -i2); - } else { - tcg_gen_add_i32(tmp32_2, tmp32_1, tmp32_3); - } - - store_reg32(r1, tmp32_2); - set_cc_add32(s, tmp32_1, tmp32_3, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xb: /* aghi r1, i2 */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64(i2); - - if (i2 < 0) { - tcg_gen_subi_i64(regs[r1], tmp, -i2); - } else { - tcg_gen_add_i64(regs[r1], tmp, tmp2); - } - set_cc_add64(s, tmp, tmp2, regs[r1]); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0xc: /* MHI R1,I2 [RI] */ tmp32_1 = load_reg32(r1); tcg_gen_muli_i32(tmp32_1, tmp32_1, i2); @@ -5078,6 +5043,12 @@ static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); } +static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s)); +} + static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From 3f4cb56a4351b0710f90d1205f2d6178a8ebc02f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 14:46:42 -0700 Subject: [PATCH 0108/1634] target-s390: Implement SUBTRACT HALFWORD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2acc8f0539..44e1ca7997 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -46,6 +46,9 @@ C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) +/* SUBTRACT HALFWORD */ + C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) + C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) /* SUBTRACT LOGICAL */ C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32) C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32) From e272b3ace35ffafe24754986b999bda19f56f373 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 16 Aug 2012 14:42:49 -0700 Subject: [PATCH 0109/1634] target-s390: Implement ADD LOGICAL WITH SIGNED IMMEDIATE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 44e1ca7997..acde181783 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -35,6 +35,11 @@ /* ADD LOGICAL IMMEDIATE */ C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32) C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64) +/* ADD LOGICAL WITH SIGNED IMMEDIATE */ + C(0xeb6e, ALSI, SIY, GIE, m1_32u, i2, new, m1_32, add, addu32) + C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) + C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) + C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0a916b1a3f..5d5856a114 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -5005,6 +5005,13 @@ static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s)); } +static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s)); +} + static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) { in1_la1(s, f, o); From d1c04a2ba05bec8567a52f28979288e2237dfe9c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Sep 2012 15:10:35 -0700 Subject: [PATCH 0110/1634] target-s390: Convert MULTIPLY HALFWORD, SINGLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 18 ++++++ target-s390x/translate.c | 121 ++++++------------------------------- 2 files changed, 36 insertions(+), 103 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index acde181783..055113a073 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -41,6 +41,24 @@ C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* MULTIPLY HALFWORD */ + C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) + C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) +/* MULTIPLY HALFWORD IMMEDIATE */ + C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) + C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY SINGLE */ + C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) + C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xe351, MSY, RXY_a, LD, r1_o, m2_32s, new, r1_32, mul, 0) + C(0xb90c, MSGR, RRE, Z, r1_o, r2_o, r1, 0, mul, 0) + C(0xb91c, MSGFR, RRE, Z, r1_o, r2_32s, r1, 0, mul, 0) + C(0xe30c, MSG, RXY_a, Z, r1_o, m2_64, r1, 0, mul, 0) + C(0xe31c, MSGF, RXY_a, Z, r1_o, m2_32s, r1, 0, mul, 0) +/* MULTIPLY SINGLE IMMEDIATE */ + C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) + C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5d5856a114..f09b7d19aa 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -575,22 +575,12 @@ static void set_cc_nabs64(DisasContext *s, TCGv_i64 v1) gen_op_update1_cc_i64(s, CC_OP_NABS_64, v1); } -static void set_cc_add32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_ADD_32, v1, v2, vr); -} - static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) { gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr); } -static void set_cc_sub32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_SUB_32, v1, v2, vr); -} - static void set_cc_abs32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1); @@ -1371,17 +1361,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0xc: /* MSG R1,D2(X2,B2) [RXY] */ - case 0x1c: /* MSGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0xc) { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } - tcg_gen_mul_i64(regs[r1], regs[r1], tmp2); - tcg_temp_free_i64(tmp2); - break; case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); @@ -2337,18 +2316,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0xc: /* MHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tcg_gen_muli_i32(tmp32_1, tmp32_1, i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0xd: /* MGHI R1,I2 [RI] */ - tmp = load_reg(r1); - tcg_gen_muli_i64(tmp, tmp, i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0xe: /* CHI R1,I2 [RI] */ tmp32_1 = load_reg32(r1); cmp_s32c(s, tmp32_1, i2); @@ -2408,14 +2375,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x52: /* MSR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x54: /* MVPG R1,R2 [RRE] */ tmp = load_reg(0); tmp2 = load_reg(r1); @@ -3083,18 +3042,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0xc: /* MSGR R1,R2 [RRE] */ - case 0x1c: /* MSGFR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - if (op == 0x1c) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - tcg_gen_mul_i64(tmp, tmp, tmp2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0xd: /* DSGR R1,R2 [RRE] */ case 0x1d: /* DSGFR R1,R2 [RRE] */ tmp = load_reg(r1 + 1); @@ -3820,41 +3767,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x4a: /* AH R1,D2(X2,B2) [RX] */ - case 0x4b: /* SH R1,D2(X2,B2) [RX] */ - case 0x4c: /* MH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - switch (opc) { - case 0x4a: - tcg_gen_add_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_add32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x4b: - tcg_gen_sub_i32(tmp32_3, tmp32_1, tmp32_2); - set_cc_sub32(s, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x4c: - tcg_gen_mul_i32(tmp32_3, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_3); - - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4022,21 +3934,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x71: /* MS R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_gen_mul_i32(tmp32_1, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x78: /* LE R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4886,6 +4783,12 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mul(DisasContext *s, DisasOps *o) +{ + tcg_gen_mul_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); @@ -4983,6 +4886,12 @@ static void in1_r1(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = load_reg(get_field(f, r1)); } +static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = regs[get_field(f, r1)]; + o->g_in1 = true; +} + static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); @@ -5027,6 +4936,12 @@ static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = load_reg(get_field(f, r2)); } +static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = regs[get_field(f, r2)]; + o->g_in2 = true; +} + static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r3)); From d87aaf934f2fa24443bba7db60036b698e04d6a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Sep 2012 15:17:59 -0700 Subject: [PATCH 0111/1634] target-s390: Convert 32-bit MULTIPLY, MULTIPLY LOGICAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 ++++ target-s390x/translate.c | 82 ++++++++++++-------------------------- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 055113a073..ca12e475b8 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -41,12 +41,19 @@ C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* MULTIPLY */ + C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) + C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) /* MULTIPLY HALFWORD */ C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) /* MULTIPLY HALFWORD IMMEDIATE */ C(0xa70c, MHI, RI_a, Z, r1_o, i2, new, r1_32, mul, 0) C(0xa70d, MGHI, RI_a, Z, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY LOGICAL */ + C(0xb996, MLR, RRE, Z, r1p1_32u, r2_32u, new, r1_D32, mul, 0) + C(0xe396, ML, RXY_a, Z, r1p1_32u, m2_32u, new, r1_D32, mul, 0) /* MULTIPLY SINGLE */ C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f09b7d19aa..a08d47163b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1624,18 +1624,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg32_i64(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x96: /* ML R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x97: /* DL R1,D2(X2,B2) [RXY] */ /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ @@ -3219,19 +3207,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x96: /* MLR R1,R2 [RRE] */ - /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x97: /* DLR R1,R2 [RRE] */ /* reg(r1) = reg(r1, r1+1) % reg(r2) */ /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ @@ -3605,21 +3580,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x1c: /* MR R1,R2 [RR] */ - /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32s_i64(tmp2, tmp2); - tcg_gen_ext32s_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3855,23 +3815,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5c: /* M R1,D2(X2,B2) [RX] */ - /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32s_i64(tmp2, tmp2); - tcg_gen_ext32s_i64(tmp3, tmp3); - tcg_gen_mul_i64(tmp2, tmp2, tmp3); - store_reg32_i64((r1 + 1) & 15, tmp2); - tcg_gen_shri_i64(tmp2, tmp2, 32); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4868,6 +4811,15 @@ static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(get_field(f, r1), o->out); } +static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + store_reg32_i64((r1 + 1) & 15, o->out); + tcg_gen_shri_i64(o->out, o->out, 32); + store_reg32_i64(r1, o->out); +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); @@ -4892,6 +4844,22 @@ static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[(r1 + 1) & 15]); +} + +static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[(r1 + 1) & 15]); +} + static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); From 1ac5889f48127321a585886524013fcb6e2c91e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Sep 2012 15:26:59 -0700 Subject: [PATCH 0112/1634] target-s390: Convert 64-bit MULTIPLY LOGICAL Use a new "retxl" member of CPUS290XState to return the "eXtra Low" part of a 128-bit value. That said, this will get used when two independent values need returning (e.g. quotient+remainder) as well. At the same time, shuffle the elements of CPUS390XState to get this new space from existing padding in the structure. Signed-off-by: Richard Henderson --- target-s390x/cpu.h | 17 ++++++++++------- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/int_helper.c | 15 ++++----------- target-s390x/translate.c | 36 ++++++++++++++++++++++++++++-------- 5 files changed, 45 insertions(+), 27 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 83e618ab0e..afe33dc4b8 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -60,17 +60,20 @@ typedef struct ExtQueue { } ExtQueue; typedef struct CPUS390XState { - uint64_t regs[16]; /* GP registers */ - - uint32_t aregs[16]; /* access registers */ - - uint32_t fpc; /* floating-point control register */ + uint64_t regs[16]; /* GP registers */ CPU_DoubleU fregs[16]; /* FP registers */ + uint32_t aregs[16]; /* access registers */ + + uint32_t fpc; /* floating-point control register */ + uint32_t cc_op; + float_status fpu_status; /* passed to softfloat lib */ + /* The low part of a 128-bit return, or remainder of a divide. */ + uint64_t retxl; + PSW psw; - uint32_t cc_op; uint64_t cc_src; uint64_t cc_dst; uint64_t cc_vr; @@ -86,8 +89,8 @@ typedef struct CPUS390XState { uint64_t cregs[16]; /* control registers */ - int pending_int; ExtQueue ext_queue[MAX_EXT_QUEUE]; + int pending_int; int ext_index; diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 2498f83be7..88a065cad3 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -9,7 +9,7 @@ DEF_HELPER_4(clc, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) DEF_HELPER_4(stcm, void, env, i32, i32, i64) -DEF_HELPER_3(mlg, void, env, i32, i64) +DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_3(dlg, void, env, i32, i64) DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ca12e475b8..94cd2205b6 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -54,6 +54,8 @@ /* MULTIPLY LOGICAL */ C(0xb996, MLR, RRE, Z, r1p1_32u, r2_32u, new, r1_D32, mul, 0) C(0xe396, ML, RXY_a, Z, r1p1_32u, m2_32u, new, r1_D32, mul, 0) + C(0xb986, MLGR, RRE, Z, r1p1, r2_o, r1_P, 0, mul128, 0) + C(0xe386, MLG, RXY_a, Z, r1p1, m2_64, r1_P, 0, mul128, 0) /* MULTIPLY SINGLE */ C(0xb252, MSR, RRE, Z, r1_o, r2_o, new, r1_32, mul, 0) C(0x7100, MS, RX_a, Z, r1_o, m2_32s, new, r1_32, mul, 0) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index b683709860..4f18d29cd4 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -30,18 +30,11 @@ #endif /* 64/64 -> 128 unsigned multiplication */ -void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) { -#if HOST_LONG_BITS == 64 && defined(__GNUC__) - /* assuming 64-bit hosts have __uint128_t */ - __uint128_t res = (__uint128_t)env->regs[r1 + 1]; - - res *= (__uint128_t)v2; - env->regs[r1] = (uint64_t)(res >> 64); - env->regs[r1 + 1] = (uint64_t)res; -#else - mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); -#endif + uint64_t reth; + mulu64(&env->retxl, &reth, v1, v2); + return reth; } /* 128 -> 64/64 unsigned division */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a08d47163b..c38dde8323 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -293,6 +293,11 @@ static inline void store_freg32(int reg, TCGv_i32 v) #endif } +static inline void return_low128(TCGv_i64 dest) +{ + tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); +} + static inline void update_psw_addr(DisasContext *s) { /* psw.addr */ @@ -1563,14 +1568,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, set_cc_nz_u64(s, regs[r1]); tcg_temp_free_i64(tmp3); break; - case 0x86: /* MLG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_mlg(cpu_env, tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); @@ -4732,6 +4729,13 @@ static ExitStatus op_mul(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mul128(DisasContext *s, DisasOps *o) +{ + gen_helper_mul128(o->out, cpu_env, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); @@ -4800,6 +4804,15 @@ static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) o->g_out = true; } +static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->out = regs[r1]; + o->out2 = regs[(r1 + 1) & 15]; + o->g_out = o->g_out2 = true; +} + /* ====================================================================== */ /* The "Write OUTput" generators. These generally perform some non-trivial copy of data to TCG globals, or to main memory. The trivial cases are @@ -4844,6 +4857,13 @@ static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = load_reg((r1 + 1) & 15); +} + static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ From 3bbfbd1f956d82f552a0fe160abf929ec88a78ad Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 16:28:39 -0700 Subject: [PATCH 0113/1634] target-s390: Convert AND, OR, XOR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 27 ++++++++ target-s390x/translate.c | 134 ++++++++----------------------------- 2 files changed, 56 insertions(+), 105 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 94cd2205b6..7563cd894f 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -41,6 +41,24 @@ C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* AND */ + C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) + C(0xb9f4, NRK, RRF_a, DO, r2, r3, new, r1_32, and, nz32) + C(0x5400, N, RX_a, Z, r1, m2_32s, new, r1_32, and, nz32) + C(0xe354, NY, RXY_a, LD, r1, m2_32s, new, r1_32, and, nz32) + C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) + C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) + C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) + +/* EXCLUSIVE OR */ + C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) + C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) + C(0x5700, X, RX_a, Z, r1, m2_32s, new, r1_32, xor, nz32) + C(0xe357, XY, RXY_a, LD, r1, m2_32s, new, r1_32, xor, nz32) + C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) + C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) + C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) + /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) @@ -68,6 +86,15 @@ C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) +/* OR */ + C(0x1600, OR, RR_a, Z, r1, r2, new, r1_32, or, nz32) + C(0xb9f6, ORK, RRF_a, DO, r2, r3, new, r1_32, or, nz32) + C(0x5600, O, RX_a, Z, r1, m2_32s, new, r1_32, or, nz32) + C(0xe356, OY, RXY_a, LD, r1, m2_32s, new, r1_32, or, nz32) + C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) + C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) + C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c38dde8323..ba154f73d9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1487,19 +1487,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x57: /* XY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_xor_i32(tmp32_2, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_2); - set_cc_nz_u32(s, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x58: /* LY R1,D2(X2,B2) [RXY] */ tmp3 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(tmp3, addr, get_mem_index(s)); @@ -1547,27 +1534,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg32_i64(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x80: /* NG R1,D2(X2,B2) [RXY] */ - case 0x81: /* OG R1,D2(X2,B2) [RXY] */ - case 0x82: /* XG R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp3, addr, get_mem_index(s)); - switch (op) { - case 0x80: - tcg_gen_and_i64(regs[r1], regs[r1], tmp3); - break; - case 0x81: - tcg_gen_or_i64(regs[r1], regs[r1], tmp3); - break; - case 0x82: - tcg_gen_xor_i64(regs[r1], regs[r1], tmp3); - break; - default: - tcg_abort(); - } - set_cc_nz_u64(s, regs[r1]); - tcg_temp_free_i64(tmp3); - break; case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); @@ -3115,29 +3081,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x80: /* NGR R1,R2 [RRE] */ - case 0x81: /* OGR R1,R2 [RRE] */ - case 0x82: /* XGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - switch (op) { - case 0x80: - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x81: - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - case 0x82: - tcg_gen_xor_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - set_cc_nz_u64(s, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -3392,23 +3335,6 @@ static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, } } -static void gen_and_or_xor_i32(int opc, TCGv_i32 tmp, TCGv_i32 tmp2) -{ - switch (opc & 0xf) { - case 0x4: - tcg_gen_and_i32(tmp, tmp, tmp2); - break; - case 0x6: - tcg_gen_or_i32(tmp, tmp, tmp2); - break; - case 0x7: - tcg_gen_xor_i32(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; @@ -3543,19 +3469,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) set_cc_comp32(s, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x14: /* NR R1,R2 [RR] */ - case 0x16: /* OR R1,R2 [RR] */ - case 0x17: /* XR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_2 = load_reg32(r2); - tmp32_1 = load_reg32(r1); - gen_and_or_xor_i32(opc, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x18: /* LR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3768,24 +3681,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x54: /* N R1,D2(X2,B2) [RX] */ - case 0x56: /* O R1,D2(X2,B2) [RX] */ - case 0x57: /* X R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - gen_and_or_xor_i32(opc, tmp32_1, tmp32_2); - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x58: /* l r1, d2(x2, b2) */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4723,6 +4618,12 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_and(DisasContext *s, DisasOps *o) +{ + tcg_gen_and_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); @@ -4736,12 +4637,24 @@ static ExitStatus op_mul128(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_or(DisasContext *s, DisasOps *o) +{ + tcg_gen_or_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); return NO_EXIT; } +static ExitStatus op_xor(DisasContext *s, DisasOps *o) +{ + tcg_gen_xor_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + /* ====================================================================== */ /* The "Cc OUTput" generators. Given the generated output (and in some cases the original inputs), update the various cc data structures in order to @@ -4767,6 +4680,17 @@ static void cout_addu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); } +static void cout_nz32(DisasContext *s, DisasOps *o) +{ + tcg_gen_ext32u_i64(cc_dst, o->out); + gen_op_update1_cc_i64(s, CC_OP_NZ, cc_dst); +} + +static void cout_nz64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ, o->out); +} + static void cout_subs32(DisasContext *s, DisasOps *o) { gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out); From a7e836d5ebef23022ec53a0dba5d3a1ac0883a03 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 16 Aug 2012 15:20:51 -0700 Subject: [PATCH 0114/1634] target-s390: Convert COMPARE, COMPARE LOGICAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 48 +++++++ target-s390x/translate.c | 267 +++++++++++-------------------------- 2 files changed, 129 insertions(+), 186 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7563cd894f..09eb30e4aa 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -50,6 +50,54 @@ C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) +/* COMPARE */ + C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) + C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xe359, CY, RXY_a, LD, r1_o, m2_32s, 0, 0, 0, cmps32) + C(0xb920, CGR, RRE, Z, r1_o, r2_o, 0, 0, 0, cmps64) + C(0xb930, CGFR, RRE, Z, r1_o, r2_32s, 0, 0, 0, cmps64) + C(0xe320, CG, RXY_a, Z, r1_o, m2_64, 0, 0, 0, cmps64) + C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) +/* COMPARE IMMEDIATE */ + C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) + C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) +/* COMPARE HALFWORD */ + C(0x4900, CH, RX_a, Z, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe379, CHY, RXY_a, LD, r1_o, m2_16s, 0, 0, 0, cmps32) + C(0xe334, CGH, RXY_a, GIE, r1_o, m2_16s, 0, 0, 0, cmps64) +/* COMPARE HALFWORD IMMEDIATE */ + C(0xa70e, CHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps32) + C(0xa70f, CGHI, RI_a, Z, r1_o, i2, 0, 0, 0, cmps64) + C(0xe554, CHHSI, SIL, GIE, m1_16s, i2, 0, 0, 0, cmps64) + C(0xe55c, CHSI, SIL, GIE, m1_32s, i2, 0, 0, 0, cmps64) + C(0xe558, CGHSI, SIL, GIE, m1_64, i2, 0, 0, 0, cmps64) +/* COMPARE HALFWORD RELATIVE LONG */ + C(0xc605, CHRL, RIL_a, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) + C(0xc604, CGHRL, RIL_a, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) + +/* COMPARE LOGICAL */ + C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32) + C(0x5500, CL, RX_a, Z, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xe355, CLY, RXY_a, LD, r1, m2_32s, 0, 0, 0, cmpu32) + C(0xb921, CLGR, RRE, Z, r1, r2, 0, 0, 0, cmpu64) + C(0xb931, CLGFR, RRE, Z, r1, r2_32u, 0, 0, 0, cmpu64) + C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) + C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL IMMEDIATE */ + C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) + C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) + C(0x9500, CLI, SI, Z, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xeb55, CLIY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, cmpu64) + C(0xe555, CLHHSI, SIL, GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64) + C(0xe55d, CLFHSI, SIL, GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64) + C(0xe559, CLGHSI, SIL, GIE, m1_64, i2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL RELATIVE LONG */ + C(0xc60f, CLRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32) + C(0xc60a, CLGRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64) + C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) + C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) + C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) + /* EXCLUSIVE OR */ C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index ba154f73d9..09c85349da 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1434,39 +1434,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg16(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x20: /* CG R1,D2(X2,B2) [RXY] */ - case 0x21: /* CLG R1,D2(X2,B2) */ - case 0x30: /* CGF R1,D2(X2,B2) [RXY] */ - case 0x31: /* CLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - switch (op) { - case 0x20: - case 0x21: - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - break; - case 0x30: - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - break; - case 0x31: - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - break; - default: - tcg_abort(); - } - switch (op) { - case 0x20: - case 0x30: - cmp_s64(s, regs[r1], tmp2); - break; - case 0x21: - case 0x31: - cmp_u64(s, regs[r1], tmp2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - break; case 0x24: /* stg r1, d2(x2,b2) */ tcg_gen_qemu_st64(regs[r1], addr, get_mem_index(s)); break; @@ -1881,17 +1848,6 @@ do_mh: tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x55: /* CLIY D1(B1),I2 [SIY] */ - tmp3 = get_address(s, 0, b2, d2); /* SIY -> this is the 1st operand */ - tmp = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld8u(tmp, tmp3, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - cmp_u32c(s, tmp32_1, (r1 << 4) | r3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i32(tmp32_1); - break; case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); @@ -2267,16 +2223,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0xe: /* CHI R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - cmp_s32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xf: /* CGHI R1,I2 [RI] */ - tmp = load_reg(r1); - cmp_s64c(s, tmp, i2); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3047,28 +2993,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x20: /* CGR R1,R2 [RRE] */ - case 0x30: /* CGFR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - if (op == 0x30) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - tmp = load_reg(r1); - cmp_s64(s, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x21: /* CLGR R1,R2 [RRE] */ - case 0x31: /* CLGFR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - if (op == 0x31) { - tcg_gen_ext32u_i64(tmp2, tmp2); - } - tmp = load_reg(r1); - cmp_u64(s, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x26: /* LBR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tcg_gen_ext8s_i32(tmp32_1, tmp32_1); @@ -3301,40 +3225,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 } } -static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) -{ - TCGv_i64 tmp; - TCGv_i32 tmp32_1; - - switch (op) { - case 0xc: /* CGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - cmp_s64c(s, tmp, (int64_t)i2); - tcg_temp_free_i64(tmp); - break; - case 0xe: /* CLGFI R1,I2 [RIL] */ - tmp = load_reg(r1); - cmp_u64c(s, tmp, (uint64_t)(uint32_t)i2); - tcg_temp_free_i64(tmp); - break; - case 0xd: /* CFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - cmp_s32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - case 0xf: /* CLFI R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - cmp_u32c(s, tmp32_1, i2); - tcg_temp_free_i32(tmp32_1); - break; - default: - LOG_DISAS("illegal c2 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; @@ -3476,20 +3366,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x15: /* CLR R1,R2 [RR] */ - case 0x19: /* CR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - if (opc == 0x15) { - cmp_u32(s, tmp32_1, tmp32_2); - } else { - cmp_s32(s, tmp32_1, tmp32_2); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3623,20 +3499,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x49: /* CH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - cmp_s32(s, tmp32_1, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3667,20 +3529,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x55: /* CL R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r1); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - cmp_u32(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x58: /* l r1, d2(x2, b2) */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3693,20 +3541,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x59: /* C R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r1); - tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - cmp_s32(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3962,15 +3796,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x95: /* CLI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - cmp_u64c(s, tmp2, i2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -4239,21 +4064,11 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) } break; case 0xc0: - case 0xc2: insn = ld_code6(env, s->pc); r1 = (insn >> 36) & 0xf; op = (insn >> 32) & 0xf; i2 = (int)insn; - switch (opc) { - case 0xc0: - disas_c0(env, s, op, r1, i2); - break; - case 0xc2: - disas_c2(env, s, op, r1, i2); - break; - default: - tcg_abort(); - } + disas_c0(env, s, op, r1, i2); break; case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ @@ -4680,6 +4495,26 @@ static void cout_addu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); } +static void cout_cmps32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2); +} + +static void cout_cmps64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTGT_64, o->in1, o->in2); +} + +static void cout_cmpu32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_32, o->in1, o->in2); +} + +static void cout_cmpu64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2); +} + static void cout_nz32(DisasContext *s, DisasOps *o) { tcg_gen_ext32u_i64(cc_dst, o->out); @@ -4819,6 +4654,27 @@ static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); } +static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s)); +} + +static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s)); +} + +static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in1_la1(s, f, o); + o->in1 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s)); +} + static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in1_la1(s, f, o); @@ -4877,6 +4733,11 @@ static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); } +static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); +} + static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); @@ -4901,11 +4762,45 @@ static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); } +static void in2_mri2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_mri2_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_mri2_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); +} + +static void in2_mri2_64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_ri2(s, f, o); + tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); +} + static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64(get_field(f, i2)); } +static void in2_i2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint8_t)get_field(f, i2)); +} + +static void in2_i2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64((uint16_t)get_field(f, i2)); +} + static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); From 22c37a08bd0ce680d6b9750c73704a025bc3fc93 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 09:45:53 -0700 Subject: [PATCH 0115/1634] target-s390: Convert LOAD, LOAD LOGICAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 20 ++++++++ target-s390x/translate.c | 100 +++++++++++++++---------------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 09eb30e4aa..0a7cba31d5 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -107,6 +107,26 @@ C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) +/* LOAD */ + C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) + C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xe358, LY, RXY_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0) + C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) + C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) + C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) +/* LOAD IMMEDIATE */ + C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) +/* LOAD RELATIVE LONG */ + C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) + C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) + C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) +/* LOAD LOGICAL */ + C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) + C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) +/* LOAD LOGICAL RELATIVE LONG */ + C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) + /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 09c85349da..5c31ecf0ba 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1350,7 +1350,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, addr = get_address(s, x2, b2, d2); switch (op) { case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ - case 0x4: /* lg r1,d2(x2,b2) */ + case 0x4: /* LG r1,d2(x2,b2) */ tcg_gen_qemu_ld64(regs[r1], addr, get_mem_index(s)); if (op == 0x2) { set_cc_s64(s, regs[r1]); @@ -1391,16 +1391,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x14: /* LGF R1,D2(X2,B2) [RXY] */ - case 0x16: /* LLGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - if (op == 0x14) { - tcg_gen_ext32s_i64(tmp2, tmp2); - } - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); @@ -1454,12 +1444,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x58: /* LY R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp3, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp3); - break; case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ store_reg(r1, addr); break; @@ -2930,9 +2914,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, } tcg_temp_free_i64(tmp); break; - case 0x4: /* LGR R1,R2 [RRE] */ - store_reg(r1, regs[r2]); - break; case 0x6: /* LGBR R1,R2 [RRE] */ tmp2 = load_reg(r2); tcg_gen_ext8s_i64(tmp2, tmp2); @@ -2959,22 +2940,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x14: /* LGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0x16: /* LLGFR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x17: /* LLGTR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tmp = tcg_temp_new_i64(); @@ -3134,11 +3099,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 store_reg(r1, tmp); tcg_temp_free_i64(tmp); break; - case 0x1: /* LGFI R1,I2 [RIL] */ - tmp = tcg_const_i64((int64_t)i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0x4: /* BRCL M1,I2 [RIL] */ if (r1 == 15) { /* m1 == r1 */ gen_goto_tb(s, 0, target); @@ -3359,13 +3319,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) set_cc_comp32(s, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x18: /* LR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3529,18 +3482,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x58: /* l r1, d2(x2, b2) */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4439,6 +4380,33 @@ static ExitStatus op_and(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ld32s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld32u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld64(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_mov2(DisasContext *s, DisasOps *o) +{ + o->out = o->in2; + o->g_out = o->g_in2; + TCGV_UNUSED_I64(o->in2); + o->g_in2 = false; + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); @@ -4578,6 +4546,11 @@ static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) generally handled by having a "prep" generator install the TCG global as the destination of the operation. */ +static void wout_r1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg(get_field(f, r1), o->out); +} + static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); @@ -4592,6 +4565,13 @@ static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(r1, o->out); } +static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + if (get_field(f, r1) != get_field(f, r2)) { + store_reg32_i64(get_field(f, r1), o->out); + } +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); From aedec19d628dacf4f04ee7258ac2c5c9e47b5a7e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 09:57:07 -0700 Subject: [PATCH 0116/1634] target-s390: Convert LOAD ADDRESS Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 14 -------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0a7cba31d5..f0dcea617c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -121,6 +121,11 @@ C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) +/* LOAD ADDRESS */ + C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0) + C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) +/* LOAD ADDRESS RELATIVE LONG */ + C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0) /* LOAD LOGICAL */ C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5c31ecf0ba..0cf090262f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1444,9 +1444,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x71: /* LAY R1,D2(X2,B2) [RXY] */ - store_reg(r1, addr); - break; case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ tmp32_1 = load_reg32(r1); tmp2 = tcg_temp_new_i64(); @@ -3094,11 +3091,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); switch (op) { - case 0: /* larl r1, i2 */ - tmp = tcg_const_i64(target); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0x4: /* BRCL M1,I2 [RIL] */ if (r1 == 15) { /* m1 == r1 */ gen_goto_tb(s, 0, target); @@ -3376,12 +3368,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x41: /* la */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ - tcg_temp_free_i64(tmp); - break; case 0x42: /* STC R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); From c698d8768756c66dd0dd55ea884c69c2212d59f9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 10:27:29 -0700 Subject: [PATCH 0117/1634] target-s390: Convert LOAD (LOGICAL) BYTE, CHARACTER, HALFWORD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 30 +++++++ target-s390x/translate.c | 157 ++++++++++++------------------------- 2 files changed, 78 insertions(+), 109 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f0dcea617c..796185f002 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -126,11 +126,41 @@ C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) /* LOAD ADDRESS RELATIVE LONG */ C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0) +/* LOAD BYTE */ + C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) + C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) + C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) + C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) +/* LOAD HALFWORD */ + C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) + C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) + C(0x4800, LH, RX_a, Z, 0, a2, new, r1_32, ld16s, 0) + C(0xe378, LHY, RXY_a, LD, 0, a2, new, r1_32, ld16s, 0) + C(0xe315, LGH, RXY_a, Z, 0, a2, r1, 0, ld16s, 0) +/* LOAD HALFWORD IMMEDIATE */ + C(0xa708, LHI, RI_a, Z, 0, i2, 0, r1_32, mov2, 0) + C(0xa709, LGHI, RI_a, Z, 0, i2, 0, r1, mov2, 0) +/* LOAD HALFWORD RELATIVE LONG */ + C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) + C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) /* LOAD LOGICAL */ C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) /* LOAD LOGICAL RELATIVE LONG */ C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) +/* LOAD LOGICAL CHARACTER */ + C(0xb994, LLCR, RRE, EI, 0, r2_8u, 0, r1_32, mov2, 0) + C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0) + C(0xe394, LLC, RXY_a, EI, 0, a2, new, r1_32, ld8u, 0) + C(0xe390, LLGC, RXY_a, Z, 0, a2, r1, 0, ld8u, 0) +/* LOAD LOGICAL HALFWORD */ + C(0xb995, LLHR, RRE, EI, 0, r2_16u, 0, r1_32, mov2, 0) + C(0xb985, LLGHR, RRE, EI, 0, r2_16u, 0, r1, mov2, 0) + C(0xe395, LLH, RXY_a, EI, 0, a2, new, r1_32, ld16u, 0) + C(0xe391, LLGH, RXY_a, Z, 0, a2, r1, 0, ld16u, 0) +/* LOAD LOGICAL HALFWORD RELATIVE LONG */ + C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) + C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0cf090262f..840bd6e3a0 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1391,12 +1391,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x15: /* LGH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); @@ -1458,30 +1452,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg8(r1, tmp3); tcg_temp_free_i64(tmp3); break; - case 0x76: /* LB R1,D2(X2,B2) [RXY] */ - case 0x77: /* LGB R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8s(tmp2, addr, get_mem_index(s)); - switch (op) { - case 0x76: - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg32_i64(r1, tmp2); - break; - case 0x77: - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg(r1, tmp2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i64(tmp2); - break; - case 0x78: /* LHY R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); @@ -1517,24 +1487,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x90: /* LLGC R1,D2(X2,B2) [RXY] */ - tcg_gen_qemu_ld8u(regs[r1], addr, get_mem_index(s)); - break; - case 0x91: /* LLGH R1,D2(X2,B2) [RXY] */ - tcg_gen_qemu_ld16u(regs[r1], addr, get_mem_index(s)); - break; - case 0x94: /* LLC R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - case 0x95: /* LLH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x97: /* DL R1,D2(X2,B2) [RXY] */ /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ @@ -2194,16 +2146,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, s->is_jmp = DISAS_TB_JUMP; tcg_temp_free_i64(tmp); break; - case 0x8: /* lhi r1, i2 */ - tmp32_1 = tcg_const_i32(i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x9: /* lghi r1, i2 */ - tmp = tcg_const_i64(i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2911,12 +2853,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, } tcg_temp_free_i64(tmp); break; - case 0x6: /* LGBR R1,R2 [RRE] */ - tmp2 = load_reg(r2); - tcg_gen_ext8s_i64(tmp2, tmp2); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0xd: /* DSGR R1,R2 [RRE] */ case 0x1d: /* DSGFR R1,R2 [RRE] */ tmp = load_reg(r1 + 1); @@ -2955,18 +2891,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x26: /* LBR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_ext8s_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x27: /* LHR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_ext16s_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -2975,18 +2899,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0x84: /* LLGCR R1,R2 [RRE] */ - tmp = load_reg(r2); - tcg_gen_andi_i64(tmp, tmp, 0xff); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x85: /* LLGHR R1,R2 [RRE] */ - tmp = load_reg(r2); - tcg_gen_andi_i64(tmp, tmp, 0xffff); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; case 0x87: /* DLGR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp = load_reg(r2); @@ -3021,18 +2933,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x94: /* LLCR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xff); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x95: /* LLHR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0xffff); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x97: /* DLR R1,R2 [RRE] */ /* reg(r1) = reg(r1, r1+1) % reg(r2) */ /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ @@ -3429,15 +3329,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); s->is_jmp = DISAS_TB_JUMP; break; - case 0x48: /* LH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); - store_reg32_i64(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4366,6 +4257,30 @@ static ExitStatus op_and(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ld8s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld8u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld8u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld16s(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld16s(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_ld16u(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_ld16u(o->out, o->in2, get_mem_index(s)); + return NO_EXIT; +} + static ExitStatus op_ld32s(DisasContext *s, DisasOps *o) { tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s)); @@ -4676,6 +4591,30 @@ static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in2 = true; } +static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext8s_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext8u_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_16s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16s_i64(o->in2, regs[get_field(f, r2)]); +} + +static void in2_r2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r2)]); +} + static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r3)); From 11bf2d73d0dba509e14dbfc2189365410a5a2c06 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 11:03:39 -0700 Subject: [PATCH 0118/1634] target-s390: Convert LOAD AND TEST Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 37 ++++++++++--------------------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 796185f002..7a8dcbd0f1 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -126,6 +126,13 @@ C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) /* LOAD ADDRESS RELATIVE LONG */ C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0) +/* LOAD AND TEST */ + C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32) + C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64) + C(0xb912, LTGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, s64) + C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) + C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) + C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) /* LOAD BYTE */ C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 840bd6e3a0..9239025169 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1349,23 +1349,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, op, r1, x2, b2, d2); addr = get_address(s, x2, b2, d2); switch (op) { - case 0x2: /* LTG R1,D2(X2,B2) [RXY] */ - case 0x4: /* LG r1,d2(x2,b2) */ - tcg_gen_qemu_ld64(regs[r1], addr, get_mem_index(s)); - if (op == 0x2) { - set_cc_s64(s, regs[r1]); - } - break; - case 0x12: /* LT R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_reg32(r1, tmp32_1); - set_cc_s32(s, tmp32_1); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); @@ -3192,16 +3175,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) store_reg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x12: /* LTR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - if (r1 != r2) { - store_reg32(r1, tmp32_1); - } - set_cc_s32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x13: /* LCR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -4395,6 +4368,16 @@ static void cout_nz64(DisasContext *s, DisasOps *o) gen_op_update1_cc_i64(s, CC_OP_NZ, o->out); } +static void cout_s32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_LTGT0_32, o->out); +} + +static void cout_s64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, o->out); +} + static void cout_subs32(DisasContext *s, DisasOps *o) { gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out); From ade9dea429e202eabf87a36a20d1d3bbc34d8910 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 11:20:33 -0700 Subject: [PATCH 0119/1634] target-s390: Convert LOAD LOGICAL IMMEDIATE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 42 +++++++++++--------------------------- 2 files changed, 19 insertions(+), 30 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7a8dcbd0f1..89bc635257 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -168,6 +168,13 @@ /* LOAD LOGICAL HALFWORD RELATIVE LONG */ C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) +/* LOAD LOGICAL IMMEDATE */ + D(0xc00e, LLIHF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32) + D(0xc00f, LLILF, RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0) + D(0xa50c, LLIHH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 48) + D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) + D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) + D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9239025169..0143758570 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2033,26 +2033,6 @@ static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32); tcg_temp_free_i64(tmp); break; - case 0xc: /* LLIHH R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 48 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xd: /* LLIHL R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 32 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xe: /* LLILH R1,I2 [RI] */ - tmp = tcg_const_i64( ((uint64_t)i2) << 16 ); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xf: /* LLILL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a5 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3043,16 +3023,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0xe: /* LLIHF R1,I2 [RIL] */ - tmp = tcg_const_i64(((uint64_t)(uint32_t)i2) << 32); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0xf: /* LLILF R1,I2 [RIL] */ - tmp = tcg_const_i64((uint32_t)i2); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -4694,6 +4664,18 @@ static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); } +static void in2_i2_16u_shl(DisasContext *s, DisasFields *f, DisasOps *o) +{ + uint64_t i2 = (uint16_t)get_field(f, i2); + o->in2 = tcg_const_i64(i2 << s->insn->data); +} + +static void in2_i2_32u_shl(DisasContext *s, DisasFields *f, DisasOps *o) +{ + uint64_t i2 = (uint32_t)get_field(f, i2); + o->in2 = tcg_const_i64(i2 << s->insn->data); +} + /* ====================================================================== */ /* Find opc within the table of insns. This is formulated as a switch From b9bca3e57a4570ce2aff46388fa1edc9da5437a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 11:38:37 -0700 Subject: [PATCH 0120/1634] target-s390: Convert LOAD COMPLIMENT, POSITIVE, NEGATIVE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 12 ++++ target-s390x/translate.c | 142 +++++++++++++------------------------ 2 files changed, 60 insertions(+), 94 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 89bc635257..9507262131 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -138,6 +138,10 @@ C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) +/* LOAD COMPLEMENT */ + C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) + C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) + C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) /* LOAD HALFWORD */ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) @@ -175,6 +179,14 @@ D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) +/* LOAD NEGATIVE */ + C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) + C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) + C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) +/* LOAD POSITIVE */ + C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) + C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) + C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0143758570..2da94f56cd 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -570,42 +570,12 @@ static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr); } -static void set_cc_abs64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_ABS_64, v1); -} - -static void set_cc_nabs64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_NABS_64, v1); -} - static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, TCGv_i32 vr) { gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr); } -static void set_cc_abs32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_ABS_32, v1); -} - -static void set_cc_nabs32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_NABS_32, v1); -} - -static void set_cc_comp32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_COMP_32, v1); -} - -static void set_cc_comp64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_COMP_64, v1); -} - static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) { gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); @@ -2779,43 +2749,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x0: /* LPGR R1,R2 [RRE] */ - case 0x1: /* LNGR R1,R2 [RRE] */ - case 0x2: /* LTGR R1,R2 [RRE] */ - case 0x3: /* LCGR R1,R2 [RRE] */ - case 0x10: /* LPGFR R1,R2 [RRE] */ - case 0x11: /* LNFGR R1,R2 [RRE] */ - case 0x12: /* LTGFR R1,R2 [RRE] */ - case 0x13: /* LCGFR R1,R2 [RRE] */ - if (op & 0x10) { - tmp = load_reg32_i64(r2); - } else { - tmp = load_reg(r2); - } - switch (op & 0xf) { - case 0x0: /* LP?GR */ - set_cc_abs64(s, tmp); - gen_helper_abs_i64(tmp, tmp); - store_reg(r1, tmp); - break; - case 0x1: /* LN?GR */ - set_cc_nabs64(s, tmp); - gen_helper_nabs_i64(tmp, tmp); - store_reg(r1, tmp); - break; - case 0x2: /* LT?GR */ - if (r1 != r2) { - store_reg(r1, tmp); - } - set_cc_s64(s, tmp); - break; - case 0x3: /* LC?GR */ - tcg_gen_neg_i64(regs[r1], tmp); - set_cc_comp64(s, regs[r1]); - break; - } - tcg_temp_free_i64(tmp); - break; case 0xd: /* DSGR R1,R2 [RRE] */ case 0x1d: /* DSGFR R1,R2 [RRE] */ tmp = load_reg(r1 + 1); @@ -3127,33 +3060,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x10: /* LPR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - set_cc_abs32(s, tmp32_1); - gen_helper_abs_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x11: /* LNR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - set_cc_nabs32(s, tmp32_1); - gen_helper_nabs_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x13: /* LCR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r2); - tcg_gen_neg_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - set_cc_comp32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x1d: /* DR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -4188,6 +4094,12 @@ struct DisasInsn { /* The operations. These perform the bulk of the work for any insn, usually after the operands have been loaded and output initialized. */ +static ExitStatus op_abs(DisasContext *s, DisasOps *o) +{ + gen_helper_abs_i64(o->out, o->in2); + return NO_EXIT; +} + static ExitStatus op_add(DisasContext *s, DisasOps *o) { tcg_gen_add_i64(o->out, o->in1, o->in2); @@ -4264,6 +4176,18 @@ static ExitStatus op_mul128(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_nabs(DisasContext *s, DisasOps *o) +{ + gen_helper_nabs_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_neg(DisasContext *s, DisasOps *o) +{ + tcg_gen_neg_i64(o->out, o->in2); + return NO_EXIT; +} + static ExitStatus op_or(DisasContext *s, DisasOps *o) { tcg_gen_or_i64(o->out, o->in1, o->in2); @@ -4287,6 +4211,16 @@ static ExitStatus op_xor(DisasContext *s, DisasOps *o) the original inputs), update the various cc data structures in order to be able to compute the new condition code. */ +static void cout_abs32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_ABS_32, o->out); +} + +static void cout_abs64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_ABS_64, o->out); +} + static void cout_adds32(DisasContext *s, DisasOps *o) { gen_op_update3_cc_i64(s, CC_OP_ADD_32, o->in1, o->in2, o->out); @@ -4327,6 +4261,26 @@ static void cout_cmpu64(DisasContext *s, DisasOps *o) gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2); } +static void cout_nabs32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NABS_32, o->out); +} + +static void cout_nabs64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NABS_64, o->out); +} + +static void cout_neg32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_COMP_32, o->out); +} + +static void cout_neg64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_COMP_64, o->out); +} + static void cout_nz32(DisasContext *s, DisasOps *o) { tcg_gen_ext32u_i64(cc_dst, o->out); From facfc8648728b5c5554b3269355a4c13824e664b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 15:01:36 -0700 Subject: [PATCH 0121/1634] target-s390: Convert AND, OR, XOR, INSERT IMMEDIATE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 25 ++++ target-s390x/translate.c | 237 +++++++++---------------------------- 2 files changed, 82 insertions(+), 180 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 9507262131..705b655a81 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -49,6 +49,13 @@ C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) +/* AND IMMEDIATE */ + D(0xc00a, NIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2020) + D(0xc00b, NILF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2000) + D(0xa504, NIHH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1030) + D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) + D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) + D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) @@ -106,6 +113,17 @@ C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) +/* EXCLUSIVE OR IMMEDIATE */ + D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) + D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) + +/* INSERT IMMEDIATE */ + D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) + D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) + D(0xa500, IIHH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1030) + D(0xa501, IIHL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1020) + D(0xa502, IILH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1010) + D(0xa503, IILL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1000) /* LOAD */ C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) @@ -223,6 +241,13 @@ C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) +/* OR IMMEDIATE */ + D(0xc00c, OIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2020) + D(0xc00d, OILF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2000) + D(0xa508, OIHH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1030) + D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) + D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) + D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2da94f56cd..06db4c5f19 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1875,141 +1875,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(addr); } -static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) -{ - TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32; - LOG_DISAS("disas_a5: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); - switch (op) { - case 0x0: /* IIHH R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 48, 16); - tcg_temp_free_i64(tmp); - break; - case 0x1: /* IIHL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 32, 16); - tcg_temp_free_i64(tmp); - break; - case 0x2: /* IILH R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 16, 16); - tcg_temp_free_i64(tmp); - break; - case 0x3: /* IILL R1,I2 [RI] */ - tmp = tcg_const_i64(i2); - tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 0, 16); - tcg_temp_free_i64(tmp); - break; - case 0x4: /* NIHH R1,I2 [RI] */ - case 0x8: /* OIHH R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x4: - tmp2 = tcg_const_i64((((uint64_t)i2) << 48) - | 0x0000ffffffffffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x8: - tmp2 = tcg_const_i64(((uint64_t)i2) << 48); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp2, tmp, 48); - tcg_gen_trunc_i64_i32(tmp32, tmp2); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x5: /* NIHL R1,I2 [RI] */ - case 0x9: /* OIHL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x5: - tmp2 = tcg_const_i64((((uint64_t)i2) << 32) - | 0xffff0000ffffffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0x9: - tmp2 = tcg_const_i64(((uint64_t)i2) << 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp2, tmp, 32); - tcg_gen_trunc_i64_i32(tmp32, tmp2); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x6: /* NILH R1,I2 [RI] */ - case 0xa: /* OILH R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x6: - tmp2 = tcg_const_i64((((uint64_t)i2) << 16) - | 0xffffffff0000ffffULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0xa: - tmp2 = tcg_const_i64(((uint64_t)i2) << 16); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp, tmp, 16); - tcg_gen_trunc_i64_i32(tmp32, tmp); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - case 0x7: /* NILL R1,I2 [RI] */ - case 0xb: /* OILL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp32 = tcg_temp_new_i32(); - switch (op) { - case 0x7: - tmp2 = tcg_const_i64(i2 | 0xffffffffffff0000ULL); - tcg_gen_and_i64(tmp, tmp, tmp2); - break; - case 0xb: - tmp2 = tcg_const_i64(i2); - tcg_gen_or_i64(tmp, tmp, tmp2); - break; - default: - tcg_abort(); - } - store_reg(r1, tmp); - tcg_gen_trunc_i64_i32(tmp32, tmp); - tcg_gen_andi_i32(tmp32, tmp32, 0xffff); - set_cc_nz_u32(s, tmp32); /* signedness should not matter here */ - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32); - tcg_temp_free_i64(tmp); - break; - default: - LOG_DISAS("illegal a5 operation 0x%x\n", op); - gen_illegal_opcode(s); - return; - } -} - static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { @@ -2918,44 +2783,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 gen_goto_tb(s, 0, target); s->is_jmp = DISAS_TB_JUMP; break; - case 0x7: /* XILF R1,I2 [RIL] */ - case 0xb: /* NILF R1,I2 [RIL] */ - case 0xd: /* OILF R1,I2 [RIL] */ - tmp32_1 = load_reg32(r1); - switch (op) { - case 0x7: - tcg_gen_xori_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - case 0xb: - tcg_gen_andi_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - case 0xd: - tcg_gen_ori_i32(tmp32_1, tmp32_1, (uint32_t)i2); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_1); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x9: /* IILF R1,I2 [RIL] */ - tmp32_1 = tcg_const_i32((uint32_t)i2); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0xa: /* NIHF R1,I2 [RIL] */ - tmp = load_reg(r1); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_andi_i64(tmp, tmp, (((uint64_t)((uint32_t)i2)) << 32) - | 0xffffffffULL); - store_reg(r1, tmp); - tcg_gen_shri_i64(tmp, tmp, 32); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - set_cc_nz_u32(s, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3487,13 +3314,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xa5: - insn = ld_code4(env, s->pc); - r1 = (insn >> 20) & 0xf; - op = (insn >> 16) & 0xf; - i2 = insn & 0xffff; - disas_a5(env, s, op, r1, i2); - break; case 0xa7: insn = ld_code4(env, s->pc); r1 = (insn >> 20) & 0xf; @@ -4112,6 +3932,31 @@ static ExitStatus op_and(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_andi(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_ori_i64(o->in2, o->in2, ~mask); + tcg_gen_and_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + +static ExitStatus op_insi(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + tcg_gen_deposit_i64(o->out, o->in1, o->in2, shift, size); + return NO_EXIT; +} + static ExitStatus op_ld8s(DisasContext *s, DisasOps *o) { tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s)); @@ -4194,6 +4039,22 @@ static ExitStatus op_or(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ori(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_or_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); @@ -4206,6 +4067,22 @@ static ExitStatus op_xor(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_xori(DisasContext *s, DisasOps *o) +{ + int shift = s->insn->data & 0xff; + int size = s->insn->data >> 8; + uint64_t mask = ((1ull << size) - 1) << shift; + + assert(!o->g_in2); + tcg_gen_shli_i64(o->in2, o->in2, shift); + tcg_gen_xor_i64(o->out, o->in1, o->in2); + + /* Produce the CC from only the bits manipulated. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + /* ====================================================================== */ /* The "Cc OUTput" generators. Given the generated output (and in some cases the original inputs), update the various cc data structures in order to From 2b280b97085ae90e804c1b31557a79d1da2789a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 16:00:08 -0700 Subject: [PATCH 0122/1634] target-s390: Convert STORE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 16 +++++++++ target-s390x/translate.c | 67 ++++++++++++++------------------------ 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 705b655a81..f441a66958 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -249,6 +249,22 @@ D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) +/* STORE */ + C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) + C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) + C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) +/* STORE RELATIVE LONG */ + C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) + C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) +/* STORE CHARACTER */ + C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) + C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) +/* STORE HALFWORD */ + C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) + C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) +/* STORE HALFWORD RELATIVE LONG */ + C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 06db4c5f19..f17fa2f74e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1371,9 +1371,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg16(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x24: /* stg r1, d2(x2,b2) */ - tcg_gen_qemu_st64(regs[r1], addr, get_mem_index(s)); - break; case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ tmp32_1 = load_reg32(r1); tmp2 = tcg_temp_new_i64(); @@ -1383,22 +1380,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x50: /* STY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; - case 0x72: /* STCY R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st8(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp2); - break; case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ tmp3 = tcg_temp_new_i64(); tcg_gen_qemu_ld8u(tmp3, addr, get_mem_index(s)); @@ -2936,22 +2917,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) store_freg32(r1, tmp32_1); tcg_temp_free_i32(tmp32_1); break; - case 0x40: /* STH R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st16(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x42: /* STC R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x43: /* IC R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3027,14 +2992,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x50: /* st r1, d2(x2, b2) */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x5d: /* D R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -4055,6 +4012,30 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_st8(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st8(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st16(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st16(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st32(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st32(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + +static ExitStatus op_st64(DisasContext *s, DisasOps *o) +{ + tcg_gen_qemu_st64(o->in1, o->in2, get_mem_index(s)); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); From 4e4bb43899c4c97e14b59fbd7cd5cb44eea850a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Aug 2012 18:52:33 -0700 Subject: [PATCH 0123/1634] target-s390: Convert ADD LOGICAL CARRY and SUBTRACT LOGICAL BORROW I'm resonably certain that the carry/borrow-out condition for both helpers was incorrect, failing to take into account the carry-in. Adding the new CC_OP codes also allows removing the awkward interface we used for the slb helpers. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 108 +++++++++++++++------ target-s390x/cpu.h | 8 ++ target-s390x/helper.h | 3 - target-s390x/insn-data.def | 10 ++ target-s390x/int_helper.c | 43 --------- target-s390x/translate.c | 191 ++++++++++++------------------------- 6 files changed, 157 insertions(+), 206 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 19ef145da9..880e3b234d 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -146,22 +146,21 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, } } -static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) { - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } + return (ar != 0) + 2 * (ar < a1); +} + +static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + /* Recover a2 + carry_in. */ + uint64_t a2c = ar - a1; + /* Check for a2+carry_in overflow, then a1+a2c overflow. */ + int carry_out = (a2c < a2) || (ar < a1); + + return (ar != 0) + 2 * carry_out; } static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, @@ -194,6 +193,25 @@ static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, } } +static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + /* We had borrow-in if normal subtraction isn't equal. */ + int borrow_in = ar - (a1 - a2); + int borrow_out; + + /* If a2 was ULONG_MAX, and borrow_in, then a2 is logically 65 bits, + and we must have had borrow out. */ + if (borrow_in && a2 == (uint64_t)-1) { + borrow_out = 1; + } else { + a2 += borrow_in; + borrow_out = (a2 > a1); + } + + return (ar != 0) + 2 * !borrow_out; +} + static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { @@ -240,22 +258,21 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, } } -static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) { - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } + return (ar != 0) + 2 * (ar < a1); +} + +static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + /* Recover a2 + carry_in. */ + uint32_t a2c = ar - a1; + /* Check for a2+carry_in overflow, then a1+a2c overflow. */ + int carry_out = (a2c < a2) || (ar < a1); + + return (ar != 0) + 2 * carry_out; } static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, @@ -288,6 +305,25 @@ static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, } } +static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + /* We had borrow-in if normal subtraction isn't equal. */ + int borrow_in = ar - (a1 - a2); + int borrow_out; + + /* If a2 was UINT_MAX, and borrow_in, then a2 is logically 65 bits, + and we must have had borrow out. */ + if (borrow_in && a2 == (uint32_t)-1) { + borrow_out = 1; + } else { + a2 += borrow_in; + borrow_out = (a2 > a1); + } + + return (ar != 0) + 2 * !borrow_out; +} + static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { @@ -426,12 +462,18 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ADDU_64: r = cc_calc_addu_64(env, src, dst, vr); break; + case CC_OP_ADDC_64: + r = cc_calc_addc_64(env, src, dst, vr); + break; case CC_OP_SUB_64: r = cc_calc_sub_64(env, src, dst, vr); break; case CC_OP_SUBU_64: r = cc_calc_subu_64(env, src, dst, vr); break; + case CC_OP_SUBB_64: + r = cc_calc_subb_64(env, src, dst, vr); + break; case CC_OP_ABS_64: r = cc_calc_abs_64(env, dst); break; @@ -448,12 +490,18 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ADDU_32: r = cc_calc_addu_32(env, src, dst, vr); break; + case CC_OP_ADDC_32: + r = cc_calc_addc_32(env, src, dst, vr); + break; case CC_OP_SUB_32: r = cc_calc_sub_32(env, src, dst, vr); break; case CC_OP_SUBU_32: r = cc_calc_subu_32(env, src, dst, vr); break; + case CC_OP_SUBB_32: + r = cc_calc_subb_32(env, src, dst, vr); + break; case CC_OP_ABS_32: r = cc_calc_abs_64(env, dst); break; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index afe33dc4b8..ea1bc8625e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -449,15 +449,19 @@ enum cc_op { CC_OP_ADD_64, /* overflow on add (64bit) */ CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ + CC_OP_ADDC_64, /* overflow on unsigned add-carry (64bit) */ CC_OP_SUB_64, /* overflow on subtraction (64bit) */ CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */ + CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */ CC_OP_ABS_64, /* sign eval on abs (64bit) */ CC_OP_NABS_64, /* sign eval on nabs (64bit) */ CC_OP_ADD_32, /* overflow on add (32bit) */ CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ + CC_OP_ADDC_32, /* overflow on unsigned add-carry (32bit) */ CC_OP_SUB_32, /* overflow on subtraction (32bit) */ CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */ + CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */ CC_OP_ABS_32, /* sign eval on abs (64bit) */ CC_OP_NABS_32, /* sign eval on nabs (64bit) */ @@ -494,14 +498,18 @@ static const char *cc_names[] = { [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", [CC_OP_ADD_64] = "CC_OP_ADD_64", [CC_OP_ADDU_64] = "CC_OP_ADDU_64", + [CC_OP_ADDC_64] = "CC_OP_ADDC_64", [CC_OP_SUB_64] = "CC_OP_SUB_64", [CC_OP_SUBU_64] = "CC_OP_SUBU_64", + [CC_OP_SUBB_64] = "CC_OP_SUBB_64", [CC_OP_ABS_64] = "CC_OP_ABS_64", [CC_OP_NABS_64] = "CC_OP_NABS_64", [CC_OP_ADD_32] = "CC_OP_ADD_32", [CC_OP_ADDU_32] = "CC_OP_ADDU_32", + [CC_OP_ADDC_32] = "CC_OP_ADDC_32", [CC_OP_SUB_32] = "CC_OP_SUB_32", [CC_OP_SUBU_32] = "CC_OP_SUBU_32", + [CC_OP_SUBB_32] = "CC_OP_SUBB_32", [CC_OP_ABS_32] = "CC_OP_ABS_32", [CC_OP_NABS_32] = "CC_OP_NABS_32", [CC_OP_COMP_32] = "CC_OP_COMP_32", diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 88a065cad3..a45b1c362b 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -26,13 +26,10 @@ DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) -DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) -DEF_HELPER_4(slb, i32, env, i32, i32, i32) -DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) DEF_HELPER_3(cefbr, void, env, i32, s32) DEF_HELPER_3(cdfbr, void, env, i32, s32) DEF_HELPER_3(cxfbr, void, env, i32, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f441a66958..373aa40fd3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -40,6 +40,11 @@ C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* ADD LOGICAL WITH CARRY */ + C(0xb998, ALCR, RRE, Z, r1, r2, new, r1_32, addc, addc32) + C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc, addc64) + C(0xe398, ALC, RXY_a, Z, r1, m2_32u, new, r1_32, addc, addc32) + C(0xe388, ALCG, RXY_a, Z, r1, m2_64, r1, 0, addc, addc64) /* AND */ C(0x1400, NR, RR_a, Z, r1, r2, new, r1_32, and, nz32) @@ -291,3 +296,8 @@ /* SUBTRACT LOGICAL IMMEDIATE */ C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32) C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64) +/* SUBTRACT LOGICAL WITH BORROW */ + C(0xb999, SLBR, RRE, Z, r1, r2, new, r1_32, subb, subb32) + C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb, subb64) + C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32) + C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 4f18d29cd4..17c4771e41 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -107,49 +107,6 @@ int64_t HELPER(nabs_i64)(int64_t val) } } -/* add with carry 32-bit unsigned */ -uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) -{ - uint32_t res; - - res = v1 + v2; - if (cc & 2) { - res++; - } - - return res; -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2) -{ - uint32_t v1 = env->regs[r1]; - uint32_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1, - uint64_t v1, uint64_t v2) -{ - uint64_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - /* find leftmost one */ uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f17fa2f74e..6f3a5df678 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -474,15 +474,6 @@ static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, s->cc_op = op; } -static void gen_op_update3_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src, - TCGv_i32 dst, TCGv_i32 vr) -{ - tcg_gen_extu_i32_i64(cc_src, src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_extu_i32_i64(cc_vr, vr); - s->cc_op = op; -} - static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val) { gen_op_update1_cc_i32(s, CC_OP_NZ, val); @@ -564,18 +555,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_addu64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - TCGv_i64 vr) -{ - gen_op_update3_cc_i64(s, CC_OP_ADDU_64, v1, v2, vr); -} - -static void set_cc_addu32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - TCGv_i32 vr) -{ - gen_op_update3_cc_i32(s, CC_OP_ADDU_32, v1, v2, vr); -} - static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) { gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); @@ -661,12 +640,16 @@ static void gen_op_calc_cc(DisasContext *s) break; case CC_OP_ADD_64: case CC_OP_ADDU_64: + case CC_OP_ADDC_64: case CC_OP_SUB_64: case CC_OP_SUBU_64: + case CC_OP_SUBB_64: case CC_OP_ADD_32: case CC_OP_ADDU_32: + case CC_OP_ADDC_32: case CC_OP_SUB_32: case CC_OP_SUBU_32: + case CC_OP_SUBB_32: /* 3 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); break; @@ -1313,7 +1296,7 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { TCGv_i64 addr, tmp, tmp2, tmp3, tmp4; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); @@ -1394,33 +1377,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x88: /* ALCG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - tcg_gen_extu_i32_i64(tmp3, cc_op); - tcg_gen_shri_i64(tmp3, tmp3, 1); - tcg_gen_andi_i64(tmp3, tmp3, 1); - tcg_gen_add_i64(tmp3, tmp2, tmp3); - tcg_gen_add_i64(tmp3, regs[r1], tmp3); - store_reg(r1, tmp3); - set_cc_addu64(s, regs[r1], tmp2, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x89: /* SLBG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x97: /* DL R1,D2(X2,B2) [RXY] */ /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ @@ -1441,37 +1397,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x98: /* ALC R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - store_reg32(r1, tmp32_3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x99: /* SLB R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2591,7 +2516,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, int r2) { TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1; LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { @@ -2648,33 +2573,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0x88: /* ALCGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = tcg_temp_new_i64(); - gen_op_calc_cc(s); - tcg_gen_extu_i32_i64(tmp3, cc_op); - tcg_gen_shri_i64(tmp3, tmp3, 1); - tcg_gen_andi_i64(tmp3, tmp3, 1); - tcg_gen_add_i64(tmp3, tmp2, tmp3); - tcg_gen_add_i64(tmp3, tmp, tmp3); - store_reg(r1, tmp3); - set_cc_addu64(s, tmp, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x89: /* SLBGR R1,R2 [RRE] */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp32_1 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x97: /* DLR R1,R2 [RRE] */ /* reg(r1) = reg(r1, r1+1) % reg(r2) */ /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ @@ -2694,28 +2592,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x98: /* ALCR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r2); - tmp32_3 = tcg_temp_new_i32(); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - gen_helper_addc_u32(tmp32_3, cc_op, tmp32_1, tmp32_2); - set_cc_addu32(s, tmp32_1, tmp32_2, tmp32_3); - store_reg32(r1, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0x99: /* SLBR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp32_2 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal b9 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3883,6 +3759,23 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_addc(DisasContext *s, DisasOps *o) +{ + TCGv_i64 cc; + + tcg_gen_add_i64(o->out, o->in1, o->in2); + + /* XXX possible optimization point */ + gen_op_calc_cc(s); + cc = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(cc, cc_op); + tcg_gen_shri_i64(cc, cc, 1); + + tcg_gen_add_i64(o->out, o->out, cc); + tcg_temp_free_i64(cc); + return NO_EXIT; +} + static ExitStatus op_and(DisasContext *s, DisasOps *o) { tcg_gen_and_i64(o->out, o->in1, o->in2); @@ -4042,6 +3935,24 @@ static ExitStatus op_sub(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_subb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 cc; + + assert(!o->g_in2); + tcg_gen_not_i64(o->in2, o->in2); + tcg_gen_add_i64(o->out, o->in1, o->in2); + + /* XXX possible optimization point */ + gen_op_calc_cc(s); + cc = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(cc, cc_op); + tcg_gen_shri_i64(cc, cc, 1); + tcg_gen_add_i64(o->out, o->out, cc); + tcg_temp_free_i64(cc); + return NO_EXIT; +} + static ExitStatus op_xor(DisasContext *s, DisasOps *o) { tcg_gen_xor_i64(o->out, o->in1, o->in2); @@ -4099,6 +4010,16 @@ static void cout_addu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_ADDU_64, o->in1, o->in2, o->out); } +static void cout_addc32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDC_32, o->in1, o->in2, o->out); +} + +static void cout_addc64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_ADDC_64, o->in1, o->in2, o->out); +} + static void cout_cmps32(DisasContext *s, DisasOps *o) { gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2); @@ -4180,6 +4101,16 @@ static void cout_subu64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_SUBU_64, o->in1, o->in2, o->out); } +static void cout_subb32(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBB_32, o->in1, o->in2, o->out); +} + +static void cout_subb64(DisasContext *s, DisasOps *o) +{ + gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, o->out); +} + /* ====================================================================== */ /* The "PREPeration" generators. These initialize the DisasOps.OUT fields with the TCG register to which we will write. Used in combination with From 8ac33cdb8bfbf319adea60363cf1ba3e5dbf5c4f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Aug 2012 11:38:19 -0700 Subject: [PATCH 0124/1634] target-s390: Convert BRANCH AND SAVE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++ target-s390x/translate.c | 102 ++++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 46 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 373aa40fd3..ba78f471d1 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -62,6 +62,13 @@ D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) +/* BRANCH AND SAVE */ + C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) + C(0x4d00, BAS, RX_a, Z, 0, a2, r1, 0, bas, 0) +/* BRANCH RELATIVE AND SAVE */ + C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) + C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) + /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6f3a5df678..6d87d08d26 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -713,20 +713,23 @@ static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2, return get_address(s, 0, *b1, *d1); } +static int use_goto_tb(DisasContext *s, uint64_t dest) +{ + /* NOTE: we handle the case where the TB spans two pages here */ + return (((dest & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) + || (dest & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) + && !s->singlestep_enabled + && !(s->tb->cflags & CF_LAST_IO)); +} + static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc) { - TranslationBlock *tb; - gen_update_cc_op(s); - tb = s->tb; - /* NOTE: we handle the case where the TB spans two pages here */ - if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) || - (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) { - /* jump to same page: we can use a direct jump */ + if (use_goto_tb(s, pc)) { tcg_gen_goto_tb(tb_num); tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb((tcg_target_long)tb + tb_num); + tcg_gen_exit_tb((tcg_target_long)s->tb + tb_num); } else { /* jump to another page: currently not optimized */ tcg_gen_movi_i64(psw_addr, pc); @@ -1817,13 +1820,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, case 0x4: /* brc m1, i2 */ gen_brc(r1, s, i2 * 2LL); return; - case 0x5: /* BRAS R1,I2 [RI] */ - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 4)); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - gen_goto_tb(s, 0, s->pc + i2 * 2LL); - s->is_jmp = DISAS_TB_JUMP; - break; case 0x6: /* BRCT R1,I2 [RI] */ tmp32_1 = load_reg32(r1); tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); @@ -2601,7 +2597,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { - TCGv_i64 tmp; TCGv_i32 tmp32_1, tmp32_2; uint64_t target = s->pc + i2 * 2LL; int l1; @@ -2633,13 +2628,6 @@ static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2 tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5: /* brasl r1, i2 */ - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 6)); - store_reg(r1, tmp); - tcg_temp_free_i64(tmp); - gen_goto_tb(s, 0, target); - s->is_jmp = DISAS_TB_JUMP; - break; default: LOG_DISAS("illegal c0 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2720,19 +2708,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd: /* BASR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 2)); - store_reg(r1, tmp); - if (r2) { - tmp2 = load_reg(r2); - tcg_gen_mov_i64(psw_addr, tmp2); - tcg_temp_free_i64(tmp2); - s->is_jmp = DISAS_JUMP; - } - tcg_temp_free_i64(tmp); - break; case 0xe: /* MVCL R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -2846,16 +2821,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); s->is_jmp = DISAS_TB_JUMP; break; - case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_const_i64(pc_to_link_info(s, s->pc + 4)); - store_reg(r1, tmp2); - tcg_gen_mov_i64(psw_addr, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - s->is_jmp = DISAS_JUMP; - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3743,6 +3708,26 @@ struct DisasInsn { uint64_t data; }; +/* ====================================================================== */ +/* Miscelaneous helpers, used by several operations. */ + +static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) +{ + if (dest == s->next_pc) { + return NO_EXIT; + } + if (use_goto_tb(s, dest)) { + gen_update_cc_op(s); + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, dest); + tcg_gen_exit_tb((tcg_target_long)s->tb); + return EXIT_GOTO_TB; + } else { + tcg_gen_movi_i64(psw_addr, dest); + return EXIT_PC_UPDATED; + } +} + /* ====================================================================== */ /* The operations. These perform the bulk of the work for any insn, usually after the operands have been loaded and output initialized. */ @@ -3799,6 +3784,23 @@ static ExitStatus op_andi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_bas(DisasContext *s, DisasOps *o) +{ + tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); + if (!TCGV_IS_UNUSED_I64(o->in2)) { + tcg_gen_mov_i64(psw_addr, o->in2); + return EXIT_PC_UPDATED; + } else { + return NO_EXIT; + } +} + +static ExitStatus op_basi(DisasContext *s, DisasOps *o) +{ + tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); + return help_goto_direct(s, s->pc + 2 * get_field(s->fields, i2)); +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; @@ -4287,6 +4289,14 @@ static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in2 = true; } +static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r2 = get_field(f, r2); + if (r2 != 0) { + o->in2 = load_reg(r2); + } +} + static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); From 7233f2ed17175eea043faad749143c1fb5ffe0b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 08:28:02 -0700 Subject: [PATCH 0125/1634] target-s390: Convert BRANCH ON CONDITION Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 + target-s390x/translate.c | 231 ++++++++++++++++++++++--------------- 2 files changed, 142 insertions(+), 95 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ba78f471d1..0bd05abd52 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -68,6 +68,12 @@ /* BRANCH RELATIVE AND SAVE */ C(0xa705, BRAS, RI_b, Z, 0, 0, r1, 0, basi, 0) C(0xc005, BRASL, RIL_b, Z, 0, 0, r1, 0, basi, 0) +/* BRANCH ON CONDITION */ + C(0x0700, BCR, RR_b, Z, 0, r2_nz, 0, 0, bc, 0) + C(0x4700, BC, RX_b, Z, 0, a2, 0, 0, bc, 0) +/* BRANCH RELATIVE ON CONDITION */ + C(0xa704, BRC, RI_c, Z, 0, 0, 0, 0, bc, 0) + C(0xc004, BRCL, RIL_c, Z, 0, 0, 0, 0, bc, 0) /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6d87d08d26..e663fe5ed8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1021,35 +1021,6 @@ static void gen_jcc(DisasContext *s, uint32_t mask, int skip) free_compare(&c); } -static void gen_bcr(DisasContext *s, uint32_t mask, TCGv_i64 target, - uint64_t offset) -{ - int skip; - - if (mask == 0xf) { - /* unconditional */ - gen_update_cc_op(s); - tcg_gen_mov_i64(psw_addr, target); - tcg_gen_exit_tb(0); - } else if (mask == 0) { - /* ignore cc and never match */ - gen_goto_tb(s, 0, offset + 2); - } else { - TCGv_i64 new_addr = tcg_temp_local_new_i64(); - - tcg_gen_mov_i64(new_addr, target); - skip = gen_new_label(); - gen_jcc(s, mask, skip); - gen_update_cc_op(s); - tcg_gen_mov_i64(psw_addr, new_addr); - tcg_temp_free_i64(new_addr); - tcg_gen_exit_tb(0); - gen_set_label(skip); - tcg_temp_free_i64(new_addr); - gen_goto_tb(s, 1, offset + 2); - } -} - static void gen_brc(uint32_t mask, DisasContext *s, int32_t offset) { int skip; @@ -2595,46 +2566,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, } } -static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) -{ - TCGv_i32 tmp32_1, tmp32_2; - uint64_t target = s->pc + i2 * 2LL; - int l1; - - LOG_DISAS("disas_c0: op 0x%x r1 %d i2 %d\n", op, r1, i2); - - switch (op) { - case 0x4: /* BRCL M1,I2 [RIL] */ - if (r1 == 15) { /* m1 == r1 */ - gen_goto_tb(s, 0, target); - s->is_jmp = DISAS_TB_JUMP; - break; - } - /* m1 & (1 << (3 - cc)) */ - tmp32_1 = tcg_const_i32(3); - tmp32_2 = tcg_const_i32(1); - gen_op_calc_cc(s); - tcg_gen_sub_i32(tmp32_1, tmp32_1, cc_op); - tcg_gen_shl_i32(tmp32_2, tmp32_2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tmp32_1 = tcg_const_i32(r1); /* m1 == r1 */ - tcg_gen_and_i32(tmp32_1, tmp32_1, tmp32_2); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1); - gen_goto_tb(s, 0, target); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 6); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - default: - LOG_DISAS("illegal c0 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; @@ -2681,18 +2612,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); } break; - case 0x7: /* BCR M1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - if (r2) { - tmp = load_reg(r2); - gen_bcr(s, r1, tmp, s->pc); - tcg_temp_free_i64(tmp); - s->is_jmp = DISAS_TB_JUMP; - } else { - /* XXX: "serialization and checkpoint-synchronization function"? */ - } - break; case 0xa: /* SVC I [RR] */ insn = ld_code2(env, s->pc); debug_insn(insn); @@ -2814,13 +2733,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x47: /* BC M1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - gen_bcr(s, r1, tmp, s->pc + 4); - tcg_temp_free_i64(tmp); - s->is_jmp = DISAS_TB_JUMP; - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3348,13 +3260,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) gen_op_movi_cc(s, 0); } break; - case 0xc0: - insn = ld_code6(env, s->pc); - r1 = (insn >> 36) & 0xf; - op = (insn >> 32) & 0xf; - i2 = (int)insn; - disas_c0(env, s, op, r1, i2); - break; case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ @@ -3728,6 +3633,131 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) } } +static ExitStatus help_branch(DisasContext *s, DisasCompare *c, + bool is_imm, int imm, TCGv_i64 cdest) +{ + ExitStatus ret; + uint64_t dest = s->pc + 2 * imm; + int lab; + + /* Take care of the special cases first. */ + if (c->cond == TCG_COND_NEVER) { + ret = NO_EXIT; + goto egress; + } + if (is_imm) { + if (dest == s->next_pc) { + /* Branch to next. */ + ret = NO_EXIT; + goto egress; + } + if (c->cond == TCG_COND_ALWAYS) { + ret = help_goto_direct(s, dest); + goto egress; + } + } else { + if (TCGV_IS_UNUSED_I64(cdest)) { + /* E.g. bcr %r0 -> no branch. */ + ret = NO_EXIT; + goto egress; + } + if (c->cond == TCG_COND_ALWAYS) { + tcg_gen_mov_i64(psw_addr, cdest); + ret = EXIT_PC_UPDATED; + goto egress; + } + } + + if (use_goto_tb(s, s->next_pc)) { + if (is_imm && use_goto_tb(s, dest)) { + /* Both exits can use goto_tb. */ + gen_update_cc_op(s); + + lab = gen_new_label(); + if (c->is_64) { + tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab); + } + + /* Branch not taken. */ + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, s->next_pc); + tcg_gen_exit_tb((tcg_target_long)s->tb + 0); + + /* Branch taken. */ + gen_set_label(lab); + tcg_gen_goto_tb(1); + tcg_gen_movi_i64(psw_addr, dest); + tcg_gen_exit_tb((tcg_target_long)s->tb + 1); + + ret = EXIT_GOTO_TB; + } else { + /* Fallthru can use goto_tb, but taken branch cannot. */ + /* Store taken branch destination before the brcond. This + avoids having to allocate a new local temp to hold it. + We'll overwrite this in the not taken case anyway. */ + if (!is_imm) { + tcg_gen_mov_i64(psw_addr, cdest); + } + + lab = gen_new_label(); + if (c->is_64) { + tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab); + } + + /* Branch not taken. */ + gen_update_cc_op(s); + tcg_gen_goto_tb(0); + tcg_gen_movi_i64(psw_addr, s->next_pc); + tcg_gen_exit_tb((tcg_target_long)s->tb + 0); + + gen_set_label(lab); + if (is_imm) { + tcg_gen_movi_i64(psw_addr, dest); + } + ret = EXIT_PC_UPDATED; + } + } else { + /* Fallthru cannot use goto_tb. This by itself is vanishingly rare. + Most commonly we're single-stepping or some other condition that + disables all use of goto_tb. Just update the PC and exit. */ + + TCGv_i64 next = tcg_const_i64(s->next_pc); + if (is_imm) { + cdest = tcg_const_i64(dest); + } + + if (c->is_64) { + tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b, + cdest, next); + } else { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 z = tcg_const_i64(0); + tcg_gen_setcond_i32(c->cond, t0, c->u.s32.a, c->u.s32.b); + tcg_gen_extu_i32_i64(t1, t0); + tcg_temp_free_i32(t0); + tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(z); + } + + if (is_imm) { + tcg_temp_free_i64(cdest); + } + tcg_temp_free_i64(next); + + ret = EXIT_PC_UPDATED; + } + + egress: + free_compare(c); + return ret; +} + /* ====================================================================== */ /* The operations. These perform the bulk of the work for any insn, usually after the operands have been loaded and output initialized. */ @@ -3801,6 +3831,17 @@ static ExitStatus op_basi(DisasContext *s, DisasOps *o) return help_goto_direct(s, s->pc + 2 * get_field(s->fields, i2)); } +static ExitStatus op_bc(DisasContext *s, DisasOps *o) +{ + int m1 = get_field(s->fields, m1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + disas_jcc(s, &c, m1); + return help_branch(s, &c, is_imm, imm, o->in2); +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; From c61aad6943cd77046e47cdb5beedad9d035d2216 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 14:22:58 -0700 Subject: [PATCH 0126/1634] target-s390: Convert BRANCH ON COUNT Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 8 ++ target-s390x/translate.c | 162 ++++++++++--------------------------- 2 files changed, 51 insertions(+), 119 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0bd05abd52..8ea6630c43 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -74,6 +74,14 @@ /* BRANCH RELATIVE ON CONDITION */ C(0xa704, BRC, RI_c, Z, 0, 0, 0, 0, bc, 0) C(0xc004, BRCL, RIL_c, Z, 0, 0, 0, 0, bc, 0) +/* BRANCH ON COUNT */ + C(0x0600, BCTR, RR_a, Z, 0, r2_nz, 0, 0, bct32, 0) + C(0xb946, BCTGR, RRE, Z, 0, r2_nz, 0, 0, bct64, 0) + C(0x4600, BCT, RX_a, Z, 0, a2, 0, 0, bct32, 0) + C(0xe346, BCTG, RXY_a, Z, 0, a2, 0, 0, bct64, 0) +/* BRANCH RELATIVE ON COUNT */ + C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) + C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e663fe5ed8..fdf0129a29 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1004,43 +1004,6 @@ static void free_compare(DisasCompare *c) } } -static void gen_jcc(DisasContext *s, uint32_t mask, int skip) -{ - DisasCompare c; - TCGCond cond; - - disas_jcc(s, &c, mask); - cond = tcg_invert_cond(c.cond); - - if (c.is_64) { - tcg_gen_brcond_i64(cond, c.u.s64.a, c.u.s64.b, skip); - } else { - tcg_gen_brcond_i32(cond, c.u.s32.a, c.u.s32.b, skip); - } - - free_compare(&c); -} - -static void gen_brc(uint32_t mask, DisasContext *s, int32_t offset) -{ - int skip; - - if (mask == 0xf) { - /* unconditional */ - gen_goto_tb(s, 0, s->pc + offset); - } else if (mask == 0) { - /* ignore cc and never match */ - gen_goto_tb(s, 0, s->pc + 4); - } else { - skip = gen_new_label(); - gen_jcc(s, mask, skip); - gen_goto_tb(s, 0, s->pc + offset); - gen_set_label(skip); - gen_goto_tb(s, 1, s->pc + 4); - } - s->is_jmp = DISAS_TB_JUMP; -} - static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) { TCGv_i64 tmp, tmp2; @@ -1759,8 +1722,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) { TCGv_i64 tmp, tmp2; - TCGv_i32 tmp32_1; - int l1; LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); switch (op) { @@ -1788,35 +1749,6 @@ static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x4: /* brc m1, i2 */ - gen_brc(r1, s, i2 * 2LL); - return; - case 0x6: /* BRCT R1,I2 [RI] */ - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp32_1, 0, l1); - gen_goto_tb(s, 0, s->pc + (i2 * 2LL)); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 4); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i32(tmp32_1); - break; - case 0x7: /* BRCTG R1,I2 [RI] */ - tmp = load_reg(r1); - tcg_gen_subi_i64(tmp, tmp, 1); - store_reg(r1, tmp); - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1); - gen_goto_tb(s, 0, s->pc + (i2 * 2LL)); - gen_set_label(l1); - gen_goto_tb(s, 1, s->pc + 4); - s->is_jmp = DISAS_TB_JUMP; - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal a7 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2574,7 +2506,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; TCGv_i32 vl; - int l1; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -2586,32 +2517,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) /* set addressing mode, but we only do 64bit anyways */ break; #endif - case 0x6: /* BCTR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - - if (r2) { - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1); - - /* not taking the branch, jump to after the instruction */ - gen_goto_tb(s, 0, s->pc + 2); - gen_set_label(l1); - - /* take the branch, move R2 into psw.addr */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_mov_i64(psw_addr, tmp); - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - } - break; case 0xa: /* SVC I [RR] */ insn = ld_code2(env, s->pc); debug_insn(insn); @@ -2709,30 +2614,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); break; - case 0x46: /* BCT R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tcg_temp_free_i64(tmp); - - tmp32_1 = load_reg32(r1); - tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); - store_reg32(r1, tmp32_1); - - gen_update_cc_op(s); - l1 = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp32_1, 0, l1); - - /* not taking the branch, jump to after the instruction */ - gen_goto_tb(s, 0, s->pc + 4); - gen_set_label(l1); - - /* take the branch, move R2 into psw.addr */ - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tcg_gen_mov_i64(psw_addr, tmp); - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3842,6 +3723,49 @@ static ExitStatus op_bc(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_bct32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + TCGv_i64 t; + + c.cond = TCG_COND_NE; + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_subi_i64(t, regs[r1], 1); + store_reg32_i64(r1, t); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_const_i32(0); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bct64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + c.cond = TCG_COND_NE; + c.is_64 = true; + c.g1 = true; + c.g2 = false; + + tcg_gen_subi_i64(regs[r1], regs[r1], 1); + c.u.s64.a = regs[r1]; + c.u.s64.b = tcg_const_i64(0); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; From 891452e5e274967ffb87d10791620154f2cdc303 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 14:02:02 -0700 Subject: [PATCH 0127/1634] target-s390: Convert DIVIDE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 5 +- target-s390x/insn-data.def | 14 +++ target-s390x/int_helper.c | 47 +++++--- target-s390x/translate.c | 215 +++++++++---------------------------- 4 files changed, 103 insertions(+), 178 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index a45b1c362b..dcc3fce502 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -10,7 +10,10 @@ DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_3(dlg, void, env, i32, i64) +DEF_HELPER_3(divs32, s64, env, s64, s64) +DEF_HELPER_3(divu32, i64, env, i64, i64) +DEF_HELPER_3(divs64, s64, env, s64, s64) +DEF_HELPER_4(divu64, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8ea6630c43..921c216b7d 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -131,6 +131,20 @@ C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* DIVIDE */ + C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) + C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) +/* DIVIDE LOGICAL */ + C(0xb997, DLR, RRE, Z, r1_D32, r2_32u, new_P, r1_P32, divu32, 0) + C(0xe397, DL, RXY_a, Z, r1_D32, m2_32u, new_P, r1_P32, divu32, 0) + C(0xb987, DLGR, RRE, Z, 0, r2_o, r1_P, 0, divu64, 0) + C(0xe387, DLG, RXY_a, Z, 0, m2_64, r1_P, 0, divu64, 0) +/* DIVIDE SINGLE */ + C(0xb90d, DSGR, RRE, Z, r1p1, r2, r1_P, 0, divs64, 0) + C(0xb91d, DSGFR, RRE, Z, r1p1, r2_32s, r1_P, 0, divs64, 0) + C(0xe30d, DSG, RXY_a, Z, r1p1, m2_64, r1_P, 0, divs64, 0) + C(0xe31d, DSGF, RXY_a, Z, r1p1, m2_32s, r1_P, 0, divs64, 0) + /* EXCLUSIVE OR */ C(0x1700, XR, RR_a, Z, r1, r2, new, r1_32, xor, nz32) C(0xb9f7, XRK, RRF_a, DO, r2, r3, new, r1_32, xor, nz32) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 17c4771e41..80e17f5b1f 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -37,32 +37,51 @@ uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) return reth; } -/* 128 -> 64/64 unsigned division */ -void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +/* 64/32 -> 32 signed division */ +int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b) { - uint64_t divisor = v2; + env->retxl = a % (int32_t)b; + return a / (int32_t)b; +} - if (!env->regs[r1]) { +/* 64/32 -> 32 unsigned division */ +uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b) +{ + env->retxl = a % (uint32_t)b; + return a / (uint32_t)b; +} + +/* 64/64 -> 64 signed division */ +int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) +{ + env->retxl = a % b; + return a / b; +} + +/* 128 -> 64/64 unsigned division */ +uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t b) +{ + uint64_t ret; + if (ah == 0) { /* 64 -> 64/64 case */ - env->regs[r1] = env->regs[r1 + 1] % divisor; - env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; - return; + env->retxl = al % b; + ret = al / b; } else { + /* ??? Move i386 idivq helper to host-utils. */ #if HOST_LONG_BITS == 64 && defined(__GNUC__) /* assuming 64-bit hosts have __uint128_t */ - __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | - (env->regs[r1 + 1]); - __uint128_t quotient = dividend / divisor; - __uint128_t remainder = dividend % divisor; - - env->regs[r1 + 1] = quotient; - env->regs[r1] = remainder; + __uint128_t a = ((__uint128_t)ah << 64) | al; + __uint128_t q = a / b; + env->retxl = a % b; + ret = q; #else /* 32-bit hosts would need special wrapper functionality - just abort if we encounter such a case; it's very unlikely anyways. */ cpu_abort(env, "128 -> 64/64 division not implemented\n"); #endif } + return ret; } /* absolute value 32-bit */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index fdf0129a29..5667155c4a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1232,31 +1232,13 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { - TCGv_i64 addr, tmp, tmp2, tmp3, tmp4; + TCGv_i64 addr, tmp2, tmp3; TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); addr = get_address(s, x2, b2, d2); switch (op) { - case 0xd: /* DSG R1,D2(X2,B2) [RXY] */ - case 0x1d: /* DSGF R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - if (op == 0x1d) { - tcg_gen_qemu_ld32s(tmp2, addr, get_mem_index(s)); - } else { - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - } - tmp4 = load_reg(r1 + 1); - tmp3 = tcg_temp_new_i64(); - tcg_gen_div_i64(tmp3, tmp4, tmp2); - store_reg(r1 + 1, tmp3); - tcg_gen_rem_i64(tmp3, tmp4, tmp2); - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0xf: /* LRVG R1,D2(X2,B2) [RXE] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); @@ -1306,34 +1288,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg8(r1, tmp3); tcg_temp_free_i64(tmp3); break; - case 0x87: /* DLG R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_const_i32(r1); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_dlg(cpu_env, tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; - case 0x97: /* DL R1,D2(X2,B2) [RXY] */ - /* reg(r1) = reg(r1, r1+1) % ld32(addr) */ - /* reg(r1+1) = reg(r1, r1+1) / ld32(addr) */ - tmp = load_reg(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp3); - - tcg_gen_rem_i64(tmp3, tmp, tmp2); - tcg_gen_div_i64(tmp, tmp, tmp2); - store_reg32_i64((r1 + 1) & 15, tmp); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2414,31 +2368,11 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, int r2) { - TCGv_i64 tmp, tmp2, tmp3; + TCGv_i64 tmp; TCGv_i32 tmp32_1; LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0xd: /* DSGR R1,R2 [RRE] */ - case 0x1d: /* DSGFR R1,R2 [RRE] */ - tmp = load_reg(r1 + 1); - if (op == 0xd) { - tmp2 = load_reg(r2); - } else { - tmp32_1 = load_reg32(r2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - } - tmp3 = tcg_temp_new_i64(); - tcg_gen_div_i64(tmp3, tmp, tmp2); - store_reg(r1 + 1, tmp3); - tcg_gen_rem_i64(tmp3, tmp, tmp2); - store_reg(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x17: /* LLGTR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tmp = tcg_temp_new_i64(); @@ -2465,32 +2399,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; - case 0x87: /* DLGR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - gen_helper_dlg(cpu_env, tmp32_1, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; - case 0x97: /* DLR R1,R2 [RRE] */ - /* reg(r1) = reg(r1, r1+1) % reg(r2) */ - /* reg(r1+1) = reg(r1, r1+1) / reg(r2) */ - tmp = load_reg(r1); - tmp2 = load_reg(r2); - tmp3 = load_reg((r1 + 1) & 15); - tcg_gen_ext32u_i64(tmp2, tmp2); - tcg_gen_ext32u_i64(tmp3, tmp3); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp3); - - tcg_gen_rem_i64(tmp3, tmp, tmp2); - tcg_gen_div_i64(tmp, tmp, tmp2); - store_reg32_i64((r1 + 1) & 15, tmp); - store_reg32_i64(r1, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; default: LOG_DISAS("illegal b9 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2543,41 +2451,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x1d: /* DR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - tmp32_3 = load_reg32(r2); - - tmp = tcg_temp_new_i64(); /* dividend */ - tmp2 = tcg_temp_new_i64(); /* divisor */ - tmp3 = tcg_temp_new_i64(); - - /* dividend is r(r1 << 32) | r(r1 + 1) */ - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_2); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - - /* divisor is r(r2) */ - tcg_gen_ext_i32_i64(tmp2, tmp32_3); - - tcg_gen_div_i64(tmp3, tmp, tmp2); - tcg_gen_rem_i64(tmp, tmp, tmp2); - - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - tcg_gen_trunc_i64_i32(tmp32_2, tmp3); - - store_reg32(r1, tmp32_1); /* remainder */ - store_reg32(r1 + 1, tmp32_2); /* quotient */ - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x28: /* LDR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -2626,40 +2499,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x5d: /* D R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - /* dividend is r(r1 << 32) | r(r1 + 1) */ - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_2); - tcg_gen_shli_i64(tmp, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - - /* divisor is in memory */ - tcg_gen_qemu_ld32s(tmp2, tmp3, get_mem_index(s)); - - /* XXX divisor == 0 -> FixP divide exception */ - - tcg_gen_div_i64(tmp3, tmp, tmp2); - tcg_gen_rem_i64(tmp, tmp, tmp2); - - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - tcg_gen_trunc_i64_i32(tmp32_2, tmp3); - - store_reg32(r1, tmp32_1); /* remainder */ - store_reg32(r1 + 1, tmp32_2); /* quotient */ - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x60: /* STD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3766,6 +3605,34 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_divs32(DisasContext *s, DisasOps *o) +{ + gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divu32(DisasContext *s, DisasOps *o) +{ + gen_helper_divu32(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divs64(DisasContext *s, DisasOps *o) +{ + gen_helper_divs64(o->out2, cpu_env, o->in1, o->in2); + return_low128(o->out); + return NO_EXIT; +} + +static ExitStatus op_divu64(DisasContext *s, DisasOps *o) +{ + gen_helper_divu64(o->out2, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out); + return NO_EXIT; +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; @@ -4089,6 +3956,12 @@ static void prep_new(DisasContext *s, DisasFields *f, DisasOps *o) o->out = tcg_temp_new_i64(); } +static void prep_new_P(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = tcg_temp_new_i64(); + o->out2 = tcg_temp_new_i64(); +} + static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = regs[get_field(f, r1)]; @@ -4120,6 +3993,14 @@ static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(get_field(f, r1), o->out); } +static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + store_reg32_i64(r1, o->out); + store_reg32_i64((r1 + 1) & 15, o->out2); +} + static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ @@ -4183,6 +4064,14 @@ static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_ext32u_i64(o->in1, regs[(r1 + 1) & 15]); } +static void in1_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be even. */ + int r1 = get_field(f, r1); + o->in1 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]); +} + static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); From b4e2bd3563af75ba5b9fe809c8cf79d2d34aecf3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 17:27:40 -0700 Subject: [PATCH 0128/1634] target-s390: Send signals for divide Signed-off-by: Richard Henderson --- target-s390x/cpu.h | 2 ++ target-s390x/int_helper.c | 51 +++++++++++++++++++++++++++++++++----- target-s390x/misc_helper.c | 20 +++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index ea1bc8625e..69269a14ca 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -931,5 +931,7 @@ uint32_t set_cc_nz_f64(float64 v); /* misc_helper.c */ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); +void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, + uintptr_t retaddr); #endif diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 80e17f5b1f..839c0e1500 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -38,22 +38,54 @@ uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) } /* 64/32 -> 32 signed division */ -int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b) +int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) { - env->retxl = a % (int32_t)b; - return a / (int32_t)b; + int32_t ret, b = b64; + int64_t q; + + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + ret = q = a / b; + env->retxl = a % b; + + /* Catch non-representable quotient. */ + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + return ret; } /* 64/32 -> 32 unsigned division */ -uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b) +uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) { - env->retxl = a % (uint32_t)b; - return a / (uint32_t)b; + uint32_t ret, b = b64; + uint64_t q; + + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + ret = q = a / b; + env->retxl = a % b; + + /* Catch non-representable quotient. */ + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } + + return ret; } /* 64/64 -> 64 signed division */ int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) { + /* Catch divide by zero, and non-representable quotient (MIN / -1). */ + if (b == 0 || (b == -1 && a == (1ll << 63))) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } env->retxl = a % b; return a / b; } @@ -63,6 +95,10 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t b) { uint64_t ret; + /* Signal divide by zero. */ + if (b == 0) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } if (ah == 0) { /* 64 -> 64/64 case */ env->retxl = al % b; @@ -75,6 +111,9 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, __uint128_t q = a / b; env->retxl = a % b; ret = q; + if (ret != q) { + runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + } #else /* 32-bit hosts would need special wrapper functionality - just abort if we encounter such a case; it's very unlikely anyways. */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 2aa1ed0b5e..6dca0ebabd 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -41,6 +41,26 @@ #define HELPER_LOG(x...) #endif +/* Raise an exception dynamically from a helper function. */ +void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, + uintptr_t retaddr) +{ + int t; + + env->exception_index = EXCP_PGM; + env->int_pgm_code = excp; + + /* Use the (ultimate) callers address to find the insn that trapped. */ + cpu_restore_state(env, retaddr); + + /* Advance past the insn. */ + t = cpu_ldub_code(env, env->psw.addr); + env->int_pgm_ilen = t = get_ilen(t); + env->psw.addr += 2 * t; + + cpu_loop_exit(env); +} + /* Raise an exception statically from a TB. */ void HELPER(exception)(CPUS390XState *env, uint32_t excp) { From 00d2dc192fb866d077935f0dd298472d65d87eb6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:20:58 -0700 Subject: [PATCH 0129/1634] target-s390: Convert TEST UNDER MASK Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 25 +++++-------- target-s390x/insn-data.def | 8 +++++ target-s390x/translate.c | 74 ++++++-------------------------------- 3 files changed, 27 insertions(+), 80 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 880e3b234d..d20342cda0 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "helper.h" +#include "qemu/host-utils.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER @@ -86,13 +87,11 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, } } -static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, - uint32_t mask) +static uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) { - uint16_t r = val & mask; + uint32_t r = val & mask; - HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); - if (r == 0 || mask == 0) { + if (r == 0) { return 0; } else if (r == mask) { return 3; @@ -101,23 +100,17 @@ static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, } } -/* set condition code for test under mask */ -static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, - uint32_t mask) +static uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint64_t mask) { - uint16_t r = val & mask; + uint64_t r = val & mask; - HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); - if (r == 0 || mask == 0) { + if (r == 0) { return 0; } else if (r == mask) { return 3; } else { - while (!(mask & 0x8000)) { - mask <<= 1; - val <<= 1; - } - if (val & 0x8000) { + int top = clz64(mask); + if ((int64_t)(val << top) < 0) { return 2; } else { return 1; diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 921c216b7d..f70ede9bcf 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -336,3 +336,11 @@ C(0xb989, SLBGR, RRE, Z, r1, r2, r1, 0, subb, subb64) C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32) C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64) + +/* TEST UNDER MASK */ + C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) + C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) + D(0xa702, TMHH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 48) + D(0xa703, TMHL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 32) + D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) + D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5667155c4a..4e3451964f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1514,16 +1514,6 @@ do_mh: tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x51: /* TMY D1(B1),I2 [SIY] */ - tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ - tmp2 = tcg_const_i64((r1 << 4) | r3); - tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s)); - /* yes, this is a 32 bit operation with 64 bit tcg registers, because - that incurs less conversions */ - cmp_64(s, tmp, tmp2, CC_OP_TM_32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x52: /* MVIY D1(B1),I2 [SIY] */ tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ tmp2 = tcg_const_i64((r1 << 4) | r3); @@ -1672,44 +1662,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(addr); } -static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, - int i2) -{ - TCGv_i64 tmp, tmp2; - - LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2); - switch (op) { - case 0x0: /* TMLH or TMH R1,I2 [RI] */ - case 0x1: /* TMLL or TML R1,I2 [RI] */ - case 0x2: /* TMHH R1,I2 [RI] */ - case 0x3: /* TMHL R1,I2 [RI] */ - tmp = load_reg(r1); - tmp2 = tcg_const_i64((uint16_t)i2); - switch (op) { - case 0x0: - tcg_gen_shri_i64(tmp, tmp, 16); - break; - case 0x1: - break; - case 0x2: - tcg_gen_shri_i64(tmp, tmp, 48); - break; - case 0x3: - tcg_gen_shri_i64(tmp, tmp, 32); - break; - } - tcg_gen_andi_i64(tmp, tmp, 0xffff); - cmp_64(s, tmp, tmp2, CC_OP_TM_64); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - default: - LOG_DISAS("illegal a7 operation 0x%x\n", op); - gen_illegal_opcode(s); - return; - } -} - static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { @@ -2678,15 +2630,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp3); tcg_temp_free_i64(tmp4); break; - case 0x91: /* TM D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_const_i64(i2); - tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s)); - cmp_64(s, tmp, tmp2, CC_OP_TM_32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x92: /* MVI D1(B1),I2 [SI] */ insn = ld_code4(env, s->pc); tmp = decode_si(s, insn, &i2, &b1, &d1); @@ -2744,13 +2687,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xa7: - insn = ld_code4(env, s->pc); - r1 = (insn >> 20) & 0xf; - op = (insn >> 16) & 0xf; - i2 = (short)insn; - disas_a7(env, s, op, r1, i2); - break; case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -3945,6 +3881,16 @@ static void cout_subb64(DisasContext *s, DisasOps *o) gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, o->out); } +static void cout_tm32(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_TM_32, o->in1, o->in2); +} + +static void cout_tm64(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_TM_64, o->in1, o->in2); +} + /* ====================================================================== */ /* The "PREPeration" generators. These initialize the DisasOps.OUT fields with the TCG register to which we will write. Used in combination with From d9a39927993a186b039d5be66cc85c0e735a78bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:28:56 -0700 Subject: [PATCH 0130/1634] target-s390: Convert SET ADDRESSING MODE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f70ede9bcf..69af25dbaa 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -344,3 +344,10 @@ D(0xa703, TMHL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 32) D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) + +#ifndef CONFIG_USER_ONLY +/* SET ADDRESSING MODE */ + /* We only do 64-bit, so accept this as a no-op. + Let SAM24 and SAM31 signal illegal instruction. */ + C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +#endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 4e3451964f..26ca49b28a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2371,12 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { -#ifndef CONFIG_USER_ONLY - case 0x01: /* SAM */ - insn = ld_code2(env, s->pc); - /* set addressing mode, but we only do 64bit anyways */ - break; -#endif case 0xa: /* SVC I [RR] */ insn = ld_code2(env, s->pc); debug_insn(insn); From b9836c1acd4ecb286bd1617857cc52df7b75c414 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:41:05 -0700 Subject: [PATCH 0131/1634] target-s390: Convert SUPERVISOR CALL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 34 +++++++++++++++++++--------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 69af25dbaa..7a0c999194 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -337,6 +337,9 @@ C(0xe399, SLB, RXY_a, Z, r1, m2_32u, new, r1_32, subb, subb32) C(0xe389, SLBG, RXY_a, Z, r1, m2_64, r1, 0, subb, subb64) +/* SUPERVISOR CALL */ + C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) + /* TEST UNDER MASK */ C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 26ca49b28a..e2b7671de8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2371,21 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0xa: /* SVC I [RR] */ - insn = ld_code2(env, s->pc); - debug_insn(insn); - i = insn & 0xff; - update_psw_addr(s); - gen_op_calc_cc(s); - tmp32_1 = tcg_const_i32(i); - tmp32_2 = tcg_const_i32(s->next_pc - s->pc); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); - tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); - gen_exception(EXCP_SVC); - s->is_jmp = DISAS_EXCP; - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xe: /* MVCL R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3717,6 +3702,25 @@ static ExitStatus op_subb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_svc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 t; + + update_psw_addr(s); + gen_op_calc_cc(s); + + t = tcg_const_i32(get_field(s->fields, i1) & 0xff); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); + tcg_temp_free_i32(t); + + t = tcg_const_i32(s->next_pc - s->pc); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); + tcg_temp_free_i32(t); + + gen_exception(EXCP_SVC); + return EXIT_NORETURN; +} + static ExitStatus op_xor(DisasContext *s, DisasOps *o) { tcg_gen_xor_i64(o->out, o->in1, o->in2); From e1eaada955aab907b53a091b85421de9e8b8dd9c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Aug 2012 16:46:49 -0700 Subject: [PATCH 0132/1634] target-s390: Convert MOVE LONG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 23 ++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7a0c999194..995c0f6e75 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -246,6 +246,9 @@ C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) +/* MOVE LONG */ + C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) + /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e2b7671de8..0437f9b9a4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2371,17 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0xe: /* MVCL R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_mvcl(cc_op, cpu_env, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x28: /* LDR R1,R2 [RR] */ insn = ld_code2(env, s->pc); decode_rr(s, insn, &r1, &r2); @@ -3607,6 +3596,18 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2)); + potential_page_fault(s); + gen_helper_mvcl(cc_op, cpu_env, r1, r2); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From d764a8d12b24c8b97fe3ff2193aec04079e8db20 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 12:24:24 -0700 Subject: [PATCH 0133/1634] target-s390: Convert FP LOAD Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 7 +++ target-s390x/translate.c | 102 ++++++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 35 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 995c0f6e75..c3b1f6f5ef 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -173,6 +173,13 @@ C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) + C(0x2800, LDR, RR_a, Z, 0, f2_o, 0, f1, mov2, 0) + C(0x6800, LD, RX_a, Z, 0, m2_64, 0, f1, mov2, 0) + C(0xed65, LDY, RXY_a, LD, 0, m2_64, 0, f1, mov2, 0) + C(0x3800, LER, RR_a, Z, 0, e2, 0, cond_e1e2, mov2, 0) + C(0x7800, LE, RX_a, Z, 0, m2_32u, 0, e1, mov2, 0) + C(0xed64, LEY, RXY_a, LD, 0, m2_32u, 0, e1, mov2, 0) + C(0xb365, LXR, RRE, Z, 0, x2_o, 0, x1, movx, 0) /* LOAD IMMEDIATE */ C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) /* LOAD RELATIVE LONG */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0437f9b9a4..d459b25170 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -224,6 +224,13 @@ static inline TCGv_i32 load_freg32(int reg) return r; } +static inline TCGv_i64 load_freg32_i64(int reg) +{ + TCGv_i64 r = tcg_temp_new_i64(); + tcg_gen_shri_i64(r, fregs[reg], 32); + return r; +} + static inline TCGv_i32 load_reg32(int reg) { TCGv_i32 r = tcg_temp_new_i32(); @@ -293,6 +300,11 @@ static inline void store_freg32(int reg, TCGv_i32 v) #endif } +static inline void store_freg32_i64(int reg, TCGv_i64 v) +{ + tcg_gen_deposit_i64(fregs[reg], fregs[reg], v, 32, 32); +} + static inline void return_low128(TCGv_i64 dest) { tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); @@ -2371,20 +2383,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x28: /* LDR R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp = load_freg(r2); - store_freg(r1, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x38: /* LER R1,R2 [RR] */ - insn = ld_code2(env, s->pc); - decode_rr(s, insn, &r1, &r2); - tmp32_1 = load_freg32(r2); - store_freg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x43: /* IC R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -2427,15 +2425,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x68: /* LD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); - store_freg(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x70: /* STE R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -2447,18 +2436,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x78: /* LE R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - store_freg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ @@ -3596,6 +3573,18 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_movx(DisasContext *s, DisasOps *o) +{ + o->out = o->in1; + o->out2 = o->in2; + o->g_out = o->g_in1; + o->g_out2 = o->g_in2; + TCGV_UNUSED_I64(o->in1); + TCGV_UNUSED_I64(o->in2); + o->g_in1 = o->g_in2 = false; + return NO_EXIT; +} + static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); @@ -3955,6 +3944,23 @@ static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(r1, o->out); } +static void wout_e1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_freg32_i64(get_field(f, r1), o->out); +} + +static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_freg(get_field(f, r1), o->out); +} + +static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int f1 = get_field(s->fields, r1); + store_freg(f1, o->out); + store_freg((f1 + 2) & 15, o->out2); +} + static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) { if (get_field(f, r1) != get_field(f, r2)) { @@ -3962,6 +3968,13 @@ static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) } } +static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + if (get_field(f, r1) != get_field(f, r2)) { + store_freg32_i64(get_field(f, r1), o->out); + } +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); @@ -4137,6 +4150,25 @@ static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]); } +static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = load_freg32_i64(get_field(f, r2)); +} + +static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = fregs[get_field(f, r2)]; + o->g_in2 = true; +} + +static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int f2 = get_field(f, r2); + o->in1 = fregs[f2]; + o->in2 = fregs[(f2 + 2) & 15]; + o->g_in1 = o->g_in2 = true; +} + static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; From afdc70bea01452367e372db7e2168b71bb3aa9b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 07:12:29 -0700 Subject: [PATCH 0134/1634] target-s390: Convert INSERT CHARACTER Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 35 +++++++++++++---------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c3b1f6f5ef..f37e69a602 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -157,6 +157,9 @@ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) +/* INSERT CHARACTER */ + C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) + C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) /* INSERT IMMEDIATE */ D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d459b25170..25bbf45f2c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -283,12 +283,6 @@ static inline void store_reg16(int reg, TCGv_i32 v) #endif } -static inline void store_reg8(int reg, TCGv_i64 v) -{ - /* 8 bit register writes keep the upper bytes */ - tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 8); -} - static inline void store_freg32(int reg, TCGv_i32 v) { /* 32 bit register writes keep the lower half */ @@ -1244,7 +1238,7 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { - TCGv_i64 addr, tmp2, tmp3; + TCGv_i64 addr, tmp2; TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", @@ -1294,12 +1288,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); tcg_temp_free_i64(tmp2); break; - case 0x73: /* ICY R1,D2(X2,B2) [RXY] */ - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp3, addr, get_mem_index(s)); - store_reg8(r1, tmp3); - tcg_temp_free_i64(tmp3); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2383,15 +2371,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x43: /* IC R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - store_reg8(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x44: /* EX R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3922,6 +3901,12 @@ static void wout_r1(DisasContext *s, DisasFields *f, DisasOps *o) store_reg(get_field(f, r1), o->out); } +static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8); +} + static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); @@ -4180,6 +4165,12 @@ static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); } +static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s)); +} + static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From 443aaeb8991022f3eadd2b65e14e805093e2a0e6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 12:36:10 -0700 Subject: [PATCH 0135/1634] target-s390: Cleanup cc computation helpers The inline markers hid the fact that {n}abs_32 were unused because of typos in the main do_calc_cc function. Let the compiler handle auto-inlining here. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 140 +++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 79 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index d20342cda0..3d89fb9dbf 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -29,8 +29,7 @@ #define HELPER_LOG(x...) #endif -static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, - int32_t dst) +static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst) { if (src == dst) { return 0; @@ -41,13 +40,12 @@ static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, } } -static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_ltgt0_32(int32_t dst) { - return cc_calc_ltgt_32(env, dst, 0); + return cc_calc_ltgt_32(dst, 0); } -static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, - int64_t dst) +static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst) { if (src == dst) { return 0; @@ -58,13 +56,12 @@ static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, } } -static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_ltgt0_64(int64_t dst) { - return cc_calc_ltgt_64(env, dst, 0); + return cc_calc_ltgt_64(dst, 0); } -static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, - uint32_t dst) +static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst) { if (src == dst) { return 0; @@ -75,8 +72,7 @@ static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, } } -static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, - uint64_t dst) +static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst) { if (src == dst) { return 0; @@ -87,7 +83,7 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, } } -static uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) +static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask) { uint32_t r = val & mask; @@ -100,7 +96,7 @@ static uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) } } -static uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint64_t mask) +static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask) { uint64_t r = val & mask; @@ -118,13 +114,12 @@ static uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint64_t mask) } } -static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) +static uint32_t cc_calc_nz(uint64_t dst) { return !!dst; } -static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) +static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -139,14 +134,12 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, } } -static uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_addu_64(uint64_t a1, uint64_t a2, uint64_t ar) { return (ar != 0) + 2 * (ar < a1); } -static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_addc_64(uint64_t a1, uint64_t a2, uint64_t ar) { /* Recover a2 + carry_in. */ uint64_t a2c = ar - a1; @@ -156,8 +149,7 @@ static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1, return (ar != 0) + 2 * carry_out; } -static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, - int64_t a2, int64_t ar) +static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -172,8 +164,7 @@ static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, } } -static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar) { if (ar == 0) { return 2; @@ -186,8 +177,7 @@ static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, } } -static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1, - uint64_t a2, uint64_t ar) +static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar) { /* We had borrow-in if normal subtraction isn't equal. */ int borrow_in = ar - (a1 - a2); @@ -205,7 +195,7 @@ static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1, return (ar != 0) + 2 * !borrow_out; } -static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_abs_64(int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -216,12 +206,12 @@ static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) } } -static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_nabs_64(int64_t dst) { return !!dst; } -static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) +static uint32_t cc_calc_comp_64(int64_t dst) { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -235,8 +225,7 @@ static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) } -static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) +static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar) { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { return 3; /* overflow */ @@ -251,14 +240,12 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, } } -static uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_addu_32(uint32_t a1, uint32_t a2, uint32_t ar) { return (ar != 0) + 2 * (ar < a1); } -static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_addc_32(uint32_t a1, uint32_t a2, uint32_t ar) { /* Recover a2 + carry_in. */ uint32_t a2c = ar - a1; @@ -268,8 +255,7 @@ static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1, return (ar != 0) + 2 * carry_out; } -static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, - int32_t a2, int32_t ar) +static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar) { if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -284,8 +270,7 @@ static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, } } -static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar) { if (ar == 0) { return 2; @@ -298,8 +283,7 @@ static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, } } -static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1, - uint32_t a2, uint32_t ar) +static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar) { /* We had borrow-in if normal subtraction isn't equal. */ int borrow_in = ar - (a1 - a2); @@ -317,7 +301,7 @@ static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1, return (ar != 0) + 2 * !borrow_out; } -static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_abs_32(int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -328,12 +312,12 @@ static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) } } -static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_nabs_32(int32_t dst) { return !!dst; } -static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) +static uint32_t cc_calc_comp_32(int32_t dst) { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -347,8 +331,7 @@ static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) } /* calculate condition code for insert character under mask insn */ -static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, - uint32_t val) +static uint32_t cc_calc_icm_32(uint32_t mask, uint32_t val) { uint32_t cc; @@ -379,8 +362,7 @@ static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, return cc; } -static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, - uint64_t shift) +static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) { uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); uint64_t match, r; @@ -409,7 +391,7 @@ static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, } -static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, +static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) { uint32_t r = 0; @@ -423,93 +405,93 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, r = cc_op; break; case CC_OP_LTGT0_32: - r = cc_calc_ltgt0_32(env, dst); + r = cc_calc_ltgt0_32(dst); break; case CC_OP_LTGT0_64: - r = cc_calc_ltgt0_64(env, dst); + r = cc_calc_ltgt0_64(dst); break; case CC_OP_LTGT_32: - r = cc_calc_ltgt_32(env, src, dst); + r = cc_calc_ltgt_32(src, dst); break; case CC_OP_LTGT_64: - r = cc_calc_ltgt_64(env, src, dst); + r = cc_calc_ltgt_64(src, dst); break; case CC_OP_LTUGTU_32: - r = cc_calc_ltugtu_32(env, src, dst); + r = cc_calc_ltugtu_32(src, dst); break; case CC_OP_LTUGTU_64: - r = cc_calc_ltugtu_64(env, src, dst); + r = cc_calc_ltugtu_64(src, dst); break; case CC_OP_TM_32: - r = cc_calc_tm_32(env, src, dst); + r = cc_calc_tm_32(src, dst); break; case CC_OP_TM_64: - r = cc_calc_tm_64(env, src, dst); + r = cc_calc_tm_64(src, dst); break; case CC_OP_NZ: - r = cc_calc_nz(env, dst); + r = cc_calc_nz(dst); break; case CC_OP_ADD_64: - r = cc_calc_add_64(env, src, dst, vr); + r = cc_calc_add_64(src, dst, vr); break; case CC_OP_ADDU_64: - r = cc_calc_addu_64(env, src, dst, vr); + r = cc_calc_addu_64(src, dst, vr); break; case CC_OP_ADDC_64: - r = cc_calc_addc_64(env, src, dst, vr); + r = cc_calc_addc_64(src, dst, vr); break; case CC_OP_SUB_64: - r = cc_calc_sub_64(env, src, dst, vr); + r = cc_calc_sub_64(src, dst, vr); break; case CC_OP_SUBU_64: - r = cc_calc_subu_64(env, src, dst, vr); + r = cc_calc_subu_64(src, dst, vr); break; case CC_OP_SUBB_64: - r = cc_calc_subb_64(env, src, dst, vr); + r = cc_calc_subb_64(src, dst, vr); break; case CC_OP_ABS_64: - r = cc_calc_abs_64(env, dst); + r = cc_calc_abs_64(dst); break; case CC_OP_NABS_64: - r = cc_calc_nabs_64(env, dst); + r = cc_calc_nabs_64(dst); break; case CC_OP_COMP_64: - r = cc_calc_comp_64(env, dst); + r = cc_calc_comp_64(dst); break; case CC_OP_ADD_32: - r = cc_calc_add_32(env, src, dst, vr); + r = cc_calc_add_32(src, dst, vr); break; case CC_OP_ADDU_32: - r = cc_calc_addu_32(env, src, dst, vr); + r = cc_calc_addu_32(src, dst, vr); break; case CC_OP_ADDC_32: - r = cc_calc_addc_32(env, src, dst, vr); + r = cc_calc_addc_32(src, dst, vr); break; case CC_OP_SUB_32: - r = cc_calc_sub_32(env, src, dst, vr); + r = cc_calc_sub_32(src, dst, vr); break; case CC_OP_SUBU_32: - r = cc_calc_subu_32(env, src, dst, vr); + r = cc_calc_subu_32(src, dst, vr); break; case CC_OP_SUBB_32: - r = cc_calc_subb_32(env, src, dst, vr); + r = cc_calc_subb_32(src, dst, vr); break; case CC_OP_ABS_32: - r = cc_calc_abs_64(env, dst); + r = cc_calc_abs_32(dst); break; case CC_OP_NABS_32: - r = cc_calc_nabs_64(env, dst); + r = cc_calc_nabs_32(dst); break; case CC_OP_COMP_32: - r = cc_calc_comp_32(env, dst); + r = cc_calc_comp_32(dst); break; case CC_OP_ICM: - r = cc_calc_icm_32(env, src, dst); + r = cc_calc_icm_32(src, dst); break; case CC_OP_SLAG: - r = cc_calc_slag(env, src, dst); + r = cc_calc_slag(src, dst); break; case CC_OP_LTGT_F32: From 58a9e35bcc23d44142a2a58ddf3fae51749f3f01 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 13:13:09 -0700 Subject: [PATCH 0136/1634] target-s390: Convert INSERT CHARACTERS UNDER MASK Change the CC handling to be more like TEST UNDER MASK, with val & mask. This lets us handle ICMH much more like ICM. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 31 ++------- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 4 ++ target-s390x/mem_helper.c | 33 --------- target-s390x/translate.c | 136 +++++++++++++++++-------------------- 5 files changed, 74 insertions(+), 131 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 3d89fb9dbf..575f7c3e75 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -331,35 +331,18 @@ static uint32_t cc_calc_comp_32(int32_t dst) } /* calculate condition code for insert character under mask insn */ -static uint32_t cc_calc_icm_32(uint32_t mask, uint32_t val) +static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) { - uint32_t cc; - - HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); - if (mask == 0xf) { - if (!val) { - return 0; - } else if (val & 0x80000000) { + if ((val & mask) == 0) { + return 0; + } else { + int top = clz64(mask); + if ((int64_t)(val << top) < 0) { return 1; } else { return 2; } } - - if (!val || !mask) { - cc = 0; - } else { - while (mask != 1) { - mask >>= 1; - val >>= 8; - } - if (val & 0x80) { - cc = 1; - } else { - cc = 2; - } - } - return cc; } static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) @@ -488,7 +471,7 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, break; case CC_OP_ICM: - r = cc_calc_icm_32(src, dst); + r = cc_calc_icm(src, dst); break; case CC_OP_SLAG: r = cc_calc_slag(src, dst); diff --git a/target-s390x/helper.h b/target-s390x/helper.h index dcc3fce502..5a0f6965a4 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -27,7 +27,6 @@ DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) DEF_HELPER_4(stcmh, void, env, i32, i64, i32) -DEF_HELPER_4(icmh, i32, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f37e69a602..38a93e3111 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -160,6 +160,10 @@ /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) +/* INSERT CHARACTERS UNDER MASK */ + D(0xbf00, ICM, RS_b, Z, 0, a2, r1, 0, icm, 0, 0) + D(0xeb81, ICMY, RSY_b, LD, 0, a2, r1, 0, icm, 0, 0) + D(0xeb80, ICMH, RSY_b, Z, 0, a2, r1, 0, icm, 0, 32) /* INSERT IMMEDIATE */ D(0xc008, IIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2020) D(0xc009, IILF, RIL_a, EI, r1_o, i2_32u, r1, 0, insi, 0, 0x2000) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 7eb3790b40..1b63259351 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -629,39 +629,6 @@ void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, } } -/* insert character under mask high; same as icm, but operates on the - upper half of r1 */ -uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address, - uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - uint64_t rmask = 0xff00000000000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = cpu_ldub_data(env, address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 25bbf45f2c..36d8cdd102 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -32,6 +32,7 @@ #include "disas/disas.h" #include "tcg-op.h" #include "qemu/log.h" +#include "qemu/host-utils.h" /* global register indexes */ static TCGv_ptr cpu_env; @@ -561,11 +562,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_icm(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - gen_op_update2_cc_i32(s, CC_OP_ICM, v1, v2); -} - static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) { tcg_gen_extu_i32_i64(cc_src, v1); @@ -896,7 +892,6 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_LTGT0_64: case CC_OP_NZ: - case CC_OP_ICM: c->u.s64.a = cc_dst; c->u.s64.b = tcg_const_i64(0); c->g1 = true; @@ -910,6 +905,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_TM_32: case CC_OP_TM_64: + case CC_OP_ICM: c->u.s64.a = tcg_temp_new_i64(); c->u.s64.b = tcg_const_i64(0); tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); @@ -1521,18 +1517,6 @@ do_mh: tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; - case 0x80: /* ICMH R1,M3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX split CC calculation out */ - gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2361,7 +2345,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { TCGv_i64 tmp, tmp2, tmp3, tmp4; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3, tmp32_4; + TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; @@ -2786,60 +2770,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - if (r3 == 15) { - /* effectively a 32-bit load */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = tcg_const_i32(r3); - tcg_gen_qemu_ld32u(tmp, tmp, get_mem_index(s)); - store_reg32_i64(r1, tmp); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - set_cc_icm(s, tmp32_2, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - } else if (r3) { - uint32_t mask = 0x00ffffffUL; - uint32_t shift = 24; - int m3 = r3; - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tmp32_3 = tcg_const_i32(r3); - tmp32_4 = tcg_const_i32(0); - while (m3) { - if (m3 & 8) { - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - if (shift) { - tcg_gen_shli_i32(tmp32_2, tmp32_2, shift); - } - tcg_gen_andi_i32(tmp32_1, tmp32_1, mask); - tcg_gen_or_i32(tmp32_1, tmp32_1, tmp32_2); - tcg_gen_or_i32(tmp32_4, tmp32_4, tmp32_2); - tcg_gen_addi_i64(tmp, tmp, 1); - } - m3 = (m3 << 1) & 0xf; - mask = (mask >> 8) | 0xff000000UL; - shift -= 8; - } - store_reg32(r1, tmp32_1); - set_cc_icm(s, tmp32_3, tmp32_4); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - tcg_temp_free_i32(tmp32_4); - } else { - /* i.e. env->cc = 0 */ - gen_op_movi_cc(s, 0); - } - break; case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ @@ -3493,6 +3423,66 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_icm(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int pos, len, base = s->insn->data; + TCGv_i64 tmp = tcg_temp_new_i64(); + uint64_t ccm; + + switch (m3) { + case 0xf: + /* Effectively a 32-bit load. */ + tcg_gen_qemu_ld32u(tmp, o->in2, get_mem_index(s)); + len = 32; + goto one_insert; + + case 0xc: + case 0x6: + case 0x3: + /* Effectively a 16-bit load. */ + tcg_gen_qemu_ld16u(tmp, o->in2, get_mem_index(s)); + len = 16; + goto one_insert; + + case 0x8: + case 0x4: + case 0x2: + case 0x1: + /* Effectively an 8-bit load. */ + tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); + len = 8; + goto one_insert; + + one_insert: + pos = base + ctz32(m3) * 8; + tcg_gen_deposit_i64(o->out, o->out, tmp, pos, len); + ccm = ((1ull << len) - 1) << pos; + break; + + default: + /* This is going to be a sequence of loads and inserts. */ + pos = base + 32 - 8; + ccm = 0; + while (m3) { + if (m3 & 0x8) { + tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 1); + tcg_gen_deposit_i64(o->out, o->out, tmp, pos, 8); + ccm |= 0xff << pos; + } + m3 = (m3 << 1) & 0xf; + pos -= 8; + } + break; + } + + tcg_gen_movi_i64(tmp, ccm); + gen_op_update2_cc_i64(s, CC_OP_ICM, tmp, o->out); + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + static ExitStatus op_insi(DisasContext *s, DisasOps *o) { int shift = s->insn->data & 0xff; From 6e764e97ca4050f2105b10e158f4fcb2801470be Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 13:48:38 -0700 Subject: [PATCH 0137/1634] target-s390: Convert EXECUTE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 39 +++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 38a93e3111..0768849266 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -157,6 +157,11 @@ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) +/* EXECUTE */ + C(0x4400, EX, RX_a, Z, r1_o, a2, 0, 0, ex, 0) +/* EXECUTE RELATIVE LONG */ + C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) + /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 36d8cdd102..bece7c56d8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2355,19 +2355,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x44: /* EX R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_reg(r1); - tmp3 = tcg_const_i64(s->pc + 4); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_ex(cc_op, cpu_env, cc_op, tmp2, tmp, tmp3); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ insn = ld_code4(env, s->pc); tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); @@ -3423,6 +3410,32 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ex(DisasContext *s, DisasOps *o) +{ + /* ??? Perhaps a better way to implement EXECUTE is to set a bit in + tb->flags, (ab)use the tb->cs_base field as the address of + the template in memory, and grab 8 bits of tb->flags/cflags for + the contents of the register. We would then recognize all this + in gen_intermediate_code_internal, generating code for exactly + one instruction. This new TB then gets executed normally. + + On the other hand, this seems to be mostly used for modifying + MVC inside of memcpy, which needs a helper call anyway. So + perhaps this doesn't bear thinking about any further. */ + + TCGv_i64 tmp; + + update_psw_addr(s); + gen_op_calc_cc(s); + + tmp = tcg_const_i64(s->next_pc); + gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); + tcg_temp_free_i64(tmp); + + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_icm(DisasContext *s, DisasOps *o) { int m3 = get_field(s->fields, m3); From 00574261e1fcb318fdd4cc1293238fc1f50de341 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 12:26:53 -0700 Subject: [PATCH 0138/1634] target-s390: Convert FP STORE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 30 +++++++++++------------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0768849266..6b81f69032 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -315,6 +315,10 @@ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) + C(0x6000, STD, RX_a, Z, f1_o, a2, 0, 0, st64, 0) + C(0xed67, STDY, RXY_a, LD, f1_o, a2, 0, 0, st64, 0) + C(0x7000, STE, RX_a, Z, e1, a2, 0, 0, st32, 0) + C(0xed66, STEY, RXY_a, LD, e1, a2, 0, 0, st32, 0) /* STORE RELATIVE LONG */ C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index bece7c56d8..8728b36d25 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2367,25 +2367,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0x60: /* STD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = load_freg(r1); - tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 0x70: /* STE R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_freg32(r1); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ @@ -4028,6 +4009,17 @@ static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = load_reg(get_field(f, r3)); } +static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = load_freg32_i64(get_field(f, r1)); +} + +static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = fregs[get_field(f, r1)]; + o->g_in1 = true; +} + static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); From c49daa51a8e19694a611971206e75bd245768e3c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:05:11 -0700 Subject: [PATCH 0139/1634] target-s390: Convert CONVERT TO DECIMAL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6b81f69032..c5c56144fb 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -131,6 +131,10 @@ C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* CONVERT TO DECIMAL */ + C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) + C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) + /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8728b36d25..9f92954db0 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2355,18 +2355,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp32_1, regs[r1]); - gen_helper_cvd(tmp2, tmp32_1); - tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; #ifndef CONFIG_USER_ONLY case 0x80: /* SSM D2(B2) [S] */ /* Set System Mask */ @@ -3363,6 +3351,18 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_cvd(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i32 t2 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t2, o->in1); + gen_helper_cvd(t1, t2); + tcg_temp_free_i32(t2); + tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s)); + tcg_temp_free_i64(t1); + return NO_EXIT; +} + static ExitStatus op_divs32(DisasContext *s, DisasOps *o) { gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); From 7d30bb73db3a2fa38a33556430754917d5d70c91 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:12:50 -0700 Subject: [PATCH 0140/1634] target-s390: Convert SET SYSTEM MASK Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 25 +++++++++---------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c5c56144fb..45c36c1607 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -383,4 +383,6 @@ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +/* SET SYSTEM MASK */ + C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9f92954db0..246d0f0a9a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2356,22 +2356,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) switch (opc) { #ifndef CONFIG_USER_ONLY - case 0x80: /* SSM D2(B2) [S] */ - /* Set System Mask */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_andi_i64(tmp3, psw_mask, ~0xff00000000000000ULL); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - tcg_gen_shli_i64(tmp2, tmp2, 56); - tcg_gen_or_i64(psw_mask, tmp3, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x82: /* LPSW D2(B2) [S] */ /* Load PSW */ check_privileged(s); @@ -3607,6 +3591,15 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_ssm(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); + return NO_EXIT; +} +#endif + static ExitStatus op_st8(DisasContext *s, DisasOps *o) { tcg_gen_qemu_st8(o->in1, o->in2, get_mem_index(s)); From 8b5ff57115e60589d772efeaa0c061ad6701e340 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:33:36 -0700 Subject: [PATCH 0141/1634] target-s390: Convert LOAD PSW Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 41 +++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 45c36c1607..b0bee9baf0 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -379,6 +379,8 @@ D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) #ifndef CONFIG_USER_ONLY +/* LOAD PSW */ + C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 246d0f0a9a..cbfcf41427 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2356,26 +2356,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) switch (opc) { #ifndef CONFIG_USER_ONLY - case 0x82: /* LPSW D2(B2) [S] */ - /* Load PSW */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_addi_i64(tmp, tmp, 4); - tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); - /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ - tcg_gen_shli_i64(tmp2, tmp2, 32); - gen_helper_load_psw(cpu_env, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - /* we need to keep cc_op intact */ - s->is_jmp = DISAS_JUMP; - break; case 0x83: /* DIAG R1,R3,D2 [RS] */ /* Diagnose call (KVM hypercall) */ check_privileged(s); @@ -3511,6 +3491,27 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1, t2; + + check_privileged(s); + + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 4); + tcg_gen_qemu_ld32u(t2, o->in2, get_mem_index(s)); + /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ + tcg_gen_shli_i64(t1, t1, 32); + gen_helper_load_psw(cpu_env, t1, t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return EXIT_NORETURN; +} +#endif + static ExitStatus op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; From 972e35b9665db113c3d4df7d394ee8cbbf7446ee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Aug 2012 14:41:36 -0700 Subject: [PATCH 0142/1634] target-s390: Convert DIAGNOSE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 33 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b0bee9baf0..0a0ec0a0c7 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -379,6 +379,8 @@ D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) #ifndef CONFIG_USER_ONLY +/* DIAGNOSE (KVM hypercall) */ + C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* SET ADDRESSING MODE */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index cbfcf41427..6848e31432 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2355,23 +2355,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { -#ifndef CONFIG_USER_ONLY - case 0x83: /* DIAG R1,R3,D2 [RS] */ - /* Diagnose call (KVM hypercall) */ - check_privileged(s); - potential_page_fault(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp32_1 = tcg_const_i32(insn & 0xfff); - tmp2 = load_reg(2); - tmp3 = load_reg(1); - gen_helper_diag(tmp2, cpu_env, tmp32_1, tmp2, tmp3); - store_reg(2, tmp2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; -#endif case 0x88: /* SRL R1,D2(B2) [RS] */ case 0x89: /* SLL R1,D2(B2) [RS] */ case 0x8a: /* SRA R1,D2(B2) [RS] */ @@ -3327,6 +3310,22 @@ static ExitStatus op_cvd(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_diag(DisasContext *s, DisasOps *o) +{ + TCGv_i32 tmp; + + check_privileged(s); + potential_page_fault(s); + + /* We pretend the format is RX_a so that D2 is the field we want. */ + tmp = tcg_const_i32(get_field(s->fields, d2) & 0xfff); + gen_helper_diag(regs[2], cpu_env, tmp, regs[2], regs[1]); + tcg_temp_free_i32(tmp); + return NO_EXIT; +} +#endif + static ExitStatus op_divs32(DisasContext *s, DisasOps *o) { gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2); From cbe24bfa91d21766f2953c2da92c1e3dd13d8387 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 09:15:19 -0700 Subject: [PATCH 0143/1634] target-s390: Convert SHIFT, ROTATE SINGLE Note that we were missing the 32-bit SLA. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 56 +++++++--- target-s390x/cpu.h | 6 +- target-s390x/insn-data.def | 21 ++++ target-s390x/translate.c | 207 +++++++++++++++++++------------------ 4 files changed, 176 insertions(+), 114 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 575f7c3e75..be4202a78e 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -345,34 +345,59 @@ static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) } } -static uint32_t cc_calc_slag(uint64_t src, uint64_t shift) +static uint32_t cc_calc_sla_32(uint32_t src, int shift) { - uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); - uint64_t match, r; + uint32_t mask = ((1U << shift) - 1U) << (32 - shift); + uint32_t sign = 1U << 31; + uint32_t match; + int32_t r; - /* check if the sign bit stays the same */ - if (src & (1ULL << 63)) { + /* Check if the sign bit stays the same. */ + if (src & sign) { match = mask; } else { match = 0; } - if ((src & mask) != match) { - /* overflow */ + /* Overflow. */ return 3; } - r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); - - if ((int64_t)r == 0) { + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { return 0; - } else if ((int64_t)r < 0) { + } else if (r < 0) { return 1; } - return 2; } +static uint32_t cc_calc_sla_64(uint64_t src, int shift) +{ + uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); + uint64_t sign = 1ULL << 63; + uint64_t match; + int64_t r; + + /* Check if the sign bit stays the same. */ + if (src & sign) { + match = mask; + } else { + match = 0; + } + if ((src & mask) != match) { + /* Overflow. */ + return 3; + } + + r = ((src << shift) & ~sign) | (src & sign); + if (r == 0) { + return 0; + } else if (r < 0) { + return 1; + } + return 2; +} static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) @@ -473,8 +498,11 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_ICM: r = cc_calc_icm(src, dst); break; - case CC_OP_SLAG: - r = cc_calc_slag(src, dst); + case CC_OP_SLA_32: + r = cc_calc_sla_32(src, dst); + break; + case CC_OP_SLA_64: + r = cc_calc_sla_64(src, dst); break; case CC_OP_LTGT_F32: diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 69269a14ca..b8e9037eeb 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -478,7 +478,8 @@ enum cc_op { CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ CC_OP_ICM, /* insert characters under mask */ - CC_OP_SLAG, /* Calculate shift left signed */ + CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ + CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ CC_OP_MAX }; @@ -521,7 +522,8 @@ static const char *cc_names[] = { [CC_OP_NZ_F32] = "CC_OP_NZ_F32", [CC_OP_NZ_F64] = "CC_OP_NZ_F64", [CC_OP_ICM] = "CC_OP_ICM", - [CC_OP_SLAG] = "CC_OP_SLAG", + [CC_OP_SLA_32] = "CC_OP_SLA_32", + [CC_OP_SLA_64] = "CC_OP_SLA_64", }; static inline const char *cc_name(int cc_op) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0a0ec0a0c7..6020e04e0b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -315,6 +315,27 @@ D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) +/* ROTATE LEFT SINGLE LOGICAL */ + C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) + C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) + +/* SHIFT LEFT SINGLE */ + D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) + D(0xebdd, SLAK, RSY_a, DO, r3, sh32, new, r1_32, sla, 0, 31) + D(0xeb0b, SLAG, RSY_a, Z, r3, sh64, r1, 0, sla, 0, 63) +/* SHIFT LEFT SINGLE LOGICAL */ + C(0x8900, SLL, RS_a, Z, r1_o, sh32, new, r1_32, sll, 0) + C(0xebdf, SLLK, RSY_a, DO, r3_o, sh32, new, r1_32, sll, 0) + C(0xeb0d, SLLG, RSY_a, Z, r3_o, sh64, r1, 0, sll, 0) +/* SHIFT RIGHT SINGLE */ + C(0x8a00, SRA, RS_a, Z, r1_32s, sh32, new, r1_32, sra, s32) + C(0xebdc, SRAK, RSY_a, DO, r3_32s, sh32, new, r1_32, sra, s32) + C(0xeb0a, SRAG, RSY_a, Z, r3_o, sh64, r1, 0, sra, s64) +/* SHIFT RIGHT SINGLE LOGICAL */ + C(0x8800, SRL, RS_a, Z, r1_32u, sh32, new, r1_32, srl, 0) + C(0xebde, SRLK, RSY_a, DO, r3_32u, sh32, new, r1_32, srl, 0) + C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh64, r1, 0, srl, 0) + /* STORE */ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6848e31432..bb3721d30b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -636,7 +636,8 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_TM_64: case CC_OP_LTGT_F32: case CC_OP_LTGT_F64: - case CC_OP_SLAG: + case CC_OP_SLA_32: + case CC_OP_SLA_64: /* 2 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; @@ -1330,74 +1331,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); switch (op) { - case 0xc: /* SRLG R1,R3,D2(B2) [RSY] */ - case 0xd: /* SLLG R1,R3,D2(B2) [RSY] */ - case 0xa: /* SRAG R1,R3,D2(B2) [RSY] */ - case 0xb: /* SLAG R1,R3,D2(B2) [RSY] */ - case 0x1c: /* RLLG R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - switch (op) { - case 0xc: - tcg_gen_shr_i64(regs[r1], regs[r3], tmp); - break; - case 0xd: - tcg_gen_shl_i64(regs[r1], regs[r3], tmp); - break; - case 0xa: - tcg_gen_sar_i64(regs[r1], regs[r3], tmp); - break; - case 0xb: - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - gen_op_update2_cc_i64(s, CC_OP_SLAG, regs[r3], tmp); - tcg_gen_shl_i64(tmp2, regs[r3], tmp); - /* override sign bit with source sign */ - tcg_gen_andi_i64(tmp2, tmp2, ~0x8000000000000000ULL); - tcg_gen_andi_i64(tmp3, regs[r3], 0x8000000000000000ULL); - tcg_gen_or_i64(regs[r1], tmp2, tmp3); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; - case 0x1c: - tcg_gen_rotl_i64(regs[r1], regs[r3], tmp); - break; - default: - tcg_abort(); - break; - } - if (op == 0xa) { - set_cc_s64(s, regs[r1]); - } - tcg_temp_free_i64(tmp); - break; - case 0x1d: /* RLL R1,R3,D2(B2) [RSY] */ - if (b2) { - tmp = get_address(s, 0, b2, d2); - tcg_gen_andi_i64(tmp, tmp, 0x3f); - } else { - tmp = tcg_const_i64(d2 & 0x3f); - } - tmp32_1 = tcg_temp_new_i32(); - tmp32_2 = load_reg32(r3); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - switch (op) { - case 0x1d: - tcg_gen_rotl_i32(tmp32_1, tmp32_2, tmp32_1); - break; - default: - tcg_abort(); - break; - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x4: /* LMG R1,R3,D2(B2) [RSE] */ case 0x24: /* STMG R1,R3,D2(B2) [RSE] */ stm_len = 8; @@ -2355,35 +2288,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x88: /* SRL R1,D2(B2) [RS] */ - case 0x89: /* SLL R1,D2(B2) [RS] */ - case 0x8a: /* SRA R1,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(tmp32_2, tmp); - tcg_gen_andi_i32(tmp32_2, tmp32_2, 0x3f); - switch (opc) { - case 0x88: - tcg_gen_shr_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x89: - tcg_gen_shl_i32(tmp32_1, tmp32_1, tmp32_2); - break; - case 0x8a: - tcg_gen_sar_i32(tmp32_1, tmp32_1, tmp32_2); - set_cc_s32(s, tmp32_1); - break; - default: - tcg_abort(); - } - store_reg32(r1, tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x8c: /* SRDL R1,D2(B2) [RS] */ case 0x8d: /* SLDL R1,D2(B2) [RS] */ case 0x8e: /* SRDA R1,D2(B2) [RS] */ @@ -3029,6 +2933,20 @@ struct DisasInsn { /* ====================================================================== */ /* Miscelaneous helpers, used by several operations. */ +static void help_l2_shift(DisasContext *s, DisasFields *f, + DisasOps *o, int mask) +{ + int b2 = get_field(f, b2); + int d2 = get_field(f, d2); + + if (b2 == 0) { + o->in2 = tcg_const_i64(d2 & mask); + } else { + o->in2 = get_address(s, 0, b2, d2); + tcg_gen_andi_i64(o->in2, o->in2, mask); + } +} + static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) { if (dest == s->next_pc) { @@ -3591,6 +3509,59 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_rll32(DisasContext *s, DisasOps *o) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 to = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, o->in1); + tcg_gen_trunc_i64_i32(t2, o->in2); + tcg_gen_rotl_i32(to, t1, t2); + tcg_gen_extu_i32_i64(o->out, to); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(to); + return NO_EXIT; +} + +static ExitStatus op_rll64(DisasContext *s, DisasOps *o) +{ + tcg_gen_rotl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sla(DisasContext *s, DisasOps *o) +{ + uint64_t sign = 1ull << s->insn->data; + enum cc_op cco = s->insn->data == 31 ? CC_OP_SLA_32 : CC_OP_SLA_64; + gen_op_update2_cc_i64(s, cco, o->in1, o->in2); + tcg_gen_shl_i64(o->out, o->in1, o->in2); + /* The arithmetic left shift is curious in that it does not affect + the sign bit. Copy that over from the source unchanged. */ + tcg_gen_andi_i64(o->out, o->out, ~sign); + tcg_gen_andi_i64(o->in1, o->in1, sign); + tcg_gen_or_i64(o->out, o->out, o->in1); + return NO_EXIT; +} + +static ExitStatus op_sll(DisasContext *s, DisasOps *o) +{ + tcg_gen_shl_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sra(DisasContext *s, DisasOps *o) +{ + tcg_gen_sar_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_srl(DisasContext *s, DisasOps *o) +{ + tcg_gen_shr_i64(o->out, o->in1, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { @@ -3961,6 +3932,18 @@ static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_r1_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1)]); +} + +static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); +} + static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ @@ -4002,6 +3985,24 @@ static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = load_reg(get_field(f, r3)); } +static void in1_r3_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = regs[get_field(f, r3)]; + o->g_in1 = true; +} + +static void in1_r3_32s(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r3)]); +} + +static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r3)]); +} + static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_freg32_i64(get_field(f, r1)); @@ -4153,6 +4154,16 @@ static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); } +static void in2_sh32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 31); +} + +static void in2_sh64(DisasContext *s, DisasFields *f, DisasOps *o) +{ + help_l2_shift(s, f, o, 63); +} + static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From a79ba3398a0aa7fdd544ce28d2950b4eeb3c16a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 09:22:23 -0700 Subject: [PATCH 0144/1634] target-s390: Convert SHIFT DOUBLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 8 ++++++++ target-s390x/translate.c | 30 ------------------------------ 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6020e04e0b..50a176476c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -335,6 +335,14 @@ C(0x8800, SRL, RS_a, Z, r1_32u, sh32, new, r1_32, srl, 0) C(0xebde, SRLK, RSY_a, DO, r3_32u, sh32, new, r1_32, srl, 0) C(0xeb0c, SRLG, RSY_a, Z, r3_o, sh64, r1, 0, srl, 0) +/* SHIFT LEFT DOUBLE */ + D(0x8f00, SLDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sla, 0, 31) +/* SHIFT LEFT DOUBLE LOGICAL */ + C(0x8d00, SLDL, RS_a, Z, r1_D32, sh64, new, r1_D32, sll, 0) +/* SHIFT RIGHT DOUBLE */ + C(0x8e00, SRDA, RS_a, Z, r1_D32, sh64, new, r1_D32, sra, s64) +/* SHIFT RIGHT DOUBLE LOGICAL */ + C(0x8c00, SRDL, RS_a, Z, r1_D32, sh64, new, r1_D32, srl, 0) /* STORE */ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index bb3721d30b..54cd2fa1de 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2288,36 +2288,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x8c: /* SRDL R1,D2(B2) [RS] */ - case 0x8d: /* SLDL R1,D2(B2) [RS] */ - case 0x8e: /* SRDA R1,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); /* shift */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = load_reg32(r1); - tmp32_2 = load_reg32(r1 + 1); - tcg_gen_concat_i32_i64(tmp2, tmp32_2, tmp32_1); /* operand */ - switch (opc) { - case 0x8c: - tcg_gen_shr_i64(tmp2, tmp2, tmp); - break; - case 0x8d: - tcg_gen_shl_i64(tmp2, tmp2, tmp); - break; - case 0x8e: - tcg_gen_sar_i64(tmp2, tmp2, tmp); - set_cc_s64(s, tmp2); - break; - } - tcg_gen_shri_i64(tmp, tmp2, 32); - tcg_gen_trunc_i64_i32(tmp32_1, tmp); - store_reg32(r1, tmp32_1); - tcg_gen_trunc_i64_i32(tmp32_2, tmp2); - store_reg32(r1 + 1, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x98: /* LM R1,R3,D2(B2) [RS] */ case 0x90: /* STM R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); From 77f8d6c3ed89ee02847709da6508cd4dcc1d2f2d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 09:49:37 -0700 Subject: [PATCH 0145/1634] target-s390: Convert LOAD, STORE MULTIPLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 14 +++ target-s390x/translate.c | 212 +++++++++++++++++++++---------------- 2 files changed, 137 insertions(+), 89 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 50a176476c..393b425f21 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -269,6 +269,13 @@ C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) +/* LOAD MULTIPLE */ + C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) + C(0xeb98, LMY, RSY_a, LD, 0, a2, 0, 0, lm32, 0) + C(0xeb04, LMG, RSY_a, Z, 0, a2, 0, 0, lm64, 0) +/* LOAD MULTIPLE HIGH */ + C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) + /* MOVE LONG */ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) @@ -364,6 +371,13 @@ /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE MULTIPLE */ + D(0x9000, STM, RS_a, Z, 0, a2, 0, 0, stm, 0, 4) + D(0xeb90, STMY, RSY_a, LD, 0, a2, 0, 0, stm, 0, 4) + D(0xeb24, STMG, RSY_a, Z, 0, a2, 0, 0, stm, 0, 8) +/* STORE MULTIPLE HIGH */ + C(0xeb26, STMH, RSY_a, Z, 0, a2, 0, 0, stmh, 0) + /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0xb9f9, SRK, RRF_a, DO, r2, r3, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 54cd2fa1de..118f832141 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -273,6 +273,11 @@ static inline void store_reg32_i64(int reg, TCGv_i64 v) tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); } +static inline void store_reg32h_i64(int reg, TCGv_i64 v) +{ + tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); +} + static inline void store_reg16(int reg, TCGv_i32 v) { /* 16 bit register writes keep the upper bytes */ @@ -1324,65 +1329,12 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, int r3, int b2, int d2) { - TCGv_i64 tmp, tmp2, tmp3, tmp4; + TCGv_i64 tmp, tmp2; TCGv_i32 tmp32_1, tmp32_2; - int i, stm_len; LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); switch (op) { - case 0x4: /* LMG R1,R3,D2(B2) [RSE] */ - case 0x24: /* STMG R1,R3,D2(B2) [RSE] */ - stm_len = 8; - goto do_mh; - case 0x26: /* STMH R1,R3,D2(B2) [RSE] */ - case 0x96: /* LMH R1,R3,D2(B2) [RSE] */ - stm_len = 4; -do_mh: - /* Apparently, unrolling lmg/stmg of any size gains performance - - even for very long ones... */ - tmp = get_address(s, 0, b2, d2); - tmp3 = tcg_const_i64(stm_len); - tmp4 = tcg_const_i64(op == 0x26 ? 32 : 4); - for (i = r1;; i = (i + 1) % 16) { - switch (op) { - case 0x4: - tcg_gen_qemu_ld64(regs[i], tmp, get_mem_index(s)); - break; - case 0x96: - tmp2 = tcg_temp_new_i64(); -#if HOST_LONG_BITS == 32 - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(TCGV_HIGH(regs[i]), tmp2); -#else - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_shl_i64(tmp2, tmp2, tmp4); - tcg_gen_ext32u_i64(regs[i], regs[i]); - tcg_gen_or_i64(regs[i], regs[i], tmp2); -#endif - tcg_temp_free_i64(tmp2); - break; - case 0x24: - tcg_gen_qemu_st64(regs[i], tmp, get_mem_index(s)); - break; - case 0x26: - tmp2 = tcg_temp_new_i64(); - tcg_gen_shr_i64(tmp2, regs[i], tmp4); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; - default: - tcg_abort(); - } - if (i == r3) { - break; - } - tcg_gen_add_i64(tmp, tmp, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ tmp = get_address(s, 0, b2, d2); tmp32_1 = tcg_const_i32(r1); @@ -2277,44 +2229,17 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { - TCGv_i64 tmp, tmp2, tmp3, tmp4; + TCGv_i64 tmp, tmp2; TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d1, d2, x2, b1, b2, i, i2, r1b; + int op, r1, r2, r3, d1, d2, x2, b1, b2, i2, r1b; TCGv_i32 vl; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x98: /* LM R1,R3,D2(B2) [RS] */ - case 0x90: /* STM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_const_i64(4); - tmp4 = tcg_const_i64(0xffffffff00000000ULL); - for (i = r1;; i = (i + 1) % 16) { - if (opc == 0x98) { - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_and_i64(regs[i], regs[i], tmp4); - tcg_gen_or_i64(regs[i], regs[i], tmp2); - } else { - tcg_gen_qemu_st32(regs[i], tmp, get_mem_index(s)); - } - if (i == r3) { - break; - } - tcg_gen_add_i64(tmp, tmp, tmp3); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - tcg_temp_free_i64(tmp4); - break; case 0x92: /* MVI D1(B1),I2 [SI] */ insn = ld_code4(env, s->pc); tmp = decode_si(s, insn, &i2, &b1, &d1); @@ -2611,19 +2536,17 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) d1 = (insn >> 16) & 0xfff; b2 = (insn >> 12) & 0xf; d2 = insn & 0xfff; - tmp = load_reg(r1); /* XXX key in r3 */ - tmp2 = get_address(s, 0, b1, d1); - tmp3 = get_address(s, 0, b2, d2); + tmp = get_address(s, 0, b1, d1); + tmp2 = get_address(s, 0, b2, d2); if (opc == 0xda) { - gen_helper_mvcp(cc_op, cpu_env, tmp, tmp2, tmp3); + gen_helper_mvcp(cc_op, cpu_env, regs[r1], tmp, tmp2); } else { - gen_helper_mvcs(cc_op, cpu_env, tmp, tmp2, tmp3); + gen_helper_mvcs(cc_op, cpu_env, regs[r1], tmp, tmp2); } set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); break; #endif case 0xe3: @@ -3399,6 +3322,69 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_lm32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + + while (1) { + tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); + store_reg32_i64(r1, t); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + return NO_EXIT; +} + +static ExitStatus op_lmh(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + + while (1) { + tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); + store_reg32h_i64(r1, t); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + return NO_EXIT; +} + +static ExitStatus op_lm64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t8 = tcg_const_i64(8); + + while (1) { + tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t8); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t8); + return NO_EXIT; +} + static ExitStatus op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; @@ -3565,6 +3551,54 @@ static ExitStatus op_st64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stm(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + int size = s->insn->data; + TCGv_i64 tsize = tcg_const_i64(size); + + while (1) { + if (size == 8) { + tcg_gen_qemu_st64(regs[r1], o->in2, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(regs[r1], o->in2, get_mem_index(s)); + } + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, tsize); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(tsize); + return NO_EXIT; +} + +static ExitStatus op_stmh(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i64 t = tcg_temp_new_i64(); + TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 t32 = tcg_const_i64(32); + + while (1) { + tcg_gen_shl_i64(t, regs[r1], t32); + tcg_gen_qemu_st32(t, o->in2, get_mem_index(s)); + if (r1 == r3) { + break; + } + tcg_gen_add_i64(o->in2, o->in2, t4); + r1 = (r1 + 1) & 15; + } + + tcg_temp_free_i64(t); + tcg_temp_free_i64(t4); + tcg_temp_free_i64(t32); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); From 6a04d76a815c7daeb9f27b7503ebddce311958fe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 10:22:28 -0700 Subject: [PATCH 0146/1634] target-s390: Convert MOVE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 ++++++ target-s390x/translate.c | 27 +++++++++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 393b425f21..c971308585 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -276,6 +276,12 @@ /* LOAD MULTIPLE HIGH */ C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) +/* MOVE */ + C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) + C(0xe54c, MVHI, SIL, GIE, la1, i2, 0, m1_32, mov2, 0) + C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) + C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0) + C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) /* MOVE LONG */ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 118f832141..0ea50431c4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1329,7 +1329,7 @@ static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, int r3, int b2, int d2) { - TCGv_i64 tmp, tmp2; + TCGv_i64 tmp; TCGv_i32 tmp32_1, tmp32_2; LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", @@ -1395,13 +1395,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x52: /* MVIY D1(B1),I2 [SIY] */ - tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */ - tmp2 = tcg_const_i64((r1 << 4) | r3); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2240,14 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x92: /* MVI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_const_i64(i2); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x94: /* NI D1(B1),I2 [SI] */ case 0x96: /* OI D1(B1),I2 [SI] */ case 0x97: /* XI D1(B1),I2 [SI] */ @@ -3912,6 +3897,16 @@ static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) } } +static void wout_m1_8(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s)); +} + +static void wout_m1_16(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s)); +} + static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); From a05d2b6b83544dd0ae915112d7a4565e8a3871f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 10:57:56 -0700 Subject: [PATCH 0147/1634] target-s390: Convert NI, XI, OI Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 ++++++ target-s390x/translate.c | 25 ------------------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c971308585..2383a366b3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -61,6 +61,8 @@ D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) + C(0x9400, NI, SI, Z, m1_8u, i2_8u, new, m1_8, and, nz64) + C(0xeb54, NIY, SIY, LD, m1_8u, i2_8u, new, m1_8, and, nz64) /* BRANCH AND SAVE */ C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) @@ -160,6 +162,8 @@ /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) + C(0x9700, XI, SI, Z, m1_8u, i2_8u, new, m1_8, xor, nz64) + C(0xeb57, XIY, SIY, LD, m1_8u, i2_8u, new, m1_8, xor, nz64) /* EXECUTE */ C(0x4400, EX, RX_a, Z, r1_o, a2, 0, 0, ex, 0) @@ -327,6 +331,8 @@ D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) + C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) + C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) /* ROTATE LEFT SINGLE LOGICAL */ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0ea50431c4..78c29cf70b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2233,31 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x94: /* NI D1(B1),I2 [SI] */ - case 0x96: /* OI D1(B1),I2 [SI] */ - case 0x97: /* XI D1(B1),I2 [SI] */ - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); - switch (opc) { - case 0x94: - tcg_gen_andi_i64(tmp2, tmp2, i2); - break; - case 0x96: - tcg_gen_ori_i64(tmp2, tmp2, i2); - break; - case 0x97: - tcg_gen_xori_i64(tmp2, tmp2, i2); - break; - default: - tcg_abort(); - } - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - set_cc_nz_u64(s, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); From 145cdb401995707d1261735da7f6be3d4a91d377 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:08:40 -0700 Subject: [PATCH 0148/1634] target-s390: Convert STNSM, STOSM Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 43 ++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2383a366b3..9859b3b701 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -444,4 +444,8 @@ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) +/* STORE THEN AND SYSTEM MASK */ + C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* STORE THEN OR SYSTEM MASK */ + C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 78c29cf70b..8425c51be2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2226,7 +2226,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d1, d2, x2, b1, b2, i2, r1b; + int op, r1, r2, r3, d1, d2, x2, b1, b2, r1b; TCGv_i32 vl; opc = cpu_ldub_code(env, s->pc); @@ -2284,23 +2284,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_2); break; #ifndef CONFIG_USER_ONLY - case 0xac: /* STNSM D1(B1),I2 [SI] */ - case 0xad: /* STOSM D1(B1),I2 [SI] */ - check_privileged(s); - insn = ld_code4(env, s->pc); - tmp = decode_si(s, insn, &i2, &b1, &d1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_shri_i64(tmp2, psw_mask, 56); - tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); - if (opc == 0xac) { - tcg_gen_andi_i64(psw_mask, psw_mask, - ((uint64_t)i2 << 56) | 0x00ffffffffffffffULL); - } else { - tcg_gen_ori_i64(psw_mask, psw_mask, (uint64_t)i2 << 56); - } - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ check_privileged(s); insn = ld_code4(env, s->pc); @@ -3485,6 +3468,30 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); return NO_EXIT; } + +static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) +{ + uint64_t i2 = get_field(s->fields, i2); + TCGv_i64 t; + + check_privileged(s); + + /* It is important to do what the instruction name says: STORE THEN. + If we let the output hook perform the store then if we fault and + restart, we'll have the wrong SYSTEM MASK in place. */ + t = tcg_temp_new_i64(); + tcg_gen_shri_i64(t, psw_mask, 56); + tcg_gen_qemu_st8(t, o->addr1, get_mem_index(s)); + tcg_temp_free_i64(t); + + if (s->fields->op == 0xac) { + tcg_gen_andi_i64(psw_mask, psw_mask, + (i2 << 56) | 0x00ffffffffffffffull); + } else { + tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56); + } + return NO_EXIT; +} #endif static ExitStatus op_st8(DisasContext *s, DisasOps *o) From 7df3e93aa953148841bd8a086cb3230f3d01a14c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 09:38:22 -0700 Subject: [PATCH 0149/1634] target-s390: Convert LAM, STAM Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 +++++ target-s390x/translate.c | 46 ++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 9859b3b701..2e09838ba8 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -279,6 +279,9 @@ C(0xeb04, LMG, RSY_a, Z, 0, a2, 0, 0, lm64, 0) /* LOAD MULTIPLE HIGH */ C(0xeb96, LMH, RSY_a, Z, 0, a2, 0, 0, lmh, 0) +/* LOAD ACCESS MULTIPLE */ + C(0x9a00, LAM, RS_a, Z, 0, a2, 0, 0, lam, 0) + C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) /* MOVE */ C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) @@ -389,6 +392,9 @@ D(0xeb24, STMG, RSY_a, Z, 0, a2, 0, 0, stm, 0, 8) /* STORE MULTIPLE HIGH */ C(0xeb26, STMH, RSY_a, Z, 0, a2, 0, 0, stmh, 0) +/* STORE ACCESS MULTIPLE */ + C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0) + C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0) /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8425c51be2..b2a258f5ce 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2233,30 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lam(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x9b: /* STAM R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stam(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -3265,6 +3241,17 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_lam(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_lam(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_lm32(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); @@ -3518,6 +3505,17 @@ static ExitStatus op_st64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stam(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_stam(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_stm(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); From eb66e6a96904e50a9d0d1a76aecfe8675f4d8673 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:24:25 -0700 Subject: [PATCH 0150/1634] target-s390: Convert CLCLE, MVCLE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 +++ target-s390x/translate.c | 50 ++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2e09838ba8..4d7f862e29 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -132,6 +132,8 @@ C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL LONG EXTENDED */ + C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) @@ -291,6 +293,8 @@ C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) /* MOVE LONG */ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) +/* MOVE LONG EXTENDED */ + C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b2a258f5ce..38eeeadf7f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2233,32 +2233,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { - case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_mvcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xa9: /* CLCLE R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_clcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; #ifndef CONFIG_USER_ONLY case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ check_privileged(s); @@ -3028,6 +3002,18 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_clcle(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_clcle(cc_op, cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_cvd(DisasContext *s, DisasOps *o) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -3348,6 +3334,18 @@ static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + gen_helper_mvcle(cc_op, cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From af9e5a04ea63b7ebbe7af2bb3553dc0e8a158d12 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:43:06 -0700 Subject: [PATCH 0151/1634] target-s390: Convert MVC The code that was in gen_op_mvc was a bit confused wrt what lengths it wanted to handle. I also disbelieve that the inline memset is worthwhile. Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 1 + target-s390x/translate.c | 177 ++----------------------------------- 2 files changed, 10 insertions(+), 168 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4d7f862e29..a8056a87c9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -286,6 +286,7 @@ C(0xeb9a, LAMY, RSY_a, LD, 0, a2, 0, 0, lam, 0) /* MOVE */ + C(0xd200, MVC, SS_a, Z, la1, a2, 0, 0, mvc, 0) C(0xe544, MVHHI, SIL, GIE, la1, i2, 0, m1_16, mov2, 0) C(0xe54c, MVHI, SIL, GIE, la1, i2, 0, m1_32, mov2, 0) C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 38eeeadf7f..294cb92fe2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1012,170 +1012,6 @@ static void free_compare(DisasCompare *c) } } -static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) -{ - TCGv_i64 tmp, tmp2; - int i; - int l_memset = gen_new_label(); - int l_out = gen_new_label(); - TCGv_i64 dest = tcg_temp_local_new_i64(); - TCGv_i64 src = tcg_temp_local_new_i64(); - TCGv_i32 vl; - - /* Find out if we should use the inline version of mvc */ - switch (l) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 11: - case 15: - /* use inline */ - break; - default: - /* Fall back to helper */ - vl = tcg_const_i32(l); - potential_page_fault(s); - gen_helper_mvc(cpu_env, vl, s1, s2); - tcg_temp_free_i32(vl); - return; - } - - tcg_gen_mov_i64(dest, s1); - tcg_gen_mov_i64(src, s2); - - if (!(s->tb->flags & FLAG_MASK_64)) { - /* XXX what if we overflow while moving? */ - tcg_gen_andi_i64(dest, dest, 0x7fffffffUL); - tcg_gen_andi_i64(src, src, 0x7fffffffUL); - } - - tmp = tcg_temp_new_i64(); - tcg_gen_addi_i64(tmp, src, 1); - tcg_gen_brcond_i64(TCG_COND_EQ, dest, tmp, l_memset); - tcg_temp_free_i64(tmp); - - switch (l) { - case 0: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - case 1: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld16u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st16(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - case 3: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st32(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - case 4: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld32u(tmp, src, get_mem_index(s)); - tcg_gen_addi_i64(src, src, 4); - tcg_gen_qemu_ld8u(tmp2, src, get_mem_index(s)); - tcg_gen_qemu_st32(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 4); - tcg_gen_qemu_st8(tmp2, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - case 7: - tmp = tcg_temp_new_i64(); - - tcg_gen_qemu_ld64(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - - tcg_temp_free_i64(tmp); - break; - default: - /* The inline version can become too big for too uneven numbers, only - use it on known good lengths */ - tmp = tcg_temp_new_i64(); - tmp2 = tcg_const_i64(8); - for (i = 0; (i + 7) <= l; i += 8) { - tcg_gen_qemu_ld64(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - - tcg_gen_add_i64(src, src, tmp2); - tcg_gen_add_i64(dest, dest, tmp2); - } - - tcg_temp_free_i64(tmp2); - tmp2 = tcg_const_i64(1); - - for (; i <= l; i++) { - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); - - tcg_gen_add_i64(src, src, tmp2); - tcg_gen_add_i64(dest, dest, tmp2); - } - - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; - } - - tcg_gen_br(l_out); - - gen_set_label(l_memset); - /* memset case (dest == (src + 1)) */ - - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - /* fill tmp with the byte */ - tcg_gen_qemu_ld8u(tmp, src, get_mem_index(s)); - tcg_gen_shli_i64(tmp2, tmp, 8); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_gen_shli_i64(tmp2, tmp, 16); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_gen_shli_i64(tmp2, tmp, 32); - tcg_gen_or_i64(tmp, tmp, tmp2); - tcg_temp_free_i64(tmp2); - - tmp2 = tcg_const_i64(8); - - for (i = 0; (i + 7) <= l; i += 8) { - tcg_gen_qemu_st64(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 8); - } - - tcg_temp_free_i64(tmp2); - tmp2 = tcg_const_i64(1); - - for (; i <= l; i++) { - tcg_gen_qemu_st8(tmp, dest, get_mem_index(s)); - tcg_gen_addi_i64(dest, dest, 1); - } - - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - - gen_set_label(l_out); - - tcg_temp_free(dest); - tcg_temp_free(src); -} - static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) { TCGv_i64 tmp; @@ -2365,7 +2201,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd2: /* MVC D1(L,B1),D2(B2) [SS] */ case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ @@ -2381,9 +2216,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tmp = get_address(s, 0, b1, d1); tmp2 = get_address(s, 0, b2, d2); switch (opc) { - case 0xd2: - gen_op_mvc(s, (insn >> 32) & 0xff, tmp, tmp2); - break; case 0xd4: potential_page_fault(s); gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); @@ -3322,6 +3154,15 @@ static ExitStatus op_movx(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_mvc(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From 0a949039596edf43e5e32dc7cb0cb4e994497e4b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 11:54:19 -0700 Subject: [PATCH 0152/1634] target-s390: Convert NC, XC, OC, TR, UNPK Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 11 +++++ target-s390x/translate.c | 88 ++++++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a8056a87c9..015a7f52ce 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -54,6 +54,7 @@ C(0xb980, NGR, RRE, Z, r1, r2, r1, 0, and, nz64) C(0xb9e4, NGRK, RRF_a, DO, r2, r3, r1, 0, and, nz64) C(0xe380, NG, RXY_a, Z, r1, m2_64, r1, 0, and, nz64) + C(0xd400, NC, SS_a, Z, la1, a2, 0, 0, nc, 0) /* AND IMMEDIATE */ D(0xc00a, NIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2020) D(0xc00b, NILF, RIL_a, EI, r1_o, i2_32u, r1, 0, andi, 0, 0x2000) @@ -161,6 +162,7 @@ C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) + C(0xd700, XC, SS_a, Z, la1, a2, 0, 0, xc, 0) /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) @@ -332,6 +334,7 @@ C(0xb981, OGR, RRE, Z, r1, r2, r1, 0, or, nz64) C(0xb9e6, OGRK, RRF_a, DO, r2, r3, r1, 0, or, nz64) C(0xe381, OG, RXY_a, Z, r1, m2_64, r1, 0, or, nz64) + C(0xd600, OC, SS_a, Z, la1, a2, 0, 0, oc, 0) /* OR IMMEDIATE */ D(0xc00c, OIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2020) D(0xc00d, OILF, RIL_a, EI, r1_o, i2_32u, r1, 0, ori, 0, 0x2000) @@ -444,6 +447,14 @@ D(0xa700, TMLH, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 16) D(0xa701, TMLL, RI_a, Z, r1_o, i2_16u_shl, 0, 0, 0, tm64, 0) +/* TRANSLATE */ + C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0) + +/* UNPACK */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) + #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 294cb92fe2..36705a2f8f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2063,7 +2063,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) unsigned char opc; uint64_t insn; int op, r1, r2, r3, d1, d2, x2, b1, b2, r1b; - TCGv_i32 vl; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -2201,51 +2200,15 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd4: /* NC D1(L,B1),D2(B2) [SS] */ case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ - case 0xd6: /* OC D1(L,B1),D2(B2) [SS] */ - case 0xd7: /* XC D1(L,B1),D2(B2) [SS] */ - case 0xdc: /* TR D1(L,B1),D2(B2) [SS] */ - case 0xf3: /* UNPK D1(L1,B1),D2(L2,B2) [SS] */ insn = ld_code6(env, s->pc); - vl = tcg_const_i32((insn >> 32) & 0xff); b1 = (insn >> 28) & 0xf; b2 = (insn >> 12) & 0xf; d1 = (insn >> 16) & 0xfff; d2 = insn & 0xfff; tmp = get_address(s, 0, b1, d1); tmp2 = get_address(s, 0, b2, d2); - switch (opc) { - case 0xd4: - potential_page_fault(s); - gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xd5: - gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2); - break; - case 0xd6: - potential_page_fault(s); - gen_helper_oc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xd7: - potential_page_fault(s); - gen_helper_xc(cc_op, cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xdc: - potential_page_fault(s); - gen_helper_tr(cpu_env, vl, tmp, tmp2); - set_cc_static(s); - break; - case 0xf3: - potential_page_fault(s); - gen_helper_unpk(cpu_env, vl, tmp, tmp2); - break; - default: - tcg_abort(); - } + gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; @@ -3206,12 +3169,32 @@ static ExitStatus op_nabs(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_nc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_neg(DisasContext *s, DisasOps *o) { tcg_gen_neg_i64(o->out, o->in2); return NO_EXIT; } +static ExitStatus op_oc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_or(DisasContext *s, DisasOps *o) { tcg_gen_or_i64(o->out, o->in1, o->in2); @@ -3446,6 +3429,35 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) return EXIT_NORETURN; } +static ExitStatus op_tr(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_tr(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_unpk(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_unpk(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + +static ExitStatus op_xc(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_xc(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_xor(DisasContext *s, DisasOps *o) { tcg_gen_xor_i64(o->out, o->in1, o->in2); From 4f7403d52b1c682df15c862f5e7ca0712b66089f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 12:54:07 -0700 Subject: [PATCH 0153/1634] target-s390: Convert CLC Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 1 + target-s390x/translate.c | 107 ++++++++++++------------------------- 2 files changed, 35 insertions(+), 73 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 015a7f52ce..ff8f57fe2b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -119,6 +119,7 @@ C(0xb931, CLGFR, RRE, Z, r1, r2_32u, 0, 0, 0, cmpu64) C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) + C(0xd500, CLC, SS_a, Z, la1, a2, 0, 0, clc, 0) /* COMPARE LOGICAL IMMEDIATE */ C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 36705a2f8f..8a7cfafb9f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1012,67 +1012,6 @@ static void free_compare(DisasCompare *c) } } -static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) -{ - TCGv_i64 tmp; - TCGv_i64 tmp2; - TCGv_i32 vl; - - /* check for simple 32bit or 64bit match */ - switch (l) { - case 0: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld8u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld8u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 1: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld16u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld16u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 3: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld32u(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld32u(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - case 7: - tmp = tcg_temp_new_i64(); - tmp2 = tcg_temp_new_i64(); - - tcg_gen_qemu_ld64(tmp, s1, get_mem_index(s)); - tcg_gen_qemu_ld64(tmp2, s2, get_mem_index(s)); - cmp_u64(s, tmp, tmp2); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - return; - } - - potential_page_fault(s); - vl = tcg_const_i32(l); - gen_helper_clc(cc_op, cpu_env, vl, s1, s2); - tcg_temp_free_i32(vl); - set_cc_static(s); -} - static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { @@ -2200,18 +2139,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0xd5: /* CLC D1(L,B1),D2(B2) [SS] */ - insn = ld_code6(env, s->pc); - b1 = (insn >> 28) & 0xf; - b2 = (insn >> 12) & 0xf; - d1 = (insn >> 16) & 0xfff; - d2 = insn & 0xfff; - tmp = get_address(s, 0, b1, d1); - tmp2 = get_address(s, 0, b2, d2); - gen_op_clc(s, (insn >> 32) & 0xff, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; #ifndef CONFIG_USER_ONLY case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ @@ -2797,6 +2724,40 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_clc(DisasContext *s, DisasOps *o) +{ + int l = get_field(s->fields, l1); + TCGv_i32 vl; + + switch (l + 1) { + case 1: + tcg_gen_qemu_ld8u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld8u(cc_dst, o->in2, get_mem_index(s)); + break; + case 2: + tcg_gen_qemu_ld16u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld16u(cc_dst, o->in2, get_mem_index(s)); + break; + case 4: + tcg_gen_qemu_ld32u(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld32u(cc_dst, o->in2, get_mem_index(s)); + break; + case 8: + tcg_gen_qemu_ld64(cc_src, o->addr1, get_mem_index(s)); + tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s)); + break; + default: + potential_page_fault(s); + vl = tcg_const_i32(l); + gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2); + tcg_temp_free_i32(vl); + set_cc_static(s); + return NO_EXIT; + } + gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, cc_src, cc_dst); + return NO_EXIT; +} + static ExitStatus op_clcle(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From 97c3ab61c46c1c0194657b8bead3d499600d8aab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 13:00:27 -0700 Subject: [PATCH 0154/1634] target-s390: Convert MVCP, MVCS Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 49 ++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ff8f57fe2b..65f0bfd768 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -461,6 +461,10 @@ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) +/* MOVE TO PRIMARY */ + C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) +/* MOVE TO SECONDARY */ + C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8a7cfafb9f..070da1e817 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2001,7 +2001,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d1, d2, x2, b1, b2, r1b; + int op, r1, r2, r3, d2, x2, b2, r1b; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -2139,31 +2139,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; -#ifndef CONFIG_USER_ONLY - case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ - case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ - check_privileged(s); - potential_page_fault(s); - insn = ld_code6(env, s->pc); - r1 = (insn >> 36) & 0xf; - r3 = (insn >> 32) & 0xf; - b1 = (insn >> 28) & 0xf; - d1 = (insn >> 16) & 0xfff; - b2 = (insn >> 12) & 0xf; - d2 = insn & 0xfff; - /* XXX key in r3 */ - tmp = get_address(s, 0, b1, d1); - tmp2 = get_address(s, 0, b2, d2); - if (opc == 0xda) { - gen_helper_mvcp(cc_op, cpu_env, regs[r1], tmp, tmp2); - } else { - gen_helper_mvcs(cc_op, cpu_env, regs[r1], tmp, tmp2); - } - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; -#endif case 0xe3: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -3111,6 +3086,28 @@ static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_mvcp(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, l1); + check_privileged(s); + potential_page_fault(s); + gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, l1); + check_privileged(s); + potential_page_fault(s); + gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From d8fe4a9c284f244679ab251637bff81126d91dfe Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 13:15:10 -0700 Subject: [PATCH 0155/1634] target-s390: Convert LRA Note that truncating the store to r1 based on PSW_MASK_64 is incorrect. We always modify the entire register. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 4 ++++ target-s390x/mem_helper.c | 13 +++---------- target-s390x/translate.c | 20 +++++++++----------- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 5a0f6965a4..0bb6d57cbc 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -131,7 +131,7 @@ DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) -DEF_HELPER_3(lra, i32, env, i64, i32) +DEF_HELPER_2(lra, i64, env, i64) DEF_HELPER_3(stura, void, env, i64, i32) #endif diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 65f0bfd768..a83ce95459 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -461,6 +461,10 @@ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) +/* LOAD REAL ADDRESS */ + C(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0) + C(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0) + C(0xe303, LRAG, RXY_a, Z, 0, a2, r1, 0, lra, 0) /* MOVE TO PRIMARY */ C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) /* MOVE TO SECONDARY */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 1b63259351..dcaa5a59d7 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1127,7 +1127,7 @@ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) } /* load real address */ -uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) +uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) { uint32_t cc = 0; int old_exc = env->exception_index; @@ -1151,14 +1151,7 @@ uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) } env->exception_index = old_exc; - if (!(env->psw.mask & PSW_MASK_64)) { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - (ret & 0xffffffffULL); - } else { - env->regs[r1] = ret; - } - - return cc; + env->cc_op = cc; + return ret; } - #endif diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 070da1e817..227b77d02b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2022,17 +2022,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; - case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ - check_privileged(s); - insn = ld_code4(env, s->pc); - tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); - tmp32_1 = tcg_const_i32(r1); - potential_page_fault(s); - gen_helper_lra(cc_op, cpu_env, tmp, tmp32_1); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; #endif case 0xb2: insn = ld_code4(env, s->pc); @@ -2938,6 +2927,15 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_lra(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_lra(o->out, cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) { TCGv_i64 t1, t2; From 0c2400155bc47dcfb7216f586457940a9f342462 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 13:52:23 -0700 Subject: [PATCH 0156/1634] target-s390: Convert SIGP Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 28 ++++++++++++---------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a83ce95459..899c6a5aa8 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -475,6 +475,8 @@ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) +/* SIGNAL PROCESSOR */ + C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 227b77d02b..e0879412c4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2007,22 +2007,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) LOG_DISAS("opc 0x%x\n", opc); switch (opc) { -#ifndef CONFIG_USER_ONLY - case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = load_reg(r3); - tmp32_1 = tcg_const_i32(r1); - potential_page_fault(s); - gen_helper_sigp(cc_op, cpu_env, tmp, tmp32_1, tmp2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; -#endif case 0xb2: insn = ld_code4(env, s->pc); op = (insn >> 16) & 0xff; @@ -3194,6 +3178,18 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_sigp(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + check_privileged(s); + potential_page_fault(s); + gen_helper_sigp(cc_op, cpu_env, o->in2, r1, o->in1); + tcg_temp_free_i32(r1); + return NO_EXIT; +} +#endif + static ExitStatus op_sla(DisasContext *s, DisasOps *o) { uint64_t sign = 1ull << s->insn->data; From ea20490fdd9faacf9768363edcda3c76fed703ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:09:05 -0700 Subject: [PATCH 0157/1634] target-s390: Convert EFPC, STFPC Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 ++++++ target-s390x/translate.c | 38 +++++++++++++------------------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 899c6a5aa8..819c3f5274 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -175,6 +175,9 @@ /* EXECUTE RELATIVE LONG */ C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) +/* EXTRACT FPC */ + C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) + /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) @@ -395,6 +398,9 @@ /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE FPC */ + C(0xb29c, STFPC, S, Z, 0, a2, new, m2_32, efpc, 0) + /* STORE MULTIPLE */ D(0x9000, STM, RS_a, Z, 0, a2, 0, 0, stm, 0, 4) D(0xeb90, STMY, RSY_a, LD, 0, a2, 0, 0, stm, 0, 4) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e0879412c4..9e648d62d2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1839,12 +1839,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); tcg_temp_free_i32(tmp32_1); break; - case 0x8c: /* EFPC R1 [RRE] */ - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x94: /* CEFBR R1,R2 [RRE] */ case 0x95: /* CDFBR R1,R2 [RRE] */ case 0x96: /* CXFBR R1,R2 [RRE] */ @@ -1997,7 +1991,7 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { - TCGv_i64 tmp, tmp2; + TCGv_i64 tmp; TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; @@ -2010,24 +2004,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) case 0xb2: insn = ld_code4(env, s->pc); op = (insn >> 16) & 0xff; - switch (op) { - case 0x9c: /* STFPC D2(B2) [S] */ - d2 = insn & 0xfff; - b2 = (insn >> 12) & 0xf; - tmp32_1 = tcg_temp_new_i32(); - tmp = tcg_temp_new_i64(); - tmp2 = get_address(s, 0, b2, d2); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - tcg_gen_qemu_st32(tmp, tmp2, get_mem_index(s)); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; - default: - disas_b2(env, s, op, insn); - break; - } + disas_b2(env, s, op, insn); break; case 0xb3: insn = ld_code4(env, s->pc); @@ -2774,6 +2751,12 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_efpc(DisasContext *s, DisasOps *o) +{ + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); + return NO_EXIT; +} + static ExitStatus op_ex(DisasContext *s, DisasOps *o) { /* ??? Perhaps a better way to implement EXECUTE is to set a bit in @@ -3700,6 +3683,11 @@ static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s)); } +static void wout_m2_32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s)); +} + /* ====================================================================== */ /* The "INput 1" generators. These load the first operand to an insn. */ From 504488b82770e053aa31861fd7ef31afdb874f27 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:17:58 -0700 Subject: [PATCH 0158/1634] target-s390: Convert LCTL, STCTL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 +++ target-s390x/translate.c | 54 +++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 819c3f5274..6fff22aa5a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -465,6 +465,8 @@ #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) +/* LOAD CONTROL */ + C(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* LOAD REAL ADDRESS */ @@ -483,6 +485,8 @@ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) +/* STORE CONTROL */ + C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9e648d62d2..265fc26800 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2014,36 +2014,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) r2 = insn & 0xf; disas_b3(env, s, op, r3, r1, r2); break; -#ifndef CONFIG_USER_ONLY - case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ - /* Store Control */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stctl(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ - /* Load Control */ - check_privileged(s); - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lctl(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; -#endif case 0xb9: insn = ld_code4(env, s->pc); r1 = (insn >> 4) & 0xf; @@ -2894,6 +2864,18 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_lctl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_lctl(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_lra(DisasContext *s, DisasOps *o) { check_privileged(s); @@ -3213,6 +3195,18 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stctl(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_stctl(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From f3de39c485027a6b47bffb741f5209aa44052b71 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:46:55 -0700 Subject: [PATCH 0159/1634] target-s390: Convert COMPARE AND SWAP Signed-off-by: Richard Henderson --- target-s390x/helper.h | 4 +- target-s390x/insn-data.def | 9 +++++ target-s390x/mem_helper.c | 33 +++++++--------- target-s390x/translate.c | 78 ++++++++++++++++++++------------------ 4 files changed, 66 insertions(+), 58 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 0bb6d57cbc..c653c1182c 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -18,9 +18,9 @@ DEF_HELPER_4(srst, i32, env, i32, i32, i32) DEF_HELPER_4(clst, i32, env, i32, i32, i32) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) DEF_HELPER_4(mvst, void, env, i32, i32, i32) -DEF_HELPER_4(csg, i32, env, i32, i64, i32) +DEF_HELPER_4(csg, i64, env, i64, i64, i64) DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) -DEF_HELPER_4(cs, i32, env, i32, i64, i32) +DEF_HELPER_4(cs, i64, env, i64, i64, i64) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6fff22aa5a..4714095f10 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -137,6 +137,15 @@ /* COMPARE LOGICAL LONG EXTENDED */ C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) +/* COMPARE AND SWAP */ + C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) + C(0xeb14, CSY, RSY_a, LD, r1_o, a2, new, r1_32, cs, 0) + C(0xeb30, CSG, RSY_a, Z, r1_o, a2, r1, 0, csg, 0) +/* COMPARE DOUBLE AND SWAP */ + C(0xbb00, CDS, RS_a, Z, r1_D32, a2, new, r1_D32, cds, 0) + C(0xeb31, CDSY, RSY_a, LD, r1_D32, a2, new, r1_D32, cds, 0) + C(0xeb3e, CDSG, RSY_a, Z, 0, a2, 0, 0, cdsg, 0) + /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index dcaa5a59d7..44c740f1c9 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -457,20 +457,18 @@ void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) } /* compare and swap 64-bit */ -uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) { /* FIXME: locking? */ - uint32_t cc; uint64_t v2 = cpu_ldq_data(env, a2); - - if (env->regs[r1] == v2) { - cc = 0; - cpu_stq_data(env, a2, env->regs[r3]); + if (r1 == v2) { + cpu_stq_data(env, a2, r3); + env->cc_op = 0; + return r1; } else { - cc = 1; - env->regs[r1] = v2; + env->cc_op = 1; + return v2; } - return cc; } /* compare double and swap 64-bit */ @@ -497,21 +495,18 @@ uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) } /* compare and swap 32-bit */ -uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) { /* FIXME: locking? */ - uint32_t cc; uint32_t v2 = cpu_ldl_data(env, a2); - - HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); - if (((uint32_t)env->regs[r1]) == v2) { - cc = 0; - cpu_stl_data(env, a2, (uint32_t)env->regs[r3]); + if ((uint32_t)r1 == v2) { + cpu_stl_data(env, a2, (uint32_t)r3); + env->cc_op = 0; + return r1; } else { - cc = 1; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; + env->cc_op = 1; + return v2; } - return cc; } static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 265fc26800..a99d3503f2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1146,30 +1146,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_2); break; #endif - case 0x30: /* CSG R1,R3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_csg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x3e: /* CDSG R1,R3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_cdsg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; default: LOG_DISAS("illegal eb operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2021,19 +1997,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xba: /* CS R1,R3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_cs(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2665,6 +2628,47 @@ static ExitStatus op_clcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cs(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + potential_page_fault(s); + gen_helper_cs(o->out, cpu_env, o->in1, o->in2, regs[r3]); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_csg(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + potential_page_fault(s); + gen_helper_csg(o->out, cpu_env, o->in1, o->in2, regs[r3]); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cds(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + TCGv_i64 in3 = tcg_temp_new_i64(); + tcg_gen_deposit_i64(in3, regs[r3 + 1], regs[r3], 32, 32); + potential_page_fault(s); + gen_helper_csg(o->out, cpu_env, o->in1, o->in2, in3); + tcg_temp_free_i64(in3); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + potential_page_fault(s); + /* XXX rewrite in tcg */ + gen_helper_cdsg(cc_op, cpu_env, r1, o->in2, r3); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_cvd(DisasContext *s, DisasOps *o) { TCGv_i64 t1 = tcg_temp_new_i64(); From 32a44d5882ae82364a8e957a5e21cbeaaacc71a3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 14:59:22 -0700 Subject: [PATCH 0160/1634] target-s390: Convert CLM Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 32 +++++++++++++++++++------------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4714095f10..15ded9785b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -136,6 +136,10 @@ C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) /* COMPARE LOGICAL LONG EXTENDED */ C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) +/* COMPARE LOGICAL CHARACTERS UNDER MASK */ + C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) + C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) + C(0xeb20, CLMH, RSY_b, Z, r1_sr32, a2, 0, 0, clm, 0) /* COMPARE AND SWAP */ C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a99d3503f2..47576fac7f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1997,19 +1997,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_clm(cc_op, cpu_env, tmp32_1, tmp32_2, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ insn = ld_code4(env, s->pc); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2628,6 +2615,19 @@ static ExitStatus op_clcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clm(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + TCGv_i32 t1 = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(t1, o->in1); + potential_page_fault(s); + gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2); + set_cc_static(s); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + static ExitStatus op_cs(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); @@ -3712,6 +3712,12 @@ static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); } +static void in1_r1_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in1, regs[get_field(f, r1)], 32); +} + static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) { /* ??? Specification exception: r1 must be even. */ From 2ae680590667b5a8e4eb667a726b5d16d6553cb9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:11:53 -0700 Subject: [PATCH 0161/1634] target-s390: Convert STCM Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 -- target-s390x/insn-data.def | 4 +++ target-s390x/mem_helper.c | 37 ------------------- target-s390x/translate.c | 73 +++++++++++++++++++++++++------------- 4 files changed, 53 insertions(+), 63 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c653c1182c..8cf9186b8b 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -8,7 +8,6 @@ DEF_HELPER_4(mvc, void, env, i32, i64, i64) DEF_HELPER_4(clc, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_4(clm, i32, env, i32, i32, i64) -DEF_HELPER_4(stcm, void, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_3(divs32, s64, env, s64, s64) DEF_HELPER_3(divu32, i64, env, i64, i64) @@ -26,7 +25,6 @@ DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) -DEF_HELPER_4(stcmh, void, env, i32, i64, i32) DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 15ded9785b..6c2f455d86 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -405,6 +405,10 @@ /* STORE CHARACTER */ C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) +/* STORE CHARACTERS UNDER MASK */ + D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0) + D(0xeb2c, STCMH, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 32) /* STORE HALFWORD */ C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 44c740f1c9..9c3ade816c 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -304,27 +304,6 @@ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, return cc; } -/* store character under mask */ -void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask, - uint64_t addr) -{ - uint8_t r; - - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, - addr); - while (mask) { - if (mask & 8) { - r = (r1 & 0xff000000UL) >> 24; - cpu_stb_data(env, addr, r); - HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); - addr++; - } - mask = (mask << 1) & 0xf; - r1 <<= 8; - } - HELPER_LOG("\n"); -} - static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) { uint64_t r = d2; @@ -608,22 +587,6 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, return cc; } -/* store character under mask high operates on the upper half of r1 */ -void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, - uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - - while (mask) { - if (mask & 8) { - cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff); - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - } -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 47576fac7f..9f20955137 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1110,16 +1110,6 @@ static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", op, r1, r3, b2, d2); switch (op) { - case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */ - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stcmh(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; #ifndef CONFIG_USER_ONLY case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ /* Load Control */ @@ -1967,8 +1957,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2; unsigned char opc; uint64_t insn; int op, r1, r2, r3, d2, x2, b2, r1b; @@ -1997,18 +1985,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ - insn = ld_code4(env, s->pc); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stcm(cpu_env, tmp32_1, tmp32_2, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xe3: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -3271,6 +3247,55 @@ static ExitStatus op_stam(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stcm(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int pos, base = s->insn->data; + TCGv_i64 tmp = tcg_temp_new_i64(); + + pos = base + ctz32(m3) * 8; + switch (m3) { + case 0xf: + /* Effectively a 32-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st32(tmp, o->in2, get_mem_index(s)); + break; + + case 0xc: + case 0x6: + case 0x3: + /* Effectively a 16-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st16(tmp, o->in2, get_mem_index(s)); + break; + + case 0x8: + case 0x4: + case 0x2: + case 0x1: + /* Effectively an 8-bit store. */ + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s)); + break; + + default: + /* This is going to be a sequence of shifts and stores. */ + pos = base + 32 - 8; + while (m3) { + if (m3 & 0x8) { + tcg_gen_shri_i64(tmp, o->in1, pos); + tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 1); + } + m3 = (m3 << 1) & 0xf; + pos -= 8; + } + break; + } + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + static ExitStatus op_stm(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); From 112bf0791d615060ff9235318e13fd4725146ff8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:15:59 -0700 Subject: [PATCH 0162/1634] target-s390: Convert TPROT Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 47 ++++++++------------------------------ 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6c2f455d86..8bfc6f99c6 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -508,4 +508,6 @@ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* TEST PROTECTION */ + C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9f20955137..274c5e7573 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1073,34 +1073,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(addr); } -#ifndef CONFIG_USER_ONLY -static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) -{ - TCGv_i64 tmp, tmp2; - int op = (insn >> 32) & 0xff; - - tmp = get_address(s, 0, (insn >> 28) & 0xf, (insn >> 16) & 0xfff); - tmp2 = get_address(s, 0, (insn >> 12) & 0xf, insn & 0xfff); - - LOG_DISAS("disas_e5: insn %" PRIx64 "\n", insn); - switch (op) { - case 0x01: /* TPROT D1(B1),D2(B2) [SSE] */ - /* Test Protection */ - potential_page_fault(s); - gen_helper_tprot(cc_op, tmp, tmp2); - set_cc_static(s); - break; - default: - LOG_DISAS("illegal e5 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); -} -#endif - static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, int r3, int b2, int d2) { @@ -1996,15 +1968,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) | ((insn << 4) & 0xff000)) << 12)) >> 12; disas_e3(env, s, op, r1, x2, b2, d2 ); break; -#ifndef CONFIG_USER_ONLY - case 0xe5: - /* Test Protection */ - check_privileged(s); - insn = ld_code6(env, s->pc); - debug_insn(insn); - disas_e5(env, s, insn); - break; -#endif case 0xeb: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -3387,6 +3350,16 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) return EXIT_NORETURN; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_tprot(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_tprot(cc_op, o->addr1, o->in2); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_tr(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); From 3e398cf9c2ffdee0c8f61d3bc8966357d0b8e095 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 2 Sep 2012 10:12:48 -0700 Subject: [PATCH 0163/1634] target-s390: Convert LOAD CONTROL, part 2 Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 + target-s390x/translate.c | 76 ++++++++++++-------------------------- 2 files changed, 25 insertions(+), 53 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8bfc6f99c6..a8dffcdcd5 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -484,6 +484,7 @@ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* LOAD CONTROL */ C(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0) + C(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) /* LOAD REAL ADDRESS */ @@ -504,6 +505,7 @@ C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) + C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 274c5e7573..0afc25f25b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1073,48 +1073,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, tcg_temp_free_i64(addr); } -static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, - int r3, int b2, int d2) -{ - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2; - - LOG_DISAS("disas_eb: op 0x%x r1 %d r3 %d b2 %d d2 0x%x\n", - op, r1, r3, b2, d2); - switch (op) { -#ifndef CONFIG_USER_ONLY - case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ - /* Load Control */ - check_privileged(s); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_lctlg(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ - /* Store Control */ - check_privileged(s); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r3); - potential_page_fault(s); - gen_helper_stctg(cpu_env, tmp32_1, tmp, tmp32_2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; -#endif - default: - LOG_DISAS("illegal eb operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { @@ -1968,17 +1926,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) | ((insn << 4) & 0xff000)) << 12)) >> 12; disas_e3(env, s, op, r1, x2, b2, d2 ); break; - case 0xeb: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - r3 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = ((int)((((insn >> 16) & 0xfff) - | ((insn << 4) & 0xff000)) << 12)) >> 12; - disas_eb(env, s, op, r1, r3, b2, d2); - break; case 0xed: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -2819,6 +2766,17 @@ static ExitStatus op_lctl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_lctlg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_lctlg(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} static ExitStatus op_lra(DisasContext *s, DisasOps *o) { check_privileged(s); @@ -3138,6 +3096,18 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stctg(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + check_privileged(s); + potential_page_fault(s); + gen_helper_stctg(cpu_env, r1, o->in2, r3); + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r3); + return NO_EXIT; +} + static ExitStatus op_stctl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From d54f58654187f8bafb4523a286a9baf46c531d06 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:35:40 -0700 Subject: [PATCH 0164/1634] target-s390: Convert LOAD REVERSED Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 6 +++ target-s390x/translate.c | 77 +++++++++++++++----------------------- 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a8dffcdcd5..1ee0d42930 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -293,6 +293,12 @@ C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) +/* LOAD REVERSED */ + C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) + C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) + C(0xe31f, LRVH, RXY_a, Z, 0, m2_16u, new, r1_16, rev16, 0) + C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) + C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) /* LOAD MULTIPLE */ C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0afc25f25b..397511ca44 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -278,17 +278,6 @@ static inline void store_reg32h_i64(int reg, TCGv_i64 v) tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); } -static inline void store_reg16(int reg, TCGv_i32 v) -{ - /* 16 bit register writes keep the upper bytes */ -#if HOST_LONG_BITS == 32 - tcg_gen_deposit_i32(TCGV_LOW(regs[reg]), TCGV_LOW(regs[reg]), v, 0, 16); -#else - tcg_gen_deposit_i64(regs[reg], regs[reg], - MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 16); -#endif -} - static inline void store_freg32(int reg, TCGv_i32 v) { /* 32 bit register writes keep the lower half */ @@ -1022,13 +1011,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, op, r1, x2, b2, d2); addr = get_address(s, x2, b2, d2); switch (op) { - case 0xf: /* LRVG R1,D2(X2,B2) [RXE] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - tcg_gen_bswap64_i64(tmp2, tmp2); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ tmp2 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); @@ -1036,26 +1018,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x1e: /* LRV R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x1f: /* LRVH R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld16u(tmp2, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_temp_free_i64(tmp2); - tcg_gen_bswap16_i32(tmp32_1, tmp32_1); - store_reg16(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ tmp32_1 = load_reg32(r1); tmp2 = tcg_temp_new_i64(); @@ -1861,15 +1823,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x0f: /* LRVGR R1,R2 [RRE] */ - tcg_gen_bswap64_i64(regs[r1], regs[r2]); - break; - case 0x1f: /* LRVR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -3023,6 +2976,24 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_rev16(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap16_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_rev32(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap32_i64(o->out, o->in2); + return NO_EXIT; +} + +static ExitStatus op_rev64(DisasContext *s, DisasOps *o) +{ + tcg_gen_bswap64_i64(o->out, o->in2); + return NO_EXIT; +} + static ExitStatus op_rll32(DisasContext *s, DisasOps *o) { TCGv_i32 t1 = tcg_temp_new_i32(); @@ -3576,6 +3547,12 @@ static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8); } +static void wout_r1_16(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16); +} + static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); @@ -3918,6 +3895,12 @@ static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s)); } +static void in2_m2_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + in2_a2(s, f, o); + tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); +} + static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); From e025e52aba7063c8137b7812e10d69500efb1fbb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:52:55 -0700 Subject: [PATCH 0165/1634] target-s390: Convert STORE REVERSED Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 1ee0d42930..fa3ee0063c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -420,6 +420,10 @@ C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE REVERSED */ + C(0xe33f, STRVH, RXY_a, Z, la2, r1_16u, new, m1_16, rev16, 0) + C(0xe33e, STRV, RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) + C(0xe32f, STRVG, RXY_a, Z, la2, r1_o, new, m1_64, rev64, 0) /* STORE FPC */ C(0xb29c, STFPC, S, Z, 0, a2, new, m2_32, efpc, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 397511ca44..f8c1ea7727 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1005,7 +1005,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, int x2, int b2, int d2) { TCGv_i64 addr, tmp2; - TCGv_i32 tmp32_1; LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", op, r1, x2, b2, d2); @@ -1018,15 +1017,6 @@ static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, store_reg(r1, tmp2); tcg_temp_free_i64(tmp2); break; - case 0x3e: /* STRV R1,D2(X2,B2) [RXY] */ - tmp32_1 = load_reg32(r1); - tmp2 = tcg_temp_new_i64(); - tcg_gen_bswap32_i32(tmp32_1, tmp32_1); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_gen_qemu_st32(tmp2, addr, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - break; default: LOG_DISAS("illegal e3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -3738,6 +3728,12 @@ static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); } +static void in1_la2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int x2 = have_field(f, x2) ? get_field(f, x2) : 0; + o->addr1 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); +} + static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) { in1_la1(s, f, o); @@ -3783,6 +3779,24 @@ static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) /* ====================================================================== */ /* The "INput 2" generators. These load the second operand to an insn. */ +static void in2_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = regs[get_field(f, r1)]; + o->g_in2 = true; +} + +static void in2_r1_16u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r1)]); +} + +static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r1)]); +} + static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r2)); From 7691c23b1f7b508f3f5391e8f362579544be6980 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Aug 2012 15:59:19 -0700 Subject: [PATCH 0166/1634] target-s390: Convert LLGT Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 50 +++++--------------------------------- 2 files changed, 9 insertions(+), 44 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index fa3ee0063c..8914d341f7 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -285,6 +285,9 @@ D(0xa50d, LLIHL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 32) D(0xa50e, LLILH, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 16) D(0xa50f, LLILL, RI_a, Z, 0, i2_16u_shl, 0, r1, mov2, 0, 0) +/* LOAD LOGICAL THIRTY ONE BITS */ + C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) + C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) /* LOAD NEGATIVE */ C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f8c1ea7727..033f93e3ef 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1001,30 +1001,6 @@ static void free_compare(DisasCompare *c) } } -static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, - int x2, int b2, int d2) -{ - TCGv_i64 addr, tmp2; - - LOG_DISAS("disas_e3: op 0x%x r1 %d x2 %d b2 %d d2 %d\n", - op, r1, x2, b2, d2); - addr = get_address(s, x2, b2, d2); - switch (op) { - case 0x17: /* LLGT R1,D2(X2,B2) [RXY] */ - tmp2 = tcg_temp_new_i64(); - tcg_gen_qemu_ld32u(tmp2, addr, get_mem_index(s)); - tcg_gen_andi_i64(tmp2, tmp2, 0x7fffffffULL); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp2); - break; - default: - LOG_DISAS("illegal e3 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } - tcg_temp_free_i64(addr); -} - static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { @@ -1804,15 +1780,6 @@ static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x17: /* LLGTR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tmp = tcg_temp_new_i64(); - tcg_gen_andi_i32(tmp32_1, tmp32_1, 0x7fffffffUL); - tcg_gen_extu_i32_i64(tmp, tmp32_1); - store_reg(r1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); @@ -1858,17 +1825,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xe3: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - x2 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = ((int)((((insn >> 16) & 0xfff) - | ((insn << 4) & 0xff000)) << 12)) >> 12; - disas_e3(env, s, op, r1, x2, b2, d2 ); - break; case 0xed: insn = ld_code6(env, s->pc); debug_insn(insn); @@ -2654,6 +2610,12 @@ static ExitStatus op_insi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_llgt(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); + return NO_EXIT; +} + static ExitStatus op_ld8s(DisasContext *s, DisasOps *o) { tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s)); From 587626f8da5e2ee15bbf9f636c78991d6c953387 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 10:48:20 -0700 Subject: [PATCH 0167/1634] target-s390: Convert FP ADD, COMPARE, LOAD TEST/ROUND/LENGTHENED Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 9 +- target-s390x/cpu.h | 10 +- target-s390x/fpu_helper.c | 298 ++++++++++++++----------------------- target-s390x/helper.h | 37 ++--- target-s390x/insn-data.def | 25 ++++ target-s390x/translate.c | 217 +++++++++++++++------------ 6 files changed, 281 insertions(+), 315 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index be4202a78e..f1038be1b5 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -505,18 +505,15 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, r = cc_calc_sla_64(src, dst); break; - case CC_OP_LTGT_F32: - r = set_cc_f32(env, src, dst); - break; - case CC_OP_LTGT_F64: - r = set_cc_f64(env, src, dst); - break; case CC_OP_NZ_F32: r = set_cc_nz_f32(dst); break; case CC_OP_NZ_F64: r = set_cc_nz_f64(dst); break; + case CC_OP_NZ_F128: + r = set_cc_nz_f128(make_float128(src, dst)); + break; default: cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index b8e9037eeb..f1d4dc67f4 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -471,11 +471,9 @@ enum cc_op { CC_OP_TM_32, /* test under mask (32bit) */ CC_OP_TM_64, /* test under mask (64bit) */ - CC_OP_LTGT_F32, /* FP compare (32bit) */ - CC_OP_LTGT_F64, /* FP compare (64bit) */ - CC_OP_NZ_F32, /* FP dst != 0 (32bit) */ CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ + CC_OP_NZ_F128, /* FP dst != 0 (128bit) */ CC_OP_ICM, /* insert characters under mask */ CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ @@ -517,10 +515,9 @@ static const char *cc_names[] = { [CC_OP_COMP_64] = "CC_OP_COMP_64", [CC_OP_TM_32] = "CC_OP_TM_32", [CC_OP_TM_64] = "CC_OP_TM_64", - [CC_OP_LTGT_F32] = "CC_OP_LTGT_F32", - [CC_OP_LTGT_F64] = "CC_OP_LTGT_F64", [CC_OP_NZ_F32] = "CC_OP_NZ_F32", [CC_OP_NZ_F64] = "CC_OP_NZ_F64", + [CC_OP_NZ_F128] = "CC_OP_NZ_F128", [CC_OP_ICM] = "CC_OP_ICM", [CC_OP_SLA_32] = "CC_OP_SLA_32", [CC_OP_SLA_64] = "CC_OP_SLA_64", @@ -926,10 +923,9 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) } /* fpu_helper.c */ -uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2); -uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2); uint32_t set_cc_nz_f32(float32 v); uint32_t set_cc_nz_f64(float64 v); +uint32_t set_cc_nz_f128(float128 v); /* misc_helper.c */ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 173f820428..92458ce8da 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -32,6 +32,52 @@ #define HELPER_LOG(x...) #endif +#define RET128(F) (env->retxl = F.low, F.high) + +#define convert_bit(mask, from, to) \ + (to < from \ + ? (mask / (from / to)) & to \ + : (mask & from) * (to / from)) + +static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr) +{ + /* Install the DXC code. */ + env->fpc = (env->fpc & ~0xff00) | (dxc << 8); + /* Trap. */ + runtime_exception(env, PGM_DATA, retaddr); +} + +/* Should be called after any operation that may raise IEEE exceptions. */ +static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr) +{ + unsigned s390_exc, qemu_exc; + + /* Get the exceptions raised by the current operation. Reset the + fpu_status contents so that the next operation has a clean slate. */ + qemu_exc = env->fpu_status.float_exception_flags; + if (qemu_exc == 0) { + return; + } + env->fpu_status.float_exception_flags = 0; + + /* Convert softfloat exception bits to s390 exception bits. */ + s390_exc = 0; + s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80); + s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40); + s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20); + s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10); + s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08); + + /* Install the exceptions that we raised. */ + env->fpc |= s390_exc << 16; + + /* Send signals for enabled exceptions. */ + s390_exc &= env->fpc >> 24; + if (s390_exc) { + ieee_exception(env, s390_exc, retaddr); + } +} + static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) { switch (float_compare) { @@ -48,19 +94,6 @@ static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) } } -/* condition codes for binary FP ops */ -uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2) -{ - return float_comp_to_cc(env, float32_compare_quiet(v1, v2, - &env->fpu_status)); -} - -uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2) -{ - return float_comp_to_cc(env, float64_compare_quiet(v1, v2, - &env->fpu_status)); -} - /* condition codes for unary FP ops */ uint32_t set_cc_nz_f32(float32 v) { @@ -88,7 +121,7 @@ uint32_t set_cc_nz_f64(float64 v) } } -static uint32_t set_cc_nz_f128(float128 v) +uint32_t set_cc_nz_f128(float128 v) { if (float128_is_any_nan(v)) { return 3; @@ -152,27 +185,31 @@ void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) env->fregs[f1].l.upper, f1); } -/* 32-bit FP addition RR */ -uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP addition */ +uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); + float32 ret = float32_add(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP addition RR */ -uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP addition */ +uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, - env->fregs[f2].d, env->fregs[f1].d, f1); + float64 ret = float64_add(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - return set_cc_nz_f64(env->fregs[f1].d); +/* 128-bit FP addition */ +uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_add(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* 32-bit FP subtraction RR */ @@ -246,50 +283,51 @@ void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) } /* convert 32-bit float to 64-bit float */ -void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) { - env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, - &env->fpu_status); + float64 ret = float32_to_float64(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 64-bit float */ -void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al) { - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); + float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 64-bit float to 128-bit float */ -void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) { - CPU_QuadU res; + float128 ret = float64_to_float128(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} - res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; +/* convert 32-bit float to 128-bit float */ +uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) +{ + float128 ret = float32_to_float128(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* convert 64-bit float to 32-bit float */ -void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2) { - float64 d2 = env->fregs[f2].d; - - env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); + float32 ret = float64_to_float32(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 32-bit float */ -void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) { - CPU_QuadU x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); + float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* absolute value of 32-bit float */ @@ -328,32 +366,6 @@ uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(v1.q); } -/* load and test 64-bit float */ -uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = env->fregs[f2].d; - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load and test 32-bit float */ -uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = env->fregs[f2].l.upper; - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load and test 128-bit float */ -uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU x; - - x.ll.upper = env->fregs[f2].ll; - x.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 2].ll = x.ll.lower; - return set_cc_nz_f128(x.q); -} - /* load complement of 32-bit float */ uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { @@ -383,18 +395,6 @@ uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(x1.q); } -/* 32-bit FP addition RM */ -void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); -} - /* 32-bit FP division RM */ void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) { @@ -419,66 +419,31 @@ void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); } -/* 32-bit FP compare RR */ -uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP compare */ +uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - float32 v1 = env->fregs[f1].l.upper; - float32 v2 = env->fregs[f2].l.upper; - - HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2); - return set_cc_f32(env, v1, v2); + int cmp = float32_compare_quiet(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } -/* 64-bit FP compare RR */ -uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP compare */ +uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - float64 v1 = env->fregs[f1].d; - float64 v2 = env->fregs[f2].d; - - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, - v1, f1, v2); - return set_cc_f64(env, v1, v2); + int cmp = float64_compare_quiet(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } -/* 128-bit FP compare RR */ -uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 128-bit FP compare */ +uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) { - CPU_QuadU v1; - CPU_QuadU v2; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - - return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q, - &env->fpu_status)); -} - -/* 64-bit FP compare RM */ -uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, - f1, v2.d); - return set_cc_f64(env, v1, v2.d); -} - -/* 64-bit FP addition RM */ -uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); + int cmp = float128_compare_quiet(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); } /* 32-bit FP subtraction RM */ @@ -672,23 +637,6 @@ uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(res.q); } -/* 128-bit FP addition RR */ -uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_add(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - /* 32-bit FP multiplication RR */ void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { @@ -747,28 +695,6 @@ void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) &env->fpu_status); } -/* convert 32-bit float to 64-bit float */ -void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - uint32_t v2; - - v2 = cpu_ldl_data(env, a2); - env->fregs[f1].d = float32_to_float64(v2, - &env->fpu_status); -} - -/* convert 64-bit float to 128-bit float */ -void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - CPU_DoubleU v2; - CPU_QuadU v1; - - v2.ll = cpu_ldq_data(env, a2); - v1.q = float64_to_float128(v2.d, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - /* test data class 32-bit */ uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 8cf9186b8b..2e6443321f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -36,40 +36,36 @@ DEF_HELPER_3(cxfbr, void, env, i32, s32) DEF_HELPER_3(cegbr, void, env, i32, s64) DEF_HELPER_3(cdgbr, void, env, i32, s64) DEF_HELPER_3(cxgbr, void, env, i32, s64) -DEF_HELPER_3(adbr, i32, env, i32, i32) -DEF_HELPER_3(aebr, i32, env, i32, i32) +DEF_HELPER_3(aeb, i64, env, i64, i64) +DEF_HELPER_3(adb, i64, env, i64, i64) +DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(sebr, i32, env, i32, i32) DEF_HELPER_3(sdbr, i32, env, i32, i32) DEF_HELPER_3(debr, void, env, i32, i32) DEF_HELPER_3(dxbr, void, env, i32, i32) DEF_HELPER_3(mdbr, void, env, i32, i32) DEF_HELPER_3(mxbr, void, env, i32, i32) -DEF_HELPER_3(ldebr, void, env, i32, i32) -DEF_HELPER_3(ldxbr, void, env, i32, i32) -DEF_HELPER_3(lxdbr, void, env, i32, i32) -DEF_HELPER_3(ledbr, void, env, i32, i32) -DEF_HELPER_3(lexbr, void, env, i32, i32) +DEF_HELPER_2(ldeb, i64, env, i64) +DEF_HELPER_3(ldxb, i64, env, i64, i64) +DEF_HELPER_2(lxdb, i64, env, i64) +DEF_HELPER_2(lxeb, i64, env, i64) +DEF_HELPER_2(ledb, i64, env, i64) +DEF_HELPER_3(lexb, i64, env, i64, i64) DEF_HELPER_3(lpebr, i32, env, i32, i32) DEF_HELPER_3(lpdbr, i32, env, i32, i32) DEF_HELPER_3(lpxbr, i32, env, i32, i32) -DEF_HELPER_3(ltebr, i32, env, i32, i32) -DEF_HELPER_3(ltdbr, i32, env, i32, i32) -DEF_HELPER_3(ltxbr, i32, env, i32, i32) DEF_HELPER_3(lcebr, i32, env, i32, i32) DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) -DEF_HELPER_3(aeb, void, env, i32, i32) DEF_HELPER_3(deb, void, env, i32, i32) DEF_HELPER_3(meeb, void, env, i32, i32) -DEF_HELPER_3(cdb, i32, env, i32, i64) -DEF_HELPER_3(adb, i32, env, i32, i64) DEF_HELPER_3(seb, void, env, i32, i32) DEF_HELPER_3(sdb, i32, env, i32, i64) DEF_HELPER_3(mdb, void, env, i32, i64) DEF_HELPER_3(ddb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(cebr, TCG_CALL_NO_SE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_NO_SE, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_NO_SE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) +DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) +DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) @@ -79,7 +75,6 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_3(axbr, i32, env, i32, i32) DEF_HELPER_3(sxbr, i32, env, i32, i32) DEF_HELPER_3(meebr, void, env, i32, i32) DEF_HELPER_3(ddbr, void, env, i32, i32) @@ -87,11 +82,9 @@ DEF_HELPER_4(madb, void, env, i32, i64, i32) DEF_HELPER_4(maebr, void, env, i32, i32, i32) DEF_HELPER_4(madbr, void, env, i32, i32, i32) DEF_HELPER_4(msdbr, void, env, i32, i32, i32) -DEF_HELPER_3(ldeb, void, env, i32, i64) -DEF_HELPER_3(lxdb, void, env, i32, i64) -DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8914d341f7..f1c37e8939 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -8,6 +8,11 @@ C(0xb9e8, AGRK, RRF_a, DO, r2, r3, r1, 0, add, adds64) C(0xe308, AG, RXY_a, Z, r1, m2_64, r1, 0, add, adds64) C(0xe318, AGF, RXY_a, Z, r1, m2_32s, r1, 0, add, adds64) + C(0xb30a, AEBR, RRE, Z, e1, e2, new, e1, aeb, f32) + C(0xb31a, ADBR, RRE, Z, f1_o, f2_o, f1, 0, adb, f64) + C(0xb34a, AXBR, RRE, Z, 0, x2_o, x1, 0, axb, f128) + C(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32) + C(0xed1a, ADB, RXE, Z, f1_o, m2_64, f1, 0, adb, f64) /* ADD IMMEDIATE */ C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32) @@ -94,6 +99,11 @@ C(0xb930, CGFR, RRE, Z, r1_o, r2_32s, 0, 0, 0, cmps64) C(0xe320, CG, RXY_a, Z, r1_o, m2_64, 0, 0, 0, cmps64) C(0xe330, CGF, RXY_a, Z, r1_o, m2_32s, 0, 0, 0, cmps64) + C(0xb309, CEBR, RRE, Z, e1, e2, 0, 0, ceb, 0) + C(0xb319, CDBR, RRE, Z, f1_o, f2_o, 0, 0, cdb, 0) + C(0xb349, CXBR, RRE, Z, x1_o, x2_o, 0, 0, cxb, 0) + C(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0) + C(0xed19, CDB, RXE, Z, f1_o, m2_64, 0, 0, cdb, 0) /* COMPARE IMMEDIATE */ C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) @@ -239,6 +249,9 @@ C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) + C(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32) + C(0xb312, LTDBR, RRE, Z, 0, f2_o, 0, f1, mov2, f64) + C(0xb342, LTXBR, RRE, Z, 0, x2_o, 0, x1, movx, f128) /* LOAD BYTE */ C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) @@ -303,6 +316,18 @@ C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) +/* LOAD LENGTHENED */ + C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) + C(0xb305, LXDBR, RRE, Z, 0, f2_o, x1, 0, lxdb, 0) + C(0xb306, LXEBR, RRE, Z, 0, e2, x1, 0, lxeb, 0) + C(0xed04, LDEB, RXE, Z, 0, m2_32u, f1, 0, ldeb, 0) + C(0xed05, LXDB, RXE, Z, 0, m2_64, x1, 0, lxdb, 0) + C(0xed06, LXEB, RXE, Z, 0, m2_32u, x1, 0, lxeb, 0) +/* LOAD ROUNDED */ + C(0xb344, LEDBR, RRE, Z, 0, f2_o, new, e1, ledb, 0) + C(0xb345, LDXBR, RRE, Z, 0, x2_o, f1, 0, ldxb, 0) + C(0xb346, LEXBR, RRE, Z, 0, x2_o, new, e1, lexb, 0) + /* LOAD MULTIPLE */ C(0x9800, LM, RS_a, Z, 0, a2, 0, 0, lm32, 0) C(0xeb98, LMY, RSY_a, LD, 0, a2, 0, 0, lm32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 033f93e3ef..f62e4f0431 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -556,14 +556,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) -{ - tcg_gen_extu_i32_i64(cc_src, v1); - tcg_gen_mov_i64(cc_dst, v2); - tcg_gen_discard_i64(cc_vr); - s->cc_op = CC_OP_LTGT_F32; -} - static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); @@ -628,10 +620,9 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_LTUGTU_64: case CC_OP_TM_32: case CC_OP_TM_64: - case CC_OP_LTGT_F32: - case CC_OP_LTGT_F64: case CC_OP_SLA_32: case CC_OP_SLA_64: + case CC_OP_NZ_F128: /* 2 arguments */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; @@ -1009,35 +1000,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { - case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_ldeb(cpu_env, tmp_r1, addr); - break; - case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_lxdb(cpu_env, tmp_r1, addr); - break; - case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = load_freg32(r1); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - set_cc_cmp_f32_i64(s, tmp32, tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; - case 0xa: /* AEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_aeb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - - tmp32 = load_freg32(r1); - gen_set_cc_nz_f32(s, tmp32); - tcg_temp_free_i32(tmp32); - break; case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ tmp = tcg_temp_new_i64(); tmp32 = tcg_temp_new_i32(); @@ -1084,16 +1046,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; - case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_adb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); @@ -1524,24 +1476,9 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x0: /* LPEBR R1,R2 [RRE] */ FP_HELPER_CC(lpebr); break; - case 0x2: /* LTEBR R1,R2 [RRE] */ - FP_HELPER_CC(ltebr); - break; case 0x3: /* LCEBR R1,R2 [RRE] */ FP_HELPER_CC(lcebr); break; - case 0x4: /* LDEBR R1,R2 [RRE] */ - FP_HELPER(ldebr); - break; - case 0x5: /* LXDBR R1,R2 [RRE] */ - FP_HELPER(lxdbr); - break; - case 0x9: /* CEBR R1,R2 [RRE] */ - FP_HELPER_CC(cebr); - break; - case 0xa: /* AEBR R1,R2 [RRE] */ - FP_HELPER_CC(aebr); - break; case 0xb: /* SEBR R1,R2 [RRE] */ FP_HELPER_CC(sebr); break; @@ -1551,9 +1488,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x10: /* LPDBR R1,R2 [RRE] */ FP_HELPER_CC(lpdbr); break; - case 0x12: /* LTDBR R1,R2 [RRE] */ - FP_HELPER_CC(ltdbr); - break; case 0x13: /* LCDBR R1,R2 [RRE] */ FP_HELPER_CC(lcdbr); break; @@ -1563,12 +1497,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x17: /* MEEBR R1,R2 [RRE] */ FP_HELPER(meebr); break; - case 0x19: /* CDBR R1,R2 [RRE] */ - FP_HELPER_CC(cdbr); - break; - case 0x1a: /* ADBR R1,R2 [RRE] */ - FP_HELPER_CC(adbr); - break; case 0x1b: /* SDBR R1,R2 [RRE] */ FP_HELPER_CC(sdbr); break; @@ -1605,27 +1533,9 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x40: /* LPXBR R1,R2 [RRE] */ FP_HELPER_CC(lpxbr); break; - case 0x42: /* LTXBR R1,R2 [RRE] */ - FP_HELPER_CC(ltxbr); - break; case 0x43: /* LCXBR R1,R2 [RRE] */ FP_HELPER_CC(lcxbr); break; - case 0x44: /* LEDBR R1,R2 [RRE] */ - FP_HELPER(ledbr); - break; - case 0x45: /* LDXBR R1,R2 [RRE] */ - FP_HELPER(ldxbr); - break; - case 0x46: /* LEXBR R1,R2 [RRE] */ - FP_HELPER(lexbr); - break; - case 0x49: /* CXBR R1,R2 [RRE] */ - FP_HELPER_CC(cxbr); - break; - case 0x4a: /* AXBR R1,R2 [RRE] */ - FP_HELPER_CC(axbr); - break; case 0x4b: /* SXBR R1,R2 [RRE] */ FP_HELPER_CC(sxbr); break; @@ -2260,6 +2170,25 @@ static ExitStatus op_addc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_aeb(DisasContext *s, DisasOps *o) +{ + gen_helper_aeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_adb(DisasContext *s, DisasOps *o) +{ + gen_helper_adb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_axb(DisasContext *s, DisasOps *o) +{ + gen_helper_axb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_and(DisasContext *s, DisasOps *o) { tcg_gen_and_i64(o->out, o->in1, o->in2); @@ -2354,6 +2283,27 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_ceb(DisasContext *s, DisasOps *o) +{ + gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cdb(DisasContext *s, DisasOps *o) +{ + gen_helper_cdb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_cxb(DisasContext *s, DisasOps *o) +{ + gen_helper_cxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); @@ -2610,6 +2560,44 @@ static ExitStatus op_insi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) +{ + gen_helper_ldeb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ledb(DisasContext *s, DisasOps *o) +{ + gen_helper_ledb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ldxb(DisasContext *s, DisasOps *o) +{ + gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_lexb(DisasContext *s, DisasOps *o) +{ + gen_helper_lexb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_lxdb(DisasContext *s, DisasOps *o) +{ + gen_helper_lxdb(o->out, cpu_env, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_lxeb(DisasContext *s, DisasOps *o) +{ + gen_helper_lxeb(o->out, cpu_env, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_llgt(DisasContext *s, DisasOps *o) { tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); @@ -3369,6 +3357,21 @@ static void cout_cmpu64(DisasContext *s, DisasOps *o) gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2); } +static void cout_f32(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F32, o->out); +} + +static void cout_f64(DisasContext *s, DisasOps *o) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F64, o->out); +} + +static void cout_f128(DisasContext *s, DisasOps *o) +{ + gen_op_update2_cc_i64(s, CC_OP_NZ_F128, o->out, o->out2); +} + static void cout_nabs32(DisasContext *s, DisasOps *o) { gen_op_update1_cc_i64(s, CC_OP_NABS_32, o->out); @@ -3482,6 +3485,21 @@ static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) o->g_out = o->g_out2 = true; } +static void prep_f1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->out = fregs[get_field(f, r1)]; + o->g_out = true; +} + +static void prep_x1(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be < 14. */ + int r1 = get_field(f, r1); + o->out = fregs[r1]; + o->out2 = fregs[(r1 + 2) & 15]; + o->g_out = o->g_out2 = true; +} + /* ====================================================================== */ /* The "Write OUTput" generators. These generally perform some non-trivial copy of data to TCG globals, or to main memory. The trivial cases are @@ -3539,6 +3557,7 @@ static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o) static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o) { + /* ??? Specification exception: r1 must be < 14. */ int f1 = get_field(s->fields, r1); store_freg(f1, o->out); store_freg((f1 + 2) & 15, o->out2); @@ -3685,6 +3704,15 @@ static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = true; } +static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + /* ??? Specification exception: r1 must be < 14. */ + int r1 = get_field(f, r1); + o->out = fregs[r1]; + o->out2 = fregs[(r1 + 2) & 15]; + o->g_out = o->g_out2 = true; +} + static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); @@ -3832,9 +3860,10 @@ static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o) static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) { - int f2 = get_field(f, r2); - o->in1 = fregs[f2]; - o->in2 = fregs[(f2 + 2) & 15]; + /* ??? Specification exception: r1 must be < 14. */ + int r2 = get_field(f, r2); + o->in1 = fregs[r2]; + o->in2 = fregs[(r2 + 2) & 15]; o->g_in1 = o->g_in2 = true; } From 1a800a2dcee541dee4f51aed5110ca9d5811c5e8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 11:05:03 -0700 Subject: [PATCH 0168/1634] target-s390: Convert FP SUBTRACT Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 74 +++++++++++--------------------------- target-s390x/helper.h | 8 ++--- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 51 ++++++++++---------------- 4 files changed, 47 insertions(+), 91 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 92458ce8da..ea61936571 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -212,27 +212,31 @@ uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, return RET128(ret); } -/* 32-bit FP subtraction RR */ -uint32_t HELPER(sebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP subtraction */ +uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); + float32 ret = float32_sub(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP subtraction RR */ -uint32_t HELPER(sdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP subtraction */ +uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", - __func__, env->fregs[f2].d, env->fregs[f1].d, f1); + float64 ret = float64_sub(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - return set_cc_nz_f64(env->fregs[f1].d); +/* 128-bit FP subtraction */ +uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_sub(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* 32-bit FP division RR */ @@ -446,27 +450,6 @@ uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return float_comp_to_cc(env, cmp); } -/* 32-bit FP subtraction RM */ -void HELPER(seb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); -} - -/* 64-bit FP subtraction RM */ -uint32_t HELPER(sdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); -} - /* 64-bit FP multiplication RM */ void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) { @@ -620,23 +603,6 @@ void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) env->fregs[f1 + 1].ll = x.ll.lower; } -/* 128-bit FP subtraction RR */ -uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; - - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_sub(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - /* 32-bit FP multiplication RR */ void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 2e6443321f..4fca4c5c9e 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -39,8 +39,9 @@ DEF_HELPER_3(cxgbr, void, env, i32, s64) DEF_HELPER_3(aeb, i64, env, i64, i64) DEF_HELPER_3(adb, i64, env, i64, i64) DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(sebr, i32, env, i32, i32) -DEF_HELPER_3(sdbr, i32, env, i32, i32) +DEF_HELPER_3(seb, i64, env, i64, i64) +DEF_HELPER_3(sdb, i64, env, i64, i64) +DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(debr, void, env, i32, i32) DEF_HELPER_3(dxbr, void, env, i32, i32) DEF_HELPER_3(mdbr, void, env, i32, i32) @@ -59,8 +60,6 @@ DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) DEF_HELPER_3(deb, void, env, i32, i32) DEF_HELPER_3(meeb, void, env, i32, i32) -DEF_HELPER_3(seb, void, env, i32, i32) -DEF_HELPER_3(sdb, i32, env, i32, i64) DEF_HELPER_3(mdb, void, env, i32, i64) DEF_HELPER_3(ddb, void, env, i32, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) @@ -75,7 +74,6 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_3(sxbr, i32, env, i32, i32) DEF_HELPER_3(meebr, void, env, i32, i32) DEF_HELPER_3(ddbr, void, env, i32, i32) DEF_HELPER_4(madb, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f1c37e8939..fdfcffc470 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -476,6 +476,11 @@ C(0xb9e9, SGRK, RRF_a, DO, r2, r3, r1, 0, sub, subs64) C(0xe309, SG, RXY_a, Z, r1, m2_64, r1, 0, sub, subs64) C(0xe319, SGF, RXY_a, Z, r1, m2_32s, r1, 0, sub, subs64) + C(0xb30b, SEBR, RRE, Z, e1, e2, new, e1, seb, f32) + C(0xb31b, SDBR, RRE, Z, f1_o, f2_o, f1, 0, sdb, f64) + C(0xb34b, SXBR, RRE, Z, 0, x2_o, x1, 0, sxb, f128) + C(0xed0b, SEB, RXE, Z, e1, m2_32u, new, e1, seb, f32) + C(0xed1b, SDB, RXE, Z, f1_o, m2_64, f1, 0, sdb, f64) /* SUBTRACT HALFWORD */ C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f62e4f0431..2b3b0fc789 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -556,11 +556,6 @@ static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); } -static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) -{ - gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); -} - /* CC value is in env->cc_op */ static inline void set_cc_static(DisasContext *s) { @@ -1000,19 +995,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { - case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_seb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - - tmp32 = load_freg32(r1); - gen_set_cc_nz_f32(s, tmp32); - tcg_temp_free_i32(tmp32); - break; case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ tmp = tcg_temp_new_i64(); tmp32 = tcg_temp_new_i32(); @@ -1046,11 +1028,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; - case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); gen_helper_mdb(cpu_env, tmp_r1, addr); @@ -1479,9 +1456,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x3: /* LCEBR R1,R2 [RRE] */ FP_HELPER_CC(lcebr); break; - case 0xb: /* SEBR R1,R2 [RRE] */ - FP_HELPER_CC(sebr); - break; case 0xd: /* DEBR R1,R2 [RRE] */ FP_HELPER(debr); break; @@ -1497,9 +1471,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x17: /* MEEBR R1,R2 [RRE] */ FP_HELPER(meebr); break; - case 0x1b: /* SDBR R1,R2 [RRE] */ - FP_HELPER_CC(sdbr); - break; case 0x1c: /* MDBR R1,R2 [RRE] */ FP_HELPER(mdbr); break; @@ -1536,9 +1507,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x43: /* LCXBR R1,R2 [RRE] */ FP_HELPER_CC(lcxbr); break; - case 0x4b: /* SXBR R1,R2 [RRE] */ - FP_HELPER_CC(sxbr); - break; case 0x4c: /* MXBR R1,R2 [RRE] */ FP_HELPER(mxbr); break; @@ -2955,6 +2923,25 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_seb(DisasContext *s, DisasOps *o) +{ + gen_helper_seb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sdb(DisasContext *s, DisasOps *o) +{ + gen_helper_sdb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sxb(DisasContext *s, DisasOps *o) +{ + gen_helper_sxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_sigp(DisasContext *s, DisasOps *o) { From f08a5c311d3047f2cafe72e3e377674e7f8acdcb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 7 Sep 2012 11:41:12 -0700 Subject: [PATCH 0169/1634] target-s390: Convert FP DIVIDE Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 68 +++++++++++--------------------------- target-s390x/helper.h | 8 ++--- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 41 +++++++++++------------ 4 files changed, 47 insertions(+), 75 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index ea61936571..b0c18ee7c2 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -239,28 +239,31 @@ uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return RET128(ret); } -/* 32-bit FP division RR */ -void HELPER(debr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP division */ +uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); + float32 ret = float32_div(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 128-bit FP division RR */ -void HELPER(dxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP division */ +uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; + float64 ret = float64_div(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_div(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; +/* 128-bit FP division */ +uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_div(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* 64-bit FP multiplication RR */ @@ -399,18 +402,6 @@ uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(x1.q); } -/* 32-bit FP division RM */ -void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); -} - /* 32-bit FP multiplication RM */ void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) { @@ -462,18 +453,6 @@ void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); } -/* 64-bit FP division RM */ -void HELPER(ddb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); -} - static void set_round_mode(CPUS390XState *env, int m3) { switch (m3) { @@ -611,13 +590,6 @@ void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) &env->fpu_status); } -/* 64-bit FP division RR */ -void HELPER(ddbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); -} - /* 64-bit FP multiply and add RM */ void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 4fca4c5c9e..bb094c0fb0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -42,8 +42,9 @@ DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(seb, i64, env, i64, i64) DEF_HELPER_3(sdb, i64, env, i64, i64) DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(debr, void, env, i32, i32) -DEF_HELPER_3(dxbr, void, env, i32, i32) +DEF_HELPER_3(deb, i64, env, i64, i64) +DEF_HELPER_3(ddb, i64, env, i64, i64) +DEF_HELPER_5(dxb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(mdbr, void, env, i32, i32) DEF_HELPER_3(mxbr, void, env, i32, i32) DEF_HELPER_2(ldeb, i64, env, i64) @@ -58,10 +59,8 @@ DEF_HELPER_3(lpxbr, i32, env, i32, i32) DEF_HELPER_3(lcebr, i32, env, i32, i32) DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) -DEF_HELPER_3(deb, void, env, i32, i32) DEF_HELPER_3(meeb, void, env, i32, i32) DEF_HELPER_3(mdb, void, env, i32, i64) -DEF_HELPER_3(ddb, void, env, i32, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) @@ -75,7 +74,6 @@ DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) DEF_HELPER_3(meebr, void, env, i32, i32) -DEF_HELPER_3(ddbr, void, env, i32, i32) DEF_HELPER_4(madb, void, env, i32, i64, i32) DEF_HELPER_4(maebr, void, env, i32, i32, i32) DEF_HELPER_4(madbr, void, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index fdfcffc470..14dcd12417 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -167,6 +167,11 @@ /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) C(0x5d00, D, RX_a, Z, r1_D32, m2_32s, new_P, r1_P32, divs32, 0) + C(0xb30d, DEBR, RRE, Z, e1, e2, new, e1, deb, 0) + C(0xb31d, DDBR, RRE, Z, f1_o, f2_o, f1, 0, ddb, 0) + C(0xb34d, DXBR, RRE, Z, 0, x2_o, x1, 0, dxb, 0) + C(0xed0d, DEB, RXE, Z, e1, m2_32u, new, e1, deb, 0) + C(0xed1d, DDB, RXE, Z, f1_o, m2_64, f1, 0, ddb, 0) /* DIVIDE LOGICAL */ C(0xb997, DLR, RRE, Z, r1_D32, r2_32u, new_P, r1_P32, divu32, 0) C(0xe397, DL, RXY_a, Z, r1_D32, m2_32u, new_P, r1_P32, divu32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2b3b0fc789..c00992db55 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -995,15 +995,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { - case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_deb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); @@ -1032,10 +1023,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, potential_page_fault(s); gen_helper_mdb(cpu_env, tmp_r1, addr); break; - case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_ddb(cpu_env, tmp_r1, addr); - break; case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ /* for RXF insns, r1 is R3 and r1b is R1 */ tmp32 = tcg_const_i32(r1b); @@ -1456,9 +1443,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x3: /* LCEBR R1,R2 [RRE] */ FP_HELPER_CC(lcebr); break; - case 0xd: /* DEBR R1,R2 [RRE] */ - FP_HELPER(debr); - break; case 0x10: /* LPDBR R1,R2 [RRE] */ FP_HELPER_CC(lpdbr); break; @@ -1474,9 +1458,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x1c: /* MDBR R1,R2 [RRE] */ FP_HELPER(mdbr); break; - case 0x1d: /* DDBR R1,R2 [RRE] */ - FP_HELPER(ddbr); - break; case 0xe: /* MAEBR R1,R3,R2 [RRF] */ case 0x1e: /* MADBR R1,R3,R2 [RRF] */ case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ @@ -1510,9 +1491,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x4c: /* MXBR R1,R2 [RRE] */ FP_HELPER(mxbr); break; - case 0x4d: /* DXBR R1,R2 [RRE] */ - FP_HELPER(dxbr); - break; case 0x65: /* LXR R1,R2 [RRE] */ tmp = load_freg(r2); store_freg(r1, tmp); @@ -2428,6 +2406,25 @@ static ExitStatus op_divu64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_deb(DisasContext *s, DisasOps *o) +{ + gen_helper_deb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_ddb(DisasContext *s, DisasOps *o) +{ + gen_helper_ddb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_dxb(DisasContext *s, DisasOps *o) +{ + gen_helper_dxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_efpc(DisasContext *s, DisasOps *o) { tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); From 83b00736f3d8033861c27b80c9d3fc7c44bbec99 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 12:02:38 -0700 Subject: [PATCH 0170/1634] target-s390: Convert FP MULTIPLY Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 87 +++++++++++++++++--------------------- target-s390x/helper.h | 10 ++--- target-s390x/insn-data.def | 9 ++++ target-s390x/translate.c | 56 ++++++++++++++---------- 4 files changed, 86 insertions(+), 76 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b0c18ee7c2..9805026c6a 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -266,27 +266,50 @@ uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return RET128(ret); } -/* 64-bit FP multiplication RR */ -void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 32-bit FP multiplication */ +uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); + float32 ret = float32_mul(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 128-bit FP multiplication RR */ -void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* 64-bit FP multiplication */ +uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { - CPU_QuadU v1; - CPU_QuadU v2; - CPU_QuadU res; + float64 ret = float64_mul(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - res.q = float128_mul(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; +/* 64/32-bit FP multiplication */ +uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) +{ + float64 ret = float32_to_float64(f2, &env->fpu_status); + ret = float64_mul(f1, ret, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* 128-bit FP multiplication */ +uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + float128 ret = float128_mul(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + +/* 128/64-bit FP multiplication */ +uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t f2) +{ + float128 ret = float64_to_float128(f2, &env->fpu_status); + ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } /* convert 32-bit float to 64-bit float */ @@ -402,18 +425,6 @@ uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) return set_cc_nz_f128(x1.q); } -/* 32-bit FP multiplication RM */ -void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - - v2.l = val; - HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); -} - /* 32-bit FP compare */ uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { @@ -441,18 +452,6 @@ uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return float_comp_to_cc(env, cmp); } -/* 64-bit FP multiplication RM */ -void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - - v2.ll = cpu_ldq_data(env, a2); - HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, - v1, f1, v2.d); - env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); -} - static void set_round_mode(CPUS390XState *env, int m3) { switch (m3) { @@ -582,14 +581,6 @@ void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) env->fregs[f1 + 1].ll = x.ll.lower; } -/* 32-bit FP multiplication RR */ -void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); -} - /* 64-bit FP multiply and add RM */ void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index bb094c0fb0..36316c3959 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -45,8 +45,11 @@ DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) DEF_HELPER_3(deb, i64, env, i64, i64) DEF_HELPER_3(ddb, i64, env, i64, i64) DEF_HELPER_5(dxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(mdbr, void, env, i32, i32) -DEF_HELPER_3(mxbr, void, env, i32, i32) +DEF_HELPER_3(meeb, i64, env, i64, i64) +DEF_HELPER_3(mdeb, i64, env, i64, i64) +DEF_HELPER_3(mdb, i64, env, i64, i64) +DEF_HELPER_5(mxb, i64, env, i64, i64, i64, i64) +DEF_HELPER_4(mxdb, i64, env, i64, i64, i64) DEF_HELPER_2(ldeb, i64, env, i64) DEF_HELPER_3(ldxb, i64, env, i64, i64) DEF_HELPER_2(lxdb, i64, env, i64) @@ -59,8 +62,6 @@ DEF_HELPER_3(lpxbr, i32, env, i32, i32) DEF_HELPER_3(lcebr, i32, env, i32, i32) DEF_HELPER_3(lcdbr, i32, env, i32, i32) DEF_HELPER_3(lcxbr, i32, env, i32, i32) -DEF_HELPER_3(meeb, void, env, i32, i32) -DEF_HELPER_3(mdb, void, env, i32, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) @@ -73,7 +74,6 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_3(meebr, void, env, i32, i32) DEF_HELPER_4(madb, void, env, i32, i64, i32) DEF_HELPER_4(maebr, void, env, i32, i32, i32) DEF_HELPER_4(madbr, void, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 14dcd12417..89f71acebb 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -359,6 +359,15 @@ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x5c00, M, RX_a, Z, r1p1_32s, m2_32s, new, r1_D32, mul, 0) C(0xe35c, MFY, RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0) + C(0xb317, MEEBR, RRE, Z, e1, e2, new, e1, meeb, 0) + C(0xb31c, MDBR, RRE, Z, f1_o, f2_o, f1, 0, mdb, 0) + C(0xb34c, MXBR, RRE, Z, 0, x2_o, x1, 0, mxb, 0) + C(0xb30c, MDEBR, RRE, Z, f1_o, e2, f1, 0, mdeb, 0) + C(0xb307, MXDBR, RRE, Z, 0, f2_o, x1, 0, mxdb, 0) + C(0xed17, MEEB, RXE, Z, e1, m2_32u, new, e1, meeb, 0) + C(0xed1c, MDB, RXE, Z, f1_o, m2_64, f1, 0, mdb, 0) + C(0xed0c, MDEB, RXE, Z, f1_o, m2_32u, f1, 0, mdeb, 0) + C(0xed07, MXDB, RXE, Z, 0, m2_64, x1, 0, mxdb, 0) /* MULTIPLY HALFWORD */ C(0x4c00, MH, RX_a, Z, r1_o, m2_16s, new, r1_32, mul, 0) C(0xe37c, MHY, RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c00992db55..10bf3a0abe 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -991,7 +991,7 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { TCGv_i32 tmp_r1, tmp32; - TCGv_i64 addr, tmp; + TCGv_i64 addr; addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); switch (op) { @@ -1010,19 +1010,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; - case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ - tmp = tcg_temp_new_i64(); - tmp32 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_meeb(cpu_env, tmp_r1, tmp32); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32); - break; - case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_mdb(cpu_env, tmp_r1, addr); - break; case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ /* for RXF insns, r1 is R3 and r1b is R1 */ tmp32 = tcg_const_i32(r1b); @@ -1452,12 +1439,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x15: /* SQBDR R1,R2 [RRE] */ FP_HELPER(sqdbr); break; - case 0x17: /* MEEBR R1,R2 [RRE] */ - FP_HELPER(meebr); - break; - case 0x1c: /* MDBR R1,R2 [RRE] */ - FP_HELPER(mdbr); - break; case 0xe: /* MAEBR R1,R3,R2 [RRF] */ case 0x1e: /* MADBR R1,R3,R2 [RRF] */ case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ @@ -1488,9 +1469,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x43: /* LCXBR R1,R2 [RRE] */ FP_HELPER_CC(lcxbr); break; - case 0x4c: /* MXBR R1,R2 [RRE] */ - FP_HELPER(mxbr); - break; case 0x65: /* LXR R1,R2 [RRE] */ tmp = load_freg(r2); store_freg(r1, tmp); @@ -2827,6 +2805,38 @@ static ExitStatus op_mul128(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_meeb(DisasContext *s, DisasOps *o) +{ + gen_helper_meeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mdeb(DisasContext *s, DisasOps *o) +{ + gen_helper_mdeb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mdb(DisasContext *s, DisasOps *o) +{ + gen_helper_mdb(o->out, cpu_env, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_mxb(DisasContext *s, DisasOps *o) +{ + gen_helper_mxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + +static ExitStatus op_mxdb(DisasContext *s, DisasOps *o) +{ + gen_helper_mxdb(o->out, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_nabs(DisasContext *s, DisasOps *o) { gen_helper_nabs_i64(o->out, o->in2); From 722bfec331504bf873a5e4ec4f232c4ed116dda2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 12:30:12 -0700 Subject: [PATCH 0171/1634] target-s390: Convert MULTIPLY AND ADD, SUBTRACT Use the new float*_muladd interface to softfloat. Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 57 ++++++++++++++++------------------ target-s390x/helper.h | 8 ++--- target-s390x/insn-data.def | 11 +++++++ target-s390x/translate.c | 63 +++++++++++++++++++------------------- 4 files changed, 72 insertions(+), 67 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 9805026c6a..8f2c504beb 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -581,47 +581,42 @@ void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) env->fregs[f1 + 1].ll = x.ll.lower; } -/* 64-bit FP multiply and add RM */ -void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) +/* 32-bit FP multiply and add */ +uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - CPU_DoubleU v2; - - HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); - v2.ll = cpu_ldq_data(env, a2); - env->fregs[f1].d = float64_add(env->fregs[f1].d, - float64_mul(v2.d, env->fregs[f3].d, - &env->fpu_status), - &env->fpu_status); + float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiply and add RR */ -void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* 64-bit FP multiply and add */ +uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); + float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 64-bit FP multiply and subtract RR */ -void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* 32-bit FP multiply and subtract */ +uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); - env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); + float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, + &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } -/* 32-bit FP multiply and add RR */ -void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +/* 64-bit FP multiply and subtract */ +uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, + uint64_t f2, uint64_t f3) { - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - float32_mul(env->fregs[f2].l.upper, - env->fregs[f3].l.upper, - &env->fpu_status), - &env->fpu_status); + float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, + &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* test data class 32-bit */ diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 36316c3959..21158493c8 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -74,10 +74,10 @@ DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) -DEF_HELPER_4(madb, void, env, i32, i64, i32) -DEF_HELPER_4(maebr, void, env, i32, i32, i32) -DEF_HELPER_4(madbr, void, env, i32, i32, i32) -DEF_HELPER_4(msdbr, void, env, i32, i32, i32) +DEF_HELPER_4(maeb, i64, env, i64, i64, i64) +DEF_HELPER_4(madb, i64, env, i64, i64, i64) +DEF_HELPER_4(mseb, i64, env, i64, i64, i64) +DEF_HELPER_4(msdb, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 89f71acebb..a924a93f7b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -391,6 +391,17 @@ C(0xc201, MSFI, RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0) C(0xc200, MSGFI, RIL_a, GIE, r1_o, i2, r1, 0, mul, 0) +/* MULTIPLY AND ADD */ + C(0xb30e, MAEBR, RRD, Z, e1, e2, new, e1, maeb, 0) + C(0xb31e, MADBR, RRD, Z, f1_o, f2_o, f1, 0, madb, 0) + C(0xed0e, MAEB, RXF, Z, e1, m2_32u, new, e1, maeb, 0) + C(0xed1e, MADB, RXF, Z, f1_o, m2_64, f1, 0, madb, 0) +/* MULTIPLY AND SUBTRACT */ + C(0xb30f, MSEBR, RRD, Z, e1, e2, new, e1, mseb, 0) + C(0xb31f, MSDBR, RRD, Z, f1_o, f2_o, f1, 0, msdb, 0) + C(0xed0f, MSEB, RXF, Z, e1, m2_32u, new, e1, mseb, 0) + C(0xed1f, MSDB, RXF, Z, f1_o, m2_64, f1, 0, msdb, 0) + /* OR */ C(0x1600, OR, RR_a, Z, r1, r2, new, r1_32, or, nz32) C(0xb9f6, ORK, RRF_a, DO, r2, r3, new, r1_32, or, nz32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 10bf3a0abe..faf979fe3c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -990,7 +990,7 @@ static void free_compare(DisasCompare *c) static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, int x2, int b2, int d2, int r1b) { - TCGv_i32 tmp_r1, tmp32; + TCGv_i32 tmp_r1; TCGv_i64 addr; addr = get_address(s, x2, b2, d2); tmp_r1 = tcg_const_i32(r1); @@ -1010,13 +1010,6 @@ static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; - case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ - /* for RXF insns, r1 is R3 and r1b is R1 */ - tmp32 = tcg_const_i32(r1b); - potential_page_fault(s); - gen_helper_madb(cpu_env, tmp32, addr, tmp_r1); - tcg_temp_free_i32(tmp32); - break; default: LOG_DISAS("illegal ed operation 0x%x\n", op); gen_illegal_opcode(s); @@ -1439,30 +1432,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, case 0x15: /* SQBDR R1,R2 [RRE] */ FP_HELPER(sqdbr); break; - case 0xe: /* MAEBR R1,R3,R2 [RRF] */ - case 0x1e: /* MADBR R1,R3,R2 [RRF] */ - case 0x1f: /* MSDBR R1,R3,R2 [RRF] */ - /* for RRF insns, m3 is R1, r1 is R3, and r2 is R2 */ - tmp32_1 = tcg_const_i32(m3); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(r1); - switch (op) { - case 0xe: - gen_helper_maebr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - case 0x1e: - gen_helper_madbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - case 0x1f: - gen_helper_msdbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x40: /* LPXBR R1,R2 [RRE] */ FP_HELPER_CC(lpxbr); break; @@ -2837,6 +2806,36 @@ static ExitStatus op_mxdb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_maeb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 r3 = load_freg32_i64(get_field(s->fields, r3)); + gen_helper_maeb(o->out, cpu_env, o->in1, o->in2, r3); + tcg_temp_free_i64(r3); + return NO_EXIT; +} + +static ExitStatus op_madb(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + gen_helper_madb(o->out, cpu_env, o->in1, o->in2, fregs[r3]); + return NO_EXIT; +} + +static ExitStatus op_mseb(DisasContext *s, DisasOps *o) +{ + TCGv_i64 r3 = load_freg32_i64(get_field(s->fields, r3)); + gen_helper_mseb(o->out, cpu_env, o->in1, o->in2, r3); + tcg_temp_free_i64(r3); + return NO_EXIT; +} + +static ExitStatus op_msdb(DisasContext *s, DisasOps *o) +{ + int r3 = get_field(s->fields, r3); + gen_helper_msdb(o->out, cpu_env, o->in1, o->in2, fregs[r3]); + return NO_EXIT; +} + static ExitStatus op_nabs(DisasContext *s, DisasOps *o) { gen_helper_nabs_i64(o->out, o->in2); From 31aa97d1ed87853835a2df4ea9db1566f85c57a2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 12:40:09 -0700 Subject: [PATCH 0172/1634] target-s390: Convert TEST DATA CLASS Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 28 ++++++---------- target-s390x/helper.h | 6 ++-- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 66 +++++++++++++------------------------- 4 files changed, 40 insertions(+), 65 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 8f2c504beb..7638a0d4a8 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -620,13 +620,12 @@ uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, } /* test data class 32-bit */ -uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tceb)(uint64_t f1, uint64_t m2) { - float32 v1 = env->fregs[f1].l.upper; + float32 v1 = f1; int neg = float32_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -636,19 +635,16 @@ uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) /* assume normalized number */ cc = 1; } - /* FIXME: denormalized? */ return cc; } /* test data class 64-bit */ -uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tcdb)(uint64_t v1, uint64_t m2) { - float64 v1 = env->fregs[f1].d; int neg = float64_is_neg(v1); uint32_t cc = 0; - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || @@ -663,20 +659,16 @@ uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) } /* test data class 128-bit */ -uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +uint32_t HELPER(tcxb)(uint64_t ah, uint64_t al, uint64_t m2) { - CPU_QuadU v1; + float128 v1 = make_float128(ah, al); + int neg = float128_is_neg(v1); uint32_t cc = 0; - int neg; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - - neg = float128_is_neg(v1.q); - if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || - (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || - (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || - (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { + if ((float128_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float128_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float128_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || + (float128_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { cc = 1; } else if (m2 & (1 << (9-neg))) { /* assume normalized number */ diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 21158493c8..71dcdb5f3d 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -78,9 +78,9 @@ DEF_HELPER_4(maeb, i64, env, i64, i64, i64) DEF_HELPER_4(madb, i64, env, i64, i64, i64) DEF_HELPER_4(mseb, i64, env, i64, i64, i64) DEF_HELPER_4(msdb, i64, env, i64, i64, i64) -DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) -DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_WG_SE, i32, env, i32, i64) +DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a924a93f7b..54b75e13b4 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -531,6 +531,11 @@ /* SUPERVISOR CALL */ C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) +/* TEST DATA CLASS */ + C(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0) + C(0xed11, TCDB, RXE, Z, f1_o, a2, 0, 0, tcdb, 0) + C(0xed12, TCXB, RXE, Z, x1_o, a2, 0, 0, tcxb, 0) + /* TEST UNDER MASK */ C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index faf979fe3c..6593d88c68 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -987,38 +987,6 @@ static void free_compare(DisasCompare *c) } } -static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, - int x2, int b2, int d2, int r1b) -{ - TCGv_i32 tmp_r1; - TCGv_i64 addr; - addr = get_address(s, x2, b2, d2); - tmp_r1 = tcg_const_i32(r1); - switch (op) { - case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tcdb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ - potential_page_fault(s); - gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); - set_cc_static(s); - break; - default: - LOG_DISAS("illegal ed operation 0x%x\n", op); - gen_illegal_opcode(s); - return; - } - tcg_temp_free_i32(tmp_r1); - tcg_temp_free_i64(addr); -} - static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { @@ -1602,7 +1570,7 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { unsigned char opc; uint64_t insn; - int op, r1, r2, r3, d2, x2, b2, r1b; + int op, r1, r2, r3; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -1628,17 +1596,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b9(env, s, op, r1, r2); break; - case 0xed: - insn = ld_code6(env, s->pc); - debug_insn(insn); - op = insn & 0xff; - r1 = (insn >> 36) & 0xf; - x2 = (insn >> 32) & 0xf; - b2 = (insn >> 28) & 0xf; - d2 = (short)((insn >> 16) & 0xfff); - r1b = (insn >> 12) & 0xf; - disas_ed(env, s, op, r1, x2, b2, d2, r1b); - break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); gen_illegal_opcode(s); @@ -3224,6 +3181,27 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) return EXIT_NORETURN; } +static ExitStatus op_tceb(DisasContext *s, DisasOps *o) +{ + gen_helper_tceb(cc_op, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_tcdb(DisasContext *s, DisasOps *o) +{ + gen_helper_tcdb(cc_op, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_tcxb(DisasContext *s, DisasOps *o) +{ + gen_helper_tcxb(cc_op, o->out, o->out2, o->in2); + set_cc_static(s); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_tprot(DisasContext *s, DisasOps *o) { From 5d7fd045cafeac1831c1999cb9e1251b7906c6b2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 15:58:27 -0700 Subject: [PATCH 0173/1634] target-s390: Convert FP LOAD COMPLIMENT, NEGATIVE, POSITIVE Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 65 ----------------------------- target-s390x/helper.h | 6 --- target-s390x/insn-data.def | 9 +++++ target-s390x/translate.c | 83 ++++++++++++++++++++++++++------------ 4 files changed, 66 insertions(+), 97 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 7638a0d4a8..b46dd02178 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -360,71 +360,6 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) return ret; } -/* absolute value of 32-bit float */ -uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float32 v1; - float32 v2 = env->fregs[f2].d; - - v1 = float32_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f32(v1); -} - -/* absolute value of 64-bit float */ -uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - float64 v1; - float64 v2 = env->fregs[f2].d; - - v1 = float64_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f64(v1); -} - -/* absolute value of 128-bit float */ -uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - v1.q = float128_abs(v2.q); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; - return set_cc_nz_f128(v1.q); -} - -/* load complement of 32-bit float */ -uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load complement of 64-bit float */ -uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_chs(env->fregs[f2].d); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load complement of 128-bit float */ -uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) -{ - CPU_QuadU x1, x2; - - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - x1.q = float128_chs(x2.q); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; - return set_cc_nz_f128(x1.q); -} - /* 32-bit FP compare */ uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 71dcdb5f3d..4d2b0530ce 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -56,12 +56,6 @@ DEF_HELPER_2(lxdb, i64, env, i64) DEF_HELPER_2(lxeb, i64, env, i64) DEF_HELPER_2(ledb, i64, env, i64) DEF_HELPER_3(lexb, i64, env, i64, i64) -DEF_HELPER_3(lpebr, i32, env, i32, i32) -DEF_HELPER_3(lpdbr, i32, env, i32, i32) -DEF_HELPER_3(lpxbr, i32, env, i32, i32) -DEF_HELPER_3(lcebr, i32, env, i32, i32) -DEF_HELPER_3(lcdbr, i32, env, i32, i32) -DEF_HELPER_3(lcxbr, i32, env, i32, i32) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 54b75e13b4..74bc9945e9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -266,6 +266,9 @@ C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) C(0xb913, LCGFR, RRE, Z, 0, r2_32s, r1, 0, neg, neg64) + C(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32) + C(0xb313, LCDBR, RRE, Z, 0, f2_o, f1, 0, negf64, f64) + C(0xb343, LCXBR, RRE, Z, 0, x2_o, x1, 0, negf128, f128) /* LOAD HALFWORD */ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) @@ -310,10 +313,16 @@ C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) C(0xb911, LNGFR, RRE, Z, 0, r2_32s, r1, 0, nabs, nabs64) + C(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32) + C(0xb311, LNDBR, RRE, Z, 0, f2_o, f1, 0, nabsf64, f64) + C(0xb341, LNXBR, RRE, Z, 0, x2_o, x1, 0, nabsf128, f128) /* LOAD POSITIVE */ C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb910, LPGFR, RRE, Z, 0, r2_32s, r1, 0, abs, abs64) + C(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32) + C(0xb310, LPDBR, RRE, Z, 0, f2_o, f1, 0, absf64, f64) + C(0xb340, LPXBR, RRE, Z, 0, x2_o, x1, 0, absf128, f128) /* LOAD REVERSED */ C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6593d88c68..b6043d6701 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1385,35 +1385,9 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_2); switch (op) { - case 0x0: /* LPEBR R1,R2 [RRE] */ - FP_HELPER_CC(lpebr); - break; - case 0x3: /* LCEBR R1,R2 [RRE] */ - FP_HELPER_CC(lcebr); - break; - case 0x10: /* LPDBR R1,R2 [RRE] */ - FP_HELPER_CC(lpdbr); - break; - case 0x13: /* LCDBR R1,R2 [RRE] */ - FP_HELPER_CC(lcdbr); - break; case 0x15: /* SQBDR R1,R2 [RRE] */ FP_HELPER(sqdbr); break; - case 0x40: /* LPXBR R1,R2 [RRE] */ - FP_HELPER_CC(lpxbr); - break; - case 0x43: /* LCXBR R1,R2 [RRE] */ - FP_HELPER_CC(lcxbr); - break; - case 0x65: /* LXR R1,R2 [RRE] */ - tmp = load_freg(r2); - store_freg(r1, tmp); - tcg_temp_free_i64(tmp); - tmp = load_freg(r2 + 2); - store_freg(r1 + 2, tmp); - tcg_temp_free_i64(tmp); - break; case 0x74: /* LZER R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); gen_helper_lzer(cpu_env, tmp32_1); @@ -1997,6 +1971,25 @@ static ExitStatus op_abs(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_absf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffull); + return NO_EXIT; +} + +static ExitStatus op_absf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull); + return NO_EXIT; +} + +static ExitStatus op_absf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_andi_i64(o->out, o->in1, 0x7fffffffffffffffull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + static ExitStatus op_add(DisasContext *s, DisasOps *o) { tcg_gen_add_i64(o->out, o->in1, o->in2); @@ -2799,6 +2792,25 @@ static ExitStatus op_nabs(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_nabsf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in2, 0x80000000ull); + return NO_EXIT; +} + +static ExitStatus op_nabsf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in2, 0x8000000000000000ull); + return NO_EXIT; +} + +static ExitStatus op_nabsf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_ori_i64(o->out, o->in1, 0x8000000000000000ull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + static ExitStatus op_nc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); @@ -2815,6 +2827,25 @@ static ExitStatus op_neg(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_negf32(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in2, 0x80000000ull); + return NO_EXIT; +} + +static ExitStatus op_negf64(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in2, 0x8000000000000000ull); + return NO_EXIT; +} + +static ExitStatus op_negf128(DisasContext *s, DisasOps *o) +{ + tcg_gen_xori_i64(o->out, o->in1, 0x8000000000000000ull); + tcg_gen_mov_i64(o->out2, o->in2); + return NO_EXIT; +} + static ExitStatus op_oc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); From 16d7b2a43b3325882d51677d76a0a3f082844f2b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 14:33:03 -0700 Subject: [PATCH 0174/1634] target-s390: Convert FP SQUARE ROOT Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 24 +++++++++++++++++++++--- target-s390x/helper.h | 4 +++- target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 22 +++++++++++++++++++--- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b46dd02178..3b28ccb620 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -613,8 +613,26 @@ uint32_t HELPER(tcxb)(uint64_t ah, uint64_t al, uint64_t m2) return cc; } -/* square root 64-bit RR */ -void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +/* square root 32-bit */ +uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) { - env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); + float32 ret = float32_sqrt(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* square root 64-bit */ +uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) +{ + float64 ret = float64_sqrt(f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* square root 128-bit */ +uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) +{ + float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); } diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 4d2b0530ce..eb8d663cc7 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -76,7 +76,9 @@ DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_3(flogr, i32, env, i32, i64) -DEF_HELPER_3(sqdbr, void, env, i32, i32) +DEF_HELPER_2(sqeb, i64, env, i64) +DEF_HELPER_2(sqdb, i64, env, i64) +DEF_HELPER_3(sqxb, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 74bc9945e9..93fd3cab19 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -459,6 +459,13 @@ /* SHIFT RIGHT DOUBLE LOGICAL */ C(0x8c00, SRDL, RS_a, Z, r1_D32, sh64, new, r1_D32, srl, 0) +/* SQUARE ROOT */ + C(0xb314, SQEBR, RRE, Z, 0, e2, new, e1, sqeb, 0) + C(0xb315, SQDBR, RRE, Z, 0, f2_o, f1, 0, sqdb, 0) + C(0xb316, SQXBR, RRE, Z, 0, x2_o, x1, 0, sqxb, 0) + C(0xed14, SQEB, RXE, Z, 0, m2_32u, new, e1, sqeb, 0) + C(0xed15, SQDB, RXE, Z, 0, m2_64, f1, 0, sqdb, 0) + /* STORE */ C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b6043d6701..dd77998201 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1385,9 +1385,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_2); switch (op) { - case 0x15: /* SQBDR R1,R2 [RRE] */ - FP_HELPER(sqdbr); - break; case 0x74: /* LZER R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); gen_helper_lzer(cpu_env, tmp32_1); @@ -2936,6 +2933,25 @@ static ExitStatus op_sxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sqeb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqeb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sqdb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqdb(o->out, cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_sqxb(DisasContext *s, DisasOps *o) +{ + gen_helper_sqxb(o->out, cpu_env, o->in1, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_sigp(DisasContext *s, DisasOps *o) { From 24db8412ec58a63556fb51fb157497342f1b08b8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:14:24 -0700 Subject: [PATCH 0175/1634] target-s390: Convert LOAD ZERO Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 22 ---------------------- target-s390x/helper.h | 3 --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 29 ++++++++++++++--------------- 4 files changed, 18 insertions(+), 40 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 3b28ccb620..b735c2c384 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -494,28 +494,6 @@ uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, return set_cc_nz_f128(v2.q); } -/* load 32-bit FP zero */ -void HELPER(lzer)(CPUS390XState *env, uint32_t f1) -{ - env->fregs[f1].l.upper = float32_zero; -} - -/* load 64-bit FP zero */ -void HELPER(lzdr)(CPUS390XState *env, uint32_t f1) -{ - env->fregs[f1].d = float64_zero; -} - -/* load 128-bit FP zero */ -void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) -{ - CPU_QuadU x; - - x.q = float64_to_float128(float64_zero, &env->fpu_status); - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 1].ll = x.ll.lower; -} - /* 32-bit FP multiply and add */ uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index eb8d663cc7..89a3218e4d 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -62,9 +62,6 @@ DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) -DEF_HELPER_2(lzer, void, env, i32) -DEF_HELPER_2(lzdr, void, env, i32) -DEF_HELPER_2(lzxr, void, env, i32) DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 93fd3cab19..e6b9a5aa7f 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -329,6 +329,10 @@ C(0xe31f, LRVH, RXY_a, Z, 0, m2_16u, new, r1_16, rev16, 0) C(0xe31e, LRV, RXY_a, Z, 0, m2_32u, new, r1_32, rev32, 0) C(0xe30f, LRVG, RXY_a, Z, 0, m2_64, r1, 0, rev64, 0) +/* LOAD ZERO */ + C(0xb374, LZER, RRE, Z, 0, 0, 0, e1, zero, 0) + C(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0) + C(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0) /* LOAD LENGTHENED */ C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dd77998201..b1bcfd393b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1385,21 +1385,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_2); switch (op) { - case 0x74: /* LZER R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzer(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x75: /* LZDR R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzdr(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; - case 0x76: /* LZXR R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_helper_lzxr(cpu_env, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x84: /* SFPC R1 [RRE] */ tmp32_1 = load_reg32(r1); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); @@ -3310,6 +3295,20 @@ static ExitStatus op_xori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_zero(DisasContext *s, DisasOps *o) +{ + o->out = tcg_const_i64(0); + return NO_EXIT; +} + +static ExitStatus op_zero2(DisasContext *s, DisasOps *o) +{ + o->out = tcg_const_i64(0); + o->out2 = o->out; + o->g_out2 = true; + return NO_EXIT; +} + /* ====================================================================== */ /* The "Cc OUTput" generators. Given the generated output (and in some cases the original inputs), update the various cc data structures in order to From 68c8bd93ccb0ee441d62b5b8b8911cf5c38663f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 15:17:35 -0700 Subject: [PATCH 0176/1634] target-s390: Convert CONVERT TO FIXED Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 98 ++++++++++++----------------- target-s390x/helper.h | 12 ++-- target-s390x/insn-data.def | 7 +++ target-s390x/translate.c | 125 +++++++++++++++++++++---------------- 4 files changed, 124 insertions(+), 118 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b735c2c384..ff3b435e89 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -387,8 +387,9 @@ uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, return float_comp_to_cc(env, cmp); } -static void set_round_mode(CPUS390XState *env, int m3) +static int swap_round_mode(CPUS390XState *env, int m3) { + int ret = env->fpu_status.float_rounding_mode; switch (m3) { case 0: /* current mode */ @@ -412,86 +413,69 @@ static void set_round_mode(CPUS390XState *env, int m3) set_float_rounding_mode(float_round_down, &env->fpu_status); break; } + return ret; } /* convert 32-bit float to 64-bit int */ -uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(env, m3); - env->regs[r1] = float32_to_int64(v2, &env->fpu_status); - return set_cc_nz_f32(v2); + int hold = swap_round_mode(env, m3); + int64_t ret = float32_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 64-bit float to 64-bit int */ -uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float64 v2 = env->fregs[f2].d; - - set_round_mode(env, m3); - env->regs[r1] = float64_to_int64(v2, &env->fpu_status); - return set_cc_nz_f64(v2); + int hold = swap_round_mode(env, m3); + int64_t ret = float64_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 64-bit int */ -uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) { - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - set_round_mode(env, m3); - env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); - if (float128_is_any_nan(v2.q)) { - return 3; - } else if (float128_is_zero(v2.q)) { - return 0; - } else if (float128_is_neg(v2.q)) { - return 1; - } else { - return 2; - } + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + int64_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 32-bit float to 32-bit int */ -uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float32 v2 = env->fregs[f2].l.upper; - - set_round_mode(env, m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float32_to_int32(v2, &env->fpu_status); - return set_cc_nz_f32(v2); + int hold = swap_round_mode(env, m3); + int32_t ret = float32_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 64-bit float to 32-bit int */ -uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { - float64 v2 = env->fregs[f2].d; - - set_round_mode(env, m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float64_to_int32(v2, &env->fpu_status); - return set_cc_nz_f64(v2); + int hold = swap_round_mode(env, m3); + int32_t ret = float64_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* convert 128-bit float to 32-bit int */ -uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, - uint32_t m3) +uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) { - CPU_QuadU v2; - - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float128_to_int32(v2.q, &env->fpu_status); - return set_cc_nz_f128(v2.q); + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + int32_t ret = float128_to_int32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; } /* 32-bit FP multiply and add */ diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 89a3218e4d..1439b5ed1f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -59,12 +59,12 @@ DEF_HELPER_3(lexb, i64, env, i64, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) -DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) -DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) -DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) +DEF_HELPER_3(cgeb, i64, env, i64, i32) +DEF_HELPER_3(cgdb, i64, env, i64, i32) +DEF_HELPER_4(cgxb, i64, env, i64, i64, i32) +DEF_HELPER_3(cfeb, i64, env, i64, i32) +DEF_HELPER_3(cfdb, i64, env, i64, i32) +DEF_HELPER_4(cfxb, i64, env, i64, i64, i32) DEF_HELPER_4(maeb, i64, env, i64, i64, i64) DEF_HELPER_4(madb, i64, env, i64, i64, i64) DEF_HELPER_4(mseb, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e6b9a5aa7f..2d88b70474 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -163,6 +163,13 @@ /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) +/* CONVERT TO FIXED */ + C(0xb398, CFEBR, RRF_e, Z, 0, e2, new, r1_32, cfeb, 0) + C(0xb399, CFDBR, RRF_e, Z, 0, f2_o, new, r1_32, cfdb, 0) + C(0xb39a, CFXBR, RRF_e, Z, 0, x2_o, new, r1_32, cfxb, 0) + C(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0) + C(0xb3a9, CGDBR, RRF_e, Z, 0, f2_o, r1, 0, cgdb, 0) + C(0xb3aa, CGXBR, RRF_e, Z, 0, x2_o, r1, 0, cgxb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b1bcfd393b..03fae68b10 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -485,6 +485,21 @@ static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) gen_op_update1_cc_i64(s, CC_OP_NZ, val); } +static inline void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val); +} + +static inline void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) +{ + gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val); +} + +static inline void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) +{ + gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl); +} + static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, enum cc_op cond) { @@ -1367,7 +1382,7 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, int r1, int r2) { TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; + TCGv_i32 tmp32_1, tmp32_2; LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); #define FP_HELPER(i) \ tmp32_1 = tcg_const_i32(r1); \ @@ -1411,30 +1426,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x98: /* CFEBR R1,R2 [RRE] */ - case 0x99: /* CFDBR R1,R2 [RRE] */ - case 0x9a: /* CFXBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - switch (op) { - case 0x98: - gen_helper_cfebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x99: - gen_helper_cfdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - case 0x9a: - gen_helper_cfxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - break; - default: - tcg_abort(); - } - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0xa4: /* CEGBR R1,R2 [RRE] */ case 0xa5: /* CDGBR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); @@ -1459,36 +1450,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0xa8: /* CGEBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xa9: /* CGDBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - case 0xaa: /* CGXBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - tmp32_3 = tcg_const_i32(m3); - gen_helper_cgxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; default: LOG_DISAS("illegal b3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2129,6 +2090,60 @@ static ExitStatus op_cxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cfeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cfdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cfxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cgeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cgdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_cgxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); From 683bb9a8889cd00e69b05ba78bd5ba27f2e4e958 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Aug 2012 21:08:22 -0700 Subject: [PATCH 0177/1634] target-s390: Convert CONVERT FROM FIXED Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 81 ++++++++++++++------------------------ target-s390x/helper.h | 9 ++--- target-s390x/insn-data.def | 7 ++++ target-s390x/translate.c | 73 ++++++++++++---------------------- 4 files changed, 66 insertions(+), 104 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index ff3b435e89..ac530e9700 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -134,57 +134,6 @@ uint32_t set_cc_nz_f128(float128 v) } } -/* convert 32-bit int to 64-bit float */ -void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) -{ - HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); -} - -/* convert 32-bit int to 128-bit float */ -void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) -{ - CPU_QuadU v1; - - v1.q = int32_to_float128(v2, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - -/* convert 64-bit int to 32-bit float */ -void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); -} - -/* convert 64-bit int to 64-bit float */ -void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); - env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); -} - -/* convert 64-bit int to 128-bit float */ -void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) -{ - CPU_QuadU x1; - - x1.q = int64_to_float128(v2, &env->fpu_status); - HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, - x1.ll.upper, x1.ll.lower); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; -} - -/* convert 32-bit int to 32-bit float */ -void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) -{ - env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); - HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, - env->fregs[f1].l.upper, f1); -} - /* 32-bit FP addition */ uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) { @@ -416,6 +365,36 @@ static int swap_round_mode(CPUS390XState *env, int m3) return ret; } +/* convert 64-bit int to 32-bit float */ +uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float32 ret = int64_to_float32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit int to 64-bit float */ +uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float64 ret = int64_to_float64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit int to 128-bit float */ +uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 ret = int64_to_float128(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + /* convert 32-bit float to 64-bit int */ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 1439b5ed1f..d9f630ecc3 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -30,12 +30,9 @@ DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) -DEF_HELPER_3(cefbr, void, env, i32, s32) -DEF_HELPER_3(cdfbr, void, env, i32, s32) -DEF_HELPER_3(cxfbr, void, env, i32, s32) -DEF_HELPER_3(cegbr, void, env, i32, s64) -DEF_HELPER_3(cdgbr, void, env, i32, s64) -DEF_HELPER_3(cxgbr, void, env, i32, s64) +DEF_HELPER_3(cegb, i64, env, s64, i32) +DEF_HELPER_3(cdgb, i64, env, s64, i32) +DEF_HELPER_3(cxgb, i64, env, s64, i32) DEF_HELPER_3(aeb, i64, env, i64, i64) DEF_HELPER_3(adb, i64, env, i64, i64) DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2d88b70474..d5e1c5c1cd 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -170,6 +170,13 @@ C(0xb3a8, CGEBR, RRF_e, Z, 0, e2, r1, 0, cgeb, 0) C(0xb3a9, CGDBR, RRF_e, Z, 0, f2_o, r1, 0, cgdb, 0) C(0xb3aa, CGXBR, RRF_e, Z, 0, x2_o, r1, 0, cgxb, 0) +/* CONVERT FROM FIXED */ + C(0xb394, CEFBR, RRF_e, Z, 0, r2_32s, new, e1, cegb, 0) + C(0xb395, CDFBR, RRF_e, Z, 0, r2_32s, f1, 0, cdgb, 0) + C(0xb396, CXFBR, RRF_e, Z, 0, r2_32s, x1, 0, cxgb, 0) + C(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0) + C(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, f1, 0, cdgb, 0) + C(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, x1, 0, cxgb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 03fae68b10..47ccc6740a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1381,8 +1381,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, int r1, int r2) { - TCGv_i64 tmp; - TCGv_i32 tmp32_1, tmp32_2; + TCGv_i32 tmp32_1; LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); #define FP_HELPER(i) \ tmp32_1 = tcg_const_i32(r1); \ @@ -1405,51 +1404,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); tcg_temp_free_i32(tmp32_1); break; - case 0x94: /* CEFBR R1,R2 [RRE] */ - case 0x95: /* CDFBR R1,R2 [RRE] */ - case 0x96: /* CXFBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = load_reg32(r2); - switch (op) { - case 0x94: - gen_helper_cefbr(cpu_env, tmp32_1, tmp32_2); - break; - case 0x95: - gen_helper_cdfbr(cpu_env, tmp32_1, tmp32_2); - break; - case 0x96: - gen_helper_cxfbr(cpu_env, tmp32_1, tmp32_2); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; - case 0xa4: /* CEGBR R1,R2 [RRE] */ - case 0xa5: /* CDGBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - switch (op) { - case 0xa4: - gen_helper_cegbr(cpu_env, tmp32_1, tmp); - break; - case 0xa5: - gen_helper_cdgbr(cpu_env, tmp32_1, tmp); - break; - default: - tcg_abort(); - } - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; - case 0xa6: /* CXGBR R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp = load_reg(r2); - gen_helper_cxgbr(cpu_env, tmp32_1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; default: LOG_DISAS("illegal b3 operation 0x%x\n", op); gen_illegal_opcode(s); @@ -2144,6 +2098,31 @@ static ExitStatus op_cgxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cegb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cegb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cdgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cdgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cxgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); From 102bf2c63535122cba0d7917ed8cfb8cc1c7b14c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 07:39:11 -0700 Subject: [PATCH 0178/1634] target-s390: Convert FLOGR Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 8 +++++ target-s390x/cpu.h | 2 ++ target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 ++ target-s390x/int_helper.c | 22 ++----------- target-s390x/translate.c | 66 +++++++++++++++++++++----------------- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index f1038be1b5..e3bed16bd3 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -399,6 +399,11 @@ static uint32_t cc_calc_sla_64(uint64_t src, int shift) return 2; } +static uint32_t cc_calc_flogr(uint64_t dst) +{ + return dst ? 2 : 0; +} + static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, uint64_t vr) { @@ -504,6 +509,9 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, case CC_OP_SLA_64: r = cc_calc_sla_64(src, dst); break; + case CC_OP_FLOGR: + r = cc_calc_flogr(dst); + break; case CC_OP_NZ_F32: r = set_cc_nz_f32(dst); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index f1d4dc67f4..dc7bbc67f6 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -478,6 +478,7 @@ enum cc_op { CC_OP_ICM, /* insert characters under mask */ CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ + CC_OP_FLOGR, /* find leftmost one */ CC_OP_MAX }; @@ -521,6 +522,7 @@ static const char *cc_names[] = { [CC_OP_ICM] = "CC_OP_ICM", [CC_OP_SLA_32] = "CC_OP_SLA_32", [CC_OP_SLA_64] = "CC_OP_SLA_64", + [CC_OP_FLOGR] = "CC_OP_FLOGR", }; static inline const char *cc_name(int cc_op) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index d9f630ecc3..e64b46d755 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -69,7 +69,7 @@ DEF_HELPER_4(msdb, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) -DEF_HELPER_3(flogr, i32, env, i32, i64) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_2(sqeb, i64, env, i64) DEF_HELPER_2(sqdb, i64, env, i64) DEF_HELPER_3(sqxb, i64, env, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index d5e1c5c1cd..771baafa37 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -220,6 +220,9 @@ /* EXTRACT FPC */ C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) +/* FIND LEFTMOST ONE */ + C(0xb983, FLOGR, RRE, EI, 0, r2_o, r1_P, 0, flogr, 0) + /* INSERT CHARACTER */ C(0x4300, IC, RX_a, Z, 0, m2_8u, 0, r1_8, mov2, 0) C(0xe373, ICY, RXY_a, LD, 0, m2_8u, 0, r1_8, mov2, 0) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 839c0e1500..dc16de206c 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -165,26 +165,10 @@ int64_t HELPER(nabs_i64)(int64_t val) } } -/* find leftmost one */ -uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) +/* count leading zeros, for find leftmost one */ +uint64_t HELPER(clz)(uint64_t v) { - uint64_t res = 0; - uint64_t ov2 = v2; - - while (!(v2 & 0x8000000000000000ULL) && v2) { - v2 <<= 1; - res++; - } - - if (!v2) { - env->regs[r1] = 64; - env->regs[r1 + 1] = 0; - return 0; - } else { - env->regs[r1] = res; - env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); - return 2; - } + return clz64(v); } uint64_t HELPER(cvd)(int32_t bin) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 47ccc6740a..e674c93ffe 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -620,6 +620,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_COMP_64: case CC_OP_NZ_F32: case CC_OP_NZ_F64: + case CC_OP_FLOGR: /* 1 argument */ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; @@ -852,6 +853,20 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) account_inline_branch(s, old_cc_op); break; + case CC_OP_FLOGR: + switch (mask & 0xa) { + case 8: /* src == 0 -> no one bit found */ + cond = TCG_COND_EQ; + break; + case 2: /* src != 0 -> one bit found */ + cond = TCG_COND_NE; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + default: do_dynamic: /* Calculate cc value. */ @@ -888,6 +903,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) case CC_OP_LTGT0_64: case CC_OP_NZ: + case CC_OP_FLOGR: c->u.s64.a = cc_dst; c->u.s64.b = tcg_const_i64(0); c->g1 = true; @@ -1414,29 +1430,6 @@ static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, #undef FP_HELPER } -static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, - int r2) -{ - TCGv_i64 tmp; - TCGv_i32 tmp32_1; - - LOG_DISAS("disas_b9: op 0x%x r1 %d r2 %d\n", op, r1, r2); - switch (op) { - case 0x83: /* FLOGR R1,R2 [RRE] */ - tmp = load_reg(r2); - tmp32_1 = tcg_const_i32(r1); - gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - break; - default: - LOG_DISAS("illegal b9 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { unsigned char opc; @@ -1460,13 +1453,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) r2 = insn & 0xf; disas_b3(env, s, op, r3, r1, r2); break; - case 0xb9: - insn = ld_code4(env, s->pc); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - op = (insn >> 16) & 0xff; - disas_b9(env, s, op, r1, r2); - break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); gen_illegal_opcode(s); @@ -2330,6 +2316,26 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_flogr(DisasContext *s, DisasOps *o) +{ + /* We'll use the original input for cc computation, since we get to + compare that against 0, which ought to be better than comparing + the real output against 64. It also lets cc_dst be a convenient + temporary during our computation. */ + gen_op_update1_cc_i64(s, CC_OP_FLOGR, o->in2); + + /* R1 = IN ? CLZ(IN) : 64. */ + gen_helper_clz(o->out, o->in2); + + /* R1+1 = IN & ~(found bit). Note that we may attempt to shift this + value by 64, which is undefined. But since the shift is 64 iff the + input is zero, we still get the correct result after and'ing. */ + tcg_gen_movi_i64(o->out2, 0x8000000000000000ull); + tcg_gen_shr_i64(o->out2, o->out2, o->out); + tcg_gen_andc_i64(o->out2, cc_dst, o->out2); + return NO_EXIT; +} + static ExitStatus op_icm(DisasContext *s, DisasOps *o) { int m3 = get_field(s->fields, m3); From 8379bfdbca195af9df1e6ecf67f04402bd80d471 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 07:44:43 -0700 Subject: [PATCH 0179/1634] target-s390: Convert LFPC, SFPC Note that we were failing to set the rounding mode in fpu_status. Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 17 ++++++++++ target-s390x/helper.h | 1 + target-s390x/insn-data.def | 6 ++++ target-s390x/translate.c | 64 +++++--------------------------------- 4 files changed, 31 insertions(+), 57 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index ac530e9700..74b94f290f 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -577,3 +577,20 @@ uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) handle_exceptions(env, GETPC()); return RET128(ret); } + +/* set fpc */ +void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) +{ + static const int rnd[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down + }; + + /* Install everything in the main FPC. */ + env->fpc = fpc; + + /* Install the rounding mode in the shadow fpu_status. */ + set_float_rounding_mode(rnd[fpc & 3], &env->fpu_status); +} diff --git a/target-s390x/helper.h b/target-s390x/helper.h index e64b46d755..3cc4cbdfaf 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -78,6 +78,7 @@ DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) DEF_HELPER_3(cksm, void, env, i32, i32) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) +DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i32, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 771baafa37..b319bebbee 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -351,6 +351,9 @@ C(0xb375, LZDR, RRE, Z, 0, 0, 0, f1, zero, 0) C(0xb376, LZXR, RRE, Z, 0, 0, 0, x1, zero2, 0) +/* LOAD FPC */ + C(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0) + /* LOAD LENGTHENED */ C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) C(0xb305, LXDBR, RRE, Z, 0, f2_o, x1, 0, lxdb, 0) @@ -455,6 +458,9 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* SET FPC */ + C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) + /* SHIFT LEFT SINGLE */ D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) D(0xebdd, SLAK, RSY_a, DO, r3, sh32, new, r1_32, sla, 0, 31) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e674c93ffe..d4f1bc432c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1337,18 +1337,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x9d: /* LFPC D2(B2) [S] */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); - tcg_gen_trunc_i64_i32(tmp32_1, tmp2); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0xb1: /* STFL D2(B2) [S] */ /* Store Facility List (CPU features) at 200 */ check_privileged(s); @@ -1394,47 +1382,11 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, } } -static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, - int r1, int r2) -{ - TCGv_i32 tmp32_1; - LOG_DISAS("disas_b3: op 0x%x m3 0x%x r1 %d r2 %d\n", op, m3, r1, r2); -#define FP_HELPER(i) \ - tmp32_1 = tcg_const_i32(r1); \ - tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i(cpu_env, tmp32_1, tmp32_2); \ - tcg_temp_free_i32(tmp32_1); \ - tcg_temp_free_i32(tmp32_2); - -#define FP_HELPER_CC(i) \ - tmp32_1 = tcg_const_i32(r1); \ - tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i(cc_op, cpu_env, tmp32_1, tmp32_2); \ - set_cc_static(s); \ - tcg_temp_free_i32(tmp32_1); \ - tcg_temp_free_i32(tmp32_2); - - switch (op) { - case 0x84: /* SFPC R1 [RRE] */ - tmp32_1 = load_reg32(r1); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i32(tmp32_1); - break; - default: - LOG_DISAS("illegal b3 operation 0x%x\n", op); - gen_illegal_opcode(s); - break; - } - -#undef FP_HELPER_CC -#undef FP_HELPER -} - static void disas_s390_insn(CPUS390XState *env, DisasContext *s) { unsigned char opc; uint64_t insn; - int op, r1, r2, r3; + int op; opc = cpu_ldub_code(env, s->pc); LOG_DISAS("opc 0x%x\n", opc); @@ -1445,14 +1397,6 @@ static void disas_s390_insn(CPUS390XState *env, DisasContext *s) op = (insn >> 16) & 0xff; disas_b2(env, s, op, insn); break; - case 0xb3: - insn = ld_code4(env, s->pc); - op = (insn >> 16) & 0xff; - r3 = (insn >> 12) & 0xf; /* aka m3 */ - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - disas_b3(env, s, op, r3, r1, r2); - break; default: qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); gen_illegal_opcode(s); @@ -2981,6 +2925,12 @@ static ExitStatus op_srl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) +{ + gen_helper_sfpc(cpu_env, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { From 6e2704e74d317ba077b680c2fc881724686fb24a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:18:21 -0700 Subject: [PATCH 0180/1634] target-s390: Convert IPM Note that the previous placement of the PM field was incorrect. Signed-off-by: Richard Henderson --- target-s390x/cc_helper.c | 12 ------------ target-s390x/helper.h | 1 - target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 25 +++++++++++++++++++------ 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index e3bed16bd3..a6d60bf885 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -544,18 +544,6 @@ uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, return do_calc_cc(env, cc_op, src, dst, vr); } -/* insert psw mask and condition code into r1 */ -void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1) -{ - uint64_t r = env->regs[r1]; - - r &= 0xffffffff00ffffffULL; - r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); - env->regs[r1] = r; - HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, - cc, env->psw.mask, r); -} - #ifndef CONFIG_USER_ONLY void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 3cc4cbdfaf..633667827f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -25,7 +25,6 @@ DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) -DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_4(stam, void, env, i32, i64, i32) DEF_HELPER_4(lam, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b319bebbee..13b1771bc3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -237,6 +237,8 @@ D(0xa501, IIHL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1020) D(0xa502, IILH, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1010) D(0xa503, IILL, RI_a, Z, r1_o, i2_16u, r1, 0, insi, 0, 0x1000) +/* INSERT PROGRAM MASK */ + C(0xb222, IPM, RRE, Z, 0, 0, r1, 0, ipm, 0) /* LOAD */ C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d4f1bc432c..702b174a10 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,12 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x22: /* IPM R1 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - gen_op_calc_cc(s); - gen_helper_ipm(cpu_env, cc_op, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x41: /* CKSM R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); @@ -2348,6 +2342,25 @@ static ExitStatus op_insi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ipm(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1; + + gen_op_calc_cc(s); + tcg_gen_andi_i64(o->out, o->out, ~0xff000000ull); + + t1 = tcg_temp_new_i64(); + tcg_gen_shli_i64(t1, psw_mask, 20); + tcg_gen_shri_i64(t1, t1, 36); + tcg_gen_or_i64(o->out, o->out, t1); + + tcg_gen_extu_i32_i64(t1, cc_op); + tcg_gen_shli_i64(t1, t1, 28); + tcg_gen_or_i64(o->out, o->out, t1); + tcg_temp_free_i64(t1); + return NO_EXIT; +} + static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) { gen_helper_ldeb(o->out, cpu_env, o->in2); From 374724f91ab236b4f60ec4796f1601720486d06b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 11:38:12 -0700 Subject: [PATCH 0181/1634] target-s390: Convert CKSM Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 +++ target-s390x/mem_helper.c | 43 ++++++++++++++++++++++---------------- target-s390x/translate.c | 31 +++++++++++++++++++-------- 4 files changed, 51 insertions(+), 28 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 633667827f..c6afcbc6b6 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -75,7 +75,7 @@ DEF_HELPER_3(sqxb, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) -DEF_HELPER_3(cksm, void, env, i32, i32) +DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 13b1771bc3..74f10323db 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -91,6 +91,9 @@ C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* CHECKSUM */ + C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) + /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 9c3ade816c..9c7815ad17 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -747,42 +747,49 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } /* checksum */ -void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, + uint64_t src, uint64_t src_len) { - uint64_t src = get_address_31fix(env, r2); - uint64_t src_len = env->regs[(r2 + 1) & 15]; - uint64_t cksm = (uint32_t)env->regs[r1]; + uint64_t max_len, len; + uint64_t cksm = (uint32_t)r1; - while (src_len >= 4) { - cksm += cpu_ldl_data(env, src); + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + max_len = (src_len > 0x2000 ? 0x2000 : src_len); - /* move to next word */ - src_len -= 4; - src += 4; + /* Process full words as available. */ + for (len = 0; len + 4 <= max_len; len += 4, src += 4) { + cksm += (uint32_t)cpu_ldl_data(env, src); } - switch (src_len) { - case 0: - break; + switch (max_len - len) { case 1: cksm += cpu_ldub_data(env, src) << 24; + len += 1; break; case 2: cksm += cpu_lduw_data(env, src) << 16; + len += 2; break; case 3: cksm += cpu_lduw_data(env, src) << 16; cksm += cpu_ldub_data(env, src + 2) << 8; + len += 3; break; } - /* indicate we've processed everything */ - env->regs[r2] = src + src_len; - env->regs[(r2 + 1) & 15] = 0; + /* Fold the carry from the checksum. Note that we can see carry-out + during folding more than once (but probably not more than twice). */ + while (cksm > 0xffffffffull) { + cksm = (uint32_t)cksm + (cksm >> 32); + } - /* store result */ - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - ((uint32_t)cksm + (cksm >> 32)); + /* Indicate whether or not we've processed everything. */ + env->cc_op = (len == src_len ? 0 : 3); + + /* Return both cksm and processed length. */ + env->retxl = cksm; + return len; } void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 702b174a10..ea2b1dc561 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,15 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x41: /* CKSM R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_cksm(cpu_env, tmp32_1, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - gen_op_movi_cc(s, 0); - break; case 0x4e: /* SAR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r1])); @@ -2047,6 +2038,23 @@ static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cksm(DisasContext *s, DisasOps *o) +{ + int r2 = get_field(s->fields, r2); + TCGv_i64 len = tcg_temp_new_i64(); + + potential_page_fault(s); + gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]); + set_cc_static(s); + return_low128(o->out); + + tcg_gen_add_i64(regs[r2], regs[r2], len); + tcg_gen_sub_i64(regs[r2 + 1], regs[r2 + 1], len); + tcg_temp_free_i64(len); + + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); @@ -3847,6 +3855,11 @@ static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = o->g_in2 = true; } +static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = get_address(s, 0, get_field(f, r2), 0); +} + static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; From d62a4c97f2cab0bd8649e3cd0b7692f989dbb577 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 11:54:04 -0700 Subject: [PATCH 0182/1634] target-s390: Convert EAR, SAR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 25 ++++++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 74f10323db..c4ce7e2332 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -220,6 +220,8 @@ /* EXECUTE RELATIVE LONG */ C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) +/* EXTRACT ACCESS */ + C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) /* EXTRACT FPC */ C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) @@ -463,6 +465,8 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* SET ACCESS */ + C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index ea2b1dc561..de9e2fe08f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,17 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x4e: /* SAR R1,R2 [RRE] */ - tmp32_1 = load_reg32(r2); - tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r1])); - tcg_temp_free_i32(tmp32_1); - break; - case 0x4f: /* EAR R1,R2 [RRE] */ - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r2])); - store_reg32(r1, tmp32_1); - tcg_temp_free_i32(tmp32_1); - break; case 0x54: /* MVPG R1,R2 [RRE] */ tmp = load_reg(0); tmp2 = load_reg(r1); @@ -2230,6 +2219,13 @@ static ExitStatus op_dxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ear(DisasContext *s, DisasOps *o) +{ + int r2 = get_field(s->fields, r2); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, aregs[r2])); + return NO_EXIT; +} + static ExitStatus op_efpc(DisasContext *s, DisasOps *o) { tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc)); @@ -2864,6 +2860,13 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sar(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + tcg_gen_st32_i64(o->in2, cpu_env, offsetof(CPUS390XState, aregs[r1])); + return NO_EXIT; +} + static ExitStatus op_seb(DisasContext *s, DisasOps *o) { gen_helper_seb(o->out, cpu_env, o->in1, o->in2); From ee6c38d5b10fda25175fa85febde532a12456346 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:19:44 -0700 Subject: [PATCH 0183/1634] target-s390: Convert MVPG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 7 ++----- target-s390x/translate.c | 20 ++++++++------------ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c4ce7e2332..4223d35efa 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -394,6 +394,8 @@ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) /* MOVE LONG EXTENDED */ C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) +/* MOVE PAGE */ + C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 9c7815ad17..61c35a2c38 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -398,12 +398,9 @@ uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) { /* XXX missing r0 handling */ + env->cc_op = 0; #ifdef CONFIG_USER_ONLY - int i; - - for (i = 0; i < TARGET_PAGE_SIZE; i++) { - cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i)); - } + memmove(g2h(r1), g2h(r2), TARGET_PAGE_SIZE); #else mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); #endif diff --git a/target-s390x/translate.c b/target-s390x/translate.c index de9e2fe08f..d77b30f762 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,18 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x54: /* MVPG R1,R2 [RRE] */ - tmp = load_reg(0); - tmp2 = load_reg(r1); - tmp3 = load_reg(r2); - potential_page_fault(s); - gen_helper_mvpg(cpu_env, tmp, tmp2, tmp3); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - /* XXX check CCO bit and set CC accordingly */ - gen_op_movi_cc(s, 0); - break; case 0x55: /* MVST R1,R2 [RRE] */ tmp32_1 = load_reg32(0); tmp32_2 = tcg_const_i32(r1); @@ -2654,6 +2642,14 @@ static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_mvpg(cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From aa31bf60312157aefb09f887e2f750c7d59a8bbc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:20:53 -0700 Subject: [PATCH 0184/1634] target-s390: Convert CLST, MVST Signed-off-by: Richard Henderson --- target-s390x/helper.h | 4 +- target-s390x/insn-data.def | 4 ++ target-s390x/mem_helper.c | 119 ++++++++++++++++++------------------- target-s390x/translate.c | 42 ++++++------- 4 files changed, 83 insertions(+), 86 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c6afcbc6b6..999d5d0604 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -14,9 +14,9 @@ DEF_HELPER_3(divu32, i64, env, i64, i64) DEF_HELPER_3(divs64, s64, env, s64, s64) DEF_HELPER_4(divu64, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i32, env, i32, i32, i32) -DEF_HELPER_4(clst, i32, env, i32, i32, i32) +DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) -DEF_HELPER_4(mvst, void, env, i32, i32, i32) +DEF_HELPER_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_4(csg, i64, env, i64, i64, i64) DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) DEF_HELPER_4(cs, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4223d35efa..b485b85e9c 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -153,6 +153,8 @@ C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) C(0xeb20, CLMH, RSY_b, Z, r1_sr32, a2, 0, 0, clm, 0) +/* COMPARE LOGICAL STRING */ + C(0xb25d, CLST, RRE, Z, r1_o, r2_o, 0, 0, clst, 0) /* COMPARE AND SWAP */ C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) @@ -396,6 +398,8 @@ C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) /* MOVE PAGE */ C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0) +/* MOVE STRING */ + C(0xb255, MVST, RRE, Z, r1_o, r2_o, 0, 0, mvst, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 61c35a2c38..7d87c746f6 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -304,36 +304,30 @@ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, return cc; } +static inline uint64_t fix_address(CPUS390XState *env, uint64_t a) +{ + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + a &= 0x7fffffff; + } + return a; +} + static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) { uint64_t r = d2; - if (x2) { r += env->regs[x2]; } - if (b2) { r += env->regs[b2]; } - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; + return fix_address(env, r); } static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) { - uint64_t r = env->regs[reg]; - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; + return fix_address(env, env->regs[reg]); } /* search string (c is byte to search, r2 is string, r1 end of string) */ @@ -359,39 +353,40 @@ uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) } /* unsigned string compare (c is string terminator) */ -uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) { - uint64_t s1 = get_address_31fix(env, r1); - uint64_t s2 = get_address_31fix(env, r2); - uint8_t v1, v2; - uint32_t cc; + uint32_t len; c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: comparing '%s' and '%s'\n", - __func__, (char *)g2h(s1), (char *)g2h(s2)); - } -#endif - for (;;) { - v1 = cpu_ldub_data(env, s1); - v2 = cpu_ldub_data(env, s2); - if ((v1 == c || v2 == c) || (v1 != v2)) { - break; + s1 = fix_address(env, s1); + s2 = fix_address(env, s2); + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + uint8_t v1 = cpu_ldub_data(env, s1 + len); + uint8_t v2 = cpu_ldub_data(env, s2 + len); + if (v1 == v2) { + if (v1 == c) { + /* Equal. CC=0, and don't advance the registers. */ + env->cc_op = 0; + env->retxl = s2; + return s1; + } + } else { + /* Unequal. CC={1,2}, and advance the registers. Note that + the terminator need not be zero, but the string that contains + the terminator is by definition "low". */ + env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2); + env->retxl = s2 + len; + return s1 + len; } - s1++; - s2++; } - if (v1 == v2) { - cc = 0; - } else { - cc = (v1 < v2) ? 1 : 2; - /* FIXME: 31-bit mode! */ - env->regs[r1] = s1; - env->regs[r2] = s2; - } - return cc; + /* CPU-determined bytes equal; advance the registers. */ + env->cc_op = 3; + env->retxl = s2 + len; + return s1 + len; } /* move page */ @@ -407,29 +402,31 @@ void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) } /* string copy (c is string terminator) */ -void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) { - uint64_t dest = get_address_31fix(env, r1); - uint64_t src = get_address_31fix(env, r2); - uint8_t v; + uint32_t len; c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), - dest); - } -#endif - for (;;) { - v = cpu_ldub_data(env, src); - cpu_stb_data(env, dest, v); + d = fix_address(env, d); + s = fix_address(env, s); + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + uint8_t v = cpu_ldub_data(env, s + len); + cpu_stb_data(env, d + len, v); if (v == c) { - break; + /* Complete. Set CC=1 and advance R1. */ + env->cc_op = 1; + env->retxl = s; + return d + len; } - src++; - dest++; } - env->regs[r1] = dest; /* FIXME: 31-bit mode! */ + + /* Incomplete. Set CC=3 and signal to advance R1 and R2. */ + env->cc_op = 3; + env->retxl = s + len; + return d + len; } /* compare and swap 64-bit */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d77b30f762..f1eb4bb8da 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -427,7 +427,7 @@ static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) return tmp; } -static void gen_op_movi_cc(DisasContext *s, uint32_t val) +static inline void gen_op_movi_cc(DisasContext *s, uint32_t val) { s->cc_op = CC_OP_CONST0 + val; } @@ -1034,28 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x55: /* MVST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_mvst(cpu_env, tmp32_1, tmp32_2, tmp32_3); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - gen_op_movi_cc(s, 1); - break; - case 0x5d: /* CLST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_clst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; case 0x5e: /* SRST R1,R2 [RRE] */ tmp32_1 = load_reg32(0); tmp32_2 = tcg_const_i32(r1); @@ -2091,6 +2069,15 @@ static ExitStatus op_clm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + static ExitStatus op_cs(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); @@ -2650,6 +2637,15 @@ static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From 4600c994d93fc9af2b045086dd31e613d2f9d7bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 14:27:42 -0700 Subject: [PATCH 0185/1634] target-s390: Convert SRST Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 +++ target-s390x/mem_helper.c | 39 +++++++++++++++++++++++++------------- target-s390x/translate.c | 33 +++++++++++++++----------------- 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 999d5d0604..dd7479abcf 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -13,7 +13,7 @@ DEF_HELPER_3(divs32, s64, env, s64, s64) DEF_HELPER_3(divu32, i64, env, i64, i64) DEF_HELPER_3(divs64, s64, env, s64, s64) DEF_HELPER_4(divu64, i64, env, i64, i64, i64) -DEF_HELPER_4(srst, i32, env, i32, i32, i32) +DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) DEF_HELPER_4(mvst, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b485b85e9c..5e1f8fda9b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -471,6 +471,9 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* SEARCH STRING */ + C(0xb25e, SRST, RRE, Z, r1_o, r2_o, 0, 0, srst, 0) + /* SET ACCESS */ C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 7d87c746f6..59877eef96 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -331,25 +331,38 @@ static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) } /* search string (c is byte to search, r2 is string, r1 end of string) */ -uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, + uint64_t str) { - uint64_t i; - uint32_t cc = 2; - uint64_t str = get_address_31fix(env, r2); - uint64_t end = get_address_31fix(env, r1); + uint32_t len; + uint8_t v, c = r0; - HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, - c, env->regs[r1], env->regs[r2]); + str = fix_address(env, str); + end = fix_address(env, end); - for (i = str; i != end; i++) { - if (cpu_ldub_data(env, i) == c) { - env->regs[r1] = i; - cc = 1; - break; + /* Assume for now that R2 is unmodified. */ + env->retxl = str; + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + for (len = 0; len < 0x2000; ++len) { + if (str + len == end) { + /* Character not found. R1 & R2 are unmodified. */ + env->cc_op = 2; + return end; + } + v = cpu_ldub_data(env, str + len); + if (v == c) { + /* Character found. Set R1 to the location; R2 is unmodified. */ + env->cc_op = 1; + return str + len; } } - return cc; + /* CPU-determined bytes processed. Advance R2 to next byte to process. */ + env->retxl = str + len; + env->cc_op = 3; + return end; } /* unsigned string compare (c is string terminator) */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index f1eb4bb8da..bbbd5fe09a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1021,12 +1021,11 @@ static void free_compare(DisasCompare *c) static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { - TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2, tmp32_3; - int r1, r2; #ifndef CONFIG_USER_ONLY + TCGv_i64 tmp, tmp2, tmp3; + TCGv_i32 tmp32_1, tmp32_2; + int r1, r2; int r3, d2, b2; -#endif r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; @@ -1034,19 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x5e: /* SRST R1,R2 [RRE] */ - tmp32_1 = load_reg32(0); - tmp32_2 = tcg_const_i32(r1); - tmp32_3 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_srst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - tcg_temp_free_i32(tmp32_3); - break; - -#ifndef CONFIG_USER_ONLY case 0x02: /* STIDP D2(B2) [S] */ /* Store CPU ID */ check_privileged(s); @@ -1314,12 +1300,14 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; -#endif default: +#endif LOG_DISAS("illegal b2 operation 0x%x\n", op); gen_illegal_opcode(s); +#ifndef CONFIG_USER_ONLY break; } +#endif } static void disas_s390_insn(CPUS390XState *env, DisasContext *s) @@ -3136,6 +3124,15 @@ static ExitStatus op_stmh(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_srst(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_srst(o->in1, cpu_env, regs[0], o->in1, o->in2); + set_cc_static(s); + return_low128(o->in2); + return NO_EXIT; +} + static ExitStatus op_sub(DisasContext *s, DisasOps *o) { tcg_gen_sub_i64(o->out, o->in1, o->in2); From 71bd666963ad9fb004d7aa919b7222165e602173 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:21:47 -0700 Subject: [PATCH 0186/1634] target-s390: Convert STIDP Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 6 ------ target-s390x/translate.c | 16 +++++++--------- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index dd7479abcf..8e90741d3f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -83,7 +83,6 @@ DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) -DEF_HELPER_FLAGS_2(stidp, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) DEF_HELPER_2(stck, i32, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 5e1f8fda9b..4d9ecf4b13 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -640,6 +640,8 @@ /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) +/* STORE CPU ID */ + C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 6dca0ebabd..009cc92660 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -131,12 +131,6 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, return r; } -/* Store CPU ID */ -void HELPER(stidp)(CPUS390XState *env, uint64_t a1) -{ - cpu_stq_data(env, a1, env->cpu_num); -} - /* Set Prefix */ void HELPER(spx)(CPUS390XState *env, uint64_t a1) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index bbbd5fe09a..d57c737fc8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x02: /* STIDP D2(B2) [S] */ - /* Store CPU ID */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stidp(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; case 0x04: /* SCK D2(B2) [S] */ /* Set Clock */ check_privileged(s); @@ -2967,6 +2958,13 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stidp(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From 352897995147c4a054679654048f5c128ca32743 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:20:49 -0700 Subject: [PATCH 0187/1634] target-s390: Convert SCK Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 3 +++ target-s390x/misc_helper.c | 8 -------- target-s390x/translate.c | 10 ---------- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 8e90741d3f..3591a92ada 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -84,7 +84,6 @@ DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_1(sck, TCG_CALL_NO_RWG, i32, i64) DEF_HELPER_2(stck, i32, env, i64) DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4d9ecf4b13..824e9dc526 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -633,6 +633,9 @@ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +/* SET CLOCK */ + /* ??? Not implemented - is it necessary? */ + C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 009cc92660..c16359134a 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -143,14 +143,6 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) tlb_flush_page(env, TARGET_PAGE_SIZE); } -/* Set Clock */ -uint32_t HELPER(sck)(uint64_t a1) -{ - /* XXX not implemented - is it necessary? */ - - return 0; -} - static inline uint64_t clock_value(CPUS390XState *env) { uint64_t time; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d57c737fc8..e835df0ce9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,16 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x04: /* SCK D2(B2) [S] */ - /* Set Clock */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sck(cc_op, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; case 0x05: /* STCK D2(B2) [S] */ /* Store Clock */ decode_rs(s, insn, &r1, &r3, &b2, &d2); From 434c91a5f4ed7219819678315b5529fbc35435e6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:31:07 -0700 Subject: [PATCH 0188/1634] target-s390: Convert STCK Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 3 +++ target-s390x/misc_helper.c | 6 ++---- target-s390x/translate.c | 17 ++++++++--------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 3591a92ada..d3a30cb4a0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -84,7 +84,7 @@ DEF_HELPER_3(servc, i32, env, i32, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_2(stck, i32, env, i64) +DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(stckc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 824e9dc526..4404791661 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -640,6 +640,9 @@ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) +/* STORE CLOCK */ + C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) + C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index c16359134a..f1edf6c67b 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -154,11 +154,9 @@ static inline uint64_t clock_value(CPUS390XState *env) } /* Store Clock */ -uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stck)(CPUS390XState *env) { - cpu_stq_data(env, a1, clock_value(env)); - - return 0; + return clock_value(env); } /* Store Clock Extended */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e835df0ce9..624ee8d99a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x05: /* STCK D2(B2) [S] */ - /* Store Clock */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stck(cc_op, cpu_env, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; case 0x06: /* SCKC D2(B2) [S] */ /* Set Clock Comparator */ check_privileged(s); @@ -2924,6 +2915,14 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stck(DisasContext *s, DisasOps *o) +{ + gen_helper_stck(o->out, cpu_env); + /* ??? We don't implement clock states. */ + gen_op_movi_cc(s, 0); + return NO_EXIT; +} + static ExitStatus op_stctg(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From dd3eb7b54f0dbcf76e3ccfdf8535201049670378 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:36:58 -0700 Subject: [PATCH 0189/1634] target-s390: Convert SCKC, STCKC Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 4 ++++ target-s390x/misc_helper.c | 8 +++----- target-s390x/translate.c | 32 ++++++++++++++------------------ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index d3a30cb4a0..a55aa9f4d7 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -87,7 +87,7 @@ DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_2(stckc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(stpt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_4(stsi, i32, env, i64, i32, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4404791661..06c780ba21 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -636,6 +636,8 @@ /* SET CLOCK */ /* ??? Not implemented - is it necessary? */ C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) +/* SET CLOCK COMPARATOR */ + C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ @@ -643,6 +645,8 @@ /* STORE CLOCK */ C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) +/* STORE CLOCK COMPARATOR */ + C(0xb207, STCKC, S, Z, la2, 0, new, m1_64, stckc, 0) /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index f1edf6c67b..9263ae727f 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -174,10 +174,8 @@ uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) } /* Set Clock Comparator */ -void HELPER(sckc)(CPUS390XState *env, uint64_t a1) +void HELPER(sckc)(CPUS390XState *env, uint64_t time) { - uint64_t time = cpu_ldq_data(env, a1); - if (time == -1ULL) { return; } @@ -191,10 +189,10 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t a1) } /* Store Clock Comparator */ -void HELPER(stckc)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stckc)(CPUS390XState *env) { /* XXX implement */ - cpu_stq_data(env, a1, 0); + return 0; } /* Set CPU Timer */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 624ee8d99a..30c7acec22 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,24 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x06: /* SCKC D2(B2) [S] */ - /* Set Clock Comparator */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sckc(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x07: /* STCKC D2(B2) [S] */ - /* Store Clock Comparator */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stckc(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; case 0x08: /* SPT D2(B2) [S] */ /* Set CPU Timer */ check_privileged(s); @@ -2923,6 +2905,20 @@ static ExitStatus op_stck(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sckc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sckc(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stckc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stckc(o->out, cpu_env); + return NO_EXIT; +} + static ExitStatus op_stctg(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From c4f0a863c3b980694e2ccb8fa3252a0eb8ef6a97 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:47:26 -0700 Subject: [PATCH 0190/1634] target-s390: Convert SPT, STPT Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 4 ++++ target-s390x/misc_helper.c | 8 +++----- target-s390x/translate.c | 32 ++++++++++++++------------------ 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index a55aa9f4d7..d7736e3aa1 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -89,7 +89,7 @@ DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_2(stpt, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_4(stsi, i32, env, i64, i32, i32) DEF_HELPER_4(lctl, void, env, i32, i64, i32) DEF_HELPER_4(lctlg, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 06c780ba21..a45454c4b9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -638,6 +638,8 @@ C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) /* SET CLOCK COMPARATOR */ C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) +/* SET CPU TIMER */ + C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ @@ -652,6 +654,8 @@ C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) /* STORE CPU ID */ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) +/* STORE CPU TIMER */ + C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 9263ae727f..431824249c 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -196,10 +196,8 @@ uint64_t HELPER(stckc)(CPUS390XState *env) } /* Set CPU Timer */ -void HELPER(spt)(CPUS390XState *env, uint64_t a1) +void HELPER(spt)(CPUS390XState *env, uint64_t time) { - uint64_t time = cpu_ldq_data(env, a1); - if (time == -1ULL) { return; } @@ -211,10 +209,10 @@ void HELPER(spt)(CPUS390XState *env, uint64_t a1) } /* Store CPU Timer */ -void HELPER(stpt)(CPUS390XState *env, uint64_t a1) +uint64_t HELPER(stpt)(CPUS390XState *env) { /* XXX implement */ - cpu_stq_data(env, a1, 0); + return 0; } /* Store System Information */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 30c7acec22..a31849253b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,24 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x08: /* SPT D2(B2) [S] */ - /* Set CPU Timer */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_spt(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x09: /* STPT D2(B2) [S] */ - /* Store CPU Timer */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stpt(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; case 0x0a: /* SPKA D2(B2) [S] */ /* Set PSW Key from Address */ check_privileged(s); @@ -2950,6 +2932,20 @@ static ExitStatus op_stidp(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_spt(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_spt(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stpt(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stpt(o->out, cpu_env); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From 28d555566719dada8e2d028ff611b4fb8a984e0c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:55:34 -0700 Subject: [PATCH 0191/1634] target-s390: Convert SPKA Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 20 ++++++++------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a45454c4b9..f95ba11b3a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -640,6 +640,8 @@ C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) /* SET CPU TIMER */ C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) +/* SET PSW KEY FROM ADDRESS */ + C(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a31849253b..6296113dca 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x0a: /* SPKA D2(B2) [S] */ - /* Set PSW Key from Address */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_andi_i64(tmp2, psw_mask, ~PSW_MASK_KEY); - tcg_gen_shli_i64(tmp, tmp, PSW_SHIFT_KEY - 4); - tcg_gen_or_i64(psw_mask, tmp2, tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; case 0x0d: /* PTLB [S] */ /* Purge TLB */ check_privileged(s); @@ -2872,6 +2860,14 @@ static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_spka(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_shri_i64(o->in2, o->in2, 4); + tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, PSW_SHIFT_KEY - 4, 4); + return NO_EXIT; +} + static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { check_privileged(s); From 0568d8aab0b48cb033aad8ecaef5bc0c531ce9ff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 15:59:26 -0700 Subject: [PATCH 0192/1634] target-s390: Convert PTLB Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f95ba11b3a..e9b9dc1038 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -629,6 +629,8 @@ C(0xda00, MVCP, SS_d, Z, la1, a2, 0, 0, mvcp, 0) /* MOVE TO SECONDARY */ C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) +/* PURGE TLB */ + C(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6296113dca..563c2e79af 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,11 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x0d: /* PTLB [S] */ - /* Purge TLB */ - check_privileged(s); - gen_helper_ptlb(cpu_env); - break; case 0x10: /* SPX D2(B2) [S] */ /* Set Prefix Register */ check_privileged(s); @@ -2725,6 +2720,15 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_ptlb(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_ptlb(cpu_env); + return NO_EXIT; +} +#endif + static ExitStatus op_rev16(DisasContext *s, DisasOps *o) { tcg_gen_bswap16_i64(o->out, o->in2); From e805a0d39e26fc85681db7e1bf58c91a5628eaff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 16:11:32 -0700 Subject: [PATCH 0193/1634] target-s390: Convert SPX, STPX Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ target-s390x/misc_helper.c | 6 ++---- target-s390x/translate.c | 35 +++++++++++++++-------------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e9b9dc1038..87a77a2ad0 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -642,6 +642,8 @@ C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) /* SET CPU TIMER */ C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) +/* SET PREFIX */ + C(0xb210, SPX, S, Z, 0, m2_32u, 0, 0, spx, 0) /* SET PSW KEY FROM ADDRESS */ C(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0) /* SET SYSTEM MASK */ @@ -660,6 +662,8 @@ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE CPU TIMER */ C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) +/* STORE PREFIX */ + C(0xb211, STPX, S, Z, la2, 0, new, m1_32, stpx, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 431824249c..b098e8869d 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -134,10 +134,8 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, /* Set Prefix */ void HELPER(spx)(CPUS390XState *env, uint64_t a1) { - uint32_t prefix; - - prefix = cpu_ldl_data(env, a1); - env->psa = prefix & 0xfffff000; + uint32_t prefix = a1 & 0x7fffe000; + env->psa = prefix; qemu_log("prefix: %#x\n", prefix); tlb_flush_page(env, 0); tlb_flush_page(env, TARGET_PAGE_SIZE); diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 563c2e79af..e355de26ce 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,26 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x10: /* SPX D2(B2) [S] */ - /* Set Prefix Register */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_spx(cpu_env, tmp); - tcg_temp_free_i64(tmp); - break; - case 0x11: /* STPX D2(B2) [S] */ - /* Store Prefix */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp2, cpu_env, offsetof(CPUS390XState, psa)); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x12: /* STAP D2(B2) [S] */ /* Store CPU Address */ check_privileged(s); @@ -2946,6 +2926,21 @@ static ExitStatus op_stpt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_spx(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_spx(cpu_env, o->in2); + return NO_EXIT; +} + +static ExitStatus op_stpx(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, psa)); + tcg_gen_andi_i64(o->out, o->out, 0x7fffe000); + return NO_EXIT; +} + static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) { uint64_t i2 = get_field(s->fields, i2); From 411fea3d8400af5479690d6e22c6492c15e10a4a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 16:18:33 -0700 Subject: [PATCH 0194/1634] target-s390: Convert STAP Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 24 ++++++++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 87a77a2ad0..f68e586e0d 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -658,6 +658,8 @@ /* STORE CONTROL */ C(0xb600, STCTL, RS_a, Z, 0, a2, 0, 0, stctl, 0) C(0xeb25, STCTG, RSY_a, Z, 0, a2, 0, 0, stctg, 0) +/* STORE CPU ADDRESS */ + C(0xb212, STAP, S, Z, la2, 0, new, m1_16, stap, 0) /* STORE CPU ID */ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE CPU TIMER */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e355de26ce..5ffbdb3b61 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,20 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x12: /* STAP D2(B2) [S] */ - /* Store CPU Address */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp32_1 = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, cpu_num)); - tcg_gen_extu_i32_i64(tmp2, tmp32_1); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i32(tmp32_1); - break; case 0x21: /* IPTE R1,R2 [RRE] */ /* Invalidate PTE */ check_privileged(s); @@ -2859,6 +2845,16 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stap(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* ??? Surely cpu address != cpu number. In any case the previous + version of this stored more than the required half-word, so it + is unlikely this has ever been tested. */ + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + return NO_EXIT; +} + static ExitStatus op_stck(DisasContext *s, DisasOps *o) { gen_helper_stck(o->out, cpu_env); From cfef53e356119bddcba0724c0c26fd5940f231e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 24 Aug 2012 16:25:28 -0700 Subject: [PATCH 0195/1634] target-s390: Convert IPTE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 20 +++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f68e586e0d..c8368cf151 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -616,6 +616,8 @@ #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) +/* INVALIDATE PAGE TABLE ENTRY */ + C(0xb221, IPTE, RRF_a, Z, r1_o, r2_o, 0, 0, ipte, 0) /* LOAD CONTROL */ C(0xb700, LCTL, RS_a, Z, 0, a2, 0, 0, lctl, 0) C(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5ffbdb3b61..b25a5e6549 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,17 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x21: /* IPTE R1,R2 [RRE] */ - /* Invalidate PTE */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp = load_reg(r1); - tmp2 = load_reg(r2); - gen_helper_ipte(cpu_env, tmp, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x29: /* ISKE R1,R2 [RRE] */ /* Insert Storage Key Extended */ check_privileged(s); @@ -2213,6 +2202,15 @@ static ExitStatus op_ipm(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_ipte(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_ipte(cpu_env, o->in1, o->in2); + return NO_EXIT; +} +#endif + static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) { gen_helper_ldeb(o->out, cpu_env, o->in2); From 8026417c7169e7efd1696f3ed15e51306729176a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:13:38 -0700 Subject: [PATCH 0196/1634] target-s390: Convert ISKE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 19 +++++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c8368cf151..87daec1a79 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -616,6 +616,8 @@ #ifndef CONFIG_USER_ONLY /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) +/* INSERT STORAGE KEY EXTENDED */ + C(0xb229, ISKE, RRE, Z, 0, r2_o, new, r1_8, iske, 0) /* INVALIDATE PAGE TABLE ENTRY */ C(0xb221, IPTE, RRF_a, Z, r1_o, r2_o, 0, 0, ipte, 0) /* LOAD CONTROL */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b25a5e6549..b9647d8833 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x29: /* ISKE R1,R2 [RRE] */ - /* Insert Storage Key Extended */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp = load_reg(r2); - tmp2 = tcg_temp_new_i64(); - gen_helper_iske(tmp2, cpu_env, tmp); - store_reg(r1, tmp2); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - break; case 0x2a: /* RRBE R1,R2 [RRE] */ /* Set Storage Key Extended */ check_privileged(s); @@ -2209,6 +2197,13 @@ static ExitStatus op_ipte(DisasContext *s, DisasOps *o) gen_helper_ipte(cpu_env, o->in1, o->in2); return NO_EXIT; } + +static ExitStatus op_iske(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_iske(o->out, cpu_env, o->in2); + return NO_EXIT; +} #endif static ExitStatus op_ldeb(DisasContext *s, DisasOps *o) From 2bbde27f2548cb48f362eada1080e590f5453404 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:18:01 -0700 Subject: [PATCH 0197/1634] target-s390: Convert SSKE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 2 +- target-s390x/translate.c | 18 +++++++----------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index d7736e3aa1..9ff0c36aa5 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -97,7 +97,7 @@ DEF_HELPER_4(stctl, void, env, i32, i64, i32) DEF_HELPER_4(stctg, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) -DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i32, i64) +DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_NO_RWG, i32, env, i32, i64) DEF_HELPER_3(csp, i32, env, i32, i32) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 87daec1a79..f554c1b567 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -650,6 +650,8 @@ C(0xb210, SPX, S, Z, 0, m2_32u, 0, 0, spx, 0) /* SET PSW KEY FROM ADDRESS */ C(0xb20a, SPKA, S, Z, 0, a2, 0, 0, spka, 0) +/* SET STORAGE KEY EXTENDED */ + C(0xb22b, SSKE, RRF_c, Z, r1_o, r2_o, 0, 0, sske, 0) /* SET SYSTEM MASK */ C(0x8000, SSM, S, Z, 0, m2_8u, 0, 0, ssm, 0) /* SIGNAL PROCESSOR */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 59877eef96..099724174a 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -946,7 +946,7 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) } /* set storage key extended */ -void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2) +void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) { uint64_t addr = get_address(env, 0, 0, r2); diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b9647d8833..2b07a8ecf6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1045,17 +1045,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; - case 0x2b: /* SSKE R1,R2 [RRE] */ - /* Set Storage Key Extended */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - gen_helper_sske(cpu_env, tmp32_1, tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x34: /* STCH ? */ /* Store Subchannel */ check_privileged(s); @@ -2831,6 +2820,13 @@ static ExitStatus op_spka(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sske(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sske(cpu_env, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_ssm(DisasContext *s, DisasOps *o) { check_privileged(s); From 5cc69c54f606005ea0432d83dafbec0f5b0e831a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:22:13 -0700 Subject: [PATCH 0198/1634] target-s390: Convert RRBE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 2 +- target-s390x/translate.c | 22 ++++++++++------------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 9ff0c36aa5..9bcf4d6b85 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -98,7 +98,7 @@ DEF_HELPER_4(stctg, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_NO_RWG, i32, env, i32, i64) +DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) DEF_HELPER_3(csp, i32, env, i32, i32) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index f554c1b567..2a045727ae 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -635,6 +635,8 @@ C(0xdb00, MVCS, SS_d, Z, la1, a2, 0, 0, mvcs, 0) /* PURGE TLB */ C(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0) +/* RESET REFERENCE BIT EXTENDED */ + C(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 099724174a..406ec9b69d 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -958,7 +958,7 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) } /* reset reference bit extended */ -uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2) +uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) { uint8_t re; uint8_t key; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2b07a8ecf6..d7d991c58a 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x2a: /* RRBE R1,R2 [RRE] */ - /* Set Storage Key Extended */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x34: /* STCH ? */ /* Store Subchannel */ check_privileged(s); @@ -2716,6 +2704,16 @@ static ExitStatus op_rll64(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_rrbe(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_rrbe(cc_op, cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_sar(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); From 2c423fc070b3e260fc368e2573c76d7ddd52e165 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:36:20 -0700 Subject: [PATCH 0199/1634] target-s390: Convert subchannel instructions While we're at it, list all of the chapter 14 subchannel insns. Which is easy since all merely need indicate non-operation. Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 14 ++++++++++++++ target-s390x/translate.c | 18 ++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 2a045727ae..24a419c416 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -680,4 +680,18 @@ C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* TEST PROTECTION */ C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) + +/* I/O Instructions. For each we simply indicate non-operation. */ + C(0xb276, XSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb230, CSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb231, HSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb232, MSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb23b, RCHP, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb238, RSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb233, SSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb234, STSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + C(0xb235, TSCH, S, Z, 0, 0, 0, 0, subchannel, 0) + /* ??? Not listed in PoO ninth edition, but there's a linux driver that + uses it: "A CHSC subchannel is usually present on LPAR only." */ + C(0xb25f, CHSC, S, Z, 0, 0, 0, 0, subchannel, 0) #endif /* CONFIG_USER_ONLY */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d7d991c58a..1172031465 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,11 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x34: /* STCH ? */ - /* Store Subchannel */ - check_privileged(s); - gen_op_movi_cc(s, 3); - break; case 0x46: /* STURA R1,R2 [RRE] */ /* Store Using Real Address */ check_privileged(s); @@ -1062,11 +1057,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); break; - case 0x5f: /* CHSC ? */ - /* Channel Subsystem Call */ - check_privileged(s); - gen_op_movi_cc(s, 3); - break; case 0x78: /* STCKE D2(B2) [S] */ /* Store Clock Extended */ decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2916,6 +2906,14 @@ static ExitStatus op_spx(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_subchannel(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* Not operational. */ + gen_op_movi_cc(s, 3); + return NO_EXIT; +} + static ExitStatus op_stpx(DisasContext *s, DisasOps *o) { check_privileged(s); From 204504e2fa0ec0f11c806ad335edf6bd1f499e34 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:45:38 -0700 Subject: [PATCH 0200/1634] target-s390: Convert STURA Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 4 ++-- target-s390x/translate.c | 20 ++++++++------------ 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 9bcf4d6b85..4597b58f59 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -107,7 +107,7 @@ DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) -DEF_HELPER_3(stura, void, env, i64, i32) +DEF_HELPER_3(stura, void, env, i64, i64) #endif #include "exec/def-helper.h" diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 24a419c416..8e457cb9f2 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -678,6 +678,8 @@ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ C(0xad00, STOSM, SI, Z, la1, 0, 0, 0, stnosm, 0) +/* STORE USING REAL ADDRESS */ + C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0) /* TEST PROTECTION */ C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 406ec9b69d..8987bbb9b1 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1093,9 +1093,9 @@ void HELPER(ptlb)(CPUS390XState *env) } /* store using real address */ -void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) +void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) { - stw_phys(get_address(env, 0, 0, addr), v1); + stw_phys(get_address(env, 0, 0, addr), (uint32_t)v1); } /* load real address */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1172031465..8079c6fc3d 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x46: /* STURA R1,R2 [RRE] */ - /* Store Using Real Address */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = load_reg32(r1); - tmp = load_reg(r2); - potential_page_fault(s); - gen_helper_stura(cpu_env, tmp, tmp32_1); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; case 0x50: /* CSP R1,R2 [RRE] */ /* Compare And Swap And Purge */ check_privileged(s); @@ -2945,6 +2933,14 @@ static ExitStatus op_stnosm(DisasContext *s, DisasOps *o) } return NO_EXIT; } + +static ExitStatus op_stura(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_stura(cpu_env, o->in2, o->in1); + return NO_EXIT; +} #endif static ExitStatus op_st8(DisasContext *s, DisasOps *o) From 3d596f491250d66fffabbc60d0621ea72859e96c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 09:57:18 -0700 Subject: [PATCH 0201/1634] target-s390: Convert CSP Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 6 +++--- target-s390x/translate.c | 24 ++++++++++++------------ 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 4597b58f59..c359377b62 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -99,7 +99,7 @@ DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) -DEF_HELPER_3(csp, i32, env, i32, i32) +DEF_HELPER_3(csp, i32, env, i32, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8e457cb9f2..12468a3ef5 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -614,6 +614,8 @@ C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) #ifndef CONFIG_USER_ONLY +/* COMPARE AND SWAP AND PURGE */ + C(0xb250, CSP, RRE, Z, 0, ra2, 0, 0, csp, 0) /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RX_a, Z, 0, 0, 0, 0, diag, 0) /* INSERT STORAGE KEY EXTENDED */ diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 8987bbb9b1..0e9bbd4035 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -984,16 +984,16 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) } /* compare and swap and purge */ -uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2) { uint32_t cc; uint32_t o1 = env->regs[r1]; - uint64_t a2 = get_address_31fix(env, r2) & ~3ULL; + uint64_t a2 = r2 & ~3ULL; uint32_t o2 = cpu_ldl_data(env, a2); if (o1 == o2) { cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]); - if (env->regs[r2] & 0x3) { + if (r2 & 0x3) { /* flush TLB / ALB */ tlb_flush(env, 1); } diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8079c6fc3d..19781edb92 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,18 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x50: /* CSP R1,R2 [RRE] */ - /* Compare And Swap And Purge */ - check_privileged(s); - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0x78: /* STCKE D2(B2) [S] */ /* Store Clock Extended */ decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -1901,6 +1889,18 @@ static ExitStatus op_csg(DisasContext *s, DisasOps *o) return NO_EXIT; } +#ifndef CONFIG_USER_ONLY +static ExitStatus op_csp(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + check_privileged(s); + gen_helper_csp(cc_op, cpu_env, r1, o->in2); + tcg_temp_free_i32(r1); + set_cc_static(s); + return NO_EXIT; +} +#endif + static ExitStatus op_cds(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); From 39a5003c89191a46ec6af722ade3dfdf457e9f58 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:11:36 -0700 Subject: [PATCH 0202/1634] target-s390: Convert STCKE Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 - target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 14 -------------- target-s390x/translate.c | 31 ++++++++++++++++++++++--------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c359377b62..3d7472eba0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -85,7 +85,6 @@ DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) -DEF_HELPER_2(stcke, i32, env, i64) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 12468a3ef5..75729fee64 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -663,6 +663,8 @@ /* STORE CLOCK */ C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) +/* STORE CLOCK EXTENDED */ + C(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0) /* STORE CLOCK COMPARATOR */ C(0xb207, STCKC, S, Z, la2, 0, new, m1_64, stckc, 0) /* STORE CONTROL */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index b098e8869d..409df4f7f8 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -157,20 +157,6 @@ uint64_t HELPER(stck)(CPUS390XState *env) return clock_value(env); } -/* Store Clock Extended */ -uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) -{ - cpu_stb_data(env, a1, 0); - /* basically the same value as stck */ - cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num); - /* more fine grained than stck */ - cpu_stq_data(env, a1 + 9, 0); - /* XXX programmable fields */ - cpu_stw_data(env, a1 + 17, 0); - - return 0; -} - /* Set Clock Comparator */ void HELPER(sckc)(CPUS390XState *env, uint64_t time) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 19781edb92..e5c3ee6dd7 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x78: /* STCKE D2(B2) [S] */ - /* Store Clock Extended */ - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_stcke(cc_op, cpu_env, tmp); - set_cc_static(s); - tcg_temp_free_i64(tmp); - break; case 0x79: /* SACF D2(B2) [S] */ /* Set Address Space Control Fast */ check_privileged(s); @@ -2828,6 +2819,28 @@ static ExitStatus op_stck(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stcke(DisasContext *s, DisasOps *o) +{ + TCGv_i64 c1 = tcg_temp_new_i64(); + TCGv_i64 c2 = tcg_temp_new_i64(); + gen_helper_stck(c1, cpu_env); + /* Shift the 64-bit value into its place as a zero-extended + 104-bit value. Note that "bit positions 64-103 are always + non-zero so that they compare differently to STCK"; we set + the least significant bit to 1. */ + tcg_gen_shli_i64(c2, c1, 56); + tcg_gen_shri_i64(c1, c1, 8); + tcg_gen_ori_i64(c2, c2, 0x10000); + tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 8); + tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s)); + tcg_temp_free_i64(c1); + tcg_temp_free_i64(c2); + /* ??? We don't implement clock states. */ + gen_op_movi_cc(s, 0); + return NO_EXIT; +} + static ExitStatus op_sckc(DisasContext *s, DisasOps *o) { check_privileged(s); From 14244b21a041161185bb53c3eb29e3d8dc7bfe6e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:17:16 -0700 Subject: [PATCH 0203/1634] target-s390: Convert SACF Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 21 ++++++++------------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 75729fee64..a389f1503e 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -643,6 +643,8 @@ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ C(0x010e, SAM64, E, Z, 0, 0, 0, 0, 0, 0) +/* SET ADDRESS SPACE CONTROL FAST */ + C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) /* SET CLOCK */ /* ??? Not implemented - is it necessary? */ C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e5c3ee6dd7..491f8fd6b6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,19 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x79: /* SACF D2(B2) [S] */ - /* Set Address Space Control Fast */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - potential_page_fault(s); - gen_helper_sacf(cpu_env, tmp); - tcg_temp_free_i64(tmp); - /* addressing mode has changed, so end the block */ - s->pc = s->next_pc; - update_psw_addr(s); - s->is_jmp = DISAS_JUMP; - break; case 0x7d: /* STSI D2,(B2) [S] */ check_privileged(s); decode_rs(s, insn, &r1, &r3, &b2, &d2); @@ -2681,6 +2668,14 @@ static ExitStatus op_rrbe(DisasContext *s, DisasOps *o) set_cc_static(s); return NO_EXIT; } + +static ExitStatus op_sacf(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sacf(cpu_env, o->in2); + /* Addressing mode has changed, so end the block. */ + return EXIT_PC_STALE; +} #endif static ExitStatus op_sar(DisasContext *s, DisasOps *o) From d14b3e09b21a297fddc62c0c7839156022079d05 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:43:38 -0700 Subject: [PATCH 0204/1634] target-s390: Convert STSI Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 4 ++-- target-s390x/translate.c | 24 ++++++++++-------------- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 3d7472eba0..f2eaef45fa 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -89,7 +89,7 @@ DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) -DEF_HELPER_4(stsi, i32, env, i64, i32, i32) +DEF_HELPER_4(stsi, i32, env, i64, i64, i64) DEF_HELPER_4(lctl, void, env, i32, i64, i32) DEF_HELPER_4(lctlg, void, env, i32, i64, i32) DEF_HELPER_4(stctl, void, env, i32, i64, i32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a389f1503e..5de3256be9 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -680,6 +680,8 @@ C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) /* STORE PREFIX */ C(0xb211, STPX, S, Z, la2, 0, new, m1_32, stpx, 0) +/* STORE SYSTEM INFORMATION */ + C(0xb27d, STSI, S, Z, 0, a2, 0, 0, stsi, 0) /* STORE THEN AND SYSTEM MASK */ C(0xac00, STNSM, SI, Z, la1, 0, 0, 0, stnosm, 0) /* STORE THEN OR SYSTEM MASK */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 409df4f7f8..60e6538fbf 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -200,8 +200,8 @@ uint64_t HELPER(stpt)(CPUS390XState *env) } /* Store System Information */ -uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0, - uint32_t r1) +uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, + uint64_t r0, uint64_t r1) { int cc = 0; int sel1, sel2; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 491f8fd6b6..6f1f799d2d 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1023,7 +1023,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, { #ifndef CONFIG_USER_ONLY TCGv_i64 tmp, tmp2, tmp3; - TCGv_i32 tmp32_1, tmp32_2; + TCGv_i32 tmp32_1; int r1, r2; int r3, d2, b2; @@ -1033,19 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x7d: /* STSI D2,(B2) [S] */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp32_1 = load_reg32(0); - tmp32_2 = load_reg32(1); - potential_page_fault(s); - gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2); - set_cc_static(s); - tcg_temp_free_i64(tmp); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - break; case 0xb1: /* STFL D2(B2) [S] */ /* Store Facility List (CPU features) at 200 */ check_privileged(s); @@ -2895,6 +2882,15 @@ static ExitStatus op_stpt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stsi(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_spx(DisasContext *s, DisasOps *o) { check_privileged(s); From fc778b55a5ae45abac2a94d591e7490622917872 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 10:58:59 -0700 Subject: [PATCH 0205/1634] target-s390: Convert STFL Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 5de3256be9..ba070f1725 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -678,6 +678,8 @@ C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0) /* STORE CPU TIMER */ C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0) +/* STORE FACILITY LIST */ + C(0xb2b1, STFL, S, Z, 0, 0, 0, 0, stfl, 0) /* STORE PREFIX */ C(0xb211, STPX, S, Z, la2, 0, new, m1_32, stpx, 0) /* STORE SYSTEM INFORMATION */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6f1f799d2d..b5cc573b6e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1033,15 +1033,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0xb1: /* STFL D2(B2) [S] */ - /* Store Facility List (CPU features) at 200 */ - check_privileged(s); - tmp2 = tcg_const_i64(0xc0000000); - tmp = tcg_const_i64(200); - tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp); - break; case 0xb2: /* LPSWE D2(B2) [S] */ /* Load PSW Extended */ check_privileged(s); @@ -2875,6 +2866,20 @@ static ExitStatus op_spt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stfl(DisasContext *s, DisasOps *o) +{ + TCGv_i64 f, a; + /* We really ought to have more complete indication of facilities + that we implement. Address this when STFLE is implemented. */ + check_privileged(s); + f = tcg_const_i64(0xc0000000); + a = tcg_const_i64(200); + tcg_gen_qemu_st32(f, a, get_mem_index(s)); + tcg_temp_free_i64(f); + tcg_temp_free_i64(a); + return NO_EXIT; +} + static ExitStatus op_stpt(DisasContext *s, DisasOps *o) { check_privileged(s); From 7ab938d706b515cfe4680a823525693124e2047d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 11:04:48 -0700 Subject: [PATCH 0206/1634] target-s390: Convert LPSWE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 ++ target-s390x/translate.c | 37 ++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ba070f1725..b0cf90880a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -627,6 +627,8 @@ C(0xeb2f, LCTLG, RSY_a, Z, 0, a2, 0, 0, lctlg, 0) /* LOAD PSW */ C(0x8200, LPSW, S, Z, 0, a2, 0, 0, lpsw, 0) +/* LOAD PSW EXTENDED */ + C(0xb2b2, LPSWE, S, Z, 0, a2, 0, 0, lpswe, 0) /* LOAD REAL ADDRESS */ C(0xb100, LRA, RX_a, Z, 0, a2, r1, 0, lra, 0) C(0xe313, LRAY, RXY_a, LD, 0, a2, r1, 0, lra, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b5cc573b6e..5472dfc1c4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1022,10 +1022,9 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { #ifndef CONFIG_USER_ONLY - TCGv_i64 tmp, tmp2, tmp3; + TCGv_i64 tmp; TCGv_i32 tmp32_1; int r1, r2; - int r3, d2, b2; r1 = (insn >> 4) & 0xf; r2 = insn & 0xf; @@ -1033,23 +1032,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0xb2: /* LPSWE D2(B2) [S] */ - /* Load PSW Extended */ - check_privileged(s); - decode_rs(s, insn, &r1, &r3, &b2, &d2); - tmp = get_address(s, 0, b2, d2); - tmp2 = tcg_temp_new_i64(); - tmp3 = tcg_temp_new_i64(); - tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); - tcg_gen_addi_i64(tmp, tmp, 8); - tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(cpu_env, tmp2, tmp3); - /* we need to keep cc_op intact */ - s->is_jmp = DISAS_JUMP; - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp3); - break; case 0x20: /* SERVC R1,R2 [RRE] */ /* SCLP Service call (PV hypercall) */ check_privileged(s); @@ -2254,6 +2236,23 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) tcg_temp_free_i64(t2); return EXIT_NORETURN; } + +static ExitStatus op_lpswe(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t1, t2; + + check_privileged(s); + + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(o->in2, o->in2, 8); + tcg_gen_qemu_ld64(t2, o->in2, get_mem_index(s)); + gen_helper_load_psw(cpu_env, t1, t2); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return EXIT_NORETURN; +} #endif static ExitStatus op_lam(DisasContext *s, DisasOps *o) From dc458df91d00986885fe12ed25876aa6d0604cee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 11:12:40 -0700 Subject: [PATCH 0207/1634] target-s390: Convert SERVC Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- target-s390x/insn-data.def | 2 ++ target-s390x/misc_helper.c | 6 ++---- target-s390x/translate.c | 29 +++++++++-------------------- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index f2eaef45fa..5d8a82175c 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -80,7 +80,7 @@ DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) #ifndef CONFIG_USER_ONLY -DEF_HELPER_3(servc, i32, env, i32, i64) +DEF_HELPER_3(servc, i32, env, i64, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b0cf90880a..cd773d0168 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -641,6 +641,8 @@ C(0xb20d, PTLB, S, Z, 0, 0, 0, 0, ptlb, 0) /* RESET REFERENCE BIT EXTENDED */ C(0xb22a, RRBE, RRE, Z, 0, r2_o, 0, 0, rrbe, 0) +/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */ + C(0xb220, SERVC, RRE, Z, r1_o, r2_o, 0, 0, servc, 0) /* SET ADDRESSING MODE */ /* We only do 64-bit, so accept this as a no-op. Let SAM24 and SAM31 signal illegal instruction. */ diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 60e6538fbf..3015bfe3f2 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -88,11 +88,9 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) } /* SCLP service call */ -uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2) +uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) { - int r; - - r = sclp_service_call(r1, r2); + int r = sclp_service_call(r1, r2); if (r < 0) { program_interrupt(env, -r, 4); return 0; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 5472dfc1c4..b4b197bb44 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1022,27 +1022,7 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, uint32_t insn) { #ifndef CONFIG_USER_ONLY - TCGv_i64 tmp; - TCGv_i32 tmp32_1; - int r1, r2; - - r1 = (insn >> 4) & 0xf; - r2 = insn & 0xf; - - LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); - switch (op) { - case 0x20: /* SERVC R1,R2 [RRE] */ - /* SCLP Service call (PV hypercall) */ - check_privileged(s); - potential_page_fault(s); - tmp32_1 = load_reg32(r2); - tmp = load_reg(r1); - gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp); - set_cc_static(s); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i64(tmp); - break; default: #endif LOG_DISAS("illegal b2 operation 0x%x\n", op); @@ -2701,6 +2681,15 @@ static ExitStatus op_sqxb(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY +static ExitStatus op_servc(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_servc(cc_op, cpu_env, o->in2, o->in1); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_sigp(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From 4f3adfb2a63416c434fdafdfa406604f2a18392b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 27 Aug 2012 11:33:58 -0700 Subject: [PATCH 0208/1634] target-s390: Delete dead code from old translator The use of inline restricts detection of static functions that are no longer used. Limit the use of inline to those functions that are conditionally used based on CONFIG_USER_ONLY. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 318 ++++----------------------------------- 1 file changed, 27 insertions(+), 291 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b4b197bb44..3d92a56a50 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -79,12 +79,7 @@ static uint64_t inline_branch_hit[CC_OP_MAX]; static uint64_t inline_branch_miss[CC_OP_MAX]; #endif -static inline void debug_insn(uint64_t insn) -{ - LOG_DISAS("insn: 0x%" PRIx64 "\n", insn); -} - -static inline uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) +static uint64_t pc_to_link_info(DisasContext *s, uint64_t pc) { if (!(s->tb->flags & FLAG_MASK_64)) { if (s->tb->flags & FLAG_MASK_32) { @@ -200,112 +195,58 @@ void s390x_translate_init(void) #include "helper.h" } -static inline TCGv_i64 load_reg(int reg) +static TCGv_i64 load_reg(int reg) { TCGv_i64 r = tcg_temp_new_i64(); tcg_gen_mov_i64(r, regs[reg]); return r; } -static inline TCGv_i64 load_freg(int reg) -{ - TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_mov_i64(r, fregs[reg]); - return r; -} - -static inline TCGv_i32 load_freg32(int reg) -{ - TCGv_i32 r = tcg_temp_new_i32(); -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(r, TCGV_HIGH(fregs[reg])); -#else - tcg_gen_shri_i64(MAKE_TCGV_I64(GET_TCGV_I32(r)), fregs[reg], 32); -#endif - return r; -} - -static inline TCGv_i64 load_freg32_i64(int reg) +static TCGv_i64 load_freg32_i64(int reg) { TCGv_i64 r = tcg_temp_new_i64(); tcg_gen_shri_i64(r, fregs[reg], 32); return r; } -static inline TCGv_i32 load_reg32(int reg) -{ - TCGv_i32 r = tcg_temp_new_i32(); - tcg_gen_trunc_i64_i32(r, regs[reg]); - return r; -} - -static inline TCGv_i64 load_reg32_i64(int reg) -{ - TCGv_i64 r = tcg_temp_new_i64(); - tcg_gen_ext32s_i64(r, regs[reg]); - return r; -} - -static inline void store_reg(int reg, TCGv_i64 v) +static void store_reg(int reg, TCGv_i64 v) { tcg_gen_mov_i64(regs[reg], v); } -static inline void store_freg(int reg, TCGv_i64 v) +static void store_freg(int reg, TCGv_i64 v) { tcg_gen_mov_i64(fregs[reg], v); } -static inline void store_reg32(int reg, TCGv_i32 v) -{ - /* 32 bit register writes keep the upper half */ -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_LOW(regs[reg]), v); -#else - tcg_gen_deposit_i64(regs[reg], regs[reg], - MAKE_TCGV_I64(GET_TCGV_I32(v)), 0, 32); -#endif -} - -static inline void store_reg32_i64(int reg, TCGv_i64 v) +static void store_reg32_i64(int reg, TCGv_i64 v) { /* 32 bit register writes keep the upper half */ tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32); } -static inline void store_reg32h_i64(int reg, TCGv_i64 v) +static void store_reg32h_i64(int reg, TCGv_i64 v) { tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32); } -static inline void store_freg32(int reg, TCGv_i32 v) -{ - /* 32 bit register writes keep the lower half */ -#if HOST_LONG_BITS == 32 - tcg_gen_mov_i32(TCGV_HIGH(fregs[reg]), v); -#else - tcg_gen_deposit_i64(fregs[reg], fregs[reg], - MAKE_TCGV_I64(GET_TCGV_I32(v)), 32, 32); -#endif -} - -static inline void store_freg32_i64(int reg, TCGv_i64 v) +static void store_freg32_i64(int reg, TCGv_i64 v) { tcg_gen_deposit_i64(fregs[reg], fregs[reg], v, 32, 32); } -static inline void return_low128(TCGv_i64 dest) +static void return_low128(TCGv_i64 dest) { tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl)); } -static inline void update_psw_addr(DisasContext *s) +static void update_psw_addr(DisasContext *s) { /* psw.addr */ tcg_gen_movi_i64(psw_addr, s->pc); } -static inline void potential_page_fault(DisasContext *s) +static void potential_page_fault(DisasContext *s) { #ifndef CONFIG_USER_ONLY update_psw_addr(s); @@ -328,7 +269,7 @@ static inline uint64_t ld_code6(CPUS390XState *env, uint64_t pc) return (ld_code2(env, pc) << 32) | ld_code4(env, pc + 2); } -static inline int get_mem_index(DisasContext *s) +static int get_mem_index(DisasContext *s) { switch (s->tb->flags & FLAG_MASK_ASC) { case PSW_ASC_PRIMARY >> 32: @@ -440,14 +381,6 @@ static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst) s->cc_op = op; } -static void gen_op_update1_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 dst) -{ - tcg_gen_discard_i64(cc_src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); - s->cc_op = op; -} - static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, TCGv_i64 dst) { @@ -457,15 +390,6 @@ static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, s->cc_op = op; } -static void gen_op_update2_cc_i32(DisasContext *s, enum cc_op op, TCGv_i32 src, - TCGv_i32 dst) -{ - tcg_gen_extu_i32_i64(cc_src, src); - tcg_gen_extu_i32_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); - s->cc_op = op; -} - static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, TCGv_i64 dst, TCGv_i64 vr) { @@ -475,104 +399,28 @@ static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, s->cc_op = op; } -static inline void set_cc_nz_u32(DisasContext *s, TCGv_i32 val) -{ - gen_op_update1_cc_i32(s, CC_OP_NZ, val); -} - -static inline void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) +static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val) { gen_op_update1_cc_i64(s, CC_OP_NZ, val); } -static inline void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) +static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val) { gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val); } -static inline void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) +static void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val) { gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val); } -static inline void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) +static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) { gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl); } -static inline void cmp_32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2, - enum cc_op cond) -{ - gen_op_update2_cc_i32(s, cond, v1, v2); -} - -static inline void cmp_64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2, - enum cc_op cond) -{ - gen_op_update2_cc_i64(s, cond, v1, v2); -} - -static inline void cmp_s32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - cmp_32(s, v1, v2, CC_OP_LTGT_32); -} - -static inline void cmp_u32(DisasContext *s, TCGv_i32 v1, TCGv_i32 v2) -{ - cmp_32(s, v1, v2, CC_OP_LTUGTU_32); -} - -static inline void cmp_s32c(DisasContext *s, TCGv_i32 v1, int32_t v2) -{ - /* XXX optimize for the constant? put it in s? */ - TCGv_i32 tmp = tcg_const_i32(v2); - cmp_32(s, v1, tmp, CC_OP_LTGT_32); - tcg_temp_free_i32(tmp); -} - -static inline void cmp_u32c(DisasContext *s, TCGv_i32 v1, uint32_t v2) -{ - TCGv_i32 tmp = tcg_const_i32(v2); - cmp_32(s, v1, tmp, CC_OP_LTUGTU_32); - tcg_temp_free_i32(tmp); -} - -static inline void cmp_s64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) -{ - cmp_64(s, v1, v2, CC_OP_LTGT_64); -} - -static inline void cmp_u64(DisasContext *s, TCGv_i64 v1, TCGv_i64 v2) -{ - cmp_64(s, v1, v2, CC_OP_LTUGTU_64); -} - -static inline void cmp_s64c(DisasContext *s, TCGv_i64 v1, int64_t v2) -{ - TCGv_i64 tmp = tcg_const_i64(v2); - cmp_s64(s, v1, tmp); - tcg_temp_free_i64(tmp); -} - -static inline void cmp_u64c(DisasContext *s, TCGv_i64 v1, uint64_t v2) -{ - TCGv_i64 tmp = tcg_const_i64(v2); - cmp_u64(s, v1, tmp); - tcg_temp_free_i64(tmp); -} - -static inline void set_cc_s32(DisasContext *s, TCGv_i32 val) -{ - gen_op_update1_cc_i32(s, CC_OP_LTGT0_32, val); -} - -static inline void set_cc_s64(DisasContext *s, TCGv_i64 val) -{ - gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val); -} - /* CC value is in env->cc_op */ -static inline void set_cc_static(DisasContext *s) +static void set_cc_static(DisasContext *s) { tcg_gen_discard_i64(cc_src); tcg_gen_discard_i64(cc_dst); @@ -580,14 +428,14 @@ static inline void set_cc_static(DisasContext *s) s->cc_op = CC_OP_STATIC; } -static inline void gen_op_set_cc_op(DisasContext *s) +static void gen_op_set_cc_op(DisasContext *s) { if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { tcg_gen_movi_i32(cc_op, s->cc_op); } } -static inline void gen_update_cc_op(DisasContext *s) +static void gen_update_cc_op(DisasContext *s) { gen_op_set_cc_op(s); } @@ -667,51 +515,6 @@ static void gen_op_calc_cc(DisasContext *s) set_cc_static(s); } -static inline void decode_rr(DisasContext *s, uint64_t insn, int *r1, int *r2) -{ - debug_insn(insn); - - *r1 = (insn >> 4) & 0xf; - *r2 = insn & 0xf; -} - -static inline TCGv_i64 decode_rx(DisasContext *s, uint64_t insn, int *r1, - int *x2, int *b2, int *d2) -{ - debug_insn(insn); - - *r1 = (insn >> 20) & 0xf; - *x2 = (insn >> 16) & 0xf; - *b2 = (insn >> 12) & 0xf; - *d2 = insn & 0xfff; - - return get_address(s, *x2, *b2, *d2); -} - -static inline void decode_rs(DisasContext *s, uint64_t insn, int *r1, int *r3, - int *b2, int *d2) -{ - debug_insn(insn); - - *r1 = (insn >> 20) & 0xf; - /* aka m3 */ - *r3 = (insn >> 16) & 0xf; - *b2 = (insn >> 12) & 0xf; - *d2 = insn & 0xfff; -} - -static inline TCGv_i64 decode_si(DisasContext *s, uint64_t insn, int *i2, - int *b1, int *d1) -{ - debug_insn(insn); - - *i2 = (insn >> 16) & 0xff; - *b1 = (insn >> 12) & 0xf; - *d1 = insn & 0xfff; - - return get_address(s, 0, *b1, *d1); -} - static int use_goto_tb(DisasContext *s, uint64_t dest) { /* NOTE: we handle the case where the TB spans two pages here */ @@ -721,29 +524,14 @@ static int use_goto_tb(DisasContext *s, uint64_t dest) && !(s->tb->cflags & CF_LAST_IO)); } -static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc) -{ - gen_update_cc_op(s); - - if (use_goto_tb(s, pc)) { - tcg_gen_goto_tb(tb_num); - tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb((tcg_target_long)s->tb + tb_num); - } else { - /* jump to another page: currently not optimized */ - tcg_gen_movi_i64(psw_addr, pc); - tcg_gen_exit_tb(0); - } -} - -static inline void account_noninline_branch(DisasContext *s, int cc_op) +static void account_noninline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES inline_branch_miss[cc_op]++; #endif } -static inline void account_inline_branch(DisasContext *s, int cc_op) +static void account_inline_branch(DisasContext *s, int cc_op) { #ifdef DEBUG_INLINE_BRANCHES inline_branch_hit[cc_op]++; @@ -1018,43 +806,6 @@ static void free_compare(DisasCompare *c) } } -static void disas_b2(CPUS390XState *env, DisasContext *s, int op, - uint32_t insn) -{ -#ifndef CONFIG_USER_ONLY - switch (op) { - default: -#endif - LOG_DISAS("illegal b2 operation 0x%x\n", op); - gen_illegal_opcode(s); -#ifndef CONFIG_USER_ONLY - break; - } -#endif -} - -static void disas_s390_insn(CPUS390XState *env, DisasContext *s) -{ - unsigned char opc; - uint64_t insn; - int op; - - opc = cpu_ldub_code(env, s->pc); - LOG_DISAS("opc 0x%x\n", opc); - - switch (opc) { - case 0xb2: - insn = ld_code4(env, s->pc); - op = (insn >> 16) & 0xff; - disas_b2(env, s, op, insn); - break; - default: - qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); - gen_illegal_opcode(s); - break; - } -} - /* ====================================================================== */ /* Define the insn format enumeration. */ #define F0(N) FMT_##N, @@ -4108,30 +3859,15 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) DisasFields f; DisasOps o; + /* Search for the insn in the table. */ insn = extract_insn(env, s, &f); - /* If not found, try the old interpreter. This includes ILLOPC. */ + /* Not found means unimplemented/illegal opcode. */ if (insn == NULL) { - disas_s390_insn(env, s); - switch (s->is_jmp) { - case DISAS_NEXT: - ret = NO_EXIT; - break; - case DISAS_TB_JUMP: - ret = EXIT_GOTO_TB; - break; - case DISAS_JUMP: - ret = EXIT_PC_UPDATED; - break; - case DISAS_EXCP: - ret = EXIT_NORETURN; - break; - default: - abort(); - } - - s->pc = s->next_pc; - return ret; + qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n", + f.op, f.op2); + gen_illegal_opcode(s); + return EXIT_NORETURN; } /* Set up the strutures we use to communicate with the helpers. */ From 2cf5e350c4f7ec08aab5d70193310c721b8179e9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 29 Aug 2012 12:57:55 -0700 Subject: [PATCH 0209/1634] target-s390: Implement BRANCH ON INDEX Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 10 ++++++++ target-s390x/translate.c | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index cd773d0168..8b89ce6217 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -90,6 +90,16 @@ /* BRANCH RELATIVE ON COUNT */ C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* BRANCH ON INDEX */ + D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0) + D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1) + D(0xeb44, BXHG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 0) + D(0xeb45, BXLEG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 1) +/* BRANCH RELATIVE ON INDEX */ + D(0x8400, BRXH, RSI, Z, 0, 0, 0, 0, bx32, 0, 0) + D(0x8500, BRXLE, RSI, Z, 0, 0, 0, 0, bx32, 0, 1) + D(0xec44, BRXHG, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 0) + D(0xec45, BRXHLE, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 1) /* CHECKSUM */ C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 3d92a56a50..6553e486c3 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1355,6 +1355,58 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_bx32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + TCGv_i64 t; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_add_i64(t, regs[r1], regs[r3]); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_gen_trunc_i64_i32(c.u.s32.b, regs[r3 | 1]); + store_reg32_i64(r1, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bx64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = true; + + if (r1 == (r3 | 1)) { + c.u.s64.b = load_reg(r3 | 1); + c.g2 = false; + } else { + c.u.s64.b = regs[r3 | 1]; + c.g2 = true; + } + + tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]); + c.u.s64.a = regs[r1]; + c.g1 = true; + + return help_branch(s, &c, is_imm, imm, o->in2); +} + static ExitStatus op_ceb(DisasContext *s, DisasOps *o) { gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); From 7a6c7067f034c5b887cda5e45ef660fe50ebbd1b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 17:28:17 -0700 Subject: [PATCH 0210/1634] target-s390: Tidy s->op_cc handling There's no need to force computation of the true cc_op when taking an exception or single stepping. In either case we'll enter the next TB with s->cc_op = DYNAMIC and recompute anyway. Just make sure that s->cc_op is stored back to env->cc_op as needed. Delete some dead functions, avoid allocating unused TCG temps, drop the old s->is_jmp setting. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 95 +++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 6553e486c3..c87d97ffe2 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -55,7 +55,6 @@ struct DisasContext { uint64_t pc, next_pc; enum cc_op cc_op; bool singlestep_enabled; - int is_jmp; }; /* Information carried about a condition to be evaluated. */ @@ -72,8 +71,6 @@ typedef struct { #define DISAS_EXCP 4 -static void gen_op_calc_cc(DisasContext *s); - #ifdef DEBUG_INLINE_BRANCHES static uint64_t inline_branch_hit[CC_OP_MAX]; static uint64_t inline_branch_miss[CC_OP_MAX]; @@ -246,12 +243,17 @@ static void update_psw_addr(DisasContext *s) tcg_gen_movi_i64(psw_addr, s->pc); } +static void update_cc_op(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { + tcg_gen_movi_i32(cc_op, s->cc_op); + } +} + static void potential_page_fault(DisasContext *s) { -#ifndef CONFIG_USER_ONLY update_psw_addr(s); - gen_op_calc_cc(s); -#endif + update_cc_op(s); } static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) @@ -309,13 +311,10 @@ static void gen_program_exception(DisasContext *s, int code) update_psw_addr(s); /* Save off cc. */ - gen_op_calc_cc(s); + update_cc_op(s); /* Trigger exception. */ gen_exception(EXCP_PGM); - - /* End TB here. */ - s->is_jmp = DISAS_EXCP; } static inline void gen_illegal_opcode(DisasContext *s) @@ -428,23 +427,40 @@ static void set_cc_static(DisasContext *s) s->cc_op = CC_OP_STATIC; } -static void gen_op_set_cc_op(DisasContext *s) -{ - if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { - tcg_gen_movi_i32(cc_op, s->cc_op); - } -} - -static void gen_update_cc_op(DisasContext *s) -{ - gen_op_set_cc_op(s); -} - /* calculates cc into cc_op */ static void gen_op_calc_cc(DisasContext *s) { - TCGv_i32 local_cc_op = tcg_const_i32(s->cc_op); - TCGv_i64 dummy = tcg_const_i64(0); + TCGv_i32 local_cc_op; + TCGv_i64 dummy; + + TCGV_UNUSED_I32(local_cc_op); + TCGV_UNUSED_I64(dummy); + switch (s->cc_op) { + default: + dummy = tcg_const_i64(0); + /* FALLTHRU */ + case CC_OP_ADD_64: + case CC_OP_ADDU_64: + case CC_OP_ADDC_64: + case CC_OP_SUB_64: + case CC_OP_SUBU_64: + case CC_OP_SUBB_64: + case CC_OP_ADD_32: + case CC_OP_ADDU_32: + case CC_OP_ADDC_32: + case CC_OP_SUB_32: + case CC_OP_SUBU_32: + case CC_OP_SUBB_32: + local_cc_op = tcg_const_i32(s->cc_op); + break; + case CC_OP_CONST0: + case CC_OP_CONST1: + case CC_OP_CONST2: + case CC_OP_CONST3: + case CC_OP_STATIC: + case CC_OP_DYNAMIC: + break; + } switch (s->cc_op) { case CC_OP_CONST0: @@ -508,8 +524,12 @@ static void gen_op_calc_cc(DisasContext *s) tcg_abort(); } - tcg_temp_free_i32(local_cc_op); - tcg_temp_free_i64(dummy); + if (!TCGV_IS_UNUSED_I32(local_cc_op)) { + tcg_temp_free_i32(local_cc_op); + } + if (!TCGV_IS_UNUSED_I64(dummy)) { + tcg_temp_free_i64(dummy); + } /* We now have cc in cc_op as constant */ set_cc_static(s); @@ -1054,7 +1074,7 @@ static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) return NO_EXIT; } if (use_goto_tb(s, dest)) { - gen_update_cc_op(s); + update_cc_op(s); tcg_gen_goto_tb(0); tcg_gen_movi_i64(psw_addr, dest); tcg_gen_exit_tb((tcg_target_long)s->tb); @@ -1103,7 +1123,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, if (use_goto_tb(s, s->next_pc)) { if (is_imm && use_goto_tb(s, dest)) { /* Both exits can use goto_tb. */ - gen_update_cc_op(s); + update_cc_op(s); lab = gen_new_label(); if (c->is_64) { @@ -1141,7 +1161,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, } /* Branch not taken. */ - gen_update_cc_op(s); + update_cc_op(s); tcg_gen_goto_tb(0); tcg_gen_movi_i64(psw_addr, s->next_pc); tcg_gen_exit_tb((tcg_target_long)s->tb + 0); @@ -1749,7 +1769,7 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) TCGv_i64 tmp; update_psw_addr(s); - gen_op_calc_cc(s); + update_cc_op(s); tmp = tcg_const_i64(s->next_pc); gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); @@ -2913,7 +2933,7 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) TCGv_i32 t; update_psw_addr(s); - gen_op_calc_cc(s); + update_cc_op(s); t = tcg_const_i32(get_field(s->fields, i1) & 0xff); tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); @@ -3999,7 +4019,6 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; do_debug = dc.singlestep_enabled = env->singlestep_enabled; - dc.is_jmp = DISAS_NEXT; gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; @@ -4073,17 +4092,13 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, update_psw_addr(&dc); /* FALLTHRU */ case EXIT_PC_UPDATED: - if (singlestep && dc.cc_op != CC_OP_DYNAMIC) { - gen_op_calc_cc(&dc); - } else { - /* Next TB starts off with CC_OP_DYNAMIC, - so make sure the cc op type is in env */ - gen_op_set_cc_op(&dc); - } + /* Next TB starts off with CC_OP_DYNAMIC, so make sure the + cc op type is in env */ + update_cc_op(&dc); + /* Exit the TB, either by raising a debug exception or by return. */ if (do_debug) { gen_exception(EXCP_DEBUG); } else { - /* Generate the return instruction */ tcg_gen_exit_tb(0); } break; From 5550359f07b54d6fb6f38ee5dcbc198cff42bf51 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 10:53:49 -0700 Subject: [PATCH 0211/1634] target-s390: Implement COMPARE AND BRANCH Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 19 +++++++++++++++++++ target-s390x/translate.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8b89ce6217..4478d1c8cf 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -166,6 +166,25 @@ /* COMPARE LOGICAL STRING */ C(0xb25d, CLST, RRE, Z, r1_o, r2_o, 0, 0, clst, 0) +/* COMPARE AND BRANCH */ + D(0xecf6, CRB, RRS, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xece4, CGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xec76, CRJ, RIE_b, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0) + D(0xec64, CGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 0) + D(0xecfe, CIB, RIS, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xecfc, CGIB, RIS, GIE, r1_o, i2, 0, 0, cj, 0, 0) + D(0xec7e, CIJ, RIE_c, GIE, r1_32s, i2, 0, 0, cj, 0, 0) + D(0xec7c, CGIJ, RIE_c, GIE, r1_o, i2, 0, 0, cj, 0, 0) +/* COMPARE LOGICAL AND BRANCH */ + D(0xecf7, CLRB, RRS, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xece5, CLGRB, RRS, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xec77, CLRJ, RIE_b, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1) + D(0xec65, CLGRJ, RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 1) + D(0xecff, CLIB, RIS, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xecfd, CLGIB, RIS, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + D(0xec7f, CLIJ, RIE_c, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1) + D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) + /* COMPARE AND SWAP */ C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) C(0xeb14, CSY, RSY_a, LD, r1_o, a2, new, r1_32, cs, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c87d97ffe2..d6f7121a2e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1427,6 +1427,34 @@ static ExitStatus op_bx64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_cj(DisasContext *s, DisasOps *o) +{ + int imm, m3 = get_field(s->fields, m3); + bool is_imm; + DisasCompare c; + + /* Bit 3 of the m3 field is reserved and should be zero. + Choose to ignore it wrt the ltgt_cond table above. */ + c.cond = ltgt_cond[m3 & 14]; + if (s->insn->data) { + c.cond = tcg_unsigned_cond(c.cond); + } + c.is_64 = c.g1 = c.g2 = true; + c.u.s64.a = o->in1; + c.u.s64.b = o->in2; + + is_imm = have_field(s->fields, i4); + if (is_imm) { + imm = get_field(s->fields, i4); + } else { + imm = 0; + o->out = get_address(s, 0, get_field(s->fields, b4), + get_field(s->fields, d4)); + } + + return help_branch(s, &c, is_imm, imm, o->out); +} + static ExitStatus op_ceb(DisasContext *s, DisasOps *o) { gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); From 2d6a869833d99d89fc4bbe42bdb35b2c1d808067 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 12:50:06 -0700 Subject: [PATCH 0212/1634] target-s390: Implement RISBG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++ target-s390x/translate.c | 83 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 4478d1c8cf..c80a386c32 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -500,6 +500,11 @@ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) +/* ROTATE THEN INSERT SELECTED BITS */ + C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) + C(0xec5d, RISBHG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) + C(0xec51, RISBLG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) + /* SEARCH STRING */ C(0xb25e, SRST, RRE, Z, r1_o, r2_o, 0, 0, srst, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d6f7121a2e..1f8659f4db 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2429,6 +2429,89 @@ static ExitStatus op_ptlb(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_risbg(DisasContext *s, DisasOps *o) +{ + int i3 = get_field(s->fields, i3); + int i4 = get_field(s->fields, i4); + int i5 = get_field(s->fields, i5); + int do_zero = i4 & 0x80; + uint64_t mask, imask, pmask; + int pos, len, rot; + + /* Adjust the arguments for the specific insn. */ + switch (s->fields->op2) { + case 0x55: /* risbg */ + i3 &= 63; + i4 &= 63; + pmask = ~0; + break; + case 0x5d: /* risbhg */ + i3 &= 31; + i4 &= 31; + pmask = 0xffffffff00000000ull; + break; + case 0x51: /* risblg */ + i3 &= 31; + i4 &= 31; + pmask = 0x00000000ffffffffull; + break; + default: + abort(); + } + + /* MASK is the set of bits to be inserted from R2. + Take care for I3/I4 wraparound. */ + mask = pmask >> i3; + if (i3 <= i4) { + mask ^= pmask >> i4 >> 1; + } else { + mask |= ~(pmask >> i4 >> 1); + } + mask &= pmask; + + /* IMASK is the set of bits to be kept from R1. In the case of the high/low + insns, we need to keep the other half of the register. */ + imask = ~mask | ~pmask; + if (do_zero) { + if (s->fields->op2 == 0x55) { + imask = 0; + } else { + imask = ~pmask; + } + } + + /* In some cases we can implement this with deposit, which can be more + efficient on some hosts. */ + if (~mask == imask && i3 <= i4) { + if (s->fields->op2 == 0x5d) { + i3 += 32, i4 += 32; + } + /* Note that we rotate the bits to be inserted to the lsb, not to + the position as described in the PoO. */ + len = i4 - i3 + 1; + pos = 63 - i4; + rot = (i5 - pos) & 63; + } else { + pos = len = -1; + rot = i5 & 63; + } + + /* Rotate the input as necessary. */ + tcg_gen_rotli_i64(o->in2, o->in2, rot); + + /* Insert the selected bits into the output. */ + if (pos >= 0) { + tcg_gen_deposit_i64(o->out, o->out, o->in2, pos, len); + } else if (imask == 0) { + tcg_gen_andi_i64(o->out, o->in2, mask); + } else { + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_andi_i64(o->out, o->out, imask); + tcg_gen_or_i64(o->out, o->out, o->in2); + } + return NO_EXIT; +} + static ExitStatus op_rev16(DisasContext *s, DisasOps *o) { tcg_gen_bswap16_i64(o->out, o->in2); From 143cbbc5ebc4a5b5beb82dc31ecc5ac5f6d511d2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:52:08 -0700 Subject: [PATCH 0213/1634] target-s390: Implement LDGR, LGDR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c80a386c32..8bcfb2b98a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -364,6 +364,10 @@ /* LOAD LOGICAL THIRTY ONE BITS */ C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) +/* LOAD FPR FROM GR */ + C(0xb3c1, LDGR, RRE, FPRGR, 0, r2_o, 0, f1, mov2, 0) +/* LOAD GR FROM FPR */ + C(0xb3cd, LGDR, RRE, FPRGR, 0, f2_o, 0, r1, mov2, 0) /* LOAD NEGATIVE */ C(0x1100, LNR, RR_a, Z, 0, r2_32s, new, r1_32, nabs, nabs32) C(0xb901, LNGR, RRE, Z, 0, r2, r1, 0, nabs, nabs64) From d6c6372e186e7f17fe9eeec0c50a43b484669d71 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 13:54:13 -0700 Subject: [PATCH 0214/1634] target-s390: Implement R[NOX]SBG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 +++ target-s390x/translate.c | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 8bcfb2b98a..9582f0c847 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -508,6 +508,10 @@ C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) C(0xec5d, RISBHG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) C(0xec51, RISBLG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) +/* ROTATE_THEN SELECTED BITS */ + C(0xec54, RNSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec56, ROSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) + C(0xec57, RXSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) /* SEARCH STRING */ C(0xb25e, SRST, RRE, Z, r1_o, r2_o, 0, 0, srst, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1f8659f4db..dbc43a6754 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2512,6 +2512,59 @@ static ExitStatus op_risbg(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_rosbg(DisasContext *s, DisasOps *o) +{ + int i3 = get_field(s->fields, i3); + int i4 = get_field(s->fields, i4); + int i5 = get_field(s->fields, i5); + uint64_t mask; + + /* If this is a test-only form, arrange to discard the result. */ + if (i3 & 0x80) { + o->out = tcg_temp_new_i64(); + o->g_out = false; + } + + i3 &= 63; + i4 &= 63; + i5 &= 63; + + /* MASK is the set of bits to be operated on from R2. + Take care for I3/I4 wraparound. */ + mask = ~0ull >> i3; + if (i3 <= i4) { + mask ^= ~0ull >> i4 >> 1; + } else { + mask |= ~(~0ull >> i4 >> 1); + } + + /* Rotate the input as necessary. */ + tcg_gen_rotli_i64(o->in2, o->in2, i5); + + /* Operate. */ + switch (s->fields->op2) { + case 0x55: /* AND */ + tcg_gen_ori_i64(o->in2, o->in2, ~mask); + tcg_gen_and_i64(o->out, o->out, o->in2); + break; + case 0x56: /* OR */ + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_or_i64(o->out, o->out, o->in2); + break; + case 0x57: /* XOR */ + tcg_gen_andi_i64(o->in2, o->in2, mask); + tcg_gen_xor_i64(o->out, o->out, o->in2); + break; + default: + abort(); + } + + /* Set the CC. */ + tcg_gen_andi_i64(cc_dst, o->out, mask); + set_cc_nz_u64(s, cc_dst); + return NO_EXIT; +} + static ExitStatus op_rev16(DisasContext *s, DisasOps *o) { tcg_gen_bswap16_i64(o->out, o->in2); From e0def9094ef1997613e488768405bcfb589f0596 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 31 Aug 2012 14:10:05 -0700 Subject: [PATCH 0215/1634] target-s390: Implement PREFETCH Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 9582f0c847..eb88c550d6 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -500,6 +500,11 @@ C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) +/* PREFETCH */ + /* Implemented as nops of course. */ + C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) + C(0xc602, PFDRL, RIL_c, GIE, 0, 0, 0, 0, 0, 0) + /* ROTATE LEFT SINGLE LOGICAL */ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) From 403e217f4073b885b7e02a1b64054ceca7202bf6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:54:00 -0700 Subject: [PATCH 0216/1634] target-s390: Implement COMPARE RELATIVE LONG Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index eb88c550d6..5c19aefefc 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -120,6 +120,10 @@ /* COMPARE IMMEDIATE */ C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) +/* COMPARE RELATIVE LONG */ + C(0xc60d, CRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps32) + C(0xc608, CGRL, RIL_b, GIE, r1, mri2_64, 0, 0, 0, cmps64) + C(0xc60c, CGFRL, RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps64) /* COMPARE HALFWORD */ C(0x4900, CH, RX_a, Z, r1_o, m2_16s, 0, 0, 0, cmps32) C(0xe379, CHY, RXY_a, LD, r1_o, m2_16s, 0, 0, 0, cmps32) From 1c2687518235aa38dd3dd270fc216e559d0509eb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 17:32:54 -0700 Subject: [PATCH 0217/1634] target-s390: Implement COMPARE AND TRAP Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 11 +++++++++++ target-s390x/translate.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 5c19aefefc..b739d70d38 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -198,6 +198,17 @@ C(0xeb31, CDSY, RSY_a, LD, r1_D32, a2, new, r1_D32, cds, 0) C(0xeb3e, CDSG, RSY_a, Z, 0, a2, 0, 0, cdsg, 0) +/* COMPARE AND TRAP */ + D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0) + D(0xb960, CGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 0) + D(0xec72, CIT, RIE_a, GIE, r1_32s, i2, 0, 0, ct, 0, 0) + D(0xec70, CGIT, RIE_a, GIE, r1_o, i2, 0, 0, ct, 0, 0) +/* COMPARE LOGICAL AND TRAP */ + D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1) + D(0xb961, CLGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1) + D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1) + D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 0) + /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) C(0xe326, CVDY, RXY_a, LD, r1_o, a2, 0, 0, cvd, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dbc43a6754..e94c663180 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1705,6 +1705,35 @@ static ExitStatus op_cvd(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ct(DisasContext *s, DisasOps *o) +{ + int m3 = get_field(s->fields, m3); + int lab = gen_new_label(); + TCGv_i32 t; + TCGCond c; + + /* Bit 3 of the m3 field is reserved and should be zero. + Choose to ignore it wrt the ltgt_cond table above. */ + c = tcg_invert_cond(ltgt_cond[m3 & 14]); + if (s->insn->data) { + c = tcg_unsigned_cond(c); + } + tcg_gen_brcond_i64(c, o->in1, o->in2, lab); + + /* Set DXC to 0xff. */ + t = tcg_temp_new_i32(); + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_ori_i32(t, t, 0xff00); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_temp_free_i32(t); + + /* Trap. */ + gen_program_exception(s, PGM_DATA); + + gen_set_label(lab); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_diag(DisasContext *s, DisasOps *o) { From 632086da28e1682c0129276656ee0d32274fcd17 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Sep 2012 10:55:00 -0700 Subject: [PATCH 0218/1634] target-s390: Implement LOAD ON CONDITION Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b739d70d38..91ee0551bb 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -390,6 +390,11 @@ C(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32) C(0xb311, LNDBR, RRE, Z, 0, f2_o, f1, 0, nabsf64, f64) C(0xb341, LNXBR, RRE, Z, 0, x2_o, x1, 0, nabsf128, f128) +/* LOAD ON CONDITION */ + C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0) + C(0xb9e2, LOCGR, RRF_c, LOC, r1, r2, r1, 0, loc, 0) + C(0xebf2, LOC, RSY_b, LOC, r1, m2_32u, new, r1_32, loc, 0) + C(0xebe2, LOCG, RSY_b, LOC, r1, m2_64, r1, 0, loc, 0) /* LOAD POSITIVE */ C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index e94c663180..1edb066463 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2045,6 +2045,36 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_loc(DisasContext *s, DisasOps *o) +{ + DisasCompare c; + + disas_jcc(s, &c, get_field(s->fields, m3)); + + if (c.is_64) { + tcg_gen_movcond_i64(c.cond, o->out, c.u.s64.a, c.u.s64.b, + o->in2, o->in1); + free_compare(&c); + } else { + TCGv_i32 t32 = tcg_temp_new_i32(); + TCGv_i64 t, z; + + tcg_gen_setcond_i32(c.cond, t32, c.u.s32.a, c.u.s32.b); + free_compare(&c); + + t = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t, t32); + tcg_temp_free_i32(t32); + + z = tcg_const_i64(0); + tcg_gen_movcond_i64(TCG_COND_NE, o->out, t, z, o->in2, o->in1); + tcg_temp_free_i64(t); + tcg_temp_free_i64(z); + } + + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_lctl(DisasContext *s, DisasOps *o) { From b92fa33486b240404923308b483a3318eb804c4a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 09:45:20 -0700 Subject: [PATCH 0219/1634] target-s390: Implement STORE ON CONDITION Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 91ee0551bb..00b95b681d 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -601,6 +601,9 @@ C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE ON CONDITION */ + D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0) + D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1) /* STORE REVERSED */ C(0xe33f, STRVH, RXY_a, Z, la2, r1_16u, new, m1_16, rev16, 0) C(0xe33e, STRV, RXY_a, Z, la2, r1_32u, new, m1_32, rev32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1edb066463..321fc46a13 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2747,6 +2747,35 @@ static ExitStatus op_sigp(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_soc(DisasContext *s, DisasOps *o) +{ + DisasCompare c; + TCGv_i64 a; + int lab, r1; + + disas_jcc(s, &c, get_field(s->fields, m3)); + + lab = gen_new_label(); + if (c.is_64) { + tcg_gen_brcond_i64(c.cond, c.u.s64.a, c.u.s64.b, lab); + } else { + tcg_gen_brcond_i32(c.cond, c.u.s32.a, c.u.s32.b, lab); + } + free_compare(&c); + + r1 = get_field(s->fields, r1); + a = get_address(s, 0, get_field(s->fields, b2), get_field(s->fields, d2)); + if (s->insn->data) { + tcg_gen_qemu_st64(regs[r1], a, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(regs[r1], a, get_mem_index(s)); + } + tcg_temp_free_i64(a); + + gen_set_label(lab); + return NO_EXIT; +} + static ExitStatus op_sla(DisasContext *s, DisasOps *o) { uint64_t sign = 1ull << s->insn->data; From 6ac1b45f9b3cb788255c0fde7637ba663eba632c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 10:42:54 -0700 Subject: [PATCH 0220/1634] target-s390: Implement CONVERT TO LOGICAL Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 66 ++++++++++++++++++++++++++++++++++++++ target-s390x/helper.h | 6 ++++ target-s390x/insn-data.def | 7 ++++ target-s390x/translate.c | 54 +++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 74b94f290f..6a76541833 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -457,6 +457,72 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) return ret; } +/* convert 32-bit float to 64-bit uint */ +uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint64_t ret; + v2 = float32_to_float64(v2, &env->fpu_status); + ret = float64_to_uint64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit float to 64-bit uint */ +uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint64_t ret = float64_to_uint64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 128-bit float to 64-bit uint */ +uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + /* ??? Not 100% correct. */ + uint64_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 32-bit float to 32-bit uint */ +uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint32_t ret = float32_to_uint32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit float to 32-bit uint */ +uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + uint32_t ret = float64_to_uint32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 128-bit float to 32-bit uint */ +uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 v2 = make_float128(h, l); + /* Not 100% correct. */ + uint32_t ret = float128_to_int64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + /* 32-bit FP multiply and add */ uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 5d8a82175c..0204e8505f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -61,6 +61,12 @@ DEF_HELPER_4(cgxb, i64, env, i64, i64, i32) DEF_HELPER_3(cfeb, i64, env, i64, i32) DEF_HELPER_3(cfdb, i64, env, i64, i32) DEF_HELPER_4(cfxb, i64, env, i64, i64, i32) +DEF_HELPER_3(clgeb, i64, env, i64, i32) +DEF_HELPER_3(clgdb, i64, env, i64, i32) +DEF_HELPER_4(clgxb, i64, env, i64, i64, i32) +DEF_HELPER_3(clfeb, i64, env, i64, i32) +DEF_HELPER_3(clfdb, i64, env, i64, i32) +DEF_HELPER_4(clfxb, i64, env, i64, i64, i32) DEF_HELPER_4(maeb, i64, env, i64, i64, i64) DEF_HELPER_4(madb, i64, env, i64, i64, i64) DEF_HELPER_4(mseb, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 00b95b681d..a67fdcc6ad 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -226,6 +226,13 @@ C(0xb3a4, CEGBR, RRF_e, Z, 0, r2_o, new, e1, cegb, 0) C(0xb3a5, CDGBR, RRF_e, Z, 0, r2_o, f1, 0, cdgb, 0) C(0xb3a6, CXGBR, RRF_e, Z, 0, r2_o, x1, 0, cxgb, 0) +/* CONVERT TO LOGICAL */ + C(0xb39c, CLFEBR, RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0) + C(0xb39d, CLFDBR, RRF_e, FPE, 0, f2_o, new, r1_32, clfdb, 0) + C(0xb39e, CLFXBR, RRF_e, FPE, 0, x2_o, new, r1_32, clfxb, 0) + C(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0) + C(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2_o, r1, 0, clgdb, 0) + C(0xb3ae, CLGXBR, RRF_e, FPE, 0, x2_o, r1, 0, clgxb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 321fc46a13..1b7a8dc946 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1530,6 +1530,60 @@ static ExitStatus op_cgxb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clfeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clfdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clfxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgeb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgeb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f32(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgdb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgdb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f64(s, o->in2); + return NO_EXIT; +} + +static ExitStatus op_clgxb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m3); + tcg_temp_free_i32(m3); + gen_set_cc_nz_f128(s, o->in1, o->in2); + return NO_EXIT; +} + static ExitStatus op_cegb(DisasContext *s, DisasOps *o) { TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); From 2112bf1bfb696def31b211425e5e74e89f9574c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 11:08:17 -0700 Subject: [PATCH 0221/1634] target-s390: Implement CONVERT FROM LOGICAL Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 31 +++++++++++++++++++++++++++++++ target-s390x/helper.h | 3 +++ target-s390x/insn-data.def | 7 +++++++ target-s390x/translate.c | 25 +++++++++++++++++++++++++ 4 files changed, 66 insertions(+) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 6a76541833..58c2e6135c 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -395,6 +395,37 @@ uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3) return RET128(ret); } +/* convert 64-bit uint to 32-bit float */ +uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float32 ret = uint64_to_float32(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit uint to 64-bit float */ +uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float64 ret = uint64_to_float64(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* convert 64-bit uint to 128-bit float */ +uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + /* ??? Not 50% correct. */ + float128 ret = int64_to_float128(v2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + /* convert 32-bit float to 64-bit int */ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 0204e8505f..aef6f0faf8 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -32,6 +32,9 @@ DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32) DEF_HELPER_3(cdgb, i64, env, s64, i32) DEF_HELPER_3(cxgb, i64, env, s64, i32) +DEF_HELPER_3(celgb, i64, env, i64, i32) +DEF_HELPER_3(cdlgb, i64, env, i64, i32) +DEF_HELPER_3(cxlgb, i64, env, i64, i32) DEF_HELPER_3(aeb, i64, env, i64, i64) DEF_HELPER_3(adb, i64, env, i64, i64) DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a67fdcc6ad..0777b5567b 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -233,6 +233,13 @@ C(0xb3ac, CLGEBR, RRF_e, FPE, 0, e2, r1, 0, clgeb, 0) C(0xb3ad, CLGDBR, RRF_e, FPE, 0, f2_o, r1, 0, clgdb, 0) C(0xb3ae, CLGXBR, RRF_e, FPE, 0, x2_o, r1, 0, clgxb, 0) +/* CONVERT FROM LOGICAL */ + C(0xb390, CELFBR, RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0) + C(0xb391, CDLFBR, RRF_e, FPE, 0, r2_32u, f1, 0, cdlgb, 0) + C(0xb392, CXLFBR, RRF_e, FPE, 0, r2_32u, x1, 0, cxlgb, 0) + C(0xb3a0, CELGBR, RRF_e, FPE, 0, r2_o, new, e1, celgb, 0) + C(0xb3a1, CDLGBR, RRF_e, FPE, 0, r2_o, f1, 0, cdlgb, 0) + C(0xb3a2, CXLGBR, RRF_e, FPE, 0, r2_o, x1, 0, cxlgb, 0) /* DIVIDE */ C(0x1d00, DR, RR_a, Z, r1_D32, r2_32s, new_P, r1_P32, divs32, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1b7a8dc946..dc5aac7941 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1609,6 +1609,31 @@ static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_celgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_celgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cdlgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cdlgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_cxlgb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_cxlgb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return_low128(o->out2); + return NO_EXIT; +} + static ExitStatus op_cksm(DisasContext *s, DisasOps *o) { int r2 = get_field(s->fields, r2); From 99b4f24b3e636ab241b53bc16bf8f0a0ac4a2271 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 11:14:04 -0700 Subject: [PATCH 0222/1634] target-s390: Implement POPCNT Signed-off-by: Richard Henderson --- target-s390x/helper.h | 1 + target-s390x/insn-data.def | 3 +++ target-s390x/int_helper.c | 12 ++++++++++++ target-s390x/translate.c | 6 ++++++ 4 files changed, 22 insertions(+) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index aef6f0faf8..23d23d5b3a 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -87,6 +87,7 @@ DEF_HELPER_4(tr, void, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 0777b5567b..49e4a441fd 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -539,6 +539,9 @@ C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) C(0xc602, PFDRL, RIL_c, GIE, 0, 0, 0, 0, 0, 0) +/* POPULATION COUNT */ + C(0xb9e1, POPCNT, RRE, PC, 0, r2_o, r1, 0, popcnt, nz64) + /* ROTATE LEFT SINGLE LOGICAL */ C(0xeb1d, RLL, RSY_a, Z, r3_o, sh32, new, r1_32, rll32, 0) C(0xeb1c, RLLG, RSY_a, Z, r3_o, sh64, r1, 0, rll64, 0) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index dc16de206c..685830124f 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -191,3 +191,15 @@ uint64_t HELPER(cvd)(int32_t bin) return dec; } + +uint64_t HELPER(popcnt)(uint64_t r2) +{ + uint64_t ret = 0; + int i; + + for (i = 0; i < 64; i += 8) { + uint64_t t = ctpop32((r2 >> i) & 0xff); + ret |= t << i; + } + return ret; +} diff --git a/target-s390x/translate.c b/target-s390x/translate.c index dc5aac7941..fe880956f0 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2558,6 +2558,12 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_popcnt(DisasContext *s, DisasOps *o) +{ + gen_helper_popcnt(o->out, o->in2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_ptlb(DisasContext *s, DisasOps *o) { From 2db014b5a73f295f6edbdc2c8400a94ccfc90624 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 1 Sep 2012 14:13:52 -0700 Subject: [PATCH 0223/1634] target-s390: Implement CPSDR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 49e4a441fd..b023911cec 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -104,6 +104,9 @@ /* CHECKSUM */ C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) +/* COPY SIGN */ + C(0xb372, CPSDR, RRF_b, FPSSH, f3_o, f2_o, f1, 0, cps, 0) + /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index fe880956f0..2873f7d2e4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1719,6 +1719,16 @@ static ExitStatus op_clst(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cps(DisasContext *s, DisasOps *o) +{ + TCGv_i64 t = tcg_temp_new_i64(); + tcg_gen_andi_i64(t, o->in1, 0x8000000000000000ull); + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull); + tcg_gen_or_i64(o->out, o->out, t); + tcg_temp_free_i64(t); + return NO_EXIT; +} + static ExitStatus op_cs(DisasContext *s, DisasOps *o) { int r3 = get_field(s->fields, r3); @@ -3801,6 +3811,12 @@ static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_out = o->g_out2 = true; } +static void in1_f3_o(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = fregs[get_field(f, r3)]; + o->g_in1 = true; +} + static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); From 49f7ee802fa6695af61dc1e88638f426d47a22a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 7 Sep 2012 16:16:57 -0700 Subject: [PATCH 0224/1634] target-s390: Check insn operand specifications Removes all the fixmes for even register numbers, etc. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 195 +++++++++++++++++++++++++++++++-------- 1 file changed, 159 insertions(+), 36 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2873f7d2e4..b4dd68e3f5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -993,6 +993,17 @@ typedef struct { TCGv_i64 addr1; } DisasOps; +/* Instructions can place constraints on their operands, raising specification + exceptions if they are violated. To make this easy to automate, each "in1", + "in2", "prep", "wout" helper will have a SPEC_ define that equals one + of the following, or 0. To make this easy to document, we'll put the + SPEC_ defines next to . */ + +#define SPEC_r1_even 1 +#define SPEC_r2_even 2 +#define SPEC_r1_f128 4 +#define SPEC_r2_f128 8 + /* Return values from translate_one, indicating the state of the TB. */ typedef enum { /* Continue the TB. */ @@ -1038,6 +1049,7 @@ struct DisasInsn { unsigned opc:16; DisasFormat fmt:6; DisasFacility fac:6; + unsigned spec:4; const char *name; @@ -3561,42 +3573,46 @@ static void prep_new(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = tcg_temp_new_i64(); } +#define SPEC_prep_new 0 static void prep_new_P(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = tcg_temp_new_i64(); o->out2 = tcg_temp_new_i64(); } +#define SPEC_prep_new_P 0 static void prep_r1(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = regs[get_field(f, r1)]; o->g_out = true; } +#define SPEC_prep_r1 0 static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); o->out = regs[r1]; - o->out2 = regs[(r1 + 1) & 15]; + o->out2 = regs[r1 + 1]; o->g_out = o->g_out2 = true; } +#define SPEC_prep_r1_P SPEC_r1_even static void prep_f1(DisasContext *s, DisasFields *f, DisasOps *o) { o->out = fregs[get_field(f, r1)]; o->g_out = true; } +#define SPEC_prep_f1 0 static void prep_x1(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int r1 = get_field(f, r1); o->out = fregs[r1]; - o->out2 = fregs[(r1 + 2) & 15]; + o->out2 = fregs[r1 + 2]; o->g_out = o->g_out2 = true; } +#define SPEC_prep_x1 SPEC_r1_f128 /* ====================================================================== */ /* The "Write OUTput" generators. These generally perform some non-trivial @@ -3608,58 +3624,64 @@ static void wout_r1(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg(get_field(f, r1), o->out); } +#define SPEC_wout_r1 0 static void wout_r1_8(DisasContext *s, DisasFields *f, DisasOps *o) { int r1 = get_field(f, r1); tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8); } +#define SPEC_wout_r1_8 0 static void wout_r1_16(DisasContext *s, DisasFields *f, DisasOps *o) { int r1 = get_field(f, r1); tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16); } +#define SPEC_wout_r1_16 0 static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) { store_reg32_i64(get_field(f, r1), o->out); } +#define SPEC_wout_r1_32 0 static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); store_reg32_i64(r1, o->out); - store_reg32_i64((r1 + 1) & 15, o->out2); + store_reg32_i64(r1 + 1, o->out2); } +#define SPEC_wout_r1_P32 SPEC_r1_even static void wout_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); - store_reg32_i64((r1 + 1) & 15, o->out); + store_reg32_i64(r1 + 1, o->out); tcg_gen_shri_i64(o->out, o->out, 32); store_reg32_i64(r1, o->out); } +#define SPEC_wout_r1_D32 SPEC_r1_even static void wout_e1(DisasContext *s, DisasFields *f, DisasOps *o) { store_freg32_i64(get_field(f, r1), o->out); } +#define SPEC_wout_e1 0 static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o) { store_freg(get_field(f, r1), o->out); } +#define SPEC_wout_f1 0 static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int f1 = get_field(s->fields, r1); store_freg(f1, o->out); - store_freg((f1 + 2) & 15, o->out2); + store_freg(f1 + 2, o->out2); } +#define SPEC_wout_x1 SPEC_r1_f128 static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3667,6 +3689,7 @@ static void wout_cond_r1r2_32(DisasContext *s, DisasFields *f, DisasOps *o) store_reg32_i64(get_field(f, r1), o->out); } } +#define SPEC_wout_cond_r1r2_32 0 static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3674,31 +3697,37 @@ static void wout_cond_e1e2(DisasContext *s, DisasFields *f, DisasOps *o) store_freg32_i64(get_field(f, r1), o->out); } } +#define SPEC_wout_cond_e1e2 0 static void wout_m1_8(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_8 0 static void wout_m1_16(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_16 0 static void wout_m1_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_32 0 static void wout_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s)); } +#define SPEC_wout_m1_64 0 static void wout_m2_32(DisasContext *s, DisasFields *f, DisasOps *o) { tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s)); } +#define SPEC_wout_m2_32 0 /* ====================================================================== */ /* The "INput 1" generators. These load the first operand to an insn. */ @@ -3707,126 +3736,138 @@ static void in1_r1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r1)); } +#define SPEC_in1_r1 0 static void in1_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = regs[get_field(f, r1)]; o->g_in1 = true; } +#define SPEC_in1_r1_o 0 static void in1_r1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1)]); } +#define SPEC_in1_r1_32s 0 static void in1_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1)]); } +#define SPEC_in1_r1_32u 0 static void in1_r1_sr32(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_shri_i64(o->in1, regs[get_field(f, r1)], 32); } +#define SPEC_in1_r1_sr32 0 static void in1_r1p1(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ - int r1 = get_field(f, r1); - o->in1 = load_reg((r1 + 1) & 15); + o->in1 = load_reg(get_field(f, r1) + 1); } +#define SPEC_in1_r1p1 SPEC_r1_even static void in1_r1p1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ - int r1 = get_field(f, r1); o->in1 = tcg_temp_new_i64(); - tcg_gen_ext32s_i64(o->in1, regs[(r1 + 1) & 15]); + tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r1) + 1]); } +#define SPEC_in1_r1p1_32s SPEC_r1_even static void in1_r1p1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ - int r1 = get_field(f, r1); o->in1 = tcg_temp_new_i64(); - tcg_gen_ext32u_i64(o->in1, regs[(r1 + 1) & 15]); + tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r1) + 1]); } +#define SPEC_in1_r1p1_32u SPEC_r1_even static void in1_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be even. */ int r1 = get_field(f, r1); o->in1 = tcg_temp_new_i64(); tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]); } +#define SPEC_in1_r1_D32 SPEC_r1_even static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r2)); } +#define SPEC_in1_r2 0 static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r3)); } +#define SPEC_in1_r3 0 static void in1_r3_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = regs[get_field(f, r3)]; o->g_in1 = true; } +#define SPEC_in1_r3_o 0 static void in1_r3_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32s_i64(o->in1, regs[get_field(f, r3)]); } +#define SPEC_in1_r3_32s 0 static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in1, regs[get_field(f, r3)]); } +#define SPEC_in1_r3_32u 0 static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_freg32_i64(get_field(f, r1)); } +#define SPEC_in1_e1 0 static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = fregs[get_field(f, r1)]; o->g_in1 = true; } +#define SPEC_in1_f1_o 0 static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int r1 = get_field(f, r1); o->out = fregs[r1]; - o->out2 = fregs[(r1 + 2) & 15]; + o->out2 = fregs[r1 + 2]; o->g_out = o->g_out2 = true; } +#define SPEC_in1_x1_o SPEC_r1_f128 static void in1_f3_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = fregs[get_field(f, r3)]; o->g_in1 = true; } +#define SPEC_in1_f3_o 0 static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o) { o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1)); } +#define SPEC_in1_la1 0 static void in1_la2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; o->addr1 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); } +#define SPEC_in1_la2 0 static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3834,6 +3875,7 @@ static void in1_m1_8u(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_8u 0 static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3841,6 +3883,7 @@ static void in1_m1_16s(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_16s 0 static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3848,6 +3891,7 @@ static void in1_m1_16u(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_16u 0 static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3855,6 +3899,7 @@ static void in1_m1_32s(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_32s 0 static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3862,6 +3907,7 @@ static void in1_m1_32u(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_32u 0 static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3869,6 +3915,7 @@ static void in1_m1_64(DisasContext *s, DisasFields *f, DisasOps *o) o->in1 = tcg_temp_new_i64(); tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s)); } +#define SPEC_in1_m1_64 0 /* ====================================================================== */ /* The "INput 2" generators. These load the second operand to an insn. */ @@ -3878,29 +3925,34 @@ static void in2_r1_o(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = regs[get_field(f, r1)]; o->g_in2 = true; } +#define SPEC_in2_r1_o 0 static void in2_r1_16u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r1)]); } +#define SPEC_in2_r1_16u 0 static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r1)]); } +#define SPEC_in2_r1_32u 0 static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r2)); } +#define SPEC_in2_r2 0 static void in2_r2_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = regs[get_field(f, r2)]; o->g_in2 = true; } +#define SPEC_in2_r2_o 0 static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o) { @@ -3909,185 +3961,216 @@ static void in2_r2_nz(DisasContext *s, DisasFields *f, DisasOps *o) o->in2 = load_reg(r2); } } +#define SPEC_in2_r2_nz 0 static void in2_r2_8s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext8s_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_8s 0 static void in2_r2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext8u_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_8u 0 static void in2_r2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext16s_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_16s 0 static void in2_r2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext16u_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_16u 0 static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r3)); } +#define SPEC_in2_r3 0 static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext32s_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_32s 0 static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); tcg_gen_ext32u_i64(o->in2, regs[get_field(f, r2)]); } +#define SPEC_in2_r2_32u 0 static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_freg32_i64(get_field(f, r2)); } +#define SPEC_in2_e2 0 static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = fregs[get_field(f, r2)]; o->g_in2 = true; } +#define SPEC_in2_f2_o 0 static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) { - /* ??? Specification exception: r1 must be < 14. */ int r2 = get_field(f, r2); o->in1 = fregs[r2]; - o->in2 = fregs[(r2 + 2) & 15]; + o->in2 = fregs[r2 + 2]; o->g_in1 = o->g_in2 = true; } +#define SPEC_in2_x2_o SPEC_r2_f128 static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = get_address(s, 0, get_field(f, r2), 0); } +#define SPEC_in2_ra2 0 static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; o->in2 = get_address(s, x2, get_field(f, b2), get_field(f, d2)); } +#define SPEC_in2_a2 0 static void in2_ri2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64(s->pc + (int64_t)get_field(f, i2) * 2); } +#define SPEC_in2_ri2 0 static void in2_sh32(DisasContext *s, DisasFields *f, DisasOps *o) { help_l2_shift(s, f, o, 31); } +#define SPEC_in2_sh32 0 static void in2_sh64(DisasContext *s, DisasFields *f, DisasOps *o) { help_l2_shift(s, f, o, 63); } +#define SPEC_in2_sh64 0 static void in2_m2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_8u 0 static void in2_m2_16s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_16s 0 static void in2_m2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_16u 0 static void in2_m2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_32s 0 static void in2_m2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_32u 0 static void in2_m2_64(DisasContext *s, DisasFields *f, DisasOps *o) { in2_a2(s, f, o); tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_m2_64 0 static void in2_mri2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_16u 0 static void in2_mri2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_32s 0 static void in2_mri2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_32u 0 static void in2_mri2_64(DisasContext *s, DisasFields *f, DisasOps *o) { in2_ri2(s, f, o); tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s)); } +#define SPEC_in2_mri2_64 0 static void in2_i2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64(get_field(f, i2)); } +#define SPEC_in2_i2 0 static void in2_i2_8u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint8_t)get_field(f, i2)); } +#define SPEC_in2_i2_8u 0 static void in2_i2_16u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint16_t)get_field(f, i2)); } +#define SPEC_in2_i2_16u 0 static void in2_i2_32u(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_const_i64((uint32_t)get_field(f, i2)); } +#define SPEC_in2_i2_32u 0 static void in2_i2_16u_shl(DisasContext *s, DisasFields *f, DisasOps *o) { uint64_t i2 = (uint16_t)get_field(f, i2); o->in2 = tcg_const_i64(i2 << s->insn->data); } +#define SPEC_in2_i2_16u_shl 0 static void in2_i2_32u_shl(DisasContext *s, DisasFields *f, DisasOps *o) { uint64_t i2 = (uint32_t)get_field(f, i2); o->in2 = tcg_const_i64(i2 << s->insn->data); } +#define SPEC_in2_i2_32u_shl 0 /* ====================================================================== */ @@ -4106,18 +4189,19 @@ enum DisasInsnEnum { }; #undef D -#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \ - .opc = OPC, \ - .fmt = FMT_##FT, \ - .fac = FAC_##FC, \ - .name = #NM, \ - .help_in1 = in1_##I1, \ - .help_in2 = in2_##I2, \ - .help_prep = prep_##P, \ - .help_wout = wout_##W, \ - .help_cout = cout_##CC, \ - .help_op = op_##OP, \ - .data = D \ +#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) { \ + .opc = OPC, \ + .fmt = FMT_##FT, \ + .fac = FAC_##FC, \ + .spec = SPEC_in1_##I1 | SPEC_in2_##I2 | SPEC_prep_##P | SPEC_wout_##W, \ + .name = #NM, \ + .help_in1 = in1_##I1, \ + .help_in2 = in2_##I2, \ + .help_prep = prep_##P, \ + .help_wout = wout_##W, \ + .help_cout = cout_##CC, \ + .help_op = op_##OP, \ + .data = D \ }, /* Allow 0 to be used for NULL in the table below. */ @@ -4128,6 +4212,11 @@ enum DisasInsnEnum { #define cout_0 NULL #define op_0 NULL +#define SPEC_in1_0 0 +#define SPEC_in2_0 0 +#define SPEC_prep_0 0 +#define SPEC_wout_0 0 + static const DisasInsn insn_info[] = { #include "insn-data.def" }; @@ -4295,6 +4384,40 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) return EXIT_NORETURN; } + /* Check for insn specification exceptions. */ + if (insn->spec) { + int spec = insn->spec, excp = 0, r; + + if (spec & SPEC_r1_even) { + r = get_field(&f, r1); + if (r & 1) { + excp = PGM_SPECIFICATION; + } + } + if (spec & SPEC_r2_even) { + r = get_field(&f, r2); + if (r & 1) { + excp = PGM_SPECIFICATION; + } + } + if (spec & SPEC_r1_f128) { + r = get_field(&f, r1); + if (r > 13) { + excp = PGM_SPECIFICATION; + } + } + if (spec & SPEC_r2_f128) { + r = get_field(&f, r2); + if (r > 13) { + excp = PGM_SPECIFICATION; + } + } + if (excp) { + gen_program_exception(s, excp); + return EXIT_NORETURN; + } + } + /* Set up the strutures we use to communicate with the helpers. */ s->insn = insn; s->fields = &f; From 1d1f63013539bccc877899116cccf106d318b04a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 9 Sep 2012 14:31:43 -0700 Subject: [PATCH 0225/1634] target-s390: Implement LCDFR Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 1 + 1 file changed, 1 insertion(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index b023911cec..6e92790c5e 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -356,6 +356,7 @@ C(0xb303, LCEBR, RRE, Z, 0, e2, new, e1, negf32, f32) C(0xb313, LCDBR, RRE, Z, 0, f2_o, f1, 0, negf64, f64) C(0xb343, LCXBR, RRE, Z, 0, x2_o, x1, 0, negf128, f128) + C(0xb373, LCDFR, RRE, FPSSH, 0, f2_o, f1, 0, negf64, 0) /* LOAD HALFWORD */ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0) C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0) From d2d9feac6fa9f6fd40e8f251bcfdd9a9a0f421f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 9 Sep 2012 16:04:17 -0700 Subject: [PATCH 0226/1634] target-s390: Use uint64_to_float128 Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 58c2e6135c..b6e5040ff5 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -419,8 +419,7 @@ uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3) { int hold = swap_round_mode(env, m3); - /* ??? Not 50% correct. */ - float128 ret = int64_to_float128(v2, &env->fpu_status); + float128 ret = uint64_to_float128(v2, &env->fpu_status); set_float_rounding_mode(hold, &env->fpu_status); handle_exceptions(env, GETPC()); return RET128(ret); From a12000b9ece917f62d6405e7ee83c8abb6ad7afa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Sep 2012 16:26:35 -0700 Subject: [PATCH 0227/1634] target-s390: Implement SET ROUNDING MODE Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 5 +++++ target-s390x/translate.c | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 6e92790c5e..79341a4b41 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -566,6 +566,11 @@ C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) +/* SET BFP ROUNDING MODE */ + C(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0) + C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0) +/* SET DFP ROUNDING MODE */ + C(0xb2b9, SRNMT, S, DFP, 0, 0, 0, 0, srnm, 0) /* SHIFT LEFT SINGLE */ D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b4dd68e3f5..c4d9fffa21 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2921,6 +2921,45 @@ static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_srnm(DisasContext *s, DisasOps *o) +{ + int b2 = get_field(s->fields, b2); + int d2 = get_field(s->fields, d2); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + int mask, pos, len; + + switch (s->fields->op2) { + case 0x99: /* SRNM */ + pos = 0, len = 2; + break; + case 0xb8: /* SRNMB */ + pos = 0, len = 3; + break; + case 0xb9: /* SRNMT */ + pos = 4, len = 3; + default: + tcg_abort(); + } + mask = (1 << len) - 1; + + /* Insert the value into the appropriate field of the FPC. */ + if (b2 == 0) { + tcg_gen_movi_i64(t1, d2 & mask); + } else { + tcg_gen_addi_i64(t1, regs[b2], d2); + tcg_gen_andi_i64(t1, t1, mask); + } + tcg_gen_ld32u_i64(t2, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_deposit_i64(t2, t2, t1, pos, len); + tcg_temp_free_i64(t1); + + /* Then install the new FPC to set the rounding mode in fpu_status. */ + gen_helper_sfpc(cpu_env, t2); + tcg_temp_free_i64(t2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_spka(DisasContext *s, DisasOps *o) { From 411edc22cbab9a44f6d6c6cdef8637ba1f313e37 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Sep 2012 17:23:13 -0700 Subject: [PATCH 0228/1634] target-s390: Implement LOAD/SET FP AND SIGNAL Signed-off-by: Richard Henderson --- target-s390x/fpu_helper.c | 37 +++++++++++++++++++++++++++++-------- target-s390x/helper.h | 1 + target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 6 ++++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b6e5040ff5..94375b6a63 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -674,19 +674,40 @@ uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) return RET128(ret); } +static const int fpc_to_rnd[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + /* set fpc */ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) { - static const int rnd[4] = { - float_round_nearest_even, - float_round_to_zero, - float_round_up, - float_round_down - }; - /* Install everything in the main FPC. */ env->fpc = fpc; /* Install the rounding mode in the shadow fpu_status. */ - set_float_rounding_mode(rnd[fpc & 3], &env->fpu_status); + set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status); +} + +/* set fpc and signal */ +void HELPER(sfas)(CPUS390XState *env, uint64_t val) +{ + uint32_t signalling = env->fpc; + uint32_t source = val; + uint32_t s390_exc; + + /* The contents of the source operand are placed in the FPC register; + then the flags in the FPC register are set to the logical OR of the + signalling flags and the source flags. */ + env->fpc = source | (signalling & 0x00ff0000); + set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status); + + /* If any signalling flag is 1 and the corresponding source mask + is also 1, a simulated-iee-exception trap occurs. */ + s390_exc = (signalling >> 16) & (source >> 24); + if (s390_exc) { + ieee_exception(env, s390_exc | 3, GETPC()); + } } diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 23d23d5b3a..b7376339cd 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -87,6 +87,7 @@ DEF_HELPER_4(tr, void, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) #ifndef CONFIG_USER_ONLY diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 79341a4b41..e915984828 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -433,6 +433,8 @@ /* LOAD FPC */ C(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0) +/* LOAD FPC AND SIGNAL */ + C(0xb2bd, LFAS, S, IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0) /* LOAD LENGTHENED */ C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) @@ -566,6 +568,8 @@ C(0xb24e, SAR, RRE, Z, 0, r2_o, 0, 0, sar, 0) /* SET FPC */ C(0xb384, SFPC, RRE, Z, 0, r1_o, 0, 0, sfpc, 0) +/* SET FPC AND SIGNAL */ + C(0xb385, SFASR, RRE, IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0) /* SET BFP ROUNDING MODE */ C(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0) C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c4d9fffa21..34b9cdf127 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2921,6 +2921,12 @@ static ExitStatus op_sfpc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sfas(DisasContext *s, DisasOps *o) +{ + gen_helper_sfas(cpu_env, o->in2); + return NO_EXIT; +} + static ExitStatus op_srnm(DisasContext *s, DisasOps *o) { int b2 = get_field(s->fields, b2); From 90b4f8ad7226960d3a21bd8fca894ce1e6b5e4cf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Sep 2012 16:52:31 -0700 Subject: [PATCH 0229/1634] target-s390: Fix cpu_clone_regs R2 is the syscall return register, not R0. Signed-off-by: Richard Henderson --- target-s390x/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index dc7bbc67f6..bc3fab226b 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -116,7 +116,7 @@ static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) if (newsp) { env->regs[15] = newsp; } - env->regs[0] = 0; + env->regs[2] = 0; } #endif From d074ac6d266129f8f4e2aac5b0e6c39c22964d9a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Sep 2012 13:48:46 -0700 Subject: [PATCH 0230/1634] target-s390: Optimize XC Notice XC with same address and convert that to store of zero. Signed-off-by: Richard Henderson --- target-s390x/insn-data.def | 2 +- target-s390x/translate.c | 50 +++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e915984828..480f1fdf51 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -271,7 +271,7 @@ C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) - C(0xd700, XC, SS_a, Z, la1, a2, 0, 0, xc, 0) + C(0xd700, XC, SS_a, Z, 0, 0, 0, 0, xc, 0) /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 34b9cdf127..7f8a5503d9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3403,10 +3403,54 @@ static ExitStatus op_unpk(DisasContext *s, DisasOps *o) static ExitStatus op_xc(DisasContext *s, DisasOps *o) { - TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + int d1 = get_field(s->fields, d1); + int d2 = get_field(s->fields, d2); + int b1 = get_field(s->fields, b1); + int b2 = get_field(s->fields, b2); + int l = get_field(s->fields, l1); + TCGv_i32 t32; + + o->addr1 = get_address(s, 0, b1, d1); + + /* If the addresses are identical, this is a store/memset of zero. */ + if (b1 == b2 && d1 == d2 && (l + 1) <= 32) { + o->in2 = tcg_const_i64(0); + + l++; + while (l >= 8) { + tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s)); + l -= 8; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 8); + } + } + if (l >= 4) { + tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s)); + l -= 4; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 4); + } + } + if (l >= 2) { + tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s)); + l -= 2; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 2); + } + } + if (l) { + tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s)); + } + gen_op_movi_cc(s, 0); + return NO_EXIT; + } + + /* But in general we'll defer to a helper. */ + o->in2 = get_address(s, 0, b2, d2); + t32 = tcg_const_i32(l); potential_page_fault(s); - gen_helper_xc(cc_op, cpu_env, l, o->addr1, o->in2); - tcg_temp_free_i32(l); + gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2); + tcg_temp_free_i32(t32); set_cc_static(s); return NO_EXIT; } From f24c49c24a4979fe50eff7afe18f371f5809177d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 19 Sep 2012 13:50:07 -0700 Subject: [PATCH 0231/1634] target-s390: Optmize emitting discards While they aren't expensive, they aren't free to process. When we know that the three cc helper variables are dead, don't kill them. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 7f8a5503d9..cfe3766e81 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -367,25 +367,41 @@ static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) return tmp; } +static inline bool live_cc_data(DisasContext *s) +{ + return (s->cc_op != CC_OP_DYNAMIC + && s->cc_op != CC_OP_STATIC + && s->cc_op > 3); +} + static inline void gen_op_movi_cc(DisasContext *s, uint32_t val) { + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_dst); + tcg_gen_discard_i64(cc_vr); + } s->cc_op = CC_OP_CONST0 + val; } static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst) { - tcg_gen_discard_i64(cc_src); + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_vr); + } tcg_gen_mov_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); s->cc_op = op; } static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src, TCGv_i64 dst) { + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_vr); + } tcg_gen_mov_i64(cc_src, src); tcg_gen_mov_i64(cc_dst, dst); - tcg_gen_discard_i64(cc_vr); s->cc_op = op; } @@ -421,9 +437,11 @@ static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl) /* CC value is in env->cc_op */ static void set_cc_static(DisasContext *s) { - tcg_gen_discard_i64(cc_src); - tcg_gen_discard_i64(cc_dst); - tcg_gen_discard_i64(cc_vr); + if (live_cc_data(s)) { + tcg_gen_discard_i64(cc_src); + tcg_gen_discard_i64(cc_dst); + tcg_gen_discard_i64(cc_vr); + } s->cc_op = CC_OP_STATIC; } From de379661d5c7cc1d219000d0741f5d96ced56553 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 07:55:51 -0700 Subject: [PATCH 0232/1634] target-s390: Tidy comparisons After full conversion, we can audit the uses of LTGT cc ops and see that none of the instructions can ever set CC=3. Thus we can extend the table to treat that bit as ignored. This fixes a regression wrt the pre-conversion translation in which NE was used for both m=6 and m=7. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index cfe3766e81..2949bb1fc4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -577,30 +577,29 @@ static void account_inline_branch(DisasContext *s, int cc_op) } /* Table of mask values to comparison codes, given a comparison as input. - For a true comparison CC=3 will never be set, but we treat this - conservatively for possible use when CC=3 indicates overflow. */ + For such, CC=3 should not be possible. */ static const TCGCond ltgt_cond[16] = { TCG_COND_NEVER, TCG_COND_NEVER, /* | | | x */ - TCG_COND_GT, TCG_COND_NEVER, /* | | GT | x */ - TCG_COND_LT, TCG_COND_NEVER, /* | LT | | x */ - TCG_COND_NE, TCG_COND_NEVER, /* | LT | GT | x */ - TCG_COND_EQ, TCG_COND_NEVER, /* EQ | | | x */ - TCG_COND_GE, TCG_COND_NEVER, /* EQ | | GT | x */ - TCG_COND_LE, TCG_COND_NEVER, /* EQ | LT | | x */ + TCG_COND_GT, TCG_COND_GT, /* | | GT | x */ + TCG_COND_LT, TCG_COND_LT, /* | LT | | x */ + TCG_COND_NE, TCG_COND_NE, /* | LT | GT | x */ + TCG_COND_EQ, TCG_COND_EQ, /* EQ | | | x */ + TCG_COND_GE, TCG_COND_GE, /* EQ | | GT | x */ + TCG_COND_LE, TCG_COND_LE, /* EQ | LT | | x */ TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | LT | GT | x */ }; /* Table of mask values to comparison codes, given a logic op as input. For such, only CC=0 and CC=1 should be possible. */ static const TCGCond nz_cond[16] = { - /* | | x | x */ - TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, TCG_COND_NEVER, - /* | NE | x | x */ - TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, TCG_COND_NE, - /* EQ | | x | x */ - TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, TCG_COND_EQ, - /* EQ | NE | x | x */ - TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, TCG_COND_ALWAYS, + TCG_COND_NEVER, TCG_COND_NEVER, /* | | x | x */ + TCG_COND_NEVER, TCG_COND_NEVER, + TCG_COND_NE, TCG_COND_NE, /* | NE | x | x */ + TCG_COND_NE, TCG_COND_NE, + TCG_COND_EQ, TCG_COND_EQ, /* EQ | | x | x */ + TCG_COND_EQ, TCG_COND_EQ, + TCG_COND_ALWAYS, TCG_COND_ALWAYS, /* EQ | NE | x | x */ + TCG_COND_ALWAYS, TCG_COND_ALWAYS, }; /* Interpret MASK in terms of S->CC_OP, and fill in C with all the @@ -1463,9 +1462,7 @@ static ExitStatus op_cj(DisasContext *s, DisasOps *o) bool is_imm; DisasCompare c; - /* Bit 3 of the m3 field is reserved and should be zero. - Choose to ignore it wrt the ltgt_cond table above. */ - c.cond = ltgt_cond[m3 & 14]; + c.cond = ltgt_cond[m3]; if (s->insn->data) { c.cond = tcg_unsigned_cond(c.cond); } @@ -1831,9 +1828,7 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o) TCGv_i32 t; TCGCond c; - /* Bit 3 of the m3 field is reserved and should be zero. - Choose to ignore it wrt the ltgt_cond table above. */ - c = tcg_invert_cond(ltgt_cond[m3 & 14]); + c = tcg_invert_cond(ltgt_cond[m3]); if (s->insn->data) { c = tcg_unsigned_cond(c); } From a359b770c60bf3085c244bc9d5a5fd8fcf286bce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 09:41:33 -0700 Subject: [PATCH 0233/1634] target-s390: Optimize ADDU/SUBU CC testing We can easily generate some masks for logical add/subtract inline. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 2949bb1fc4..04001e34d4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -692,6 +692,49 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) account_inline_branch(s, old_cc_op); break; + case CC_OP_ADDU_32: + case CC_OP_ADDU_64: + switch (mask) { + case 8 | 2: /* vr == 0 */ + cond = TCG_COND_EQ; + break; + case 4 | 1: /* vr != 0 */ + cond = TCG_COND_NE; + break; + case 8 | 4: /* no carry -> vr >= src */ + cond = TCG_COND_GEU; + break; + case 2 | 1: /* carry -> vr < src */ + cond = TCG_COND_LTU; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + + case CC_OP_SUBU_32: + case CC_OP_SUBU_64: + /* Note that CC=0 is impossible; treat it as dont-care. */ + switch (mask & 7) { + case 2: /* zero -> op1 == op2 */ + cond = TCG_COND_EQ; + break; + case 4 | 1: /* !zero -> op1 != op2 */ + cond = TCG_COND_NE; + break; + case 4: /* borrow (!carry) -> op1 < op2 */ + cond = TCG_COND_LTU; + break; + case 2 | 1: /* !borrow (carry) -> op1 >= op2 */ + cond = TCG_COND_GEU; + break; + default: + goto do_dynamic; + } + account_inline_branch(s, old_cc_op); + break; + default: do_dynamic: /* Calculate cc value. */ @@ -719,6 +762,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) break; case CC_OP_LTGT_32: case CC_OP_LTUGTU_32: + case CC_OP_SUBU_32: c->is_64 = false; c->u.s32.a = tcg_temp_new_i32(); tcg_gen_trunc_i64_i32(c->u.s32.a, cc_src); @@ -735,6 +779,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) break; case CC_OP_LTGT_64: case CC_OP_LTUGTU_64: + case CC_OP_SUBU_64: c->u.s64.a = cc_src; c->u.s64.b = cc_dst; c->g1 = c->g2 = true; @@ -748,6 +793,29 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask) tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst); break; + case CC_OP_ADDU_32: + c->is_64 = false; + c->u.s32.a = tcg_temp_new_i32(); + c->u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c->u.s32.a, cc_vr); + if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { + tcg_gen_movi_i32(c->u.s32.b, 0); + } else { + tcg_gen_trunc_i64_i32(c->u.s32.b, cc_src); + } + break; + + case CC_OP_ADDU_64: + c->u.s64.a = cc_vr; + c->g1 = true; + if (cond == TCG_COND_EQ || cond == TCG_COND_NE) { + c->u.s64.b = tcg_const_i64(0); + } else { + c->u.s64.b = cc_src; + c->g2 = true; + } + break; + case CC_OP_STATIC: c->is_64 = false; c->u.s32.a = cc_op; From c95ec459c6c39b7a7e1850f82abd95eca4ccfcce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 09:51:40 -0700 Subject: [PATCH 0234/1634] target-s390: Optimize ADDC/SUBB Giving the proper mask to disas_jcc allows us to generate an inline comparison generating the carry/borrow with setcond. In the very worst case, when we must use the external helper to compute a value for CC, we generate (cc > 1) instead of (cc >> 1), which is only very slightly slower on common cpus. In the very best case, when the CC comes from a COMPARE insn and the compiler is using ALCG with zero, everything folds out to become just the setcond that the compiler wanted. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 56 ++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 04001e34d4..8d293d3be5 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1344,18 +1344,28 @@ static ExitStatus op_add(DisasContext *s, DisasOps *o) static ExitStatus op_addc(DisasContext *s, DisasOps *o) { - TCGv_i64 cc; + DisasCompare cmp; + TCGv_i64 carry; tcg_gen_add_i64(o->out, o->in1, o->in2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - cc = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(cc, cc_op); - tcg_gen_shri_i64(cc, cc, 1); + /* The carry flag is the msb of CC, therefore the branch mask that would + create that comparison is 3. Feeding the generated comparison to + setcond produces the carry flag that we desire. */ + disas_jcc(s, &cmp, 3); + carry = tcg_temp_new_i64(); + if (cmp.is_64) { + tcg_gen_setcond_i64(cmp.cond, carry, cmp.u.s64.a, cmp.u.s64.b); + } else { + TCGv_i32 t = tcg_temp_new_i32(); + tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); + tcg_gen_extu_i32_i64(carry, t); + tcg_temp_free_i32(t); + } + free_compare(&cmp); - tcg_gen_add_i64(o->out, o->out, cc); - tcg_temp_free_i64(cc); + tcg_gen_add_i64(o->out, o->out, carry); + tcg_temp_free_i64(carry); return NO_EXIT; } @@ -3397,19 +3407,27 @@ static ExitStatus op_sub(DisasContext *s, DisasOps *o) static ExitStatus op_subb(DisasContext *s, DisasOps *o) { - TCGv_i64 cc; + DisasCompare cmp; + TCGv_i64 borrow; - assert(!o->g_in2); - tcg_gen_not_i64(o->in2, o->in2); - tcg_gen_add_i64(o->out, o->in1, o->in2); + tcg_gen_sub_i64(o->out, o->in1, o->in2); - /* XXX possible optimization point */ - gen_op_calc_cc(s); - cc = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(cc, cc_op); - tcg_gen_shri_i64(cc, cc, 1); - tcg_gen_add_i64(o->out, o->out, cc); - tcg_temp_free_i64(cc); + /* The !borrow flag is the msb of CC. Since we want the inverse of + that, we ask for a comparison of CC=0 | CC=1 -> mask of 8 | 4. */ + disas_jcc(s, &cmp, 8 | 4); + borrow = tcg_temp_new_i64(); + if (cmp.is_64) { + tcg_gen_setcond_i64(cmp.cond, borrow, cmp.u.s64.a, cmp.u.s64.b); + } else { + TCGv_i32 t = tcg_temp_new_i32(); + tcg_gen_setcond_i32(cmp.cond, t, cmp.u.s32.a, cmp.u.s32.b); + tcg_gen_extu_i32_i64(borrow, t); + tcg_temp_free_i32(t); + } + free_compare(&cmp); + + tcg_gen_sub_i64(o->out, o->out, borrow); + tcg_temp_free_i64(borrow); return NO_EXIT; } From bacf43c62e54ee21494c4bf0c39d96d2bcc0e260 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Sep 2012 06:57:09 -0700 Subject: [PATCH 0235/1634] target-s390: Optimize get_address Don't load the displacement into a register first, add it second so that tcg_gen_addi_i64 can eliminate zeros. Don't mask the displacement first so that we don't turn small negative numbers into large positive numbers. Signed-off-by: Richard Henderson --- target-s390x/translate.c | 44 ++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 8d293d3be5..0ad78d2eb4 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -331,37 +331,29 @@ static inline void check_privileged(DisasContext *s) static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2) { - TCGv_i64 tmp; + TCGv_i64 tmp = tcg_temp_new_i64(); + bool need_31 = !(s->tb->flags & FLAG_MASK_64); - /* 31-bitify the immediate part; register contents are dealt with below */ - if (!(s->tb->flags & FLAG_MASK_64)) { - d2 &= 0x7fffffffUL; - } + /* Note that d2 is limited to 20 bits, signed. If we crop negative + displacements early we create larger immedate addends. */ - if (x2) { - if (d2) { - tmp = tcg_const_i64(d2); - tcg_gen_add_i64(tmp, tmp, regs[x2]); - } else { - tmp = load_reg(x2); - } - if (b2) { - tcg_gen_add_i64(tmp, tmp, regs[b2]); - } + /* Note that addi optimizes the imm==0 case. */ + if (b2 && x2) { + tcg_gen_add_i64(tmp, regs[b2], regs[x2]); + tcg_gen_addi_i64(tmp, tmp, d2); } else if (b2) { - if (d2) { - tmp = tcg_const_i64(d2); - tcg_gen_add_i64(tmp, tmp, regs[b2]); - } else { - tmp = load_reg(b2); - } + tcg_gen_addi_i64(tmp, regs[b2], d2); + } else if (x2) { + tcg_gen_addi_i64(tmp, regs[x2], d2); } else { - tmp = tcg_const_i64(d2); + if (need_31) { + d2 &= 0x7fffffff; + need_31 = false; + } + tcg_gen_movi_i64(tmp, d2); } - - /* 31-bit mode mask if there are values loaded from registers */ - if (!(s->tb->flags & FLAG_MASK_64) && (x2 || b2)) { - tcg_gen_andi_i64(tmp, tmp, 0x7fffffffUL); + if (need_31) { + tcg_gen_andi_i64(tmp, tmp, 0x7fffffff); } return tmp; From b7886de3f36111b71ee0664a0b992f6c5b55de7d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Sep 2012 17:09:35 -0700 Subject: [PATCH 0236/1634] target-s390: Perform COMPARE AND SWAP inline Still no proper solution for CONFIG_USER_ONLY, but the system version is significantly better. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 3 - target-s390x/insn-data.def | 12 +-- target-s390x/mem_helper.c | 53 ------------- target-s390x/translate.c | 152 ++++++++++++++++++++++++++++--------- 4 files changed, 124 insertions(+), 96 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index b7376339cd..a5844b3ee0 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -17,9 +17,6 @@ DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) DEF_HELPER_4(mvst, i64, env, i64, i64, i64) -DEF_HELPER_4(csg, i64, env, i64, i64, i64) -DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) -DEF_HELPER_4(cs, i64, env, i64, i64, i64) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 480f1fdf51..b42ebb6a1a 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -193,13 +193,13 @@ D(0xec7d, CLGIJ, RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1) /* COMPARE AND SWAP */ - C(0xba00, CS, RS_a, Z, r1_o, a2, new, r1_32, cs, 0) - C(0xeb14, CSY, RSY_a, LD, r1_o, a2, new, r1_32, cs, 0) - C(0xeb30, CSG, RSY_a, Z, r1_o, a2, r1, 0, csg, 0) + D(0xba00, CS, RS_a, Z, r3_32u, r1_32u, new, r1_32, cs, 0, 0) + D(0xeb14, CSY, RSY_a, LD, r3_32u, r1_32u, new, r1_32, cs, 0, 0) + D(0xeb30, CSG, RSY_a, Z, r3_o, r1_o, new, r1, cs, 0, 1) /* COMPARE DOUBLE AND SWAP */ - C(0xbb00, CDS, RS_a, Z, r1_D32, a2, new, r1_D32, cds, 0) - C(0xeb31, CDSY, RSY_a, LD, r1_D32, a2, new, r1_D32, cds, 0) - C(0xeb3e, CDSG, RSY_a, Z, 0, a2, 0, 0, cdsg, 0) + D(0xbb00, CDS, RS_a, Z, r3_D32, r1_D32, new, r1_D32, cs, 0, 1) + D(0xeb31, CDSY, RSY_a, LD, r3_D32, r1_D32, new, r1_D32, cs, 0, 1) + C(0xeb3e, CDSG, RSY_a, Z, 0, 0, 0, 0, cdsg, 0) /* COMPARE AND TRAP */ D(0xb972, CRT, RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 0e9bbd4035..372334b3c8 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -442,59 +442,6 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) return d + len; } -/* compare and swap 64-bit */ -uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) -{ - /* FIXME: locking? */ - uint64_t v2 = cpu_ldq_data(env, a2); - if (r1 == v2) { - cpu_stq_data(env, a2, r3); - env->cc_op = 0; - return r1; - } else { - env->cc_op = 1; - return v2; - } -} - -/* compare double and swap 64-bit */ -uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2_hi = cpu_ldq_data(env, a2); - uint64_t v2_lo = cpu_ldq_data(env, a2 + 8); - uint64_t v1_hi = env->regs[r1]; - uint64_t v1_lo = env->regs[r1 + 1]; - - if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { - cc = 0; - cpu_stq_data(env, a2, env->regs[r3]); - cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]); - } else { - cc = 1; - env->regs[r1] = v2_hi; - env->regs[r1 + 1] = v2_lo; - } - - return cc; -} - -/* compare and swap 32-bit */ -uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3) -{ - /* FIXME: locking? */ - uint32_t v2 = cpu_ldl_data(env, a2); - if ((uint32_t)r1 == v2) { - cpu_stl_data(env, a2, (uint32_t)r3); - env->cc_op = 0; - return r1; - } else { - env->cc_op = 1; - return v2; - } -} - static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, uint32_t mask) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0ad78d2eb4..a57296c64f 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1078,8 +1078,9 @@ typedef struct { #define SPEC_r1_even 1 #define SPEC_r2_even 2 -#define SPEC_r1_f128 4 -#define SPEC_r2_f128 8 +#define SPEC_r3_even 4 +#define SPEC_r1_f128 8 +#define SPEC_r2_f128 16 /* Return values from translate_one, indicating the state of the TB. */ typedef enum { @@ -1124,9 +1125,9 @@ typedef enum DisasFacility { struct DisasInsn { unsigned opc:16; - DisasFormat fmt:6; - DisasFacility fac:6; - unsigned spec:4; + DisasFormat fmt:8; + DisasFacility fac:8; + unsigned spec:8; const char *name; @@ -1828,18 +1829,102 @@ static ExitStatus op_cps(DisasContext *s, DisasOps *o) static ExitStatus op_cs(DisasContext *s, DisasOps *o) { - int r3 = get_field(s->fields, r3); - potential_page_fault(s); - gen_helper_cs(o->out, cpu_env, o->in1, o->in2, regs[r3]); + /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */ + int d2 = get_field(s->fields, d2); + int b2 = get_field(s->fields, b2); + int is_64 = s->insn->data; + TCGv_i64 addr, mem, cc, z; + + /* Note that in1 = R3 (new value) and + in2 = (zero-extended) R1 (expected value). */ + + /* Load the memory into the (temporary) output. While the PoO only talks + about moving the memory to R1 on inequality, if we include equality it + means that R1 is equal to the memory in all conditions. */ + addr = get_address(s, 0, b2, d2); + if (is_64) { + tcg_gen_qemu_ld64(o->out, addr, get_mem_index(s)); + } else { + tcg_gen_qemu_ld32u(o->out, addr, get_mem_index(s)); + } + + /* Are the memory and expected values (un)equal? Note that this setcond + produces the output CC value, thus the NE sense of the test. */ + cc = tcg_temp_new_i64(); + tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in2, o->out); + + /* If the memory and expected values are equal (CC==0), copy R3 to MEM. + Recall that we are allowed to unconditionally issue the store (and + thus any possible write trap), so (re-)store the original contents + of MEM in case of inequality. */ + z = tcg_const_i64(0); + mem = tcg_temp_new_i64(); + tcg_gen_movcond_i64(TCG_COND_EQ, mem, cc, z, o->in1, o->out); + if (is_64) { + tcg_gen_qemu_st64(mem, addr, get_mem_index(s)); + } else { + tcg_gen_qemu_st32(mem, addr, get_mem_index(s)); + } + tcg_temp_free_i64(z); + tcg_temp_free_i64(mem); + tcg_temp_free_i64(addr); + + /* Store CC back to cc_op. Wait until after the store so that any + exception gets the old cc_op value. */ + tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_temp_free_i64(cc); set_cc_static(s); return NO_EXIT; } -static ExitStatus op_csg(DisasContext *s, DisasOps *o) +static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) { + /* FIXME: needs an atomic solution for CONFIG_USER_ONLY. */ + int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - potential_page_fault(s); - gen_helper_csg(o->out, cpu_env, o->in1, o->in2, regs[r3]); + int d2 = get_field(s->fields, d2); + int b2 = get_field(s->fields, b2); + TCGv_i64 addrh, addrl, memh, meml, outh, outl, cc, z; + + /* Note that R1:R1+1 = expected value and R3:R3+1 = new value. */ + + addrh = get_address(s, 0, b2, d2); + addrl = get_address(s, 0, b2, d2 + 8); + outh = tcg_temp_new_i64(); + outl = tcg_temp_new_i64(); + + tcg_gen_qemu_ld64(outh, addrh, get_mem_index(s)); + tcg_gen_qemu_ld64(outl, addrl, get_mem_index(s)); + + /* Fold the double-word compare with arithmetic. */ + cc = tcg_temp_new_i64(); + z = tcg_temp_new_i64(); + tcg_gen_xor_i64(cc, outh, regs[r1]); + tcg_gen_xor_i64(z, outl, regs[r1 + 1]); + tcg_gen_or_i64(cc, cc, z); + tcg_gen_movi_i64(z, 0); + tcg_gen_setcond_i64(TCG_COND_NE, cc, cc, z); + + memh = tcg_temp_new_i64(); + meml = tcg_temp_new_i64(); + tcg_gen_movcond_i64(TCG_COND_EQ, memh, cc, z, regs[r3], outh); + tcg_gen_movcond_i64(TCG_COND_EQ, meml, cc, z, regs[r3 + 1], outl); + tcg_temp_free_i64(z); + + tcg_gen_qemu_st64(memh, addrh, get_mem_index(s)); + tcg_gen_qemu_st64(meml, addrl, get_mem_index(s)); + tcg_temp_free_i64(memh); + tcg_temp_free_i64(meml); + tcg_temp_free_i64(addrh); + tcg_temp_free_i64(addrl); + + /* Save back state now that we've passed all exceptions. */ + tcg_gen_mov_i64(regs[r1], outh); + tcg_gen_mov_i64(regs[r1 + 1], outl); + tcg_gen_trunc_i64_i32(cc_op, cc); + tcg_temp_free_i64(outh); + tcg_temp_free_i64(outl); + tcg_temp_free_i64(cc); set_cc_static(s); return NO_EXIT; } @@ -1856,29 +1941,6 @@ static ExitStatus op_csp(DisasContext *s, DisasOps *o) } #endif -static ExitStatus op_cds(DisasContext *s, DisasOps *o) -{ - int r3 = get_field(s->fields, r3); - TCGv_i64 in3 = tcg_temp_new_i64(); - tcg_gen_deposit_i64(in3, regs[r3 + 1], regs[r3], 32, 32); - potential_page_fault(s); - gen_helper_csg(o->out, cpu_env, o->in1, o->in2, in3); - tcg_temp_free_i64(in3); - set_cc_static(s); - return NO_EXIT; -} - -static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) -{ - TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); - TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - potential_page_fault(s); - /* XXX rewrite in tcg */ - gen_helper_cdsg(cc_op, cpu_env, r1, o->in2, r3); - set_cc_static(s); - return NO_EXIT; -} - static ExitStatus op_cvd(DisasContext *s, DisasOps *o) { TCGv_i64 t1 = tcg_temp_new_i64(); @@ -4007,6 +4069,14 @@ static void in1_r3_32u(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in1_r3_32u 0 +static void in1_r3_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r3 = get_field(f, r3); + o->in1 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in1, regs[r3 + 1], regs[r3]); +} +#define SPEC_in1_r3_D32 SPEC_r3_even + static void in1_e1(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_freg32_i64(get_field(f, r1)); @@ -4121,6 +4191,14 @@ static void in2_r1_32u(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in2_r1_32u 0 +static void in2_r1_D32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + int r1 = get_field(f, r1); + o->in2 = tcg_temp_new_i64(); + tcg_gen_concat32_i64(o->in2, regs[r1 + 1], regs[r1]); +} +#define SPEC_in2_r1_D32 SPEC_r1_even + static void in2_r2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_reg(get_field(f, r2)); @@ -4580,6 +4658,12 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) excp = PGM_SPECIFICATION; } } + if (spec & SPEC_r3_even) { + r = get_field(&f, r3); + if (r & 1) { + excp = PGM_SPECIFICATION; + } + } if (spec & SPEC_r1_f128) { r = get_field(&f, r1); if (r > 13) { From d918a65c690c321f56e7ce4b5a9e1f2fbe32bb1b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:20:43 -0800 Subject: [PATCH 0237/1634] target-s390: Use TCG_CALL_NO_WG for memory helpers Those that do not read or write tcg registers, but can raise exceptions via memory faults. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index a5844b3ee0..e9664fa304 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,13 +1,13 @@ #include "exec/def-helper.h" DEF_HELPER_2(exception, void, env, i32) -DEF_HELPER_4(nc, i32, env, i32, i64, i64) -DEF_HELPER_4(oc, i32, env, i32, i64, i64) -DEF_HELPER_4(xc, i32, env, i32, i64, i64) -DEF_HELPER_4(mvc, void, env, i32, i64, i64) -DEF_HELPER_4(clc, i32, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) -DEF_HELPER_4(clm, i32, env, i32, i32, i64) +DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_3(divs32, s64, env, s64, s64) DEF_HELPER_3(divu32, i64, env, i64, i64) @@ -22,8 +22,8 @@ DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) -DEF_HELPER_4(stam, void, env, i32, i64, i32) -DEF_HELPER_4(lam, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32) @@ -79,8 +79,8 @@ DEF_HELPER_2(sqeb, i64, env, i64) DEF_HELPER_2(sqdb, i64, env, i64) DEF_HELPER_3(sqxb, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) -DEF_HELPER_4(unpk, void, env, i32, i64, i64) -DEF_HELPER_4(tr, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) @@ -98,10 +98,10 @@ DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_4(stsi, i32, env, i64, i64, i64) -DEF_HELPER_4(lctl, void, env, i32, i64, i32) -DEF_HELPER_4(lctlg, void, env, i32, i64, i32) -DEF_HELPER_4(stctl, void, env, i32, i64, i32) -DEF_HELPER_4(stctg, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) @@ -114,7 +114,7 @@ DEF_HELPER_2(sacf, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) -DEF_HELPER_3(stura, void, env, i64, i64) +DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64) #endif #include "exec/def-helper.h" From c482ea94eaf26761e5cc0e53259cf1a98db29622 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:21:54 -0800 Subject: [PATCH 0238/1634] target-s390: Use TCG_CALL_NO_WG for floating-point helpers None of them read or write tcg registers, but most can raise fp exceptions. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index e9664fa304..77f8f7d76b 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -32,52 +32,52 @@ DEF_HELPER_3(cxgb, i64, env, s64, i32) DEF_HELPER_3(celgb, i64, env, i64, i32) DEF_HELPER_3(cdlgb, i64, env, i64, i32) DEF_HELPER_3(cxlgb, i64, env, i64, i32) -DEF_HELPER_3(aeb, i64, env, i64, i64) -DEF_HELPER_3(adb, i64, env, i64, i64) -DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(seb, i64, env, i64, i64) -DEF_HELPER_3(sdb, i64, env, i64, i64) -DEF_HELPER_5(sxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(deb, i64, env, i64, i64) -DEF_HELPER_3(ddb, i64, env, i64, i64) -DEF_HELPER_5(dxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_3(meeb, i64, env, i64, i64) -DEF_HELPER_3(mdeb, i64, env, i64, i64) -DEF_HELPER_3(mdb, i64, env, i64, i64) -DEF_HELPER_5(mxb, i64, env, i64, i64, i64, i64) -DEF_HELPER_4(mxdb, i64, env, i64, i64, i64) -DEF_HELPER_2(ldeb, i64, env, i64) -DEF_HELPER_3(ldxb, i64, env, i64, i64) -DEF_HELPER_2(lxdb, i64, env, i64) -DEF_HELPER_2(lxeb, i64, env, i64) -DEF_HELPER_2(ledb, i64, env, i64) -DEF_HELPER_3(lexb, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(aeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(adb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(axb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(seb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(sdb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(sxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(deb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(ddb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(dxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(meeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mdeb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_2(ldeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(ledb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(lexb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) -DEF_HELPER_3(cgeb, i64, env, i64, i32) -DEF_HELPER_3(cgdb, i64, env, i64, i32) -DEF_HELPER_4(cgxb, i64, env, i64, i64, i32) -DEF_HELPER_3(cfeb, i64, env, i64, i32) -DEF_HELPER_3(cfdb, i64, env, i64, i32) -DEF_HELPER_4(cfxb, i64, env, i64, i64, i32) -DEF_HELPER_3(clgeb, i64, env, i64, i32) -DEF_HELPER_3(clgdb, i64, env, i64, i32) -DEF_HELPER_4(clgxb, i64, env, i64, i64, i32) -DEF_HELPER_3(clfeb, i64, env, i64, i32) -DEF_HELPER_3(clfdb, i64, env, i64, i32) -DEF_HELPER_4(clfxb, i64, env, i64, i64, i32) -DEF_HELPER_4(maeb, i64, env, i64, i64, i64) -DEF_HELPER_4(madb, i64, env, i64, i64, i64) -DEF_HELPER_4(mseb, i64, env, i64, i64, i64) -DEF_HELPER_4(msdb, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(cfeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(cfdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(cfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(clgeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(clgdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(msdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_2(tceb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_NO_RWG_SE, i32, i64, i64) DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_NO_RWG_SE, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_2(sqeb, i64, env, i64) -DEF_HELPER_2(sqdb, i64, env, i64) -DEF_HELPER_3(sqxb, i64, env, i64, i64) +DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) From c20fec4055f06de6d96789d1a290f284fac48fc4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:25:57 -0800 Subject: [PATCH 0239/1634] target-s390: Use TCG_CALL_NO_WG for integer helpers The division routines do not read or write tcg registers, but can raise fixed-point divide exceptions. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 77f8f7d76b..f5dabb701e 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -9,10 +9,10 @@ DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) -DEF_HELPER_3(divs32, s64, env, s64, s64) -DEF_HELPER_3(divu32, i64, env, i64, i64) -DEF_HELPER_3(divs64, s64, env, s64, s64) -DEF_HELPER_4(divu64, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64) +DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) +DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) From 893e1660d5b9be0900bb1f09e574b1856eb30783 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:31:29 -0800 Subject: [PATCH 0240/1634] target-s390: Use TCG_CALL_NO_WG for misc helpers Signed-off-by: Richard Henderson --- target-s390x/helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index f5dabb701e..dea7071d84 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -110,7 +110,7 @@ DEF_HELPER_3(csp, i32, env, i32, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) -DEF_HELPER_2(sacf, void, env, i64) +DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) From 26cc0a3fd11d537bdd2649b5f3c385ad858b1857 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 15 Nov 2012 10:32:25 -0800 Subject: [PATCH 0241/1634] target-s390: Use noreturn for exception and load_psw Both always exit the cpu loop. Signed-off-by: Richard Henderson --- target-s390x/helper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index dea7071d84..dd90d93bee 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,6 +1,6 @@ #include "exec/def-helper.h" -DEF_HELPER_2(exception, void, env, i32) +DEF_HELPER_2(exception, noreturn, env, i32) DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) @@ -90,7 +90,7 @@ DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) DEF_HELPER_4(diag, i64, env, i32, i64, i64) -DEF_HELPER_3(load_psw, void, env, i64, i64) +DEF_HELPER_3(load_psw, noreturn, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) From 2b35e93fbfc52c2be6cf85e5a54a3707cdabd914 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 5 Dec 2012 09:23:25 -0600 Subject: [PATCH 0242/1634] target-s390: Claim maintainership Signed-off-by: Richard Henderson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index cf39e5a00a..4b7553efea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -98,6 +98,7 @@ S: Maintained F: target-ppc/ S390 +M: Richard Henderson M: Alexander Graf S: Maintained F: target-s390x/ From 1d728c394652d40a9065668606d62f28bc544949 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Tue, 1 May 2012 18:45:39 +0000 Subject: [PATCH 0243/1634] tests: add gcov support Add support for compiling for GCOV test coverage, enabled with '--enable-gcov' during configure. Test coverage will be reported after each test. Signed-off-by: Blue Swirl --- Makefile.objs | 2 ++ configure | 20 +++++++++++++++++++- tests/Makefile | 43 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/Makefile.objs b/Makefile.objs index 3a3a4028c5..a3eab4b410 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -31,6 +31,8 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o # coroutines coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o coroutine-obj-y += qemu-coroutine-sleep.o + +# If you change this logic, please also check tests/Makefile ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o else diff --git a/configure b/configure index 837a84aff0..fe18ed2b25 100755 --- a/configure +++ b/configure @@ -176,6 +176,8 @@ strip_opt="yes" tcg_interpreter="no" bigendian="no" mingw32="no" +gcov="no" +gcov_tool="gcov" EXESUF="" prefix="/usr/local" mandir="\${prefix}/share/man" @@ -600,6 +602,8 @@ for opt do ;; --python=*) python="$optarg" ;; + --gcov=*) gcov_tool="$optarg" + ;; --smbd=*) smbd="$optarg" ;; --extra-cflags=*) @@ -620,6 +624,8 @@ for opt do ;; --enable-gprof) gprof="yes" ;; + --enable-gcov) gcov="yes" + ;; --static) static="yes" LDFLAGS="-static $LDFLAGS" @@ -1134,6 +1140,8 @@ echo " --with-coroutine=BACKEND coroutine backend. Supported options:" echo " gthread, ucontext, sigaltstack, windows" echo " --enable-glusterfs enable GlusterFS backend" echo " --disable-glusterfs disable GlusterFS backend" +echo " --enable-gcov enable test coverage analysis with gcov" +echo " --gcov=GCOV use specified gcov [$gcov_tool]" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -3120,10 +3128,14 @@ fi # End of CC checks # After here, no more $cc or $ld runs -if test "$debug" = "no" ; then +if test "$gcov" = "yes" ; then + CFLAGS="-fprofile-arcs -ftest-coverage -g $CFLAGS" + LDFLAGS="-fprofile-arcs -ftest-coverage $LDFLAGS" +elif test "$debug" = "no" ; then CFLAGS="-O2 -D_FORTIFY_SOURCE=2 $CFLAGS" fi + # Disable zero malloc errors for official releases unless explicitly told to # enable/disable if test -z "$zero_malloc" ; then @@ -3305,6 +3317,8 @@ echo "seccomp support $seccomp" echo "coroutine backend $coroutine_backend" echo "GlusterFS support $glusterfs" echo "virtio-blk-data-plane $virtio_blk_data_plane" +echo "gcov $gcov_tool" +echo "gcov enabled $gcov" if test "$sdl_too_old" = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -3738,6 +3752,10 @@ echo "EXESUF=$EXESUF" >> $config_host_mak echo "LIBS_QGA+=$libs_qga" >> $config_host_mak echo "POD2MAN=$POD2MAN" >> $config_host_mak echo "TRANSLATE_OPT_CFLAGS=$TRANSLATE_OPT_CFLAGS" >> $config_host_mak +if test "$gcov" = "yes" ; then + echo "CONFIG_GCOV=y" >> $config_host_mak + echo "GCOV=$gcov_tool" >> $config_host_mak +fi # generate list of library paths for linker script diff --git a/tests/Makefile b/tests/Makefile index b60f0fb8f0..b09a3437cd 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,33 +1,65 @@ export SRC_PATH check-unit-y = tests/check-qdict$(EXESUF) +gcov-files-check-qdict-y = qdict.c check-unit-y += tests/check-qfloat$(EXESUF) +gcov-files-check-qfloat-y = qfloat.c check-unit-y += tests/check-qint$(EXESUF) +gcov-files-check-qint-y = qint.c check-unit-y += tests/check-qstring$(EXESUF) +gcov-files-check-qstring-y = qstring.c check-unit-y += tests/check-qlist$(EXESUF) +gcov-files-check-qlist-y = qlist.c check-unit-y += tests/check-qjson$(EXESUF) +gcov-files-check-qjson-y = qjson.c check-unit-y += tests/test-qmp-output-visitor$(EXESUF) +gcov-files-test-qmp-output-visitor-y = qapi/qmp-output-visitor.c check-unit-y += tests/test-qmp-input-visitor$(EXESUF) +gcov-files-test-qmp-input-visitor-y = qapi/qmp-input-visitor.c check-unit-y += tests/test-qmp-input-strict$(EXESUF) check-unit-y += tests/test-qmp-commands$(EXESUF) +gcov-files-test-qmp-commands-y = qapi/qmp-dispatch.c check-unit-y += tests/test-string-input-visitor$(EXESUF) +gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c check-unit-y += tests/test-string-output-visitor$(EXESUF) +gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c check-unit-y += tests/test-coroutine$(EXESUF) +ifeq ($(CONFIG_WIN32),y) +gcov-files-test-coroutine-y = coroutine-win32.c +else +ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) +gcov-files-test-coroutine-y = coroutine-ucontext.c +else +ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y) +gcov-files-test-coroutine-y = coroutine-sigaltstack.c +else +gcov-files-test-coroutine-y = coroutine-gthread.c +endif +endif +endif check-unit-y += tests/test-visitor-serialization$(EXESUF) check-unit-y += tests/test-iov$(EXESUF) +gcov-files-test-iov-y = iov.c check-unit-y += tests/test-aio$(EXESUF) +gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c +gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c check-unit-y += tests/test-thread-pool$(EXESUF) +gcov-files-test-thread-pool-y = thread-pool.c check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh # All QTests for now are POSIX-only, but the dependencies are # really in libqtest, not in the testcases themselves. check-qtest-i386-y = tests/fdc-test$(EXESUF) +gcov-files-i386-y = hw/fdc.c check-qtest-i386-y += tests/hd-geo-test$(EXESUF) +gcov-files-i386-y += hw/hd-geometry.c check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) +gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) +gcov-files-sparc-y += hw/m48t59.c GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h @@ -108,17 +140,28 @@ check-help: SPEED = quick GTESTER_OPTIONS = -k $(if $(V),--verbose,-q) +GCOV_OPTIONS = -n $(if $(V),-f,) # gtester tests, possibly with verbose output .PHONY: $(patsubst %, check-qtest-%, $(QTEST_TARGETS)) $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y) + $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@") + $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \ + echo Gcov report for $$f:;\ + $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ + done,) .PHONY: $(patsubst %, check-%, $(check-unit-y)) $(patsubst %, check-%, $(check-unit-y)): check-%: % + $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,) $(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*") + $(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y); do \ + echo Gcov report for $$f:;\ + $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ + done,) # gtester tests with XML output From 9807caccd605d09a72495637959568d690e10175 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 14 Apr 2012 20:39:14 +0000 Subject: [PATCH 0244/1634] virtio-pci: replace byte swap hack Remove byte swaps by declaring the config space as native endian. Signed-off-by: Blue Swirl --- exec.c | 18 ------------------ hw/virtio-pci.c | 17 +---------------- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/exec.c b/exec.c index a6923addd4..140eb5668f 100644 --- a/exec.c +++ b/exec.c @@ -2587,24 +2587,6 @@ int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr, } #endif -#if !defined(CONFIG_USER_ONLY) - -/* - * A helper function for the _utterly broken_ virtio device model to find out if - * it's running on a big endian machine. Don't do this at home kids! - */ -bool virtio_is_big_endian(void); -bool virtio_is_big_endian(void) -{ -#if defined(TARGET_WORDS_BIGENDIAN) - return true; -#else - return false; -#endif -} - -#endif - #ifndef CONFIG_USER_ONLY bool cpu_physical_memory_is_io(hwaddr phys_addr) { diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index c7f0c4d4ed..e714bcac72 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -92,9 +92,6 @@ */ #define wmb() do { } while (0) -/* HACK for virtio to determine if it's running a big endian guest */ -bool virtio_is_big_endian(void); - /* virtio device */ /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */ static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d) @@ -403,15 +400,9 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, break; case 2: val = virtio_config_readw(proxy->vdev, addr); - if (virtio_is_big_endian()) { - val = bswap16(val); - } break; case 4: val = virtio_config_readl(proxy->vdev, addr); - if (virtio_is_big_endian()) { - val = bswap32(val); - } break; } return val; @@ -436,15 +427,9 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr, virtio_config_writeb(proxy->vdev, addr, val); break; case 2: - if (virtio_is_big_endian()) { - val = bswap16(val); - } virtio_config_writew(proxy->vdev, addr, val); break; case 4: - if (virtio_is_big_endian()) { - val = bswap32(val); - } virtio_config_writel(proxy->vdev, addr, val); break; } @@ -457,7 +442,7 @@ static const MemoryRegionOps virtio_pci_config_ops = { .min_access_size = 1, .max_access_size = 4, }, - .endianness = DEVICE_LITTLE_ENDIAN, + .endianness = DEVICE_NATIVE_ENDIAN, }; static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, From 8e4a424b305e29dc0e454f52df3b35577f342975 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 6 Jan 2013 18:30:17 +0000 Subject: [PATCH 0245/1634] Revert "virtio-pci: replace byte swap hack" This reverts commit 9807caccd605d09a72495637959568d690e10175. Signed-off-by: Blue Swirl --- exec.c | 18 ++++++++++++++++++ hw/virtio-pci.c | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 140eb5668f..a6923addd4 100644 --- a/exec.c +++ b/exec.c @@ -2587,6 +2587,24 @@ int cpu_memory_rw_debug(CPUArchState *env, target_ulong addr, } #endif +#if !defined(CONFIG_USER_ONLY) + +/* + * A helper function for the _utterly broken_ virtio device model to find out if + * it's running on a big endian machine. Don't do this at home kids! + */ +bool virtio_is_big_endian(void); +bool virtio_is_big_endian(void) +{ +#if defined(TARGET_WORDS_BIGENDIAN) + return true; +#else + return false; +#endif +} + +#endif + #ifndef CONFIG_USER_ONLY bool cpu_physical_memory_is_io(hwaddr phys_addr) { diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index e714bcac72..c7f0c4d4ed 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -92,6 +92,9 @@ */ #define wmb() do { } while (0) +/* HACK for virtio to determine if it's running a big endian guest */ +bool virtio_is_big_endian(void); + /* virtio device */ /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */ static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d) @@ -400,9 +403,15 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, break; case 2: val = virtio_config_readw(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap16(val); + } break; case 4: val = virtio_config_readl(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap32(val); + } break; } return val; @@ -427,9 +436,15 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr, virtio_config_writeb(proxy->vdev, addr, val); break; case 2: + if (virtio_is_big_endian()) { + val = bswap16(val); + } virtio_config_writew(proxy->vdev, addr, val); break; case 4: + if (virtio_is_big_endian()) { + val = bswap32(val); + } virtio_config_writel(proxy->vdev, addr, val); break; } @@ -442,7 +457,7 @@ static const MemoryRegionOps virtio_pci_config_ops = { .min_access_size = 1, .max_access_size = 4, }, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_LITTLE_ENDIAN, }; static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, From 2c0331f4f7d241995452b99afaf0aab00493334a Mon Sep 17 00:00:00 2001 From: Michael Contreras Date: Wed, 5 Dec 2012 13:31:30 -0500 Subject: [PATCH 0246/1634] e1000: Discard oversized packets based on SBP|LPE Discard packets longer than 16384 when !SBP to match the hardware behavior. Signed-off-by: Michael Contreras Signed-off-by: Stefan Hajnoczi --- hw/e1000.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index 92fb00a89f..8fd165456a 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -61,6 +61,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); /* this is the size past which hardware will drop packets when setting LPE=0 */ #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 +/* this is the size past which hardware will drop packets when setting LPE=1 */ +#define MAXIMUM_ETHERNET_LPE_SIZE 16384 /* * HW models: @@ -809,8 +811,9 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) } /* Discard oversized packets if !LPE and !SBP. */ - if (size > MAXIMUM_ETHERNET_VLAN_SIZE - && !(s->mac_reg[RCTL] & E1000_RCTL_LPE) + if ((size > MAXIMUM_ETHERNET_LPE_SIZE || + (size > MAXIMUM_ETHERNET_VLAN_SIZE + && !(s->mac_reg[RCTL] & E1000_RCTL_LPE))) && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { return size; } From f30dbae63a46f23116715dff8d130c7d01ff02be Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Tue, 11 Dec 2012 22:20:15 +0800 Subject: [PATCH 0247/1634] net: clean up network at qemu process termination We don't clean up network if fails to parse "-device" parameters without calling net_cleanup(). I touch a problem, the tap device which is created by qemu-ifup script could not be removed by qemu-ifdown script. Some similar problems also exist in vl.c In this patch, if network initialization successes, a cleanup function will be registered to be called at qemu process termination. Signed-off-by: Amos Kong Acked-by: Michael S. Tsirkin Signed-off-by: Stefan Hajnoczi --- vl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index f056c95807..79e5122393 100644 --- a/vl.c +++ b/vl.c @@ -3762,6 +3762,9 @@ int main(int argc, char **argv, char **envp) } configure_icount(icount_option); + /* clean up network at qemu process termination */ + atexit(&net_cleanup); + if (net_init_clients() < 0) { exit(1); } @@ -4014,7 +4017,6 @@ int main(int argc, char **argv, char **envp) main_loop(); bdrv_close_all(); pause_all_vcpus(); - net_cleanup(); res_free(); return 0; From 84dd2120247a7d25ff1bb337de21c0e76816ad2d Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 28 Dec 2012 17:29:10 +0800 Subject: [PATCH 0248/1634] e1000: no need auto-negotiation if link was down Commit b9d03e352cb6b31a66545763f6a1e20c9abf0c2c added link auto-negotiation emulation, it would always set link up by callback function. Problem exists if original link status was down, link status should not be changed in auto-negotiation. Signed-off-by: Jason Wang Signed-off-by: Amos Kong Signed-off-by: Stefan Hajnoczi --- hw/e1000.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/e1000.c b/hw/e1000.c index 8fd165456a..0f177ff844 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -166,6 +166,11 @@ static void set_phy_ctrl(E1000State *s, int index, uint16_t val) { if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { + /* no need auto-negotiation if link was down */ + if (s->nic->nc.link_down) { + s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; + return; + } s->nic->nc.link_down = true; e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; From 83f58e570f21c3e7227e7fbef1fc0e18b5ed7ea9 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Fri, 28 Dec 2012 17:29:11 +0800 Subject: [PATCH 0249/1634] rtl8139: preserve link state across device reset A device reset does not affect the link state, only set_link does. Signed-off-by: Amos Kong Signed-off-by: Stefan Hajnoczi --- hw/rtl8139.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index c59ec6b6df..3e080621f6 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1258,7 +1258,8 @@ static void rtl8139_reset(DeviceState *d) s->BasicModeStatus = 0x7809; //s->BasicModeStatus |= 0x0040; /* UTP medium */ s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ - s->BasicModeStatus |= 0x0004; /* link is up */ + /* preserve link state */ + s->BasicModeStatus |= s->nic->nc.link_down ? 0 : 0x04; s->NWayAdvert = 0x05e1; /* all modes, full duplex */ s->NWayLPAR = 0x05e1; /* all modes, full duplex */ From f881c8d36b5c524348bc337b46baf34636079cf6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:22 +0100 Subject: [PATCH 0250/1634] ehci: Add a ehci_writeback_async_complete_packet helper function Also drop the warning printf, which was there mainly because this was an untested code path (as the previous bug fixes to it show), but that no longer is the case now :) Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 7536837fb2..218b1d7efe 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -438,6 +438,22 @@ static inline bool ehci_periodic_enabled(EHCIState *s) return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); } +/* Finish executing and writeback a packet outside of the regular + fetchqh -> fetchqtd -> execute -> writeback cycle */ +static void ehci_writeback_async_complete_packet(EHCIPacket *p) +{ + EHCIQueue *q = p->queue; + int state; + + state = ehci_get_state(q->ehci, q->async); + ehci_state_executing(q); + ehci_state_writeback(q); /* Frees the packet! */ + if (!(q->qh.token & QTD_TOKEN_HALT)) { + ehci_state_advqueue(q); + } + ehci_set_state(q->ehci, q->async, state); +} + /* packet management */ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) @@ -455,17 +471,7 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) static void ehci_free_packet(EHCIPacket *p) { if (p->async == EHCI_ASYNC_FINISHED) { - EHCIQueue *q = p->queue; - int state = ehci_get_state(q->ehci, q->async); - /* This is a normal, but rare condition (cancel racing completion) */ - fprintf(stderr, "EHCI: Warning packet completed but not processed\n"); - ehci_state_executing(q); - ehci_state_writeback(q); - if (!(q->qh.token & QTD_TOKEN_HALT)) { - ehci_state_advqueue(q); - } - ehci_set_state(q->ehci, q->async, state); - /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ + ehci_writeback_async_complete_packet(p); return; } trace_usb_ehci_packet_action(p->queue, p, "free"); From c643263409b42a31fd9b1458cd5158280b9c62e1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:23 +0100 Subject: [PATCH 0251/1634] ehci: Add ehci_verify_qh and ehci_verify_qtd helper functions Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 51 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 218b1d7efe..0d315971a9 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -438,6 +438,36 @@ static inline bool ehci_periodic_enabled(EHCIState *s) return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); } +static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh) +{ + uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR); + uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP); + if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || + (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || + (qh->current_qtd != q->qh.current_qtd) || + (q->async && qh->next_qtd != q->qh.next_qtd) || + (memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd, + 7 * sizeof(uint32_t)) != 0) || + (q->dev != NULL && q->dev->addr != devaddr)) { + return false; + } else { + return true; + } +} + +static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) +{ + if (p->qtdaddr != p->queue->qtdaddr || + (p->queue->async && !NLPTR_TBIT(p->qtd.next) && + (p->qtd.next != qtd->next)) || + (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) || + p->qtd.bufptr[0] != qtd->bufptr[0]) { + return false; + } else { + return true; + } +} + /* Finish executing and writeback a packet outside of the regular fetchqh -> fetchqtd -> execute -> writeback cycle */ static void ehci_writeback_async_complete_packet(EHCIPacket *p) @@ -1557,8 +1587,8 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { + uint32_t entry; EHCIPacket *p; - uint32_t entry, devaddr, endp; EHCIQueue *q; EHCIqh qh; @@ -1588,15 +1618,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) * The overlay area of the qh should never be changed by the guest, * except when idle, in which case the reset is a nop. */ - devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR); - endp = get_field(qh.epchar, QH_EPCHAR_EP); - if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || - (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || - (qh.current_qtd != q->qh.current_qtd) || - (q->async && qh.next_qtd != q->qh.next_qtd) || - (memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd, - 7 * sizeof(uint32_t)) != 0) || - (q->dev != NULL && q->dev->addr != devaddr)) { + if (!ehci_verify_qh(q, &qh)) { if (ehci_reset_queue(q) > 0) { ehci_trace_guest_bug(ehci, "guest updated active QH"); } @@ -1610,7 +1632,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) } if (q->dev == NULL) { - q->dev = ehci_find_device(q->ehci, devaddr); + q->dev = ehci_find_device(q->ehci, + get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)); } if (p && p->async == EHCI_ASYNC_FINISHED) { @@ -1768,11 +1791,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q) p = QTAILQ_FIRST(&q->packets); if (p != NULL) { - if (p->qtdaddr != q->qtdaddr || - (q->async && !NLPTR_TBIT(p->qtd.next) && - (p->qtd.next != qtd.next)) || - (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) || - p->qtd.bufptr[0] != qtd.bufptr[0]) { + if (!ehci_verify_qtd(p, &qtd)) { ehci_cancel_queue(q); ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD"); p = NULL; From d066c57b1c97a1967c949aba643bba35329b32ee Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:24 +0100 Subject: [PATCH 0252/1634] ehci: Verify guest does not change the token of inflight qtd-s This is not allowed, except for clearing active on cancellation, so don't warn when the new token does not have its active bit set. This unifies the cancellation path for modified qtd-s, and prepares ehci_verify_qtd to be used ad an extra check inside ehci_writeback_async_complete_packet(). Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 0d315971a9..04301ce173 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -461,6 +461,7 @@ static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) (p->queue->async && !NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd->next)) || (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) || + p->qtd.token != qtd->token || p->qtd.bufptr[0] != qtd->bufptr[0]) { return false; } else { @@ -1793,7 +1794,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q) if (p != NULL) { if (!ehci_verify_qtd(p, &qtd)) { ehci_cancel_queue(q); - ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD"); + if (qtd.token & QTD_TOKEN_ACTIVE) { + ehci_trace_guest_bug(q->ehci, "guest updated active qTD"); + } p = NULL; } else { p->qtd = qtd; @@ -1802,11 +1805,6 @@ static int ehci_state_fetchqtd(EHCIQueue *q) } if (!(qtd.token & QTD_TOKEN_ACTIVE)) { - if (p != NULL) { - /* transfer canceled by guest (clear active) */ - ehci_cancel_queue(q); - p = NULL; - } ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } else if (p != NULL) { switch (p->async) { From 190d849249fd7fecbc75ec38f348197c152f4e87 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:25 +0100 Subject: [PATCH 0253/1634] ehci: Move get / put_dwords upwards No other changes. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 84 +++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 04301ce173..934af55dc6 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -438,6 +438,48 @@ static inline bool ehci_periodic_enabled(EHCIState *s) return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); } +/* Get an array of dwords from main memory */ +static inline int get_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) +{ + int i; + + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + dma_memory_read(ehci->dma, addr, buf, sizeof(*buf)); + *buf = le32_to_cpu(*buf); + } + + return num; +} + +/* Put an array of dwords in to main memory */ +static inline int put_dwords(EHCIState *ehci, uint32_t addr, + uint32_t *buf, int num) +{ + int i; + + if (!ehci->dma) { + ehci_raise_irq(ehci, USBSTS_HSE); + ehci->usbcmd &= ~USBCMD_RUNSTOP; + trace_usb_ehci_dma_error(); + return -1; + } + + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { + uint32_t tmp = cpu_to_le32(*buf); + dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp)); + } + + return num; +} + static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh) { uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR); @@ -1054,48 +1096,6 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, *mmio, old); } -/* Get an array of dwords from main memory */ -static inline int get_dwords(EHCIState *ehci, uint32_t addr, - uint32_t *buf, int num) -{ - int i; - - if (!ehci->dma) { - ehci_raise_irq(ehci, USBSTS_HSE); - ehci->usbcmd &= ~USBCMD_RUNSTOP; - trace_usb_ehci_dma_error(); - return -1; - } - - for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - dma_memory_read(ehci->dma, addr, buf, sizeof(*buf)); - *buf = le32_to_cpu(*buf); - } - - return num; -} - -/* Put an array of dwords in to main memory */ -static inline int put_dwords(EHCIState *ehci, uint32_t addr, - uint32_t *buf, int num) -{ - int i; - - if (!ehci->dma) { - ehci_raise_irq(ehci, USBSTS_HSE); - ehci->usbcmd &= ~USBCMD_RUNSTOP; - trace_usb_ehci_dma_error(); - return -1; - } - - for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - uint32_t tmp = cpu_to_le32(*buf); - dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp)); - } - - return num; -} - /* * Write the qh back to guest physical memory. This step isn't * in the EHCI spec but we need to do it since we don't share From 2b3de6ada5d180130ba083d5b45ed51ce8e4def2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:26 +0100 Subject: [PATCH 0254/1634] ehci: writeback_async_complete_packet: verify qh and qtd Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 934af55dc6..96a014442c 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -192,6 +192,7 @@ static int ehci_state_executing(EHCIQueue *q); static int ehci_state_writeback(EHCIQueue *q); static int ehci_state_advqueue(EHCIQueue *q); static int ehci_fill_queue(EHCIPacket *p); +static void ehci_free_packet(EHCIPacket *p); static const char *nr2str(const char **n, size_t len, uint32_t nr) { @@ -516,8 +517,21 @@ static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) static void ehci_writeback_async_complete_packet(EHCIPacket *p) { EHCIQueue *q = p->queue; + EHCIqtd qtd; + EHCIqh qh; int state; + /* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */ + get_dwords(q->ehci, NLPTR_GET(q->qhaddr), + (uint32_t *) &qh, sizeof(EHCIqh) >> 2); + get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), + (uint32_t *) &qtd, sizeof(EHCIqtd) >> 2); + if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) { + p->async = EHCI_ASYNC_INITIALIZED; + ehci_free_packet(p); + return; + } + state = ehci_get_state(q->ehci, q->async); ehci_state_executing(q); ehci_state_writeback(q); /* Frees the packet! */ From e3fdfd488c47c2d6920e0964364f1238fb5bf0e2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:27 +0100 Subject: [PATCH 0255/1634] ehci: Verify qtd for async completed packets Remove the short-circuiting of fetchqtd in fetchqh, so that the qtd gets properly verified before completing the transaction. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 96a014442c..dde2ff3130 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1603,7 +1603,6 @@ out: static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) { uint32_t entry; - EHCIPacket *p; EHCIQueue *q; EHCIqh qh; @@ -1612,7 +1611,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) if (NULL == q) { q = ehci_alloc_queue(ehci, entry, async); } - p = QTAILQ_FIRST(&q->packets); q->seen++; if (q->seen > 1) { @@ -1637,7 +1635,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) if (ehci_reset_queue(q) > 0) { ehci_trace_guest_bug(ehci, "guest updated active QH"); } - p = NULL; } q->qh = qh; @@ -1651,13 +1648,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)); } - if (p && p->async == EHCI_ASYNC_FINISHED) { - /* I/O finished -- continue processing queue */ - trace_usb_ehci_packet_action(p->queue, p, "complete"); - ehci_set_state(ehci, async, EST_EXECUTING); - goto out; - } - if (async && (q->qh.epchar & QH_EPCHAR_H)) { /* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */ @@ -1834,10 +1824,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q) ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); break; case EHCI_ASYNC_FINISHED: - /* - * We get here when advqueue moves to a packet which is already - * finished, which can happen with packets queued up by fill_queue - */ + /* Complete executing of the packet */ ehci_set_state(q->ehci, q->async, EST_EXECUTING); break; } From 51e0c5d02951ee5bd653132e46123f6e963ff23f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:28 +0100 Subject: [PATCH 0256/1634] ehci: Add an ehci_get_pid helper function Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index dde2ff3130..dae414abb9 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -481,6 +481,21 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr, return num; } +static int ehci_get_pid(EHCIqtd *qtd) +{ + switch (get_field(qtd->token, QTD_TOKEN_PID)) { + case 0: + return USB_TOKEN_OUT; + case 1: + return USB_TOKEN_IN; + case 2: + return USB_TOKEN_SETUP; + default: + fprintf(stderr, "bad token\n"); + return 0; + } +} + static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh) { uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR); @@ -1352,22 +1367,7 @@ static int ehci_execute(EHCIPacket *p, const char *action) return -1; } - p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH; - switch (p->pid) { - case 0: - p->pid = USB_TOKEN_OUT; - break; - case 1: - p->pid = USB_TOKEN_IN; - break; - case 2: - p->pid = USB_TOKEN_SETUP; - break; - default: - fprintf(stderr, "bad token\n"); - break; - } - + p->pid = ehci_get_pid(&p->qtd); endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); ep = usb_ep_get(p->queue->dev, p->pid, endp); From bbbc39ccacf66ef58261c155f9eed503947c3023 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:29 +0100 Subject: [PATCH 0257/1634] ehci: Verify a queue's ep direction does not change ehci_fill_queue assumes that there is a one on one relationship between an ep and a qh, this patch adds a check to ensure this. Note I don't expect this to ever trigger, this is just something I noticed the guest might do while working on other stuff. The only way this check can trigger is if a guest mixes in and out qtd-s in a single qh for a non control ep. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 19 +++++++++++++++++++ hw/usb/hcd-ehci.h | 1 + 2 files changed, 20 insertions(+) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index dae414abb9..5d314a09f1 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -527,6 +527,19 @@ static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) } } +static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd) +{ + int ep = get_field(q->qh.epchar, QH_EPCHAR_EP); + int pid = ehci_get_pid(qtd); + + /* Note the pid changing is normal for ep 0 (the control ep) */ + if (q->last_pid && ep != 0 && pid != q->last_pid) { + return false; + } else { + return true; + } +} + /* Finish executing and writeback a packet outside of the regular fetchqh -> fetchqtd -> execute -> writeback cycle */ static void ehci_writeback_async_complete_packet(EHCIPacket *p) @@ -634,6 +647,7 @@ static int ehci_reset_queue(EHCIQueue *q) packets = ehci_cancel_queue(q); q->dev = NULL; q->qtdaddr = 0; + q->last_pid = 0; return packets; } @@ -1368,6 +1382,7 @@ static int ehci_execute(EHCIPacket *p, const char *action) } p->pid = ehci_get_pid(&p->qtd); + p->queue->last_pid = p->pid; endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); ep = usb_ep_get(p->queue->dev, p->pid, endp); @@ -1883,6 +1898,10 @@ static int ehci_fill_queue(EHCIPacket *p) if (!(qtd.token & QTD_TOKEN_ACTIVE)) { break; } + if (!ehci_verify_pid(q, &qtd)) { + ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid"); + break; + } p = ehci_alloc_packet(q); p->qtdaddr = qtdaddr; p->qtd = qtd; diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index e35144d386..14ee3bea5a 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -248,6 +248,7 @@ struct EHCIQueue { EHCIqh qh; /* copy of current QH (being worked on) */ uint32_t qhaddr; /* address QH read from */ uint32_t qtdaddr; /* address QTD read from */ + int last_pid; /* pid of last packet executed */ USBDevice *dev; QTAILQ_HEAD(pkts_head, EHCIPacket) packets; }; From 9359a58b122187964d7465d48165680eadbf69d3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 18 Dec 2012 14:17:02 +0100 Subject: [PATCH 0258/1634] ehci: Use uframe precision for interrupt threshold checking (v2) Before this patch, the following could happen: 1) Transfer completes, raises interrupt 2) .5 ms later we check if the guest has queued up any new transfers 3) We find and execute a new transfer 4) .2 ms later the new transfer completes 5) We re-run our frame_timer to write back the completion, but less then 1 ms has passed since our last run, so frindex is not changed, so the interrupt threshold code delays the interrupt 6) 1 ms from the re-run our frame-timer runs again and finally delivers the interrupt This leads to unnecessary large delays of interrupts, this code fixes this by changing frindex to uframe precision and using that for interrupt threshold control, making the interrupt fire at step 5 for guest which have low interrupt threshold settings (like Linux). Note that the guest still sees the frindex move in steps of 8 for migration compatibility. This boosts Linux read speed of a simple cheap USB thumb drive by 6 %. Changes in v2: -Make the guest see frindex move in steps of 8 by modifying ehci_opreg_read, rather then using a shadow variable Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 70 +++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 5d314a09f1..efa1d778e3 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -109,12 +109,13 @@ #define FRAME_TIMER_FREQ 1000 #define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ) +#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8) #define NB_MAXINTRATE 8 // Max rate at which controller issues ints #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_QH 100 // Max allowable queue heads in a chain -#define MIN_FR_PER_TICK 3 // Min frames to process when catching up -#define PERIODIC_ACTIVE 64 +#define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */ +#define PERIODIC_ACTIVE 512 /* Micro-frames */ /* Internal periodic / asynchronous schedule state machine states */ @@ -955,7 +956,15 @@ static uint64_t ehci_opreg_read(void *ptr, hwaddr addr, EHCIState *s = ptr; uint32_t val; - val = s->opreg[addr >> 2]; + switch (addr) { + case FRINDEX: + /* Round down to mult of 8, else it can go backwards on migration */ + val = s->frindex & ~7; + break; + default: + val = s->opreg[addr >> 2]; + } + trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val); return val; } @@ -1106,7 +1115,8 @@ static void ehci_opreg_write(void *ptr, hwaddr addr, break; case FRINDEX: - val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */ + val &= 0x00003fff; /* frindex is 14bits */ + s->usbsts_frindex = val; break; case CONFIGFLAG: @@ -2219,16 +2229,16 @@ static void ehci_advance_periodic_state(EHCIState *ehci) } } -static void ehci_update_frindex(EHCIState *ehci, int frames) +static void ehci_update_frindex(EHCIState *ehci, int uframes) { int i; - if (!ehci_enabled(ehci)) { + if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) { return; } - for (i = 0; i < frames; i++) { - ehci->frindex += 8; + for (i = 0; i < uframes; i++) { + ehci->frindex++; if (ehci->frindex == 0x00002000) { ehci_raise_irq(ehci, USBSTS_FLR); @@ -2252,33 +2262,33 @@ static void ehci_frame_timer(void *opaque) int need_timer = 0; int64_t expire_time, t_now; uint64_t ns_elapsed; - int frames, skipped_frames; + int uframes, skipped_uframes; int i; t_now = qemu_get_clock_ns(vm_clock); ns_elapsed = t_now - ehci->last_run_ns; - frames = ns_elapsed / FRAME_TIMER_NS; + uframes = ns_elapsed / UFRAME_TIMER_NS; if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { need_timer++; - if (frames > ehci->maxframes) { - skipped_frames = frames - ehci->maxframes; - ehci_update_frindex(ehci, skipped_frames); - ehci->last_run_ns += FRAME_TIMER_NS * skipped_frames; - frames -= skipped_frames; - DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames); + if (uframes > (ehci->maxframes * 8)) { + skipped_uframes = uframes - (ehci->maxframes * 8); + ehci_update_frindex(ehci, skipped_uframes); + ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes; + uframes -= skipped_uframes; + DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes); } - for (i = 0; i < frames; i++) { + for (i = 0; i < uframes; i++) { /* * If we're running behind schedule, we should not catch up * too fast, as that will make some guests unhappy: - * 1) We must process a minimum of MIN_FR_PER_TICK frames, + * 1) We must process a minimum of MIN_UFR_PER_TICK frames, * otherwise we will never catch up * 2) Process frames until the guest has requested an irq (IOC) */ - if (i >= MIN_FR_PER_TICK) { + if (i >= MIN_UFR_PER_TICK) { ehci_commit_irq(ehci); if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) { break; @@ -2288,13 +2298,15 @@ static void ehci_frame_timer(void *opaque) ehci->periodic_sched_active--; } ehci_update_frindex(ehci, 1); - ehci_advance_periodic_state(ehci); - ehci->last_run_ns += FRAME_TIMER_NS; + if ((ehci->frindex & 7) == 0) { + ehci_advance_periodic_state(ehci); + } + ehci->last_run_ns += UFRAME_TIMER_NS; } } else { ehci->periodic_sched_active = 0; - ehci_update_frindex(ehci, frames); - ehci->last_run_ns += FRAME_TIMER_NS * frames; + ehci_update_frindex(ehci, uframes); + ehci->last_run_ns += UFRAME_TIMER_NS * uframes; } if (ehci->periodic_sched_active) { @@ -2373,6 +2385,17 @@ static USBBusOps ehci_bus_ops = { .wakeup_endpoint = ehci_wakeup_endpoint, }; +static void usb_ehci_pre_save(void *opaque) +{ + EHCIState *ehci = opaque; + uint32_t new_frindex; + + /* Round down frindex to a multiple of 8 for migration compatibility */ + new_frindex = ehci->frindex & ~7; + ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS; + ehci->frindex = new_frindex; +} + static int usb_ehci_post_load(void *opaque, int version_id) { EHCIState *s = opaque; @@ -2423,6 +2446,7 @@ const VMStateDescription vmstate_ehci = { .name = "ehci-core", .version_id = 2, .minimum_version_id = 1, + .pre_save = usb_ehci_pre_save, .post_load = usb_ehci_post_load, .fields = (VMStateField[]) { /* mmio registers */ From 52c15e5986cd0f6531a2989a81a964f77b4ed9c2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:31 +0100 Subject: [PATCH 0259/1634] ehci: Further speedup rescanning if async schedule after raising an interrupt I tried lowering the time between raising an interrupt and rescanning the async schedule to see if the guest has queued a new transfer before, but that did not have any positive effect. I now believe the cause for this is that lowering this time made it more likely to hit the 1 ms interrupt threshold penalty for the next packet, as described in my "ehci: Use uframe precision for interrupt threshold checking" commit. Now that we do interrupt threshold handling with uframe precision, futher lowering this time from .5 to .25 ms gives an extra 15% improvement in speed (MB/s) reading from a simple USB-2.0 thumb-drive. While at it also properly set the int_req_by_async flag for short packet completions. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index efa1d778e3..8da4b6a6d2 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1347,6 +1347,9 @@ static void ehci_execute_complete(EHCIQueue *q) if (tbytes) { /* 4.15.1.2 must raise int on a short input packet */ ehci_raise_irq(q->ehci, USBSTS_INT); + if (q->async) { + q->ehci->int_req_by_async = true; + } } } else { tbytes = 0; @@ -2337,7 +2340,7 @@ static void ehci_frame_timer(void *opaque) /* If we've raised int, we speed up the timer, so that we quickly * notice any new packets queued up in response */ if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) { - expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 2); + expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 4); ehci->int_req_by_async = false; } else { expire_time = t_now + (get_ticks_per_sec() From 4a9ef2c042207e4eddbd010ccf2e1c8264d8f0d6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:32 +0100 Subject: [PATCH 0260/1634] ehci: Don't call commit_irq after raising PCD ehci_raise_irq(s, USBSTS_PCD), gets applied immediately so there is no need to call commit_irq after it. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 8da4b6a6d2..1713394c65 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -757,7 +757,6 @@ static void ehci_attach(USBPort *port) *portsc |= PORTSC_CSC; ehci_raise_irq(s, USBSTS_PCD); - ehci_commit_irq(s); } static void ehci_detach(USBPort *port) @@ -787,7 +786,6 @@ static void ehci_detach(USBPort *port) *portsc |= PORTSC_CSC; ehci_raise_irq(s, USBSTS_PCD); - ehci_commit_irq(s); } static void ehci_child_detach(USBPort *port, USBDevice *child) From 719c130dcaa3b1269beed71ca9cf6c43a0219b30 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:33 +0100 Subject: [PATCH 0261/1634] uhci: Fix 1 ms delay in interrupt reporting to the guest Re-arrange how we process frames / increase frnum / report pending interrupts, to avoid a 1 ms delay in interrupt reporting to the guest. This increases the packet throughput for cases where the guest submits a single packet, then waits for its completion then re-submits from 500 pkts / sec to 1000 pkts / sec. This impacts for example the use of redirected / virtual usb to serial convertors. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-uhci.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 2af754b5cf..5685b9f3a9 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1191,17 +1191,7 @@ static void uhci_frame_timer(void *opaque) return; } - /* Complete the previous frame */ - if (s->pending_int_mask) { - s->status2 |= s->pending_int_mask; - s->status |= UHCI_STS_USBINT; - uhci_update_irq(s); - } - s->pending_int_mask = 0; - - /* Start new frame */ - s->frnum = (s->frnum + 1) & 0x7ff; - + /* Process the current frame */ trace_usb_uhci_frame_start(s->frnum); uhci_async_validate_begin(s); @@ -1210,6 +1200,18 @@ static void uhci_frame_timer(void *opaque) uhci_async_validate_end(s); + /* The uhci spec says frnum reflects the frame currently being processed, + * and the guest must look at frnum - 1 on interrupt, so inc frnum now */ + s->frnum = (s->frnum + 1) & 0x7ff; + + /* Complete the previous frame */ + if (s->pending_int_mask) { + s->status2 |= s->pending_int_mask; + s->status |= UHCI_STS_USBINT; + uhci_update_irq(s); + } + s->pending_int_mask = 0; + qemu_mod_timer(s->frame_timer, s->expire_time); } From ecfdc15f4351a17989d446f4f1e6d1931d9c1677 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:34 +0100 Subject: [PATCH 0262/1634] uhci: Fix pending interrupts getting lost on migration Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-uhci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 5685b9f3a9..e82e5cc809 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -433,7 +433,7 @@ static int uhci_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_uhci = { .name = "uhci", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .minimum_version_id_old = 1, .post_load = uhci_post_load, @@ -451,6 +451,7 @@ static const VMStateDescription vmstate_uhci = { VMSTATE_UINT8(status2, UHCIState), VMSTATE_TIMER(frame_timer, UHCIState), VMSTATE_INT64_V(expire_time, UHCIState, 2), + VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3), VMSTATE_END_OF_LIST() } }; From 475443cf14d7ef01b9ea56eed8657804f7bdf664 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:35 +0100 Subject: [PATCH 0263/1634] uhci: Add a QH_VALID define Rather then using the magic 32 value in various places. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-uhci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index e82e5cc809..d61d879c1c 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -75,6 +75,9 @@ #define FRAME_MAX_LOOPS 256 +/* Must be large enough to handle 10 frame delay for initial isoc requests */ +#define QH_VALID 32 + #define NB_PORTS 2 enum { @@ -206,9 +209,7 @@ static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td, queue->ep = ep; QTAILQ_INIT(&queue->asyncs); QTAILQ_INSERT_HEAD(&s->queues, queue, next); - /* valid needs to be large enough to handle 10 frame delay - * for initial isochronous requests */ - queue->valid = 32; + queue->valid = QH_VALID; trace_usb_uhci_queue_add(queue->token); return queue; } @@ -854,7 +855,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, } if (q) { - q->valid = 32; + q->valid = QH_VALID; } /* Is active ? */ From f8f48b6957bf182339495e6be429f7bdc7ef1981 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:36 +0100 Subject: [PATCH 0264/1634] uhci: Limit amount of frames processed in one go Before this patch uhci would process an unlimited amount of frames when behind on schedule, by setting the timer to a time already past, causing the timer subsys to immediately recall the frame_timer function gain. This would cause invalid cancellations of bulk queues when the catching up processed more then 32 frames at a moment when the bulk qh was temporarily unlinked (which the Linux uhci driver does). This patch fixes this by processing maximum 16 frames in one go, and always setting the timer one ms later, making the code behave more like the ehci code. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-uhci.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index d61d879c1c..e5c3e595f1 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -78,6 +78,8 @@ /* Must be large enough to handle 10 frame delay for initial isoc requests */ #define QH_VALID 32 +#define MAX_FRAMES_PER_TICK (QH_VALID / 2) + #define NB_PORTS 2 enum { @@ -500,7 +502,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) trace_usb_uhci_schedule_start(); s->expire_time = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); + qemu_mod_timer(s->frame_timer, s->expire_time); s->status &= ~UHCI_STS_HCHALTED; } else if (!(val & UHCI_CMD_RS)) { s->status |= UHCI_STS_HCHALTED; @@ -1176,10 +1178,10 @@ static void uhci_bh(void *opaque) static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; + uint64_t t_now, t_last_run; + int i, frames; + const uint64_t frame_t = get_ticks_per_sec() / FRAME_TIMER_FREQ; - /* prepare the timer for the next frame */ - s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); - s->frame_bytes = 0; s->completions_only = false; qemu_bh_cancel(s->bh); @@ -1193,20 +1195,29 @@ static void uhci_frame_timer(void *opaque) return; } - /* Process the current frame */ - trace_usb_uhci_frame_start(s->frnum); + /* We still store expire_time in our state, for migration */ + t_last_run = s->expire_time - frame_t; + t_now = qemu_get_clock_ns(vm_clock); - uhci_async_validate_begin(s); + /* Process up to MAX_FRAMES_PER_TICK frames */ + frames = (t_now - t_last_run) / frame_t; + if (frames > MAX_FRAMES_PER_TICK) { + frames = MAX_FRAMES_PER_TICK; + } - uhci_process_frame(s); + for (i = 0; i < frames; i++) { + s->frame_bytes = 0; + trace_usb_uhci_frame_start(s->frnum); + uhci_async_validate_begin(s); + uhci_process_frame(s); + uhci_async_validate_end(s); + /* The spec says frnum is the frame currently being processed, and + * the guest must look at frnum - 1 on interrupt, so inc frnum now */ + s->frnum = (s->frnum + 1) & 0x7ff; + s->expire_time += frame_t; + } - uhci_async_validate_end(s); - - /* The uhci spec says frnum reflects the frame currently being processed, - * and the guest must look at frnum - 1 on interrupt, so inc frnum now */ - s->frnum = (s->frnum + 1) & 0x7ff; - - /* Complete the previous frame */ + /* Complete the previous frame(s) */ if (s->pending_int_mask) { s->status2 |= s->pending_int_mask; s->status |= UHCI_STS_USBINT; @@ -1214,7 +1225,7 @@ static void uhci_frame_timer(void *opaque) } s->pending_int_mask = 0; - qemu_mod_timer(s->frame_timer, s->expire_time); + qemu_mod_timer(s->frame_timer, t_now + frame_t); } static const MemoryRegionPortio uhci_portio[] = { From 9fdf70272702095f57efc51a80c79493fd0829b8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:37 +0100 Subject: [PATCH 0265/1634] uhci: Maximize how many frames we catch up when behind If somehow we've gotten behind a lot, simply skip ahead, like the ehci code does. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-uhci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index e5c3e595f1..bd3377e36a 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -171,6 +171,7 @@ struct UHCIState { /* Properties */ char *masterbus; uint32_t firstport; + uint32_t maxframes; }; typedef struct UHCI_TD { @@ -1201,6 +1202,12 @@ static void uhci_frame_timer(void *opaque) /* Process up to MAX_FRAMES_PER_TICK frames */ frames = (t_now - t_last_run) / frame_t; + if (frames > s->maxframes) { + int skipped = frames - s->maxframes; + s->expire_time += skipped * frame_t; + s->frnum = (s->frnum + skipped) & 0x7ff; + frames -= skipped; + } if (frames > MAX_FRAMES_PER_TICK) { frames = MAX_FRAMES_PER_TICK; } @@ -1326,6 +1333,7 @@ static Property uhci_properties[] = { DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280), + DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128), DEFINE_PROP_END_OF_LIST(), }; From 027c03f7327faa696e1d876954a18b5214c18583 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:38 +0100 Subject: [PATCH 0266/1634] hid: Change idle handling to use a timer This leads to cleaner code in usb-hid, and removes up to a 1000 calls / sec to qemu_get_clock_ns(vm_clock) if idle-time is set to its default value of 0. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/hid.c | 43 +++++++++++++++++++++++++++++++++++++------ hw/hid.h | 5 +++-- hw/usb/dev-hid.c | 8 +++----- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/hw/hid.c b/hw/hid.c index 0fee3b6ddd..89b5415c0f 100644 --- a/hw/hid.c +++ b/hw/hid.c @@ -71,12 +71,38 @@ static const uint8_t hid_usage_keys[0x100] = { bool hid_has_events(HIDState *hs) { - return hs->n > 0; + return hs->n > 0 || hs->idle_pending; } -void hid_set_next_idle(HIDState *hs, int64_t curtime) +static void hid_idle_timer(void *opaque) { - hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000; + HIDState *hs = opaque; + + hs->idle_pending = true; + hs->event(hs); +} + +static void hid_del_idle_timer(HIDState *hs) +{ + if (hs->idle_timer) { + qemu_del_timer(hs->idle_timer); + qemu_free_timer(hs->idle_timer); + hs->idle_timer = NULL; + } +} + +void hid_set_next_idle(HIDState *hs) +{ + if (hs->idle) { + uint64_t expire_time = qemu_get_clock_ns(vm_clock) + + get_ticks_per_sec() * hs->idle * 4 / 1000; + if (!hs->idle_timer) { + hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs); + } + qemu_mod_timer_ns(hs->idle_timer, expire_time); + } else { + hid_del_idle_timer(hs); + } } static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) @@ -232,6 +258,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int index; HIDPointerEvent *e; + hs->idle_pending = false; + hid_pointer_activate(hs); /* When the buffer is empty, return the last event. Relative @@ -319,6 +347,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len) { + hs->idle_pending = false; + if (len < 2) { return 0; } @@ -377,6 +407,8 @@ void hid_reset(HIDState *hs) hs->n = 0; hs->protocol = 1; hs->idle = 0; + hs->idle_pending = false; + hid_del_idle_timer(hs); } void hid_free(HIDState *hs) @@ -390,6 +422,7 @@ void hid_free(HIDState *hs) qemu_remove_mouse_event_handler(hs->ptr.eh_entry); break; } + hid_del_idle_timer(hs); } void hid_init(HIDState *hs, int kind, HIDEventFunc event) @@ -412,9 +445,7 @@ static int hid_post_load(void *opaque, int version_id) { HIDState *s = opaque; - if (s->idle) { - hid_set_next_idle(s, qemu_get_clock_ns(vm_clock)); - } + hid_set_next_idle(s); return 0; } diff --git a/hw/hid.h b/hw/hid.h index 100b121663..56c71ed5ae 100644 --- a/hw/hid.h +++ b/hw/hid.h @@ -43,7 +43,8 @@ struct HIDState { int kind; int32_t protocol; uint8_t idle; - int64_t next_idle_clock; + bool idle_pending; + QEMUTimer *idle_timer; HIDEventFunc event; }; @@ -52,7 +53,7 @@ void hid_reset(HIDState *hs); void hid_free(HIDState *hs); bool hid_has_events(HIDState *hs); -void hid_set_next_idle(HIDState *hs, int64_t curtime); +void hid_set_next_idle(HIDState *hs); void hid_pointer_activate(HIDState *hs); int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len); int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len); diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index ce38fef9f6..b4ace04eef 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -501,7 +501,7 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p, break; case SET_IDLE: hs->idle = (uint8_t) (value >> 8); - hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock)); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } @@ -523,16 +523,14 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) switch (p->pid) { case USB_TOKEN_IN: if (p->ep->nr == 1) { - int64_t curtime = qemu_get_clock_ns(vm_clock); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { hid_pointer_activate(hs); } - if (!hid_has_events(hs) && - (!hs->idle || hs->next_idle_clock - curtime > 0)) { + if (!hid_has_events(hs)) { p->status = USB_RET_NAK; return; } - hid_set_next_idle(hs, curtime); + hid_set_next_idle(hs); if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { len = hid_pointer_poll(hs, buf, p->iov.size); } else if (hs->kind == HID_KEYBOARD) { From 6735d433729f80fab80c0a1f70ae131398645613 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:39 +0100 Subject: [PATCH 0267/1634] usb: Fix usb_ep_find_packet_by_id usb_ep_find_packet_by_id mistakenly only checks the first packet and if that is not a match, keeps trying the first packet! This patch fixes this. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/core.c b/hw/usb/core.c index e315fc1021..d057aab900 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -761,7 +761,7 @@ USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); USBPacket *p; - while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) { + QTAILQ_FOREACH(p, &uep->queue, queue) { if (p->id == id) { return p; } From f79738b03ba55a5c9733c6dc2455964a6f8fdac9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:40 +0100 Subject: [PATCH 0268/1634] usb: Add an usb_device_ep_stopped USBDevice method Some usb devices (host or network redirection) can benefit from knowing when the guest stops using an endpoint. Redirection may involve submitting packets independently from the guest (in combination with a fifo buffer between the redirection code and the guest), to ensure that buffers of the real usb device are timely emptied. This is done for example for isoc traffic and for interrupt input endpoints. But when the (re)submission of packets is done by the device code, then how does it know when to stop this? For isoc endpoints this is handled by detecting a set interface (change alt setting) command, which works well for isoc endpoints. But for interrupt endpoints currently the redirection code never stops receiving data from the device, which is less then ideal. However the controller emulation is aware when a guest looses interest, as then the qh for the endpoint gets unlinked (ehci, ohci, uhci) or the endpoint is explicitly stopped (xhci). This patch adds a new ep_stopped USBDevice method and modifies the hcd code to call this on queue unlink / ep stop. This makes it possible for the redirection code to properly stop receiving interrupt input (*) data when the guest no longer has interest in it. *) And in the future also buffered bulk input. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb.h | 8 ++++++++ hw/usb/bus.c | 8 ++++++++ hw/usb/hcd-ehci.c | 19 ++++++++++++++++++- hw/usb/hcd-ohci.c | 30 ++++++++++++++++++++++++++---- hw/usb/hcd-uhci.c | 1 + hw/usb/hcd-xhci.c | 7 +++++++ 6 files changed, 68 insertions(+), 5 deletions(-) diff --git a/hw/usb.h b/hw/usb.h index 81e265c4fd..aca8ff6950 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -307,6 +307,12 @@ typedef struct USBDeviceClass { */ void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep); + /* + * Called by the hcd to let the device know the queue for an endpoint + * has been unlinked / stopped. Optional may be NULL. + */ + void (*ep_stopped)(USBDevice *dev, USBEndpoint *ep); + const char *product_desc; const USBDesc *usb_desc; } USBDeviceClass; @@ -539,6 +545,8 @@ void usb_device_set_interface(USBDevice *dev, int interface, void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep); +void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep); + const char *usb_device_get_product_desc(USBDevice *dev); const USBDesc *usb_device_get_usb_desc(USBDevice *dev); diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 10260a13ac..180d1d739b 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -189,6 +189,14 @@ void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) } } +void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->ep_stopped) { + klass->ep_stopped(dev, ep); + } +} + static int usb_qdev_init(DeviceState *qdev) { USBDevice *dev = USB_DEVICE(qdev); diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 1713394c65..320b7e7239 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -622,6 +622,17 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) return q; } +static void ehci_queue_stopped(EHCIQueue *q) +{ + int endp = get_field(q->qh.epchar, QH_EPCHAR_EP); + + if (!q->last_pid || !q->dev) { + return; + } + + usb_device_ep_stopped(q->dev, usb_ep_get(q->dev, q->last_pid, endp)); +} + static int ehci_cancel_queue(EHCIQueue *q) { EHCIPacket *p; @@ -629,7 +640,7 @@ static int ehci_cancel_queue(EHCIQueue *q) p = QTAILQ_FIRST(&q->packets); if (p == NULL) { - return 0; + goto leave; } trace_usb_ehci_queue_action(q, "cancel"); @@ -637,6 +648,9 @@ static int ehci_cancel_queue(EHCIQueue *q) ehci_free_packet(p); packets++; } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); + +leave: + ehci_queue_stopped(q); return packets; } @@ -1392,6 +1406,9 @@ static int ehci_execute(EHCIPacket *p, const char *action) return -1; } + if (!ehci_verify_pid(p->queue, &p->qtd)) { + ehci_queue_stopped(p->queue); /* Mark the ep in the prev dir stopped */ + } p->pid = ehci_get_pid(&p->qtd); p->queue->last_pid = p->pid; endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 052c4a3037..29bafa6da9 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -430,6 +430,23 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr) return NULL; } +static void ohci_stop_endpoints(OHCIState *ohci) +{ + USBDevice *dev; + int i, j; + + for (i = 0; i < ohci->num_ports; i++) { + dev = ohci->rhport[i].port.dev; + if (dev && dev->attached) { + usb_device_ep_stopped(dev, &dev->ep_ctl); + for (j = 0; j < USB_MAX_ENDPOINTS; j++) { + usb_device_ep_stopped(dev, &dev->ep_in[j]); + usb_device_ep_stopped(dev, &dev->ep_out[j]); + } + } + } +} + /* Reset the controller */ static void ohci_reset(void *opaque) { @@ -478,6 +495,7 @@ static void ohci_reset(void *opaque) usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; } + ohci_stop_endpoints(ohci); DPRINTF("usb-ohci: Reset %s\n", ohci->name); } @@ -1147,6 +1165,8 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) if (ohci->async_td && addr == ohci->async_td) { usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; + usb_device_ep_stopped(ohci->usb_packet.ep->dev, + ohci->usb_packet.ep); } continue; } @@ -1227,10 +1247,12 @@ static void ohci_frame_boundary(void *opaque) } /* Cancel all pending packets if either of the lists has been disabled. */ - if (ohci->async_td && - ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { - usb_cancel_packet(&ohci->usb_packet); - ohci->async_td = 0; + if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) { + if (ohci->async_td) { + usb_cancel_packet(&ohci->usb_packet); + ohci->async_td = 0; + } + ohci_stop_endpoints(ohci); } ohci->old_ctl = ohci->ctl; ohci_process_lists(ohci, 0); diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index bd3377e36a..0cd68cf355 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -226,6 +226,7 @@ static void uhci_queue_free(UHCIQueue *queue, const char *reason) async = QTAILQ_FIRST(&queue->asyncs); uhci_async_cancel(async); } + usb_device_ep_stopped(queue->ep->dev, queue->ep); trace_usb_uhci_queue_del(queue->token, reason); QTAILQ_REMOVE(&s->queues, queue, next); diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index e2de71ef1a..40542b8d05 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1177,6 +1177,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, XHCISlot *slot; XHCIEPContext *epctx; int i, xferi, killed = 0; + USBEndpoint *ep = NULL; assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); @@ -1192,9 +1193,15 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, xferi = epctx->next_xfer; for (i = 0; i < TD_QUEUE; i++) { + if (epctx->transfers[xferi].packet.ep) { + ep = epctx->transfers[xferi].packet.ep; + } killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi]); xferi = (xferi + 1) % TD_QUEUE; } + if (ep) { + usb_device_ep_stopped(ep->dev, ep); + } return killed; } From f8c126f329892ec8941e5bbe6ba411d78cfc66cb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:41 +0100 Subject: [PATCH 0269/1634] usbredir: Add an usbredir_stop_ep helper function Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 0abe1ff4d1..c5704c176a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -752,6 +752,23 @@ static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep) } } +static void usbredir_stop_ep(USBRedirDevice *dev, int i) +{ + uint8_t ep = I2EP(i); + + switch (dev->endpoint[i].type) { + case USB_ENDPOINT_XFER_ISOC: + usbredir_stop_iso_stream(dev, ep); + break; + case USB_ENDPOINT_XFER_INT: + if (ep & USB_DIR_IN) { + usbredir_stop_interrupt_receiving(dev, ep); + } + break; + } + usbredir_free_bufpq(dev, ep); +} + static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, int config) { @@ -761,17 +778,7 @@ static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, DPRINTF("set config %d id %"PRIu64"\n", config, p->id); for (i = 0; i < MAX_ENDPOINTS; i++) { - switch (dev->endpoint[i].type) { - case USB_ENDPOINT_XFER_ISOC: - usbredir_stop_iso_stream(dev, I2EP(i)); - break; - case USB_ENDPOINT_XFER_INT: - if (i & 0x10) { - usbredir_stop_interrupt_receiving(dev, I2EP(i)); - } - break; - } - usbredir_free_bufpq(dev, I2EP(i)); + usbredir_stop_ep(dev, i); } set_config.configuration = config; @@ -799,17 +806,7 @@ static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, for (i = 0; i < MAX_ENDPOINTS; i++) { if (dev->endpoint[i].interface == interface) { - switch (dev->endpoint[i].type) { - case USB_ENDPOINT_XFER_ISOC: - usbredir_stop_iso_stream(dev, I2EP(i)); - break; - case USB_ENDPOINT_XFER_INT: - if (i & 0x10) { - usbredir_stop_interrupt_receiving(dev, I2EP(i)); - } - break; - } - usbredir_free_bufpq(dev, I2EP(i)); + usbredir_stop_ep(dev, i); } } From 7e9638d3eb5c0b4c5920dac72bb2e6885652c029 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:42 +0100 Subject: [PATCH 0270/1634] usbredir: Add USBEP2I and I2USBEP helper macros Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index c5704c176a..0ffcc7db48 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -44,6 +44,11 @@ #define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */ #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) +#define USBEP2I(usb_ep) (((usb_ep)->pid == USB_TOKEN_IN) ? \ + ((usb_ep)->nr | 0x10) : ((usb_ep)->nr)) +#define I2USBEP(d, i) (usb_ep_get(&(d)->dev, \ + ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \ + (i) & 0x0f)) typedef struct USBRedirDevice USBRedirDevice; @@ -1351,11 +1356,10 @@ static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep) static void usbredir_setup_usb_eps(USBRedirDevice *dev) { struct USBEndpoint *usb_ep; - int i, pid; + int i; for (i = 0; i < MAX_ENDPOINTS; i++) { - pid = (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT; - usb_ep = usb_ep_get(&dev->dev, pid, i & 0x0f); + usb_ep = I2USBEP(dev, i); usb_ep->type = dev->endpoint[i].type; usb_ep->ifnum = dev->endpoint[i].interface; usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; From d8553dd0475a967042193cdcf4d02c8ce5e73730 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:43 +0100 Subject: [PATCH 0271/1634] usbredir: Add ep_stopped USBDevice method To ensure that interrupt receiving is properly stopped when the guest is no longer interested in an interrupt endpoint. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 0ffcc7db48..855c76563a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -774,6 +774,14 @@ static void usbredir_stop_ep(USBRedirDevice *dev, int i) usbredir_free_bufpq(dev, ep); } +static void usbredir_ep_stopped(USBDevice *udev, USBEndpoint *uep) +{ + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + + usbredir_stop_ep(dev, USBEP2I(uep)); + usbredirparser_do_write(dev->parser); +} + static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p, int config) { @@ -1995,6 +2003,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usbredir_handle_data; uc->handle_control = usbredir_handle_control; uc->flush_ep_queue = usbredir_flush_ep_queue; + uc->ep_stopped = usbredir_ep_stopped; dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; } From d3aea641a4002e0abe940c65d318ef38eda245df Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:44 +0100 Subject: [PATCH 0272/1634] usbredir: Verify we have 32 bits bulk length cap when redirecting to xhci The xhci-hcd may submit bulk transfers > 65535 bytes even when not using bulk-in pipeling, so usbredir can only be used in combination with an xhci hcd if the client has the 32 bits bulk length capability. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 855c76563a..566737d8f5 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -979,6 +979,8 @@ static void usbredir_do_attach(void *opaque) if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !( usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_ep_info_max_packet_size) && + usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_32bits_bulk_length) && usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_64bits_ids))) { ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n"); From bd019b735ac422bf9a40e1865e3d59f2e128604f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:45 +0100 Subject: [PATCH 0273/1634] usbredir: Add usbredir_init_endpoints() helper Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 566737d8f5..ad22491f2c 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1063,6 +1063,17 @@ static void usbredir_vm_state_change(void *priv, int running, RunState state) } } +static void usbredir_init_endpoints(USBRedirDevice *dev) +{ + int i; + + usb_ep_init(&dev->dev); + memset(dev->endpoint, 0, sizeof(dev->endpoint)); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +} + static int usbredir_initfn(USBDevice *udev) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); @@ -1089,9 +1100,7 @@ static int usbredir_initfn(USBDevice *udev) packet_id_queue_init(&dev->cancelled, dev, "cancelled"); packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } + usbredir_init_endpoints(dev); /* We'll do the attach once we receive the speed from the usb-host */ udev->auto_attach = 0; @@ -1295,7 +1304,6 @@ static void usbredir_device_connect(void *priv, static void usbredir_device_disconnect(void *priv) { USBRedirDevice *dev = priv; - int i; /* Stop any pending attaches */ qemu_del_timer(dev->attach_timer); @@ -1312,11 +1320,7 @@ static void usbredir_device_disconnect(void *priv) /* Reset state so that the next dev connected starts with a clean slate */ usbredir_cleanup_device_queues(dev); - memset(dev->endpoint, 0, sizeof(dev->endpoint)); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } - usb_ep_init(&dev->dev); + usbredir_init_endpoints(dev); dev->interface_info.interface_count = NO_INTERFACE_INFO; dev->dev.addr = 0; dev->dev.speed = 0; From e97f0aca796fb949f9d34c50603511048a52b39b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Dec 2012 14:35:46 +0100 Subject: [PATCH 0274/1634] usb-redir: Add debugging to bufpq save / restore Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index ad22491f2c..f15dc914ab 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -61,6 +61,7 @@ struct buf_packet { }; struct endp_data { + USBRedirDevice *dev; uint8_t type; uint8_t interval; uint8_t interface; /* bInterfaceNumber this ep belongs to */ @@ -1070,6 +1071,7 @@ static void usbredir_init_endpoints(USBRedirDevice *dev) usb_ep_init(&dev->dev); memset(dev->endpoint, 0, sizeof(dev->endpoint)); for (i = 0; i < MAX_ENDPOINTS; i++) { + dev->endpoint[i].dev = dev; QTAILQ_INIT(&dev->endpoint[i].bufpq); } } @@ -1783,22 +1785,26 @@ static const VMStateInfo usbredir_parser_vmstate_info = { static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) { struct endp_data *endp = priv; + USBRedirDevice *dev = endp->dev; struct buf_packet *bufp; - int remain = endp->bufpq_size; + int i = 0; qemu_put_be32(f, endp->bufpq_size); QTAILQ_FOREACH(bufp, &endp->bufpq, next) { + DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, + bufp->len, bufp->status); qemu_put_be32(f, bufp->len); qemu_put_be32(f, bufp->status); qemu_put_buffer(f, bufp->data, bufp->len); - remain--; + i++; } - assert(remain == 0); + assert(i == endp->bufpq_size); } static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) { struct endp_data *endp = priv; + USBRedirDevice *dev = endp->dev; struct buf_packet *bufp; int i; @@ -1810,6 +1816,8 @@ static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ qemu_get_buffer(f, bufp->data, bufp->len); QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); + DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, + bufp->len, bufp->status); } return 0; } From a820b575787ac0b6b274b6a89aa6ef9813b4c782 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 14 Dec 2012 13:10:39 +0100 Subject: [PATCH 0275/1634] xhci: call set-address with dummy usbpacket Due to the way devices are addressed with xhci (done by hardware, not the guest os) there is no packet when invoking the set-address control request. Create a dummy packet in that case to avoid null pointer dereferences. Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 40542b8d05..9132920932 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1970,13 +1970,18 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, if (bsr) { slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT; } else { + USBPacket p; slot->devaddr = xhci->devaddr++; slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr; DPRINTF("xhci: device address is %d\n", slot->devaddr); usb_device_reset(dev); - usb_device_handle_control(dev, NULL, + usb_packet_setup(&p, USB_TOKEN_OUT, + usb_ep_get(dev, USB_TOKEN_OUT, 0), + 0, false, false); + usb_device_handle_control(dev, &p, DeviceOutRequest | USB_REQ_SET_ADDRESS, slot->devaddr, 0, 0, NULL); + assert(p.status != USB_RET_ASYNC); } res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx); From 5aa3ca9f53cc7a1bf76b7583c46937a73914394a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 16 Dec 2012 04:49:43 +0100 Subject: [PATCH 0276/1634] usb/ehci: Clean up SysBus and PCI EHCI split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SysBus EHCI was introduced in a hurry before 1.3 Soft Freeze. To use QOM casts in place of DO_UPCAST() / FROM_SYSBUS(), we need an identifying type. Introduce generic abstract base types for PCI and SysBus EHCI to allow multiple types to access the shared fields. While at it, move the state structs being amended with macros to the header file so that they can be embedded. The VMSTATE_PCI_DEVICE() macro does not play nice with the QOM parent_obj naming convention, so defer that cleanup. Signed-off-by: Andreas Färber Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci-pci.c | 39 ++++++++++++++++++++++++--------------- hw/usb/hcd-ehci-sysbus.c | 19 ++++++++++--------- hw/usb/hcd-ehci.h | 26 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index ee77d41db5..0eb78269f7 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -16,14 +16,8 @@ */ #include "hw/usb/hcd-ehci.h" -#include "hw/pci/pci.h" #include "qemu/range.h" -typedef struct EHCIPCIState { - PCIDevice pcidev; - EHCIState ehci; -} EHCIPCIState; - typedef struct EHCIPCIInfo { const char *name; uint16_t vendor_id; @@ -33,7 +27,7 @@ typedef struct EHCIPCIInfo { static int usb_ehci_pci_initfn(PCIDevice *dev) { - EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev); + EHCIPCIState *i = PCI_EHCI(dev); EHCIState *s = &i->ehci; uint8_t *pci_conf = dev->config; @@ -83,7 +77,7 @@ static int usb_ehci_pci_initfn(PCIDevice *dev) static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int l) { - EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev); + EHCIPCIState *i = PCI_EHCI(dev); bool busmaster; pci_default_write_config(dev, addr, val, l); @@ -115,12 +109,8 @@ static void ehci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - EHCIPCIInfo *i = data; k->init = usb_ehci_pci_initfn; - k->vendor_id = i->vendor_id; - k->device_id = i->device_id; - k->revision = i->revision; k->class_id = PCI_CLASS_SERIAL_USB; k->config_write = usb_ehci_pci_write_config; k->no_hotplug = 1; @@ -128,6 +118,24 @@ static void ehci_class_init(ObjectClass *klass, void *data) dc->props = ehci_pci_properties; } +static const TypeInfo ehci_pci_type_info = { + .name = TYPE_PCI_EHCI, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EHCIPCIState), + .abstract = true, + .class_init = ehci_class_init, +}; + +static void ehci_data_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + EHCIPCIInfo *i = data; + + k->vendor_id = i->vendor_id; + k->device_id = i->device_id; + k->revision = i->revision; +} + static struct EHCIPCIInfo ehci_pci_info[] = { { .name = "usb-ehci", @@ -150,12 +158,13 @@ static struct EHCIPCIInfo ehci_pci_info[] = { static void ehci_pci_register_types(void) { TypeInfo ehci_type_info = { - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EHCIPCIState), - .class_init = ehci_class_init, + .parent = TYPE_PCI_EHCI, + .class_init = ehci_data_class_init, }; int i; + type_register_static(&ehci_pci_type_info); + for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) { ehci_type_info.name = ehci_pci_info[i].name; ehci_type_info.class_data = ehci_pci_info + i; diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 803df92f31..d4311936ba 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -16,12 +16,6 @@ */ #include "hw/usb/hcd-ehci.h" -#include "hw/sysbus.h" - -typedef struct EHCISysBusState { - SysBusDevice busdev; - EHCIState ehci; -} EHCISysBusState; static const VMStateDescription vmstate_ehci_sysbus = { .name = "ehci-sysbus", @@ -40,7 +34,7 @@ static Property ehci_sysbus_properties[] = { static int usb_ehci_sysbus_initfn(SysBusDevice *dev) { - EHCISysBusState *i = FROM_SYSBUS(EHCISysBusState, dev); + EHCISysBusState *i = SYS_BUS_EHCI(dev); EHCIState *s = &i->ehci; s->capsbase = 0x100; @@ -63,15 +57,22 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data) dc->props = ehci_sysbus_properties; } -TypeInfo ehci_xlnx_type_info = { - .name = "xlnx,ps7-usb", +static const TypeInfo ehci_type_info = { + .name = TYPE_SYS_BUS_EHCI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(EHCISysBusState), + .abstract = true, .class_init = ehci_sysbus_class_init, }; +static const TypeInfo ehci_xlnx_type_info = { + .name = "xlnx,ps7-usb", + .parent = TYPE_SYS_BUS_EHCI, +}; + static void ehci_sysbus_register_types(void) { + type_register_static(&ehci_type_info); type_register_static(&ehci_xlnx_type_info); } diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 14ee3bea5a..5ba3faf2b8 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -24,6 +24,8 @@ #include "trace.h" #include "sysemu/dma.h" #include "sysemu/sysemu.h" +#include "hw/pci/pci.h" +#include "hw/sysbus.h" #ifndef EHCI_DEBUG #define EHCI_DEBUG 0 @@ -322,4 +324,28 @@ extern const VMStateDescription vmstate_ehci; void usb_ehci_initfn(EHCIState *s, DeviceState *dev); +#define TYPE_PCI_EHCI "pci-ehci-usb" +#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI) + +typedef struct EHCIPCIState { + /*< private >*/ + PCIDevice pcidev; + /*< public >*/ + + EHCIState ehci; +} EHCIPCIState; + + +#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" +#define SYS_BUS_EHCI(obj) \ + OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI) + +typedef struct EHCISysBusState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + EHCIState ehci; +} EHCISysBusState; + #endif From 4a4343671e183824a3f5db76ad561ce01e6c6e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 16 Dec 2012 04:49:44 +0100 Subject: [PATCH 0277/1634] usb/ehci: Move capsbase and opregbase into SysBus EHCI class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows specific derived models to use different values. Signed-off-by: Andreas Färber Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci-sysbus.c | 15 +++++++++++++-- hw/usb/hcd-ehci.h | 13 +++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index d4311936ba..5a94ce31ef 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -35,10 +35,11 @@ static Property ehci_sysbus_properties[] = { static int usb_ehci_sysbus_initfn(SysBusDevice *dev) { EHCISysBusState *i = SYS_BUS_EHCI(dev); + SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(dev); EHCIState *s = &i->ehci; - s->capsbase = 0x100; - s->opregbase = 0x140; + s->capsbase = sec->capsbase; + s->opregbase = sec->opregbase; s->dma = &dma_context_memory; usb_ehci_initfn(s, DEVICE(dev)); @@ -63,11 +64,21 @@ static const TypeInfo ehci_type_info = { .instance_size = sizeof(EHCISysBusState), .abstract = true, .class_init = ehci_sysbus_class_init, + .class_size = sizeof(SysBusEHCIClass), }; +static void ehci_xlnx_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + + sec->capsbase = 0x100; + sec->opregbase = 0x140; +} + static const TypeInfo ehci_xlnx_type_info = { .name = "xlnx,ps7-usb", .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_xlnx_class_init, }; static void ehci_sysbus_register_types(void) diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 5ba3faf2b8..2b0b5a17ab 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -339,6 +339,10 @@ typedef struct EHCIPCIState { #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" #define SYS_BUS_EHCI(obj) \ OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI) +#define SYS_BUS_EHCI_CLASS(class) \ + OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI) +#define SYS_BUS_EHCI_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI) typedef struct EHCISysBusState { /*< private >*/ @@ -348,4 +352,13 @@ typedef struct EHCISysBusState { EHCIState ehci; } EHCISysBusState; +typedef struct SysBusEHCIClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + + uint16_t capsbase; + uint16_t opregbase; +} SysBusEHCIClass; + #endif From aee7499a59d6778c10b018da41db4a22655ef8a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 16 Dec 2012 04:49:45 +0100 Subject: [PATCH 0278/1634] usb/ehci: Add SysBus EHCI device for Exynos4210 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It uses a different capsbase and opregbase than the Xilinx device. Signed-off-by: Liming Wang Signed-off-by: Andreas Färber Cc: Igor Mitsyanko Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci-sysbus.c | 15 +++++++++++++++ hw/usb/hcd-ehci.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 5a94ce31ef..b68a66a63b 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -81,10 +81,25 @@ static const TypeInfo ehci_xlnx_type_info = { .class_init = ehci_xlnx_class_init, }; +static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + + sec->capsbase = 0x0; + sec->opregbase = 0x10; +} + +static const TypeInfo ehci_exynos4210_type_info = { + .name = TYPE_EXYNOS4210_EHCI, + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_exynos4210_class_init, +}; + static void ehci_sysbus_register_types(void) { type_register_static(&ehci_type_info); type_register_static(&ehci_xlnx_type_info); + type_register_static(&ehci_exynos4210_type_info); } type_init(ehci_sysbus_register_types) diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 2b0b5a17ab..e95bb7ec46 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -337,6 +337,8 @@ typedef struct EHCIPCIState { #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" +#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb" + #define SYS_BUS_EHCI(obj) \ OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI) #define SYS_BUS_EHCI_CLASS(class) \ From 358d615b6908b4916c74819ffad823cb4a74314e Mon Sep 17 00:00:00 2001 From: Liming Wang Date: Sun, 16 Dec 2012 04:49:46 +0100 Subject: [PATCH 0279/1634] exynos4210: Add EHCI support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add EHCI USB host controller to exynos4210. Signed-off-by: Liming Wang Signed-off-by: Andreas Färber Reviewed-by: Igor Mitsyanko Signed-off-by: Gerd Hoffmann --- hw/exynos4210.c | 7 +++++++ hw/exynos4210_gic.c | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/exynos4210.c b/hw/exynos4210.c index a7b84d61a0..246a0fc1c3 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -27,6 +27,7 @@ #include "arm-misc.h" #include "loader.h" #include "exynos4210.h" +#include "usb/hcd-ehci.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@ -72,6 +73,9 @@ /* Display controllers (FIMD) */ #define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000 +/* EHCI */ +#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000 + static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; @@ -338,5 +342,8 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, s->irq_table[exynos4210_get_irq(11, 2)], NULL); + sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR, + s->irq_table[exynos4210_get_irq(28, 3)]); + return s; } diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 4fea09873a..959de5679d 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -140,7 +140,7 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, EXT_GIC_ID_I2C7 }, /* int combiner group 28 */ - { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 }, + { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST}, /* int combiner group 29 */ { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, From 71c6cacb241689bbf99d54467dc2ae6912ffdab9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:11:59 +0000 Subject: [PATCH 0280/1634] openpic: symbolicize some magic numbers Deefine symbolic names for some register bits, and use some that have already been defined. Also convert some register values from hex to decimal when it improves readability. IPVP_PRIORITY_MASK is corrected from (0x1F << 16) to (0xF << 16), in conjunction with making wider use of the symbolic name. I looked at Freescale and IBM MPIC docs and at the base OpenPIC spec, and all three had priority as 4 bits rather than 5. Plus, the magic nubmer that is being replaced with symbolic values treated the field as 4 bits wide. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 54 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 9c956b9dcc..eff1eee010 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -124,6 +124,11 @@ #define VENI_GENERIC 0x00000000 /* Generic Vendor ID */ +#define GLBC_RESET 0x80000000 + +#define TIBC_CI 0x80000000 /* count inhibit */ +#define TICC_TOG 0x80000000 /* toggles when decrement to zero */ + #define IDR_EP_SHIFT 31 #define IDR_EP_MASK (1 << IDR_EP_SHIFT) #define IDR_CI0_SHIFT 30 @@ -190,11 +195,15 @@ typedef struct IRQ_src_t { #define IPVP_SENSE_SHIFT 22 #define IPVP_SENSE_MASK (1 << IPVP_SENSE_SHIFT) -#define IPVP_PRIORITY_MASK (0x1F << 16) +#define IPVP_PRIORITY_MASK (0xF << 16) #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) +/* IDE[EP/CI] are only for FSL MPIC prior to v4.0 */ +#define IDE_EP 0x80000000 /* external pin */ +#define IDE_CI 0x40000000 /* critical interrupt */ + typedef struct IRQ_dst_t { uint32_t pctp; /* CPU current task priority */ uint32_t pcsr; /* CPU sensitivity register */ @@ -375,7 +384,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; } - if (src->ide == 0x00000000) { + if (src->ide == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; @@ -432,13 +441,13 @@ static void openpic_reset(DeviceState *d) OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d)); int i; - opp->glbc = 0x80000000; + opp->glbc = GLBC_RESET; /* Initialise controller registers */ opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) | ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) | (opp->vid << FREP_VID_SHIFT); - opp->pint = 0x00000000; + opp->pint = 0; opp->spve = -1 & opp->spve_mask; opp->tifr = opp->tifr_reset; /* Initialise IRQ sources */ @@ -448,7 +457,7 @@ static void openpic_reset(DeviceState *d) } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].pctp = 0x0000000F; + opp->dst[i].pctp = 15; opp->dst[i].pcsr = 0x00000000; memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); opp->dst[i].raised.next = -1; @@ -457,11 +466,11 @@ static void openpic_reset(DeviceState *d) } /* Initialise timers */ for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].ticc = 0x00000000; - opp->timers[i].tibc = 0x80000000; + opp->timers[i].ticc = 0; + opp->timers[i].tibc = TIBC_CI; } /* Go out of RESET state */ - opp->glbc = 0x00000000; + opp->glbc = 0; } static inline uint32_t read_IRQreg_ide(OpenPICState *opp, int n_IRQ) @@ -478,7 +487,7 @@ static inline void write_IRQreg_ide(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t tmp; - tmp = val & 0xC0000000; + tmp = val & (IDE_EP | IDE_CI); tmp |= val & ((1ULL << MAX_CPU) - 1); opp->src[n_IRQ].ide = tmp; DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); @@ -488,8 +497,8 @@ static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) { /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000) - | (val & 0x800F00FF); + opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & IPVP_ACTIVITY_MASK) | + (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | IPVP_VECTOR_MASK)); openpic_update_irq(opp, n_IRQ); DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ipvp); @@ -521,7 +530,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x1000: /* FREP */ break; case 0x1020: /* GLBC */ - if (val & 0x80000000) { + if (val & GLBC_RESET) { openpic_reset(&opp->busdev.qdev); } break; @@ -634,10 +643,11 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, case 0x00: /* TICC (GTCCR) */ break; case 0x10: /* TIBC (GTBCR) */ - if ((opp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x80000000) == 0 && - (opp->timers[idx].tibc & 0x80000000) != 0) - opp->timers[idx].ticc &= ~0x80000000; + if ((opp->timers[idx].ticc & TICC_TOG) != 0 && + (val & TIBC_CI) == 0 && + (opp->timers[idx].tibc & TIBC_CI) != 0) { + opp->timers[idx].ticc &= ~TICC_TOG; + } opp->timers[idx].tibc = val; break; case 0x20: /* TIVP (GTIVPR) */ @@ -1190,9 +1200,9 @@ static int openpic_init(SysBusDevice *dev) opp->vid = VID_REVISION_1_2; opp->veni = VENI_GENERIC; opp->spve_mask = 0xFFFF; - opp->tifr_reset = 0x00000000; - opp->ipvp_reset = 0x80000000; - opp->ide_reset = 0x00000001; + opp->tifr_reset = 0; + opp->ipvp_reset = IPVP_MASK_MASK; + opp->ide_reset = 1 << 0; opp->max_irq = FSL_MPIC_20_MAX_IRQ; opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; @@ -1206,9 +1216,9 @@ static int openpic_init(SysBusDevice *dev) opp->vid = VID_REVISION_1_3; opp->veni = VENI_GENERIC; opp->spve_mask = 0xFF; - opp->tifr_reset = 0x003F7A00; - opp->ipvp_reset = 0xA0000000; - opp->ide_reset = 0x00000000; + opp->tifr_reset = 4160000; + opp->ipvp_reset = IPVP_MASK_MASK | IPVP_MODE_MASK; + opp->ide_reset = 0; opp->max_irq = RAVEN_MAX_IRQ; opp->irq_ipi0 = RAVEN_IPI_IRQ; opp->irq_tim0 = RAVEN_TMR_IRQ; From c975330ec4f5674f2899331f914c04ecba6edf26 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:00 +0000 Subject: [PATCH 0281/1634] openpic: remove pcsr (CPU sensitivity register) I could not find this register in any spec (FSL, IBM, or OpenPIC) and the code doesn't do anything with it but initialize, save, or restore it. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index eff1eee010..44f7cc4731 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -206,7 +206,6 @@ typedef struct IRQ_src_t { typedef struct IRQ_dst_t { uint32_t pctp; /* CPU current task priority */ - uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; IRQ_queue_t servicing; qemu_irq *irqs; @@ -458,7 +457,6 @@ static void openpic_reset(DeviceState *d) /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { opp->dst[i].pctp = 15; - opp->dst[i].pcsr = 0x00000000; memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); opp->dst[i].raised.next = -1; memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); @@ -1083,7 +1081,6 @@ static void openpic_save(QEMUFile* f, void *opaque) for (i = 0; i < opp->nb_cpus; i++) { qemu_put_be32s(f, &opp->dst[i].pctp); - qemu_put_be32s(f, &opp->dst[i].pcsr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); } @@ -1130,7 +1127,6 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) for (i = 0; i < opp->nb_cpus; i++) { qemu_get_be32s(f, &opp->dst[i].pctp); - qemu_get_be32s(f, &opp->dst[i].pcsr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); } From 0fe04622c11a4f131070196ad5cd97ce94d9c33b Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:01 +0000 Subject: [PATCH 0282/1634] openpic: support large vectors on FSL mpic Previously only the spurious vector was sized appropriately to the openpic model. Also, instances of "IPVP_VECTOR(opp->spve)" were replace with just "opp->spve", as opp->spve is already just a vector and not an IVPR. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 44f7cc4731..f0877fae5e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -51,7 +51,6 @@ #define MAX_CPU 15 #define MAX_SRC 256 #define MAX_TMR 4 -#define VECTOR_BITS 8 #define MAX_IPI 4 #define MAX_MSI 8 #define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) @@ -197,8 +196,7 @@ typedef struct IRQ_src_t { #define IPVP_PRIORITY_MASK (0xF << 16) #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) -#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) -#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) +#define IPVP_VECTOR(opp, _ipvpr_) ((_ipvpr_) & (opp)->vector_mask) /* IDE[EP/CI] are only for FSL MPIC prior to v4.0 */ #define IDE_EP 0x80000000 /* external pin */ @@ -221,7 +219,7 @@ typedef struct OpenPICState { uint32_t nb_irqs; uint32_t vid; uint32_t veni; /* Vendor identification register */ - uint32_t spve_mask; + uint32_t vector_mask; uint32_t tifr_reset; uint32_t ipvp_reset; uint32_t ide_reset; @@ -447,7 +445,7 @@ static void openpic_reset(DeviceState *d) (opp->vid << FREP_VID_SHIFT); opp->pint = 0; - opp->spve = -1 & opp->spve_mask; + opp->spve = -1 & opp->vector_mask; opp->tifr = opp->tifr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { @@ -496,7 +494,7 @@ static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & IPVP_ACTIVITY_MASK) | - (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | IPVP_VECTOR_MASK)); + (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | opp->vector_mask)); openpic_update_irq(opp, n_IRQ); DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ipvp); @@ -559,7 +557,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, } break; case 0x10E0: /* SPVE */ - opp->spve = val & opp->spve_mask; + opp->spve = val & opp->vector_mask; break; default: break; @@ -896,7 +894,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, DPRINTF("PIAC: irq=%d\n", n_IRQ); if (n_IRQ == -1) { /* No more interrupt pending */ - retval = IPVP_VECTOR(opp->spve); + retval = opp->spve; } else { src = &opp->src[n_IRQ]; if (!(src->ipvp & IPVP_ACTIVITY_MASK) || @@ -906,11 +904,11 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, * and the pending IRQ isn't allowed anymore */ src->ipvp &= ~IPVP_ACTIVITY_MASK; - retval = IPVP_VECTOR(opp->spve); + retval = opp->spve; } else { /* IRQ enter servicing state */ IRQ_setbit(&dst->servicing, n_IRQ); - retval = IPVP_VECTOR(src->ipvp); + retval = IPVP_VECTOR(opp, src->ipvp); } IRQ_resetbit(&dst->raised, n_IRQ); dst->raised.next = -1; @@ -1195,7 +1193,7 @@ static int openpic_init(SysBusDevice *dev) opp->nb_irqs = 80; opp->vid = VID_REVISION_1_2; opp->veni = VENI_GENERIC; - opp->spve_mask = 0xFFFF; + opp->vector_mask = 0xFFFF; opp->tifr_reset = 0; opp->ipvp_reset = IPVP_MASK_MASK; opp->ide_reset = 1 << 0; @@ -1211,7 +1209,7 @@ static int openpic_init(SysBusDevice *dev) opp->nb_irqs = RAVEN_MAX_EXT; opp->vid = VID_REVISION_1_3; opp->veni = VENI_GENERIC; - opp->spve_mask = 0xFF; + opp->vector_mask = 0xFF; opp->tifr_reset = 4160000; opp->ipvp_reset = IPVP_MASK_MASK | IPVP_MODE_MASK; opp->ide_reset = 0; From 0d4046833ba44c5f29e5dcce2dde0a6202225e59 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:03 +0000 Subject: [PATCH 0283/1634] openpic: BRR1 is not a CPU-specific register. It's in the address range that normally contains a magic redirection to the CPU-specific region of the curretn CPU, but it isn't actually a per-CPU register. On real hardware BRR1 shows up only at 0x40000, not at 0x60000 or other non-magic per-CPU areas. Plus, this makes it possible to read the register on the QEMU command line with "xp". Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index f0877fae5e..337dbf5a44 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -587,6 +587,8 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) retval = 0x00000000; break; case 0x00: /* Block Revision Register1 (BRR1) */ + retval = opp->brr1; + break; case 0x40: case 0x50: case 0x60: @@ -878,9 +880,6 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { - case 0x00: /* Block Revision Register1 (BRR1) */ - retval = opp->brr1; - break; case 0x80: /* PCTP */ retval = dst->pctp; break; From a26a7b38331dc14893a66fbe78f34afab153d6b2 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:04 +0000 Subject: [PATCH 0284/1634] openpic: s/opp->nb_irqs -1/opp->nb_cpus - 1/ "opp->nb_irqs-1" would have been a minor coding style error, but putting in one space but not the other makes it look confusingly like a numeric literal "-1". Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 337dbf5a44..10dbdf7863 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -440,8 +440,8 @@ static void openpic_reset(DeviceState *d) opp->glbc = GLBC_RESET; /* Initialise controller registers */ - opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) | - ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) | + opp->frep = ((opp->nb_irqs - 1) << FREP_NIRQ_SHIFT) | + ((opp->nb_cpus - 1) << FREP_NCPU_SHIFT) | (opp->vid << FREP_VID_SHIFT); opp->pint = 0; From c3203fa5b2c17a1c446e44c87788fef21b4af5f4 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 13 Dec 2012 16:12:02 +0000 Subject: [PATCH 0285/1634] openpic: don't crash on a register access without a CPU context If we access a register via the QEMU memory inspection commands (e.g. "xp") rather than from guest code, we won't have a CPU context. Gracefully fail to access the register in that case, rather than crashing. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/openpic.c b/hw/openpic.c index 10dbdf7863..93e8208075 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -161,7 +161,11 @@ static inline int test_bit(uint32_t *field, int bit) static int get_current_cpu(void) { - return cpu_single_env->cpu_index; + if (!cpu_single_env) { + return -1; + } + + return cpu_single_env->cpu_index; } static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, @@ -810,6 +814,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, addr, val); + + if (idx < 0) { + return; + } + if (addr & 0xF) return; dst = &opp->dst[idx]; @@ -875,6 +884,11 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; + + if (idx < 0) { + return retval; + } + if (addr & 0xF) return retval; dst = &opp->dst[idx]; From d56af005dc3d6354bd39411e8446b415bbcf86b8 Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Tue, 18 Dec 2012 01:13:58 +0000 Subject: [PATCH 0286/1634] powerpc: linux header sync script includes epapr_hcalls.h epapr_hcalls.h is now referenced by kvm_para.h. so this is needed for QEMU to get compiled on powerpc. Signed-off-by: Bharat Bhushan Signed-off-by: Alexander Graf --- scripts/update-linux-headers.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 4c7b566fdf..120a694313 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -54,6 +54,9 @@ for arch in $ARCHLIST; do if [ $arch = x86 ]; then cp "$tmpdir/include/asm/hyperv.h" "$output/linux-headers/asm-x86" fi + if [ $arch = powerpc ]; then + cp "$tmpdir/include/asm/epapr_hcalls.h" "$output/linux-headers/asm-powerpc/" + fi done rm -rf "$output/linux-headers/linux" From af7e9e74c6a62a5bcd911726a9e88d28b61490e0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 20 Dec 2012 17:30:58 +0100 Subject: [PATCH 0287/1634] openpic: fix coding style issues This patch fixes the following coding style violations: - structs have to be typedef and be CamelCase - if()s are always surrounded by curly braces Signed-off-by: Alexander Graf --- hw/openpic.c | 100 ++++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 93e8208075..55e96d1334 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -173,19 +173,19 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); -typedef struct IRQ_queue_t { +typedef struct IRQQueue { uint32_t queue[BF_WIDTH(MAX_IRQ)]; int next; int priority; int pending; /* nr of pending bits in queue */ -} IRQ_queue_t; +} IRQQueue; -typedef struct IRQ_src_t { +typedef struct IRQSource { uint32_t ipvp; /* IRQ vector/priority register */ uint32_t ide; /* IRQ destination register */ int last_cpu; int pending; /* TRUE if IRQ is pending */ -} IRQ_src_t; +} IRQSource; #define IPVP_MASK_SHIFT 31 #define IPVP_MASK_MASK (1 << IPVP_MASK_SHIFT) @@ -206,12 +206,12 @@ typedef struct IRQ_src_t { #define IDE_EP 0x80000000 /* external pin */ #define IDE_CI 0x40000000 /* critical interrupt */ -typedef struct IRQ_dst_t { +typedef struct IRQDest { uint32_t pctp; /* CPU current task priority */ - IRQ_queue_t raised; - IRQ_queue_t servicing; + IRQQueue raised; + IRQQueue servicing; qemu_irq *irqs; -} IRQ_dst_t; +} IRQDest; typedef struct OpenPICState { SysBusDevice busdev; @@ -239,9 +239,9 @@ typedef struct OpenPICState { uint32_t spve; /* Spurious vector register */ uint32_t tifr; /* Timer frequency reporting register */ /* Source registers */ - IRQ_src_t src[MAX_IRQ]; + IRQSource src[MAX_IRQ]; /* Local registers per output pin */ - IRQ_dst_t dst[MAX_CPU]; + IRQDest dst[MAX_CPU]; uint32_t nb_cpus; /* Timer registers */ struct { @@ -258,26 +258,26 @@ typedef struct OpenPICState { uint32_t irq_msi; } OpenPICState; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src); +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src); -static inline void IRQ_setbit(IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { q->pending++; set_bit(q->queue, n_IRQ); } -static inline void IRQ_resetbit(IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) { q->pending--; reset_bit(q->queue, n_IRQ); } -static inline int IRQ_testbit(IRQ_queue_t *q, int n_IRQ) +static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) { return test_bit(q->queue, n_IRQ); } -static void IRQ_check(OpenPICState *opp, IRQ_queue_t *q) +static void IRQ_check(OpenPICState *opp, IRQQueue *q) { int next, i; int priority; @@ -306,7 +306,7 @@ out: q->priority = priority; } -static int IRQ_get_next(OpenPICState *opp, IRQ_queue_t *q) +static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) { if (q->next == -1) { /* XXX: optimize */ @@ -318,8 +318,8 @@ static int IRQ_get_next(OpenPICState *opp, IRQ_queue_t *q) static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) { - IRQ_dst_t *dst; - IRQ_src_t *src; + IRQDest *dst; + IRQSource *src; int priority; dst = &opp->dst[n_CPU]; @@ -360,7 +360,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) /* update pic state because registers for n_IRQ have changed value */ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) { - IRQ_src_t *src; + IRQSource *src; int i; src = &opp->src[n_IRQ]; @@ -404,8 +404,9 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) } else { /* Distributed delivery mode */ for (i = src->last_cpu + 1; i != src->last_cpu; i++) { - if (i == opp->nb_cpus) + if (i == opp->nb_cpus) { i = 0; + } if (src->ide & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; @@ -418,7 +419,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) static void openpic_set_irq(void *opaque, int n_IRQ, int level) { OpenPICState *opp = opaque; - IRQ_src_t *src; + IRQSource *src; src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", @@ -431,8 +432,9 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) } } else { /* edge-sensitive irq */ - if (level) + if (level) { src->pending = 1; + } } openpic_update_irq(opp, n_IRQ); } @@ -459,9 +461,9 @@ static void openpic_reset(DeviceState *d) /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { opp->dst[i].pctp = 15; - memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); + memset(&opp->dst[i].raised, 0, sizeof(IRQQueue)); opp->dst[i].raised.next = -1; - memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); + memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue)); opp->dst[i].servicing.next = -1; } /* Initialise timers */ @@ -508,12 +510,13 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { OpenPICState *opp = opaque; - IRQ_dst_t *dst; + IRQDest *dst; int idx; DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) + if (addr & 0xF) { return; + } switch (addr) { case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ break; @@ -575,8 +578,9 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) + if (addr & 0xF) { return retval; + } switch (addr) { case 0x1000: /* FREP */ retval = opp->frep; @@ -631,8 +635,9 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) + if (addr & 0xF) { return; + } idx = (addr >> 6) & 0x3; addr = addr & 0x30; @@ -705,8 +710,9 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) + if (addr & 0xF) { return; + } addr = addr & 0xFFF0; idx = addr >> 5; if (addr & 0x10) { @@ -726,8 +732,9 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) DPRINTF("%s: addr %08x\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) + if (addr & 0xF) { return retval; + } addr = addr & 0xFFF0; idx = addr >> 5; if (addr & 0x10) { @@ -808,8 +815,8 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx) { OpenPICState *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; + IRQSource *src; + IRQDest *dst; int s_IRQ, n_IRQ; DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, @@ -819,8 +826,9 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, return; } - if (addr & 0xF) + if (addr & 0xF) { return; + } dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { @@ -877,8 +885,8 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx) { OpenPICState *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; + IRQSource *src; + IRQDest *dst; uint32_t retval; int n_IRQ; @@ -889,8 +897,9 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, return retval; } - if (addr & 0xF) + if (addr & 0xF) { return retval; + } dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { @@ -1059,7 +1068,7 @@ static const MemoryRegionOps openpic_msi_ops_be = { }, }; -static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) +static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; @@ -1102,7 +1111,7 @@ static void openpic_save(QEMUFile* f, void *opaque) } } -static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) +static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; @@ -1118,8 +1127,9 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - if (version_id != 1) + if (version_id != 1) { return -EINVAL; + } qemu_get_be32s(f, &opp->glbc); qemu_get_be32s(f, &opp->veni); @@ -1150,7 +1160,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) return 0; } -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src) +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src) { int n_ci = IDR_CI0_SHIFT - n_CPU; @@ -1161,19 +1171,19 @@ static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src) } } -struct memreg { +typedef struct MemReg { const char *name; MemoryRegionOps const *ops; bool map; hwaddr start_addr; ram_addr_t size; -}; +} MemReg; static int openpic_init(SysBusDevice *dev) { OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); int i, j; - struct memreg list_le[] = { + MemReg list_le[] = { {"glb", &openpic_glb_ops_le, true, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, {"tmr", &openpic_tmr_ops_le, true, @@ -1185,7 +1195,7 @@ static int openpic_init(SysBusDevice *dev) {"cpu", &openpic_cpu_ops_le, true, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, }; - struct memreg list_be[] = { + MemReg list_be[] = { {"glb", &openpic_glb_ops_be, true, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, {"tmr", &openpic_tmr_ops_be, true, @@ -1197,7 +1207,7 @@ static int openpic_init(SysBusDevice *dev) {"cpu", &openpic_cpu_ops_be, true, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, }; - struct memreg *list; + MemReg *list; switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: From 88a78d9093917096feffeba66802be27d0e64ead Mon Sep 17 00:00:00 2001 From: Bharat Bhushan Date: Thu, 27 Dec 2012 19:16:51 +0000 Subject: [PATCH 0288/1634] PPC: Reset qemu timers when guest reset This patch install the timer reset handler. This will be called when the guest is reset. Signed-off-by: Bharat Bhushan [agraf: adjust for QOM'ification] Signed-off-by: Alexander Graf --- hw/ppc_booke.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index 4483b8d292..25a4e91b69 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -237,6 +237,17 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) } +static void ppc_booke_timer_reset_handle(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + env->spr[SPR_BOOKE_TSR] = 0; + env->spr[SPR_BOOKE_TCR] = 0; + + booke_update_irq(cpu); +} + void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) { ppc_tb_t *tb_env; @@ -257,4 +268,6 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu); booke_timer->wdt_timer = qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); + + qemu_register_reset(ppc_booke_timer_reset_handle, cpu); } From beb526b12134a6b6744125deec5a7fe24a8f92e3 Mon Sep 17 00:00:00 2001 From: Samuel Seay Date: Wed, 2 Jan 2013 10:53:46 +0000 Subject: [PATCH 0289/1634] PPC: fix segfault in signal handling code Removed h2g() macro around the ka->_sa_handler due to the _sa_handler being a guest memory address. Changed the __put_user to put_user as it was attempting to put a value at the stack address but the new address is a guest memory address, __put_user is for host memory addresses. Signed-off-by: Samuel Seay Reviewed-by: Peter Maydell [agraf: change subject line, reformat commit message] Signed-off-by: Alexander Graf --- linux-user/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 95e2ffa007..c43b8ac30a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4584,7 +4584,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, signal = current_exec_domain_sig(sig); - err |= __put_user(h2g(ka->_sa_handler), &sc->handler); + err |= __put_user(ka->_sa_handler, &sc->handler); err |= __put_user(set->sig[0], &sc->oldmask); #if defined(TARGET_PPC64) err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]); @@ -4606,7 +4606,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* Create a stack frame for the caller of the handler. */ newsp = frame_addr - SIGNAL_FRAMESIZE; - err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp); + err |= put_user(env->gpr[1], newsp, target_ulong); if (err) goto sigsegv; From 4c4f0e4801ac79632d03867c88aafc90b4ce503c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:38 +0000 Subject: [PATCH 0290/1634] openpic: fix debug prints Fix various format errors when debug prints are enabled. Also cause error checking to happen even when debug prints are not enabled, and consistently use 0x for hex output. Signed-off-by: Scott Wood [agraf: adjust for more recent code base, prettify DPRINTF macro] Signed-off-by: Alexander Graf --- hw/openpic.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 55e96d1334..9243e70db8 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -43,11 +43,17 @@ //#define DEBUG_OPENPIC #ifdef DEBUG_OPENPIC -#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0) +static const int debug_openpic = 1; #else -#define DPRINTF(fmt, ...) do { } while (0) +static const int debug_openpic = 0; #endif +#define DPRINTF(fmt, ...) do { \ + if (debug_openpic) { \ + printf(fmt , ## __VA_ARGS__); \ + } \ + } while (0) + #define MAX_CPU 15 #define MAX_SRC 256 #define MAX_TMR 4 @@ -422,7 +428,7 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) IRQSource *src; src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", + DPRINTF("openpic: set irq %d = %d ipvp=0x%08x\n", n_IRQ, level, src->ipvp); if (src->ipvp & IPVP_SENSE_MASK) { /* level-sensitive irq */ @@ -513,7 +519,8 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, IRQDest *dst; int idx; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -576,7 +583,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) OpenPICState *opp = opaque; uint32_t retval; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; if (addr & 0xF) { return retval; @@ -623,7 +630,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) default: break; } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -634,7 +641,8 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -672,7 +680,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) uint32_t retval = -1; int idx; - DPRINTF("%s: addr %08x\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); if (addr & 0xF) { goto out; } @@ -698,7 +706,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) } out: - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -709,7 +717,8 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -730,7 +739,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) uint32_t retval; int idx; - DPRINTF("%s: addr %08x\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; if (addr & 0xF) { return retval; @@ -744,7 +753,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) /* EXVP / IFEVP / IEEVP */ retval = read_IRQreg_ipvp(opp, idx); } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -756,7 +765,8 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, int idx = opp->irq_msi; int srs, ibs; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", + __func__, addr, val); if (addr & 0xF) { return; } @@ -781,7 +791,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) uint64_t r = 0; int i, srs; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); if (addr & 0xF) { return -1; } @@ -819,7 +829,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, IRQDest *dst; int s_IRQ, n_IRQ; - DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx, addr, val); if (idx < 0) { @@ -890,7 +900,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, uint32_t retval; int n_IRQ; - DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr); + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; if (idx < 0) { @@ -958,7 +968,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, default: break; } - DPRINTF("%s: => %08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } From e99fd8af63a1692a1159cba8fa4943f2589adf97 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:39 +0000 Subject: [PATCH 0291/1634] openpic: lower interrupt when reading the MSI register This will stop things from breaking once it's properly treated as a level-triggered interrupt. Note that it's the MPIC's MSI cascade interrupts that are level-triggered; the individual MSIs are edge-triggered. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/openpic.c b/hw/openpic.c index 9243e70db8..f4df66dc10 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -810,6 +810,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) r = opp->msi[srs].msir; /* Clear on read */ opp->msi[srs].msir = 0; + openpic_set_irq(opp, opp->irq_msi + srs, 0); break; case 0x120: /* MSISR */ for (i = 0; i < MAX_MSI; i++) { From a1bb73849fbd7d992b6ac2cf30c034244fb2299d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:41 +0000 Subject: [PATCH 0292/1634] ppc/booke: fix crit/mcheck/debug exceptions Book E does not play games with certain bits of xSRR1 being MSR save bits and others being error status. xSRR1 is the old MSR, period. This was causing things like MSR[CE] to be lost, even in the saved version, as soon as you take an exception. rfci/rfdi/rfmci are fixed to pass the actual xSRR1 register contents, rather than the register number. Put FIXME comments on the hack that is "asrr0/1". The whole point of separate exception levels is so that you can, for example, take a machine check or debug interrupt without corrupting critical-level operations. The right xSRR0/1 set needs to be chosen based on CPU type flags. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- target-ppc/excp_helper.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 5e34ad08a8..41037a7e26 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -84,7 +84,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) " => %08x (%02x)\n", env->nip, excp, env->error_code); /* new srr1 value excluding must-be-zero bits */ - msr = env->msr & ~0x783f0000ULL; + if (excp_model == POWERPC_EXCP_BOOKE) { + msr = env->msr; + } else { + msr = env->msr & ~0x783f0000ULL; + } /* new interrupt handler msr */ new_msr = env->msr & ((target_ulong)1 << MSR_ME); @@ -145,6 +149,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) srr1 = SPR_40x_SRR3; break; case POWERPC_EXCP_BOOKE: + /* FIXME: choose one or the other based on CPU type */ srr0 = SPR_BOOKE_MCSRR0; srr1 = SPR_BOOKE_MCSRR1; asrr0 = SPR_BOOKE_CSRR0; @@ -275,6 +280,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_DEBUG: /* Debug interrupt */ switch (excp_model) { case POWERPC_EXCP_BOOKE: + /* FIXME: choose one or the other based on CPU type */ srr0 = SPR_BOOKE_DSRR0; srr1 = SPR_BOOKE_DSRR1; asrr0 = SPR_BOOKE_CSRR0; @@ -836,8 +842,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, void helper_rfi(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], - ~((target_ulong)0x783F0000), 1); + if (env->excp_model == POWERPC_EXCP_BOOKE) { + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0), 0); + } else { + do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], + ~((target_ulong)0x783F0000), 1); + } } #if defined(TARGET_PPC64) @@ -864,20 +875,22 @@ void helper_40x_rfci(CPUPPCState *env) void helper_rfci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1, - ~((target_ulong)0x3FFF0000), 0); + do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], + ~((target_ulong)0), 0); } void helper_rfdi(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1, - ~((target_ulong)0x3FFF0000), 0); + /* FIXME: choose CSRR1 or DSRR1 based on cpu type */ + do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1], + ~((target_ulong)0), 0); } void helper_rfmci(CPUPPCState *env) { - do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1, - ~((target_ulong)0x3FFF0000), 0); + /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */ + do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1], + ~((target_ulong)0), 0); } #endif From be7c236fa2e59090d7cd0193ca3f225c331d5f81 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:42 +0000 Subject: [PATCH 0293/1634] openpic: make register names correspond better with hw docs The base openpic specification doesn't provide abbreviated register names, so it's somewhat understandable that the QEMU code made up its own, except that most of the names that QEMU used didn't correspond to the terminology used by any implementation I could find. In some cases, like PCTP, the phrase "processor current task priority" could be found in the openpic spec when describing the concept, but the register itself was labelled "current task priority register" and every implementation seems to use either CTPR or the full phrase. In other cases, individual implementations disagree on what to call the register. The implementations I have documentation for are Freescale, Raven (MCP750), and IBM. The Raven docs tend to not use abbreviations at all. The IBM MPIC isn't implemented in QEMU. Thus, where there's disagreement I chose to use the Freescale abbreviations. Signed-off-by: Scott Wood [agraf: rebase on current state of the code] Signed-off-by: Alexander Graf --- hw/openpic.c | 352 +++++++++++++++++++++++++-------------------------- 1 file changed, 176 insertions(+), 176 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index f4df66dc10..6362497237 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -63,7 +63,7 @@ static const int debug_openpic = 0; #define VID 0x03 /* MPIC version ID */ /* OpenPIC capability flags */ -#define OPENPIC_FLAG_IDE_CRIT (1 << 0) +#define OPENPIC_FLAG_IDR_CRIT (1 << 0) /* OpenPIC address map */ #define OPENPIC_GLB_REG_START 0x0 @@ -120,19 +120,19 @@ static const int debug_openpic = 0; #define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ #define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ -#define FREP_NIRQ_SHIFT 16 -#define FREP_NCPU_SHIFT 8 -#define FREP_VID_SHIFT 0 +#define FRR_NIRQ_SHIFT 16 +#define FRR_NCPU_SHIFT 8 +#define FRR_VID_SHIFT 0 #define VID_REVISION_1_2 2 #define VID_REVISION_1_3 3 -#define VENI_GENERIC 0x00000000 /* Generic Vendor ID */ +#define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ -#define GLBC_RESET 0x80000000 +#define GCR_RESET 0x80000000 -#define TIBC_CI 0x80000000 /* count inhibit */ -#define TICC_TOG 0x80000000 /* toggles when decrement to zero */ +#define TBCR_CI 0x80000000 /* count inhibit */ +#define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ #define IDR_EP_SHIFT 31 #define IDR_EP_MASK (1 << IDR_EP_SHIFT) @@ -187,33 +187,33 @@ typedef struct IRQQueue { } IRQQueue; typedef struct IRQSource { - uint32_t ipvp; /* IRQ vector/priority register */ - uint32_t ide; /* IRQ destination register */ + uint32_t ivpr; /* IRQ vector/priority register */ + uint32_t idr; /* IRQ destination register */ int last_cpu; int pending; /* TRUE if IRQ is pending */ } IRQSource; -#define IPVP_MASK_SHIFT 31 -#define IPVP_MASK_MASK (1 << IPVP_MASK_SHIFT) -#define IPVP_ACTIVITY_SHIFT 30 -#define IPVP_ACTIVITY_MASK (1 << IPVP_ACTIVITY_SHIFT) -#define IPVP_MODE_SHIFT 29 -#define IPVP_MODE_MASK (1 << IPVP_MODE_SHIFT) -#define IPVP_POLARITY_SHIFT 23 -#define IPVP_POLARITY_MASK (1 << IPVP_POLARITY_SHIFT) -#define IPVP_SENSE_SHIFT 22 -#define IPVP_SENSE_MASK (1 << IPVP_SENSE_SHIFT) +#define IVPR_MASK_SHIFT 31 +#define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) +#define IVPR_ACTIVITY_SHIFT 30 +#define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) +#define IVPR_MODE_SHIFT 29 +#define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) +#define IVPR_POLARITY_SHIFT 23 +#define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) +#define IVPR_SENSE_SHIFT 22 +#define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) -#define IPVP_PRIORITY_MASK (0xF << 16) -#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) -#define IPVP_VECTOR(opp, _ipvpr_) ((_ipvpr_) & (opp)->vector_mask) +#define IVPR_PRIORITY_MASK (0xF << 16) +#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) +#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) -/* IDE[EP/CI] are only for FSL MPIC prior to v4.0 */ -#define IDE_EP 0x80000000 /* external pin */ -#define IDE_CI 0x40000000 /* critical interrupt */ +/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ +#define IDR_EP 0x80000000 /* external pin */ +#define IDR_CI 0x40000000 /* critical interrupt */ typedef struct IRQDest { - uint32_t pctp; /* CPU current task priority */ + uint32_t ctpr; /* CPU current task priority */ IRQQueue raised; IRQQueue servicing; qemu_irq *irqs; @@ -228,22 +228,22 @@ typedef struct OpenPICState { uint32_t flags; uint32_t nb_irqs; uint32_t vid; - uint32_t veni; /* Vendor identification register */ + uint32_t vir; /* Vendor identification register */ uint32_t vector_mask; - uint32_t tifr_reset; - uint32_t ipvp_reset; - uint32_t ide_reset; + uint32_t tfrr_reset; + uint32_t ivpr_reset; + uint32_t idr_reset; uint32_t brr1; /* Sub-regions */ MemoryRegion sub_io_mem[5]; /* Global registers */ - uint32_t frep; /* Feature reporting register */ - uint32_t glbc; /* Global configuration register */ - uint32_t pint; /* Processor initialization register */ + uint32_t frr; /* Feature reporting register */ + uint32_t gcr; /* Global configuration register */ + uint32_t pir; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ - uint32_t tifr; /* Timer frequency reporting register */ + uint32_t tfrr; /* Timer frequency reporting register */ /* Source registers */ IRQSource src[MAX_IRQ]; /* Local registers per output pin */ @@ -251,8 +251,8 @@ typedef struct OpenPICState { uint32_t nb_cpus; /* Timer registers */ struct { - uint32_t ticc; /* Global timer current count register */ - uint32_t tibc; /* Global timer base count register */ + uint32_t tccr; /* Global timer current count register */ + uint32_t tbcr; /* Global timer base count register */ } timers[MAX_TMR]; /* Shared MSI registers */ struct { @@ -298,11 +298,11 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q) for (i = 0; i < opp->max_irq; i++) { if (IRQ_testbit(q, i)) { - DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", - i, IPVP_PRIORITY(opp->src[i].ipvp), priority); - if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { + DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", + i, IVPR_PRIORITY(opp->src[i].ivpr), priority); + if (IVPR_PRIORITY(opp->src[i].ivpr) > priority) { next = i; - priority = IPVP_PRIORITY(opp->src[i].ipvp); + priority = IVPR_PRIORITY(opp->src[i].ivpr); } } } @@ -330,8 +330,8 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; - priority = IPVP_PRIORITY(src->ipvp); - if (priority <= dst->pctp) { + priority = IVPR_PRIORITY(src->ivpr); + if (priority <= dst->ctpr) { /* Too low priority */ DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", __func__, n_IRQ, n_CPU); @@ -343,7 +343,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) __func__, n_IRQ, n_CPU); return; } - src->ipvp |= IPVP_ACTIVITY_MASK; + src->ivpr |= IVPR_ACTIVITY_MASK; IRQ_setbit(&dst->raised, n_IRQ); if (priority < dst->raised.priority) { /* An higher priority IRQ is already raised */ @@ -376,34 +376,34 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } - if (src->ipvp & IPVP_MASK_MASK) { + if (src->ivpr & IVPR_MASK_MASK) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; } - if (IPVP_PRIORITY(src->ipvp) == 0) { + if (IVPR_PRIORITY(src->ivpr) == 0) { /* Priority set to zero */ DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); return; } - if (src->ipvp & IPVP_ACTIVITY_MASK) { + if (src->ivpr & IVPR_ACTIVITY_MASK) { /* IRQ already active */ DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; } - if (src->ide == 0) { + if (src->idr == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } - if (src->ide == (1 << src->last_cpu)) { + if (src->idr == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ IRQ_local_pipe(opp, src->last_cpu, n_IRQ); - } else if (!(src->ipvp & IPVP_MODE_MASK)) { + } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { - if (src->ide & (1 << i)) { + if (src->idr & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); } } @@ -413,7 +413,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if (i == opp->nb_cpus) { i = 0; } - if (src->ide & (1 << i)) { + if (src->idr & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; break; @@ -428,13 +428,13 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) IRQSource *src; src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ipvp=0x%08x\n", - n_IRQ, level, src->ipvp); - if (src->ipvp & IPVP_SENSE_MASK) { + DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", + n_IRQ, level, src->ivpr); + if (src->ivpr & IVPR_SENSE_MASK) { /* level-sensitive irq */ src->pending = level; if (!level) { - src->ipvp &= ~IPVP_ACTIVITY_MASK; + src->ivpr &= ~IVPR_ACTIVITY_MASK; } } else { /* edge-sensitive irq */ @@ -450,23 +450,23 @@ static void openpic_reset(DeviceState *d) OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d)); int i; - opp->glbc = GLBC_RESET; + opp->gcr = GCR_RESET; /* Initialise controller registers */ - opp->frep = ((opp->nb_irqs - 1) << FREP_NIRQ_SHIFT) | - ((opp->nb_cpus - 1) << FREP_NCPU_SHIFT) | - (opp->vid << FREP_VID_SHIFT); + opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | + ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) | + (opp->vid << FRR_VID_SHIFT); - opp->pint = 0; + opp->pir = 0; opp->spve = -1 & opp->vector_mask; - opp->tifr = opp->tifr_reset; + opp->tfrr = opp->tfrr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ipvp = opp->ipvp_reset; - opp->src[i].ide = opp->ide_reset; + opp->src[i].ivpr = opp->ivpr_reset; + opp->src[i].idr = opp->idr_reset; } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].pctp = 15; + opp->dst[i].ctpr = 15; memset(&opp->dst[i].raised, 0, sizeof(IRQQueue)); opp->dst[i].raised.next = -1; memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue)); @@ -474,42 +474,42 @@ static void openpic_reset(DeviceState *d) } /* Initialise timers */ for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].ticc = 0; - opp->timers[i].tibc = TIBC_CI; + opp->timers[i].tccr = 0; + opp->timers[i].tbcr = TBCR_CI; } /* Go out of RESET state */ - opp->glbc = 0; + opp->gcr = 0; } -static inline uint32_t read_IRQreg_ide(OpenPICState *opp, int n_IRQ) +static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) { - return opp->src[n_IRQ].ide; + return opp->src[n_IRQ].idr; } -static inline uint32_t read_IRQreg_ipvp(OpenPICState *opp, int n_IRQ) +static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) { - return opp->src[n_IRQ].ipvp; + return opp->src[n_IRQ].ivpr; } -static inline void write_IRQreg_ide(OpenPICState *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t tmp; - tmp = val & (IDE_EP | IDE_CI); + tmp = val & (IDR_EP | IDR_CI); tmp |= val & ((1ULL << MAX_CPU) - 1); - opp->src[n_IRQ].ide = tmp; - DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); + opp->src[n_IRQ].idr = tmp; + DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].idr); } -static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) { /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & IPVP_ACTIVITY_MASK) | - (val & (IPVP_MASK_MASK | IPVP_PRIORITY_MASK | opp->vector_mask)); + opp->src[n_IRQ].ivpr = (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | + (val & (IVPR_MASK_MASK | IVPR_PRIORITY_MASK | opp->vector_mask)); openpic_update_irq(opp, n_IRQ); - DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, - opp->src[n_IRQ].ipvp); + DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, + opp->src[n_IRQ].ivpr); } static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, @@ -537,37 +537,37 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0xB0: openpic_cpu_write_internal(opp, addr, val, get_current_cpu()); break; - case 0x1000: /* FREP */ + case 0x1000: /* FRR */ break; - case 0x1020: /* GLBC */ - if (val & GLBC_RESET) { + case 0x1020: /* GCR */ + if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); } break; - case 0x1080: /* VENI */ + case 0x1080: /* VIR */ break; - case 0x1090: /* PINT */ + case 0x1090: /* PIR */ for (idx = 0; idx < opp->nb_cpus; idx++) { - if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) { + if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); dst = &opp->dst[idx]; qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); - } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) { + } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); dst = &opp->dst[idx]; qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); } } - opp->pint = val; + opp->pir = val; break; - case 0x10A0: /* IPI_IPVP */ + case 0x10A0: /* IPI_IVPR */ case 0x10B0: case 0x10C0: case 0x10D0: { int idx; idx = (addr - 0x10A0) >> 4; - write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val); + write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); } break; case 0x10E0: /* SPVE */ @@ -589,16 +589,16 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) return retval; } switch (addr) { - case 0x1000: /* FREP */ - retval = opp->frep; + case 0x1000: /* FRR */ + retval = opp->frr; break; - case 0x1020: /* GLBC */ - retval = opp->glbc; + case 0x1020: /* GCR */ + retval = opp->gcr; break; - case 0x1080: /* VENI */ - retval = opp->veni; + case 0x1080: /* VIR */ + retval = opp->vir; break; - case 0x1090: /* PINT */ + case 0x1090: /* PIR */ retval = 0x00000000; break; case 0x00: /* Block Revision Register1 (BRR1) */ @@ -614,14 +614,14 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) case 0xB0: retval = openpic_cpu_read_internal(opp, addr, get_current_cpu()); break; - case 0x10A0: /* IPI_IPVP */ + case 0x10A0: /* IPI_IVPR */ case 0x10B0: case 0x10C0: case 0x10D0: { int idx; idx = (addr - 0x10A0) >> 4; - retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx); + retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); } break; case 0x10E0: /* SPVE */ @@ -650,26 +650,26 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, addr = addr & 0x30; if (addr == 0x0) { - /* TIFR (TFRR) */ - opp->tifr = val; + /* TFRR */ + opp->tfrr = val; return; } switch (addr & 0x30) { - case 0x00: /* TICC (GTCCR) */ + case 0x00: /* TCCR */ break; - case 0x10: /* TIBC (GTBCR) */ - if ((opp->timers[idx].ticc & TICC_TOG) != 0 && - (val & TIBC_CI) == 0 && - (opp->timers[idx].tibc & TIBC_CI) != 0) { - opp->timers[idx].ticc &= ~TICC_TOG; + case 0x10: /* TBCR */ + if ((opp->timers[idx].tccr & TCCR_TOG) != 0 && + (val & TBCR_CI) == 0 && + (opp->timers[idx].tbcr & TBCR_CI) != 0) { + opp->timers[idx].tccr &= ~TCCR_TOG; } - opp->timers[idx].tibc = val; + opp->timers[idx].tbcr = val; break; - case 0x20: /* TIVP (GTIVPR) */ - write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val); + case 0x20: /* TVPR */ + write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); break; - case 0x30: /* TIDE (GTIDR) */ - write_IRQreg_ide(opp, opp->irq_tim0 + idx, val); + case 0x30: /* TDR */ + write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); break; } } @@ -686,22 +686,22 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) } idx = (addr >> 6) & 0x3; if (addr == 0x0) { - /* TIFR (TFRR) */ - retval = opp->tifr; + /* TFRR */ + retval = opp->tfrr; goto out; } switch (addr & 0x30) { - case 0x00: /* TICC (GTCCR) */ - retval = opp->timers[idx].ticc; + case 0x00: /* TCCR */ + retval = opp->timers[idx].tccr; break; - case 0x10: /* TIBC (GTBCR) */ - retval = opp->timers[idx].tibc; + case 0x10: /* TBCR */ + retval = opp->timers[idx].tbcr; break; - case 0x20: /* TIPV (TIPV) */ - retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx); + case 0x20: /* TIPV */ + retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); break; case 0x30: /* TIDE (TIDR) */ - retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx); + retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); break; } @@ -726,10 +726,10 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(opp, idx, val); + write_IRQreg_idr(opp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(opp, idx, val); + write_IRQreg_ivpr(opp, idx, val); } } @@ -748,10 +748,10 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(opp, idx); + retval = read_IRQreg_idr(opp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(opp, idx); + retval = read_IRQreg_ivpr(opp, idx); } DPRINTF("%s: => 0x%08x\n", __func__, retval); @@ -849,22 +849,22 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0x70: idx = (addr - 0x40) >> 4; /* we use IDE as mask which CPUs to deliver the IPI to still. */ - write_IRQreg_ide(opp, opp->irq_ipi0 + idx, - opp->src[opp->irq_ipi0 + idx].ide | val); + write_IRQreg_idr(opp, opp->irq_ipi0 + idx, + opp->src[opp->irq_ipi0 + idx].idr | val); openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; - case 0x80: /* PCTP */ - dst->pctp = val & 0x0000000F; + case 0x80: /* CTPR */ + dst->ctpr = val & 0x0000000F; break; case 0x90: /* WHOAMI */ /* Read-only register */ break; - case 0xA0: /* PIAC */ + case 0xA0: /* IACK */ /* Read-only register */ break; - case 0xB0: /* PEOI */ - DPRINTF("PEOI\n"); + case 0xB0: /* EOI */ + DPRINTF("EOI\n"); s_IRQ = IRQ_get_next(opp, &dst->servicing); IRQ_resetbit(&dst->servicing, s_IRQ); dst->servicing.next = -1; @@ -875,7 +875,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, src = &opp->src[n_IRQ]; if (n_IRQ != -1 && (s_IRQ == -1 || - IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { + IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); openpic_irq_raise(opp, idx, src); @@ -914,56 +914,56 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { - case 0x80: /* PCTP */ - retval = dst->pctp; + case 0x80: /* CTPR */ + retval = dst->ctpr; break; case 0x90: /* WHOAMI */ retval = idx; break; - case 0xA0: /* PIAC */ + case 0xA0: /* IACK */ DPRINTF("Lower OpenPIC INT output\n"); qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); n_IRQ = IRQ_get_next(opp, &dst->raised); - DPRINTF("PIAC: irq=%d\n", n_IRQ); + DPRINTF("IACK: irq=%d\n", n_IRQ); if (n_IRQ == -1) { /* No more interrupt pending */ retval = opp->spve; } else { src = &opp->src[n_IRQ]; - if (!(src->ipvp & IPVP_ACTIVITY_MASK) || - !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { + if (!(src->ivpr & IVPR_ACTIVITY_MASK) || + !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { /* - Spurious level-sensitive IRQ * - Priorities has been changed * and the pending IRQ isn't allowed anymore */ - src->ipvp &= ~IPVP_ACTIVITY_MASK; + src->ivpr &= ~IVPR_ACTIVITY_MASK; retval = opp->spve; } else { /* IRQ enter servicing state */ IRQ_setbit(&dst->servicing, n_IRQ); - retval = IPVP_VECTOR(opp, src->ipvp); + retval = IVPR_VECTOR(opp, src->ivpr); } IRQ_resetbit(&dst->raised, n_IRQ); dst->raised.next = -1; - if (!(src->ipvp & IPVP_SENSE_MASK)) { + if (!(src->ivpr & IVPR_SENSE_MASK)) { /* edge-sensitive IRQ */ - src->ipvp &= ~IPVP_ACTIVITY_MASK; + src->ivpr &= ~IVPR_ACTIVITY_MASK; src->pending = 0; } if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { - src->ide &= ~(1 << idx); - if (src->ide && !(src->ipvp & IPVP_SENSE_MASK)) { + src->idr &= ~(1 << idx); + if (src->idr && !(src->ivpr & IVPR_SENSE_MASK)) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, n_IRQ, 1); openpic_set_irq(opp, n_IRQ, 0); /* if all CPUs knew about it, set active bit again */ - src->ipvp |= IPVP_ACTIVITY_MASK; + src->ivpr |= IVPR_ACTIVITY_MASK; } } } break; - case 0xB0: /* PEOI */ + case 0xB0: /* EOI */ retval = 0; break; default: @@ -1095,15 +1095,15 @@ static void openpic_save(QEMUFile* f, void *opaque) OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - qemu_put_be32s(f, &opp->glbc); - qemu_put_be32s(f, &opp->veni); - qemu_put_be32s(f, &opp->pint); + qemu_put_be32s(f, &opp->gcr); + qemu_put_be32s(f, &opp->vir); + qemu_put_be32s(f, &opp->pir); qemu_put_be32s(f, &opp->spve); - qemu_put_be32s(f, &opp->tifr); + qemu_put_be32s(f, &opp->tfrr); for (i = 0; i < opp->max_irq; i++) { - qemu_put_be32s(f, &opp->src[i].ipvp); - qemu_put_be32s(f, &opp->src[i].ide); + qemu_put_be32s(f, &opp->src[i].ivpr); + qemu_put_be32s(f, &opp->src[i].idr); qemu_put_sbe32s(f, &opp->src[i].last_cpu); qemu_put_sbe32s(f, &opp->src[i].pending); } @@ -1111,14 +1111,14 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_put_be32s(f, &opp->dst[i].pctp); + qemu_put_be32s(f, &opp->dst[i].ctpr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); } for (i = 0; i < MAX_TMR; i++) { - qemu_put_be32s(f, &opp->timers[i].ticc); - qemu_put_be32s(f, &opp->timers[i].tibc); + qemu_put_be32s(f, &opp->timers[i].tccr); + qemu_put_be32s(f, &opp->timers[i].tbcr); } } @@ -1142,15 +1142,15 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) return -EINVAL; } - qemu_get_be32s(f, &opp->glbc); - qemu_get_be32s(f, &opp->veni); - qemu_get_be32s(f, &opp->pint); + qemu_get_be32s(f, &opp->gcr); + qemu_get_be32s(f, &opp->vir); + qemu_get_be32s(f, &opp->pir); qemu_get_be32s(f, &opp->spve); - qemu_get_be32s(f, &opp->tifr); + qemu_get_be32s(f, &opp->tfrr); for (i = 0; i < opp->max_irq; i++) { - qemu_get_be32s(f, &opp->src[i].ipvp); - qemu_get_be32s(f, &opp->src[i].ide); + qemu_get_be32s(f, &opp->src[i].ivpr); + qemu_get_be32s(f, &opp->src[i].idr); qemu_get_sbe32s(f, &opp->src[i].last_cpu); qemu_get_sbe32s(f, &opp->src[i].pending); } @@ -1158,14 +1158,14 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_get_be32s(f, &opp->dst[i].pctp); + qemu_get_be32s(f, &opp->dst[i].ctpr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); } for (i = 0; i < MAX_TMR; i++) { - qemu_get_be32s(f, &opp->timers[i].ticc); - qemu_get_be32s(f, &opp->timers[i].tibc); + qemu_get_be32s(f, &opp->timers[i].tccr); + qemu_get_be32s(f, &opp->timers[i].tbcr); } return 0; @@ -1175,7 +1175,7 @@ static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src) { int n_ci = IDR_CI0_SHIFT - n_CPU; - if ((opp->flags & OPENPIC_FLAG_IDE_CRIT) && (src->ide & (1 << n_ci))) { + if ((opp->flags & OPENPIC_FLAG_IDR_CRIT) && (src->idr & (1 << n_ci))) { qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); } else { qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); @@ -1223,14 +1223,14 @@ static int openpic_init(SysBusDevice *dev) switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: - opp->flags |= OPENPIC_FLAG_IDE_CRIT; + opp->flags |= OPENPIC_FLAG_IDR_CRIT; opp->nb_irqs = 80; opp->vid = VID_REVISION_1_2; - opp->veni = VENI_GENERIC; + opp->vir = VIR_GENERIC; opp->vector_mask = 0xFFFF; - opp->tifr_reset = 0; - opp->ipvp_reset = IPVP_MASK_MASK; - opp->ide_reset = 1 << 0; + opp->tfrr_reset = 0; + opp->ivpr_reset = IVPR_MASK_MASK; + opp->idr_reset = 1 << 0; opp->max_irq = FSL_MPIC_20_MAX_IRQ; opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; @@ -1242,11 +1242,11 @@ static int openpic_init(SysBusDevice *dev) case OPENPIC_MODEL_RAVEN: opp->nb_irqs = RAVEN_MAX_EXT; opp->vid = VID_REVISION_1_3; - opp->veni = VENI_GENERIC; + opp->vir = VIR_GENERIC; opp->vector_mask = 0xFF; - opp->tifr_reset = 4160000; - opp->ipvp_reset = IPVP_MASK_MASK | IPVP_MODE_MASK; - opp->ide_reset = 0; + opp->tfrr_reset = 4160000; + opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK; + opp->idr_reset = 0; opp->max_irq = RAVEN_MAX_IRQ; opp->irq_ipi0 = RAVEN_IPI_IRQ; opp->irq_tim0 = RAVEN_TMR_IRQ; From 5e22c276de982dd26ebc4424c8d4592cce1baab9 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:43 +0000 Subject: [PATCH 0294/1634] openpic: rework critical interrupt support Critical interrupts on FSL MPIC are not supposed to pay attention to priority, IACK, EOI, etc. On the currently modeled version it's not supposed to pay attention to the mask bit either. Also reorganize to make it easier to implement newer FSL MPIC models, which encode interrupt level information differently and support mcheck as well as crit, and to reduce problems for later patches in this set. Still missing is the ability to lower the CINT signal to the core, as IACK/EOI is not used. This will come with general IRQ-source-driven lowering in the next patch. New state is added which is not serialized, but instead is recomputed in openpic_load() by calling the appropriate write_IRQreg function. This should have the side effect of causing the IRQ outputs to be raised appropriately on load, which was missing. The serialization format is altered by swapping ivpr and idr (we'd like IDR to be restored before we run the IVPR logic), and moving interrupts to the end (so that other state has been restored by the time we run the IDR/IVPR logic. Serialization for this driver is not yet in a state where backwards compatibility is reasonable (assuming it works at all), and the current serialization format was not built for extensibility. Signed-off-by: Scott Wood [agraf: fix for current code state] Signed-off-by: Alexander Graf --- hw/openpic.c | 110 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 6362497237..fe6cf67956 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -189,7 +189,9 @@ typedef struct IRQQueue { typedef struct IRQSource { uint32_t ivpr; /* IRQ vector/priority register */ uint32_t idr; /* IRQ destination register */ + uint32_t destmask; /* bitmap of CPU destinations */ int last_cpu; + int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ int pending; /* TRUE if IRQ is pending */ } IRQSource; @@ -264,8 +266,6 @@ typedef struct OpenPICState { uint32_t irq_msi; } OpenPICState; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src); - static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { q->pending++; @@ -330,6 +330,19 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; + + if (src->output != OPENPIC_OUTPUT_INT) { + /* On Freescale MPIC, critical interrupts ignore priority, + * IACK, EOI, etc. Before MPIC v4.1 they also ignore + * masking. + */ + src->ivpr |= IVPR_ACTIVITY_MASK; + DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_raise(opp->dst[n_CPU].irqs[src->output]); + return; + } + priority = IVPR_PRIORITY(src->ivpr); if (priority <= dst->ctpr) { /* Too low priority */ @@ -360,7 +373,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) return; } DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - openpic_irq_raise(opp, n_CPU, src); + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } /* update pic state because registers for n_IRQ have changed value */ @@ -403,7 +416,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { - if (src->idr & (1 << i)) { + if (src->destmask & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); } } @@ -413,7 +426,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if (i == opp->nb_cpus) { i = 0; } - if (src->idr & (1 << i)) { + if (src->destmask & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; break; @@ -493,12 +506,45 @@ static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) { - uint32_t tmp; + IRQSource *src = &opp->src[n_IRQ]; + uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; + uint32_t crit_mask = 0; + uint32_t mask = normal_mask; + int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; + int i; - tmp = val & (IDR_EP | IDR_CI); - tmp |= val & ((1ULL << MAX_CPU) - 1); - opp->src[n_IRQ].idr = tmp; - DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].idr); + if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { + crit_mask = mask << crit_shift; + mask |= crit_mask | IDR_EP; + } + + src->idr = val & mask; + DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); + + if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { + if (src->idr & crit_mask) { + if (src->idr & normal_mask) { + DPRINTF("%s: IRQ configured for multiple output types, using " + "critical\n", __func__); + } + + src->output = OPENPIC_OUTPUT_CINT; + src->destmask = 0; + + for (i = 0; i < opp->nb_cpus; i++) { + int n_ci = IDR_CI0_SHIFT - i; + + if (src->idr & (1UL << n_ci)) { + src->destmask |= 1UL << i; + } + } + } else { + src->output = OPENPIC_OUTPUT_INT; + src->destmask = src->idr & normal_mask; + } + } else { + src->destmask = src->idr; + } } static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) @@ -878,7 +924,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); - openpic_irq_raise(opp, idx, src); + qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); } break; default: @@ -1101,13 +1147,6 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->spve); qemu_put_be32s(f, &opp->tfrr); - for (i = 0; i < opp->max_irq; i++) { - qemu_put_be32s(f, &opp->src[i].ivpr); - qemu_put_be32s(f, &opp->src[i].idr); - qemu_put_sbe32s(f, &opp->src[i].last_cpu); - qemu_put_sbe32s(f, &opp->src[i].pending); - } - qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { @@ -1120,6 +1159,13 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->timers[i].tccr); qemu_put_be32s(f, &opp->timers[i].tbcr); } + + for (i = 0; i < opp->max_irq; i++) { + qemu_put_be32s(f, &opp->src[i].ivpr); + qemu_put_be32s(f, &opp->src[i].idr); + qemu_put_sbe32s(f, &opp->src[i].last_cpu); + qemu_put_sbe32s(f, &opp->src[i].pending); + } } static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) @@ -1148,13 +1194,6 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->spve); qemu_get_be32s(f, &opp->tfrr); - for (i = 0; i < opp->max_irq; i++) { - qemu_get_be32s(f, &opp->src[i].ivpr); - qemu_get_be32s(f, &opp->src[i].idr); - qemu_get_sbe32s(f, &opp->src[i].last_cpu); - qemu_get_sbe32s(f, &opp->src[i].pending); - } - qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { @@ -1168,18 +1207,21 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->timers[i].tbcr); } - return 0; -} + for (i = 0; i < opp->max_irq; i++) { + uint32_t val; -static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQSource *src) -{ - int n_ci = IDR_CI0_SHIFT - n_CPU; + val = qemu_get_be32(f); + write_IRQreg_idr(opp, i, val); + val = qemu_get_be32(f); + write_IRQreg_ivpr(opp, i, val); - if ((opp->flags & OPENPIC_FLAG_IDR_CRIT) && (src->idr & (1 << n_ci))) { - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); - } else { - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + qemu_get_be32s(f, &opp->src[i].ivpr); + qemu_get_be32s(f, &opp->src[i].idr); + qemu_get_sbe32s(f, &opp->src[i].last_cpu); + qemu_get_sbe32s(f, &opp->src[i].pending); } + + return 0; } typedef struct MemReg { From eb4384278417297661663c54e01c0f0ffec0a9e3 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:44 +0000 Subject: [PATCH 0295/1634] openpic: make ctpr signed Other priorities are signed, so avoid comparisons between signed and unsigned. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index fe6cf67956..824b8fd2c2 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -215,7 +215,7 @@ typedef struct IRQSource { #define IDR_CI 0x40000000 /* critical interrupt */ typedef struct IRQDest { - uint32_t ctpr; /* CPU current task priority */ + int32_t ctpr; /* CPU current task priority */ IRQQueue raised; IRQQueue servicing; qemu_irq *irqs; @@ -1150,7 +1150,7 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_put_be32s(f, &opp->dst[i].ctpr); + qemu_put_sbe32s(f, &opp->dst[i].ctpr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); } @@ -1197,7 +1197,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_get_be32s(f, &opp->dst[i].ctpr); + qemu_get_sbe32s(f, &opp->dst[i].ctpr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); } From 72c1da2ca72af50e6536d0cd9c6db758f66cd7c2 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:45 +0000 Subject: [PATCH 0296/1634] openpic/fsl: critical interrupts ignore mask before v4.1 Signed-off-by: Scott Wood [agraf: make bool :1] Signed-off-by: Alexander Graf --- hw/openpic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/openpic.c b/hw/openpic.c index 824b8fd2c2..ac5027a5a0 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -193,6 +193,7 @@ typedef struct IRQSource { int last_cpu; int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ int pending; /* TRUE if IRQ is pending */ + bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ } IRQSource; #define IVPR_MASK_SHIFT 31 @@ -389,7 +390,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } - if (src->ivpr & IVPR_MASK_MASK) { + if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; @@ -529,6 +530,7 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } src->output = OPENPIC_OUTPUT_CINT; + src->nomask = true; src->destmask = 0; for (i = 0; i < opp->nb_cpus; i++) { @@ -540,6 +542,7 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } } else { src->output = OPENPIC_OUTPUT_INT; + src->nomask = false; src->destmask = src->idr & normal_mask; } } else { From 3c94378e2c500b6211e95d7457f4a9959955c3d1 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:46 +0000 Subject: [PATCH 0297/1634] openpic: always call IRQ_check from IRQ_get_next Previously the code relied on the queue's "next" field getting set to -1 sometime between an update to the bitmap, and the next call to IRQ_get_next. Sometimes this happened after the update. Sometimes it happened before the check. Sometimes it didn't happen at all. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index ac5027a5a0..19e6280023 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -315,10 +315,8 @@ out: static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) { - if (q->next == -1) { - /* XXX: optimize */ - IRQ_check(opp, q); - } + /* XXX: optimize */ + IRQ_check(opp, q); return q->next; } @@ -365,7 +363,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) __func__, n_IRQ, dst->raised.next, n_CPU); return; } - IRQ_get_next(opp, &dst->raised); + IRQ_check(opp, &dst->raised); if (IRQ_get_next(opp, &dst->servicing) != -1 && priority <= dst->servicing.priority) { DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", @@ -916,7 +914,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, DPRINTF("EOI\n"); s_IRQ = IRQ_get_next(opp, &dst->servicing); IRQ_resetbit(&dst->servicing, s_IRQ); - dst->servicing.next = -1; /* Set up next servicing IRQ */ s_IRQ = IRQ_get_next(opp, &dst->servicing); /* Check queued interrupts. */ @@ -993,7 +990,6 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, retval = IVPR_VECTOR(opp, src->ivpr); } IRQ_resetbit(&dst->raised, n_IRQ); - dst->raised.next = -1; if (!(src->ivpr & IVPR_SENSE_MASK)) { /* edge-sensitive IRQ */ src->ivpr &= ~IVPR_ACTIVITY_MASK; From 47f73749c61765f7a898ac88f11995368740da10 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:47 +0000 Subject: [PATCH 0298/1634] Revert "openpic: Accelerate pending irq search" This reverts commit a9bd83f4c65de0058659ede009fa1a241f379edd. This counting approach is not robust against setting a bit that was already set, or clearing a bit that was already clear. Perhaps that is considered a bug, but besides the lack of any documentation for that restriction, it's a pretty unpleasant way for the problem to manifest itself. It could be made more robust by testing the current value of the bit before changing the count, but a later patch speeds up IRQ_check in all cases, not just when there's nothing pending. Hopefully that should be adequate to address performance concerns. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 19e6280023..2c238fba4b 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -183,7 +183,6 @@ typedef struct IRQQueue { uint32_t queue[BF_WIDTH(MAX_IRQ)]; int next; int priority; - int pending; /* nr of pending bits in queue */ } IRQQueue; typedef struct IRQSource { @@ -269,13 +268,11 @@ typedef struct OpenPICState { static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { - q->pending++; set_bit(q->queue, n_IRQ); } static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) { - q->pending--; reset_bit(q->queue, n_IRQ); } @@ -291,12 +288,6 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q) next = -1; priority = -1; - - if (!q->pending) { - /* IRQ bitmap is empty */ - goto out; - } - for (i = 0; i < opp->max_irq; i++) { if (IRQ_testbit(q, i)) { DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", @@ -307,8 +298,6 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q) } } } - -out: q->next = next; q->priority = priority; } From e69a17f65e9f12f33c48b04a789e49d40a8993f5 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:48 +0000 Subject: [PATCH 0299/1634] openpic: use standard bitmap operations Besides the private implementation being redundant, namespace collisions prevented the use of other things in bitops.h. Serialization does get a bit more awkward, unfortunately, since the standard bitmap operations are "unsigned long" rather than "uint32_t", though in exchange we will get faster queue lookups on 64-bit hosts once we search a word at a time. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 55 +++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 2c238fba4b..b54308d042 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -39,6 +39,7 @@ #include "openpic.h" #include "sysbus.h" #include "pci/msi.h" +#include "qemu/bitops.h" //#define DEBUG_OPENPIC @@ -147,24 +148,6 @@ static const int debug_openpic = 0; #define MSIIR_IBS_SHIFT 24 #define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) -#define BF_WIDTH(_bits_) \ -(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) - -static inline void set_bit(uint32_t *field, int bit) -{ - field[bit >> 5] |= 1 << (bit & 0x1F); -} - -static inline void reset_bit(uint32_t *field, int bit) -{ - field[bit >> 5] &= ~(1 << (bit & 0x1F)); -} - -static inline int test_bit(uint32_t *field, int bit) -{ - return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; -} - static int get_current_cpu(void) { if (!cpu_single_env) { @@ -180,7 +163,10 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); typedef struct IRQQueue { - uint32_t queue[BF_WIDTH(MAX_IRQ)]; + /* 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)]; int next; int priority; } IRQQueue; @@ -268,17 +254,17 @@ typedef struct OpenPICState { static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) { - set_bit(q->queue, n_IRQ); + set_bit(n_IRQ, q->queue); } static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) { - reset_bit(q->queue, n_IRQ); + clear_bit(n_IRQ, q->queue); } static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) { - return test_bit(q->queue, n_IRQ); + return test_bit(n_IRQ, q->queue); } static void IRQ_check(OpenPICState *opp, IRQQueue *q) @@ -1117,8 +1103,16 @@ static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; - for (i = 0; i < BF_WIDTH(MAX_IRQ); i++) - qemu_put_be32s(f, &q->queue[i]); + for (i = 0; i < ARRAY_SIZE(q->queue); i++) { + /* Always put the lower half of a 64-bit long first, in case we + * restore on a 32-bit host. The least significant bits correspond + * to lower IRQ numbers in the bitmap. + */ + qemu_put_be32(f, (uint32_t)q->queue[i]); +#if LONG_MAX > 0x7FFFFFFF + qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32)); +#endif + } qemu_put_sbe32s(f, &q->next); qemu_put_sbe32s(f, &q->priority); @@ -1160,8 +1154,17 @@ static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) { unsigned int i; - for (i = 0; i < BF_WIDTH(MAX_IRQ); i++) - qemu_get_be32s(f, &q->queue[i]); + for (i = 0; i < ARRAY_SIZE(q->queue); i++) { + unsigned long val; + + val = qemu_get_be32(f); +#if LONG_MAX > 0x7FFFFFFF + val <<= 32; + val |= qemu_get_be32(f); +#endif + + q->queue[i] = val; + } qemu_get_sbe32s(f, &q->next); qemu_get_sbe32s(f, &q->priority); From 65b9d0d5659687ebb85b1305ac70b3a84df16e5a Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 21 Dec 2012 16:15:50 +0000 Subject: [PATCH 0300/1634] openpic: add some bounds checking for IRQ numbers The two checks with abort() guard against potential QEMU-internal problems, but the EOI check stops the guest from causing updates to queue position -1 and other havoc if it writes EOI with no interrupt in service. Signed-off-by: Scott Wood [agraf: remove hunk in code that didn't get applied yet] Signed-off-by: Alexander Graf --- hw/openpic.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/openpic.c b/hw/openpic.c index b54308d042..35a7fe383b 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -414,6 +414,11 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) OpenPICState *opp = opaque; IRQSource *src; + if (n_IRQ >= MAX_IRQ) { + fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ); + abort(); + } + src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", n_IRQ, level, src->ivpr); @@ -888,6 +893,12 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0xB0: /* EOI */ DPRINTF("EOI\n"); s_IRQ = IRQ_get_next(opp, &dst->servicing); + + if (s_IRQ < 0) { + DPRINTF("%s: EOI with no interrupt in service\n", __func__); + break; + } + IRQ_resetbit(&dst->servicing, s_IRQ); /* Set up next servicing IRQ */ s_IRQ = IRQ_get_next(opp, &dst->servicing); From 6c5e84c25fc70717c410150b23c765bedf0af52d Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:37 +0000 Subject: [PATCH 0301/1634] openpic: fix sense and priority bits Previously, the sense and priority bits were masked off when writing to IVPR, and all interrupts were treated as edge-triggered (despite the existence of code for handling level-triggered interrupts). Polarity is implemented only as storage. We don't simulate the bad effects that you'd get on real hardware if you set this incorrectly, but at least the guest sees the right thing when it reads back the register. Sense now controls level/edge on FSL external interrupts (and all interrupts on non-FSL MPIC). FSL internal interrupts do not have a sense bit (reads as zero), but are level. FSL timers and IPIs do not have sense or polarity bits (read as zero), and are edge-triggered. To accommodate FSL internal interrupts, QEMU's internal notion of whether an interrupt is level-triggered is separated from the IVPR bit. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 35a7fe383b..66179c22cb 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -162,6 +162,12 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); +typedef enum IRQType { + IRQ_TYPE_NORMAL = 0, + IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ + IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ +} IRQType; + 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. @@ -178,6 +184,8 @@ typedef struct IRQSource { int last_cpu; int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ int pending; /* TRUE if IRQ is pending */ + IRQType type; + bool level:1; /* level-triggered */ bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ } IRQSource; @@ -422,7 +430,7 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", n_IRQ, level, src->ivpr); - if (src->ivpr & IVPR_SENSE_MASK) { + if (src->level) { /* level-sensitive irq */ src->pending = level; if (!level) { @@ -455,6 +463,19 @@ static void openpic_reset(DeviceState *d) for (i = 0; i < opp->max_irq; i++) { opp->src[i].ivpr = opp->ivpr_reset; opp->src[i].idr = opp->idr_reset; + + switch (opp->src[i].type) { + case IRQ_TYPE_NORMAL: + opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK); + break; + + case IRQ_TYPE_FSLINT: + opp->src[i].ivpr |= IVPR_POLARITY_MASK; + break; + + case IRQ_TYPE_FSLSPECIAL: + break; + } } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { @@ -530,10 +551,36 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) { - /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ + uint32_t mask; + + /* NOTE when implementing newer FSL MPIC models: starting with v4.0, + * the polarity bit is read-only on internal interrupts. + */ + mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | + IVPR_POLARITY_MASK | opp->vector_mask; + /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ivpr = (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | - (val & (IVPR_MASK_MASK | IVPR_PRIORITY_MASK | opp->vector_mask)); + opp->src[n_IRQ].ivpr = + (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); + + /* For FSL internal interrupts, The sense bit is reserved and zero, + * and the interrupt is always level-triggered. Timers and IPIs + * have no sense or polarity bits, and are edge-triggered. + */ + switch (opp->src[n_IRQ].type) { + case IRQ_TYPE_NORMAL: + opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); + break; + + case IRQ_TYPE_FSLINT: + opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; + break; + + case IRQ_TYPE_FSLSPECIAL: + opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); + break; + } + openpic_update_irq(opp, n_IRQ); DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, opp->src[n_IRQ].ivpr); @@ -976,7 +1023,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, retval = IVPR_VECTOR(opp, src->ivpr); } IRQ_resetbit(&dst->raised, n_IRQ); - if (!(src->ivpr & IVPR_SENSE_MASK)) { + if (!src->level) { /* edge-sensitive IRQ */ src->ivpr &= ~IVPR_ACTIVITY_MASK; src->pending = 0; @@ -984,7 +1031,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { src->idr &= ~(1 << idx); - if (src->idr && !(src->ivpr & IVPR_SENSE_MASK)) { + if (src->idr && !src->level) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, n_IRQ, 1); openpic_set_irq(opp, n_IRQ, 0); @@ -1282,7 +1329,25 @@ static int openpic_init(SysBusDevice *dev) opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; msi_supported = true; list = list_be; + + for (i = 0; i < FSL_MPIC_20_MAX_EXT; i++) { + opp->src[i].level = false; + } + + /* Internal interrupts, including message and MSI */ + for (i = 16; i < MAX_SRC; i++) { + opp->src[i].type = IRQ_TYPE_FSLINT; + opp->src[i].level = true; + } + + /* timers and IPIs */ + for (i = MAX_SRC; i < MAX_IRQ; i++) { + opp->src[i].type = IRQ_TYPE_FSLSPECIAL; + opp->src[i].level = false; + } + break; + case OPENPIC_MODEL_RAVEN: opp->nb_irqs = RAVEN_MAX_EXT; opp->vid = VID_REVISION_1_3; From 4417c73305f60e46a2370bcaf3635981f5dbc050 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:38 +0000 Subject: [PATCH 0302/1634] openpic: IRQ_check: search the queue a word at a time Search the queue more efficiently by first looking for a non-zero word, and then using the common bit-searching function to find the bit within the word. It would be even nicer if bitops_ffsl() could be hooked up to the compiler intrinsic so that bit-searching instructions could be used, but that's another matter. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 66179c22cb..7645d6770e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -277,21 +277,25 @@ static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) static void IRQ_check(OpenPICState *opp, IRQQueue *q) { - int next, i; - int priority; + int irq = -1; + int next = -1; + int priority = -1; - next = -1; - priority = -1; - for (i = 0; i < opp->max_irq; i++) { - if (IRQ_testbit(q, i)) { - DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", - i, IVPR_PRIORITY(opp->src[i].ivpr), priority); - if (IVPR_PRIORITY(opp->src[i].ivpr) > priority) { - next = i; - priority = IVPR_PRIORITY(opp->src[i].ivpr); - } + for (;;) { + irq = find_next_bit(q->queue, opp->max_irq, irq + 1); + if (irq == opp->max_irq) { + break; + } + + DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", + irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); + + if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { + next = irq; + priority = IVPR_PRIORITY(opp->src[irq].ivpr); } } + q->next = next; q->priority = priority; } From a898a8fc96a071189206218b39b5db99531f5c8b Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:39 +0000 Subject: [PATCH 0303/1634] openpic: move IACK to its own function Besides making the code cleaner, we will need a separate way to access IACK in order to implement EPR (external proxy) interrupt delivery. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 95 +++++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 7645d6770e..374f80e880 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -975,14 +975,64 @@ static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); } + +static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) +{ + IRQSource *src; + int retval, irq; + + DPRINTF("Lower OpenPIC INT output\n"); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); + + irq = IRQ_get_next(opp, &dst->raised); + DPRINTF("IACK: irq=%d\n", irq); + + if (irq == -1) { + /* No more interrupt pending */ + return opp->spve; + } + + src = &opp->src[irq]; + if (!(src->ivpr & IVPR_ACTIVITY_MASK) || + !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { + /* - Spurious level-sensitive IRQ + * - Priorities has been changed + * and the pending IRQ isn't allowed anymore + */ + src->ivpr &= ~IVPR_ACTIVITY_MASK; + retval = opp->spve; + } else { + /* IRQ enter servicing state */ + IRQ_setbit(&dst->servicing, irq); + retval = IVPR_VECTOR(opp, src->ivpr); + } + IRQ_resetbit(&dst->raised, irq); + if (!src->level) { + /* edge-sensitive IRQ */ + src->ivpr &= ~IVPR_ACTIVITY_MASK; + src->pending = 0; + } + + if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { + src->idr &= ~(1 << cpu); + if (src->idr && !src->level) { + /* trigger on CPUs that didn't know about it yet */ + openpic_set_irq(opp, irq, 1); + openpic_set_irq(opp, irq, 0); + /* if all CPUs knew about it, set active bit again */ + src->ivpr |= IVPR_ACTIVITY_MASK; + } + } + + return retval; +} + static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx) { OpenPICState *opp = opaque; - IRQSource *src; IRQDest *dst; uint32_t retval; - int n_IRQ; DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; @@ -1004,46 +1054,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, retval = idx; break; case 0xA0: /* IACK */ - DPRINTF("Lower OpenPIC INT output\n"); - qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); - n_IRQ = IRQ_get_next(opp, &dst->raised); - DPRINTF("IACK: irq=%d\n", n_IRQ); - if (n_IRQ == -1) { - /* No more interrupt pending */ - retval = opp->spve; - } else { - src = &opp->src[n_IRQ]; - if (!(src->ivpr & IVPR_ACTIVITY_MASK) || - !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { - /* - Spurious level-sensitive IRQ - * - Priorities has been changed - * and the pending IRQ isn't allowed anymore - */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; - retval = opp->spve; - } else { - /* IRQ enter servicing state */ - IRQ_setbit(&dst->servicing, n_IRQ); - retval = IVPR_VECTOR(opp, src->ivpr); - } - IRQ_resetbit(&dst->raised, n_IRQ); - if (!src->level) { - /* edge-sensitive IRQ */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; - src->pending = 0; - } - - if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { - src->idr &= ~(1 << idx); - if (src->idr && !src->level) { - /* trigger on CPUs that didn't know about it yet */ - openpic_set_irq(opp, n_IRQ, 1); - openpic_set_irq(opp, n_IRQ, 0); - /* if all CPUs knew about it, set active bit again */ - src->ivpr |= IVPR_ACTIVITY_MASK; - } - } - } + retval = openpic_iack(opp, dst, idx); break; case 0xB0: /* EOI */ retval = 0; From 9f1d4b1d6939d39fe570d886f6a651f4764bcbcb Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 3 Jan 2013 13:25:40 +0000 Subject: [PATCH 0304/1634] openpic: fix CTPR and de-assertion of interrupts Properly implement level-triggered interrupts by withdrawing an interrupt from the raised queue if the interrupt source de-asserts. Also withdraw from the raised queue if the interrupt becomes masked. When CTPR is written, check whether we need to raise or lower the interrupt output. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 183 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 124 insertions(+), 59 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 374f80e880..e773d680f4 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -213,6 +213,9 @@ typedef struct IRQDest { IRQQueue raised; IRQQueue servicing; qemu_irq *irqs; + + /* Count of IRQ sources asserting on non-INT outputs */ + uint32_t outputs_active[OPENPIC_OUTPUT_NB]; } IRQDest; typedef struct OpenPICState { @@ -308,7 +311,8 @@ static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) return q->next; } -static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) +static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, + bool active, bool was_active) { IRQDest *dst; IRQSource *src; @@ -317,79 +321,113 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; + DPRINTF("%s: IRQ %d active %d was %d\n", + __func__, n_IRQ, active, was_active); + if (src->output != OPENPIC_OUTPUT_INT) { + DPRINTF("%s: output %d irq %d active %d was %d count %d\n", + __func__, src->output, n_IRQ, active, was_active, + dst->outputs_active[src->output]); + /* On Freescale MPIC, critical interrupts ignore priority, * IACK, EOI, etc. Before MPIC v4.1 they also ignore * masking. */ - src->ivpr |= IVPR_ACTIVITY_MASK; - DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", - __func__, src->output, n_CPU, n_IRQ); - qemu_irq_raise(opp->dst[n_CPU].irqs[src->output]); + if (active) { + if (!was_active && dst->outputs_active[src->output]++ == 0) { + DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_raise(dst->irqs[src->output]); + } + } else { + if (was_active && --dst->outputs_active[src->output] == 0) { + DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n", + __func__, src->output, n_CPU, n_IRQ); + qemu_irq_lower(dst->irqs[src->output]); + } + } + return; } priority = IVPR_PRIORITY(src->ivpr); - if (priority <= dst->ctpr) { - /* Too low priority */ - DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", - __func__, n_IRQ, n_CPU); - return; - } - if (IRQ_testbit(&dst->raised, n_IRQ)) { - /* Interrupt miss */ - DPRINTF("%s: IRQ %d was missed on CPU %d\n", - __func__, n_IRQ, n_CPU); - return; - } - src->ivpr |= IVPR_ACTIVITY_MASK; - IRQ_setbit(&dst->raised, n_IRQ); - if (priority < dst->raised.priority) { - /* An higher priority IRQ is already raised */ - DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->raised.next, n_CPU); - return; + + /* Even if the interrupt doesn't have enough priority, + * it is still raised, in case ctpr is lowered later. + */ + if (active) { + IRQ_setbit(&dst->raised, n_IRQ); + } else { + IRQ_resetbit(&dst->raised, n_IRQ); } + IRQ_check(opp, &dst->raised); - if (IRQ_get_next(opp, &dst->servicing) != -1 && - priority <= dst->servicing.priority) { - DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", - __func__, n_IRQ, dst->servicing.next, n_CPU); - /* Already servicing a higher priority IRQ */ - return; + + if (active && priority <= dst->ctpr) { + DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", + __func__, n_IRQ, priority, dst->ctpr, n_CPU); + active = 0; + } + + if (active) { + if (IRQ_get_next(opp, &dst->servicing) >= 0 && + priority <= dst->servicing.priority) { + DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", + __func__, n_IRQ, dst->servicing.next, n_CPU); + } else { + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", + __func__, n_CPU, n_IRQ, dst->raised.next); + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + } + } else { + IRQ_get_next(opp, &dst->servicing); + if (dst->raised.priority > dst->ctpr && + dst->raised.priority > dst->servicing.priority) { + DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", + __func__, n_IRQ, dst->raised.next, dst->raised.priority, + dst->ctpr, dst->servicing.priority, n_CPU); + /* IRQ line stays asserted */ + } else { + DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", + __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); + qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + } } - DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } /* update pic state because registers for n_IRQ have changed value */ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) { IRQSource *src; + bool active, was_active; int i; src = &opp->src[n_IRQ]; + active = src->pending; - if (!src->pending) { - /* no irq pending */ - DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); - return; - } if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); + active = false; + } + + was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); + + /* + * We don't have a similar check for already-active because + * ctpr may have changed and we need to withdraw the interrupt. + */ + if (!active && !was_active) { + DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ); return; } - if (IVPR_PRIORITY(src->ivpr) == 0) { - /* Priority set to zero */ - DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); - return; - } - if (src->ivpr & IVPR_ACTIVITY_MASK) { - /* IRQ already active */ - DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); - return; + + if (active) { + src->ivpr |= IVPR_ACTIVITY_MASK; + } else { + src->ivpr &= ~IVPR_ACTIVITY_MASK; } + if (src->idr == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); @@ -398,12 +436,12 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if (src->idr == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ - IRQ_local_pipe(opp, src->last_cpu, n_IRQ); + IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); } else if (!(src->ivpr & IVPR_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ); + IRQ_local_pipe(opp, i, n_IRQ, active, was_active); } } } else { @@ -413,7 +451,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) i = 0; } if (src->destmask & (1 << i)) { - IRQ_local_pipe(opp, i, n_IRQ); + IRQ_local_pipe(opp, i, n_IRQ, active, was_active); src->last_cpu = i; break; } @@ -437,16 +475,25 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) if (src->level) { /* level-sensitive irq */ src->pending = level; - if (!level) { - src->ivpr &= ~IVPR_ACTIVITY_MASK; - } + openpic_update_irq(opp, n_IRQ); } else { /* edge-sensitive irq */ if (level) { src->pending = 1; + openpic_update_irq(opp, n_IRQ); + } + + if (src->output != OPENPIC_OUTPUT_INT) { + /* Edge-triggered interrupts shouldn't be used + * with non-INT delivery, but just in case, + * try to make it do something sane rather than + * cause an interrupt storm. This is close to + * what you'd probably see happen in real hardware. + */ + src->pending = 0; + openpic_update_irq(opp, n_IRQ); } } - openpic_update_irq(opp, n_IRQ); } static void openpic_reset(DeviceState *d) @@ -934,6 +981,21 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, break; case 0x80: /* CTPR */ dst->ctpr = val & 0x0000000F; + + DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", + __func__, idx, dst->ctpr, dst->raised.priority, + dst->servicing.priority); + + if (dst->raised.priority <= dst->ctpr) { + DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", + __func__, idx); + qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); + } else if (dst->raised.priority > dst->servicing.priority) { + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n", + __func__, idx, dst->raised.next); + qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); + } + break; case 0x90: /* WHOAMI */ /* Read-only register */ @@ -995,22 +1057,21 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) src = &opp->src[irq]; if (!(src->ivpr & IVPR_ACTIVITY_MASK) || !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { - /* - Spurious level-sensitive IRQ - * - Priorities has been changed - * and the pending IRQ isn't allowed anymore - */ - src->ivpr &= ~IVPR_ACTIVITY_MASK; + fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", + __func__, irq, dst->ctpr, src->ivpr); + openpic_update_irq(opp, irq); retval = opp->spve; } else { /* IRQ enter servicing state */ IRQ_setbit(&dst->servicing, irq); retval = IVPR_VECTOR(opp, src->ivpr); } - IRQ_resetbit(&dst->raised, irq); + if (!src->level) { /* edge-sensitive IRQ */ src->ivpr &= ~IVPR_ACTIVITY_MASK; src->pending = 0; + IRQ_resetbit(&dst->raised, irq); } if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { @@ -1208,6 +1269,8 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_sbe32s(f, &opp->dst[i].ctpr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); openpic_save_IRQ_queue(f, &opp->dst[i].servicing); + qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, + sizeof(opp->dst[i].outputs_active)); } for (i = 0; i < MAX_TMR; i++) { @@ -1264,6 +1327,8 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_sbe32s(f, &opp->dst[i].ctpr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); openpic_load_IRQ_queue(f, &opp->dst[i].servicing); + qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, + sizeof(opp->dst[i].outputs_active)); } for (i = 0; i < MAX_TMR; i++) { From d4834ff9b72d7b89181e88b1a481564cb750c1b5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 4 Jan 2013 10:04:19 +0100 Subject: [PATCH 0305/1634] kvm: Update kernel headers Corresponding kvm.git hash: 18eb54cf4a Signed-off-by: Alexander Graf --- linux-headers/asm-powerpc/epapr_hcalls.h | 98 ++++++++++++++++++++++++ linux-headers/asm-powerpc/kvm.h | 86 +++++++++++++++++++++ linux-headers/asm-powerpc/kvm_para.h | 13 ++-- linux-headers/linux/kvm.h | 21 +++-- linux-headers/linux/kvm_para.h | 6 +- linux-headers/linux/vfio.h | 6 +- linux-headers/linux/virtio_config.h | 6 +- linux-headers/linux/virtio_ring.h | 6 +- 8 files changed, 219 insertions(+), 23 deletions(-) create mode 100644 linux-headers/asm-powerpc/epapr_hcalls.h diff --git a/linux-headers/asm-powerpc/epapr_hcalls.h b/linux-headers/asm-powerpc/epapr_hcalls.h new file mode 100644 index 0000000000..06f724786a --- /dev/null +++ b/linux-headers/asm-powerpc/epapr_hcalls.h @@ -0,0 +1,98 @@ +/* + * ePAPR hcall interface + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * + * Author: Timur Tabi + * + * This file is provided under a dual BSD/GPL license. When using or + * redistributing this file, you may do so under either license. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_POWERPC_EPAPR_HCALLS_H +#define _ASM_POWERPC_EPAPR_HCALLS_H + +#define EV_BYTE_CHANNEL_SEND 1 +#define EV_BYTE_CHANNEL_RECEIVE 2 +#define EV_BYTE_CHANNEL_POLL 3 +#define EV_INT_SET_CONFIG 4 +#define EV_INT_GET_CONFIG 5 +#define EV_INT_SET_MASK 6 +#define EV_INT_GET_MASK 7 +#define EV_INT_IACK 9 +#define EV_INT_EOI 10 +#define EV_INT_SEND_IPI 11 +#define EV_INT_SET_TASK_PRIORITY 12 +#define EV_INT_GET_TASK_PRIORITY 13 +#define EV_DOORBELL_SEND 14 +#define EV_MSGSND 15 +#define EV_IDLE 16 + +/* vendor ID: epapr */ +#define EV_LOCAL_VENDOR_ID 0 /* for private use */ +#define EV_EPAPR_VENDOR_ID 1 +#define EV_FSL_VENDOR_ID 2 /* Freescale Semiconductor */ +#define EV_IBM_VENDOR_ID 3 /* IBM */ +#define EV_GHS_VENDOR_ID 4 /* Green Hills Software */ +#define EV_ENEA_VENDOR_ID 5 /* Enea */ +#define EV_WR_VENDOR_ID 6 /* Wind River Systems */ +#define EV_AMCC_VENDOR_ID 7 /* Applied Micro Circuits */ +#define EV_KVM_VENDOR_ID 42 /* KVM */ + +/* The max number of bytes that a byte channel can send or receive per call */ +#define EV_BYTE_CHANNEL_MAX_BYTES 16 + + +#define _EV_HCALL_TOKEN(id, num) (((id) << 16) | (num)) +#define EV_HCALL_TOKEN(hcall_num) _EV_HCALL_TOKEN(EV_EPAPR_VENDOR_ID, hcall_num) + +/* epapr return codes */ +#define EV_SUCCESS 0 +#define EV_EPERM 1 /* Operation not permitted */ +#define EV_ENOENT 2 /* Entry Not Found */ +#define EV_EIO 3 /* I/O error occured */ +#define EV_EAGAIN 4 /* The operation had insufficient + * resources to complete and should be + * retried + */ +#define EV_ENOMEM 5 /* There was insufficient memory to + * complete the operation */ +#define EV_EFAULT 6 /* Bad guest address */ +#define EV_ENODEV 7 /* No such device */ +#define EV_EINVAL 8 /* An argument supplied to the hcall + was out of range or invalid */ +#define EV_INTERNAL 9 /* An internal error occured */ +#define EV_CONFIG 10 /* A configuration error was detected */ +#define EV_INVALID_STATE 11 /* The object is in an invalid state */ +#define EV_UNIMPLEMENTED 12 /* Unimplemented hypercall */ +#define EV_BUFFER_OVERFLOW 13 /* Caller-supplied buffer too small */ + +#endif /* _ASM_POWERPC_EPAPR_HCALLS_H */ diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 1bea4d8ea6..2fba8a66fb 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -221,6 +221,12 @@ struct kvm_sregs { __u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */ __u32 dbcr[3]; + /* + * iac/dac registers are 64bit wide, while this API + * interface provides only lower 32 bits on 64 bit + * processors. ONE_REG interface is added for 64bit + * iac/dac registers. + */ __u32 iac[4]; __u32 dac[2]; __u32 dvc[2]; @@ -325,6 +331,86 @@ struct kvm_book3e_206_tlb_params { __u32 reserved[8]; }; +/* For KVM_PPC_GET_HTAB_FD */ +struct kvm_get_htab_fd { + __u64 flags; + __u64 start_index; + __u64 reserved[2]; +}; + +/* Values for kvm_get_htab_fd.flags */ +#define KVM_GET_HTAB_BOLTED_ONLY ((__u64)0x1) +#define KVM_GET_HTAB_WRITE ((__u64)0x2) + +/* + * Data read on the file descriptor is formatted as a series of + * records, each consisting of a header followed by a series of + * `n_valid' HPTEs (16 bytes each), which are all valid. Following + * those valid HPTEs there are `n_invalid' invalid HPTEs, which + * are not represented explicitly in the stream. The same format + * is used for writing. + */ +struct kvm_get_htab_header { + __u32 index; + __u16 n_valid; + __u16 n_invalid; +}; + #define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1) +#define KVM_REG_PPC_IAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2) +#define KVM_REG_PPC_IAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3) +#define KVM_REG_PPC_IAC3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4) +#define KVM_REG_PPC_IAC4 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5) +#define KVM_REG_PPC_DAC1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6) +#define KVM_REG_PPC_DAC2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7) +#define KVM_REG_PPC_DABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8) +#define KVM_REG_PPC_DSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9) +#define KVM_REG_PPC_PURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa) +#define KVM_REG_PPC_SPURR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb) +#define KVM_REG_PPC_DAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc) +#define KVM_REG_PPC_DSISR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xd) +#define KVM_REG_PPC_AMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xe) +#define KVM_REG_PPC_UAMOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xf) + +#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10) +#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11) +#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12) + +#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18) +#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19) +#define KVM_REG_PPC_PMC3 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1a) +#define KVM_REG_PPC_PMC4 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1b) +#define KVM_REG_PPC_PMC5 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1c) +#define KVM_REG_PPC_PMC6 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1d) +#define KVM_REG_PPC_PMC7 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1e) +#define KVM_REG_PPC_PMC8 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x1f) + +/* 32 floating-point registers */ +#define KVM_REG_PPC_FPR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x20) +#define KVM_REG_PPC_FPR(n) (KVM_REG_PPC_FPR0 + (n)) +#define KVM_REG_PPC_FPR31 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3f) + +/* 32 VMX/Altivec vector registers */ +#define KVM_REG_PPC_VR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x40) +#define KVM_REG_PPC_VR(n) (KVM_REG_PPC_VR0 + (n)) +#define KVM_REG_PPC_VR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x5f) + +/* 32 double-width FP registers for VSX */ +/* High-order halves overlap with FP regs */ +#define KVM_REG_PPC_VSR0 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x60) +#define KVM_REG_PPC_VSR(n) (KVM_REG_PPC_VSR0 + (n)) +#define KVM_REG_PPC_VSR31 (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x7f) + +/* FP and vector status/control registers */ +#define KVM_REG_PPC_FPSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x80) +#define KVM_REG_PPC_VSCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x81) + +/* Virtual processor areas */ +/* For SLB & DTL, address in high (first) half, length in low half */ +#define KVM_REG_PPC_VPA_ADDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x82) +#define KVM_REG_PPC_VPA_SLB (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x83) +#define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84) + +#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h index 5e04383a1d..7e64f575f6 100644 --- a/linux-headers/asm-powerpc/kvm_para.h +++ b/linux-headers/asm-powerpc/kvm_para.h @@ -17,8 +17,8 @@ * Authors: Hollis Blanchard */ -#ifndef _UAPI__POWERPC_KVM_PARA_H__ -#define _UAPI__POWERPC_KVM_PARA_H__ +#ifndef __POWERPC_KVM_PARA_H__ +#define __POWERPC_KVM_PARA_H__ #include @@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared { }; #define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */ -#define HC_VENDOR_KVM (42 << 16) -#define HC_EV_SUCCESS 0 -#define HC_EV_UNIMPLEMENTED 12 + +#define KVM_HCALL_TOKEN(num) _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num) + +#include #define KVM_FEATURE_MAGIC_PAGE 1 @@ -87,4 +88,4 @@ struct kvm_vcpu_arch_shared { #define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1) -#endif /* _UAPI__POWERPC_KVM_PARA_H__ */ +#endif /* __POWERPC_KVM_PARA_H__ */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 81d2feb7ab..bfdbf4d1ad 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -167,10 +167,15 @@ struct kvm_pit_config { #define KVM_EXIT_OSI 18 #define KVM_EXIT_PAPR_HCALL 19 #define KVM_EXIT_S390_UCONTROL 20 +#define KVM_EXIT_WATCHDOG 21 /* For KVM_EXIT_INTERNAL_ERROR */ -#define KVM_INTERNAL_ERROR_EMULATION 1 -#define KVM_INTERNAL_ERROR_SIMUL_EX 2 +/* Emulate instruction failed. */ +#define KVM_INTERNAL_ERROR_EMULATION 1 +/* Encounter unexpected simultaneous exceptions. */ +#define KVM_INTERNAL_ERROR_SIMUL_EX 2 +/* Encounter unexpected vm-exit due to delivery event. */ +#define KVM_INTERNAL_ERROR_DELIVERY_EV 3 /* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */ struct kvm_run { @@ -477,6 +482,8 @@ struct kvm_ppc_smmu_info { struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ]; }; +#define KVM_PPC_PVINFO_FLAGS_EV_IDLE (1<<0) + #define KVMIO 0xAE /* machine type bits, to be used as argument to KVM_CREATE_VM */ @@ -626,6 +633,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_READONLY_MEM 81 #endif #define KVM_CAP_IRQFD_RESAMPLE 82 +#define KVM_CAP_PPC_BOOKE_WATCHDOG 83 +#define KVM_CAP_PPC_HTAB_FD 84 #ifdef KVM_CAP_IRQ_ROUTING @@ -848,6 +857,11 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info) /* Available with KVM_CAP_PPC_ALLOC_HTAB */ #define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32) +#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce) +/* Available with KVM_CAP_RMA */ +#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) +/* Available with KVM_CAP_PPC_HTAB_FD */ +#define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) /* * ioctls for vcpu fds @@ -911,9 +925,6 @@ struct kvm_s390_ucas_mapping { /* Available with KVM_CAP_XCRS */ #define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs) #define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs) -#define KVM_CREATE_SPAPR_TCE _IOW(KVMIO, 0xa8, struct kvm_create_spapr_tce) -/* Available with KVM_CAP_RMA */ -#define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) /* Available with KVM_CAP_SW_TLB */ #define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb) /* Available with KVM_CAP_ONE_REG */ diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h index cea2c5c72d..7bdcf93c1d 100644 --- a/linux-headers/linux/kvm_para.h +++ b/linux-headers/linux/kvm_para.h @@ -1,5 +1,5 @@ -#ifndef _UAPI__LINUX_KVM_PARA_H -#define _UAPI__LINUX_KVM_PARA_H +#ifndef __LINUX_KVM_PARA_H +#define __LINUX_KVM_PARA_H /* * This header file provides a method for making a hypercall to the host @@ -25,4 +25,4 @@ */ #include -#endif /* _UAPI__LINUX_KVM_PARA_H */ +#endif /* __LINUX_KVM_PARA_H */ diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 4758d1bfcf..f787b727a9 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -8,8 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef _UAPIVFIO_H -#define _UAPIVFIO_H +#ifndef VFIO_H +#define VFIO_H #include #include @@ -365,4 +365,4 @@ struct vfio_iommu_type1_dma_unmap { #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14) -#endif /* _UAPIVFIO_H */ +#endif /* VFIO_H */ diff --git a/linux-headers/linux/virtio_config.h b/linux-headers/linux/virtio_config.h index b7cda390fd..4f51d8f3af 100644 --- a/linux-headers/linux/virtio_config.h +++ b/linux-headers/linux/virtio_config.h @@ -1,5 +1,5 @@ -#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H -#define _UAPI_LINUX_VIRTIO_CONFIG_H +#ifndef _LINUX_VIRTIO_CONFIG_H +#define _LINUX_VIRTIO_CONFIG_H /* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so * anyone can use the definitions to implement compatible drivers/servers. * @@ -51,4 +51,4 @@ * suppressed them? */ #define VIRTIO_F_NOTIFY_ON_EMPTY 24 -#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */ +#endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h index 921694a084..1b333e2536 100644 --- a/linux-headers/linux/virtio_ring.h +++ b/linux-headers/linux/virtio_ring.h @@ -1,5 +1,5 @@ -#ifndef _UAPI_LINUX_VIRTIO_RING_H -#define _UAPI_LINUX_VIRTIO_RING_H +#ifndef _LINUX_VIRTIO_RING_H +#define _LINUX_VIRTIO_RING_H /* An interface for efficient virtio implementation, currently for use by KVM * and lguest, but hopefully others soon. Do NOT change this since it will * break existing servers and clients. @@ -160,4 +160,4 @@ static __inline__ int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old); } -#endif /* _UAPI_LINUX_VIRTIO_RING_H */ +#endif /* _LINUX_VIRTIO_RING_H */ From 1a61a9ae61cdf7b7d24c3eb711fe772c196c235e Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Thu, 3 Jan 2013 12:37:02 +0000 Subject: [PATCH 0306/1634] PPC: KVM: set has-idle in guest device tree On e500mc, the platform doesn't provide a way for the CPU to go idle. To still not uselessly burn CPU time, expose an idle hypercall to the guest if kvm supports it. Signed-off-by: Stuart Yoder [agraf: adjust for current code base, add patch description, fix non-kvm case] Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 4 ++++ target-ppc/kvm.c | 38 +++++++++++++++++++++++++++++--------- target-ppc/kvm_ppc.h | 6 ++++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index b262f31e5a..5d70618f72 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -225,6 +225,10 @@ static int ppce500_load_device_tree(CPUPPCState *env, kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", hypercall, sizeof(hypercall)); + /* if KVM supports the idle hcall, set property indicating this */ + if (kvmppc_get_hasidle(env)) { + qemu_devtree_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); + } } /* Create CPU nodes */ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 436ca474ff..9fe949fbec 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -989,18 +989,38 @@ uint32_t kvmppc_get_dfp(void) return kvmppc_read_int_cpu_dt("ibm,dfp"); } -int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) -{ - PowerPCCPU *cpu = ppc_env_get_cpu(env); - CPUState *cs = CPU(cpu); - uint32_t *hc = (uint32_t*)buf; - - struct kvm_ppc_pvinfo pvinfo; +static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo) + { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) && - !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) { - memcpy(buf, pvinfo.hcall, buf_len); + !kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, pvinfo)) { + return 0; + } + return 1; +} + +int kvmppc_get_hasidle(CPUPPCState *env) +{ + struct kvm_ppc_pvinfo pvinfo; + + if (!kvmppc_get_pvinfo(env, &pvinfo) && + (pvinfo.flags & KVM_PPC_PVINFO_FLAGS_EV_IDLE)) { + return 1; + } + + return 0; +} + +int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) +{ + uint32_t *hc = (uint32_t*)buf; + struct kvm_ppc_pvinfo pvinfo; + + if (!kvmppc_get_pvinfo(env, &pvinfo)) { + memcpy(buf, pvinfo.hcall, buf_len); return 0; } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 31eb9e6f22..9b0d500b50 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -19,6 +19,7 @@ uint32_t kvmppc_get_tbfreq(void); uint64_t kvmppc_get_clockfreq(void); uint32_t kvmppc_get_vmx(void); uint32_t kvmppc_get_dfp(void); +int kvmppc_get_hasidle(CPUPPCState *env); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_set_papr(PowerPCCPU *cpu); @@ -55,6 +56,11 @@ static inline uint32_t kvmppc_get_dfp(void) return 0; } +static inline int kvmppc_get_hasidle(CPUPPCState *env) +{ + return 0; +} + static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len) { return -1; From 68c2dd70068fe82a1989d0d5b70a1ab400bde19a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 4 Jan 2013 11:21:04 +0100 Subject: [PATCH 0307/1634] PPC: Bring EPR support closer to reality We already used to support the external proxy facility of FSL MPICs, but only implemented it halfway correctly. This patch adds support for * dynamic enablement of the EPR facility * interrupt acknowledgement only when the interrupt is delivered This way the implementation now is closer to real hardware. Signed-off-by: Alexander Graf --- hw/openpic.c | 21 +++++++++++++++++++++ hw/ppc/e500.c | 4 ++-- target-ppc/Makefile.objs | 1 - target-ppc/cpu.h | 4 +++- target-ppc/excp_helper.c | 4 ++++ target-ppc/helper.h | 1 - target-ppc/mpic_helper.c | 35 ----------------------------------- target-ppc/translate_init.c | 7 +------ 8 files changed, 31 insertions(+), 46 deletions(-) delete mode 100644 target-ppc/mpic_helper.c diff --git a/hw/openpic.c b/hw/openpic.c index e773d680f4..3b20a39ab5 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -131,6 +131,9 @@ static const int debug_openpic = 0; #define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ #define GCR_RESET 0x80000000 +#define GCR_MODE_PASS 0x00000000 +#define GCR_MODE_MIXED 0x20000000 +#define GCR_MODE_PROXY 0x60000000 #define TBCR_CI 0x80000000 /* count inhibit */ #define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ @@ -233,6 +236,7 @@ typedef struct OpenPICState { uint32_t ivpr_reset; uint32_t idr_reset; uint32_t brr1; + uint32_t mpic_mode_mask; /* Sub-regions */ MemoryRegion sub_io_mem[5]; @@ -667,6 +671,20 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x1020: /* GCR */ if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); + } else if (opp->mpic_mode_mask) { + CPUArchState *env; + int mpic_proxy = 0; + + opp->gcr &= ~opp->mpic_mode_mask; + opp->gcr |= val & opp->mpic_mode_mask; + + /* Set external proxy mode */ + if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { + mpic_proxy = 1; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = mpic_proxy; + } } break; case 0x1080: /* VIR */ @@ -1407,6 +1425,9 @@ static int openpic_init(SysBusDevice *dev) opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; opp->irq_msi = FSL_MPIC_20_MSI_IRQ; opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; + /* XXX really only available as of MPIC 4.0 */ + opp->mpic_mode_mask = GCR_MODE_PROXY; + msi_supported = true; list = list_be; diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 5d70618f72..3a9e1c7b43 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -497,8 +497,8 @@ void ppce500_init(PPCE500Params *params) irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; - env->mpic_cpu_base = MPC8544_CCSRBAR_BASE + - MPC8544_MPIC_REGS_OFFSET + 0x20000; + env->mpic_iack = MPC8544_CCSRBAR_BASE + + MPC8544_MPIC_REGS_OFFSET + 0x200A0; ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 237a0ed4f7..6c11ef84b7 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -9,4 +9,3 @@ obj-y += mmu_helper.o obj-y += timebase_helper.o obj-y += misc_helper.o obj-y += mem_helper.o -obj-y += mpic_helper.o diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e88ebe00d4..dc5145bf39 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1067,7 +1067,9 @@ struct CPUPPCState { target_ulong ivor_mask; target_ulong ivpr_mask; target_ulong hreset_vector; - hwaddr mpic_cpu_base; + hwaddr mpic_iack; + /* true when the external proxy facility mode is enabled */ + bool mpic_proxy; #endif /* Those resources are used only during code translation */ diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 41037a7e26..0a1ac86a42 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -178,6 +178,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) if (lpes0 == 1) { new_msr |= (target_ulong)MSR_HVB; } + if (env->mpic_proxy) { + /* IACK the IRQ on delivery */ + env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack); + } goto store_next; case POWERPC_EXCP_ALIGN: /* Alignment exception */ if (lpes1 == 0) { diff --git a/target-ppc/helper.h b/target-ppc/helper.h index d2e9a55f28..83139d5225 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -405,7 +405,6 @@ DEF_HELPER_2(store_40x_dbcr0, void, env, tl) DEF_HELPER_2(store_40x_sler, void, env, tl) DEF_HELPER_2(store_booke_tcr, void, env, tl) DEF_HELPER_2(store_booke_tsr, void, env, tl) -DEF_HELPER_1(load_epr, tl, env) DEF_HELPER_3(store_ibatl, void, env, i32, tl) DEF_HELPER_3(store_ibatu, void, env, i32, tl) DEF_HELPER_3(store_dbatl, void, env, i32, tl) diff --git a/target-ppc/mpic_helper.c b/target-ppc/mpic_helper.c deleted file mode 100644 index 2c6a4d30a9..0000000000 --- a/target-ppc/mpic_helper.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * PowerPC emulation helpers for QEMU. - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -#include "cpu.h" -#include "helper.h" - -/*****************************************************************************/ -/* SPR accesses */ - -#if !defined(CONFIG_USER_ONLY) -/* - * This is an ugly helper for EPR, which is basically the same as accessing - * the IACK (PIAC) register on the MPIC. Because we model the MPIC as a device - * that can only talk to the CPU through MMIO, let's access it that way! - */ -target_ulong helper_load_epr(CPUPPCState *env) -{ - return ldl_phys(env->mpic_cpu_base + 0xA0); -} -#endif diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 42ed748b59..e2eeb87650 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -4493,11 +4493,6 @@ static void spr_read_mas73(void *opaque, int gprn, int sprn) tcg_temp_free(mas7); } -static void spr_load_epr(void *opaque, int gprn, int sprn) -{ - gen_helper_load_epr(cpu_gpr[gprn], cpu_env); -} - #endif enum fsl_e500_version { @@ -4656,7 +4651,7 @@ static void init_proc_e500 (CPUPPCState *env, int version) 0x00000000); spr_register(env, SPR_BOOKE_EPR, "EPR", SPR_NOACCESS, SPR_NOACCESS, - &spr_load_epr, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, 0x00000000); /* XXX better abstract into Emb.xxx features */ if (version == fsl_e5500) { From 2985b86b5c9c068af203bd912309af033112039a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 6 Jan 2013 08:31:30 +0000 Subject: [PATCH 0308/1634] target-ppc: Slim conversion of model definitions to QOM subclasses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the model list is highly macrofied, keep ppc_def_t for now and save a pointer to it in PowerPCCPUClass. This results in a flat list of subclasses including aliases, to be refined later. Move cpu_ppc_init() to translate_init.c and drop helper.c. Long-term the idea is to turn translate_init.c into a standalone cpu.c. Inline cpu_ppc_usable() into type registration. Split cpu_ppc_register() in two by code movement into the initfn and by turning the remaining part into a realizefn. Move qemu_init_vcpu() call into the new realizefn and adapt create_ppc_opcodes() to return an Error. Change ppc_find_by_pvr() -> ppc_cpu_class_by_pvr(). Change ppc_find_by_name() -> ppc_cpu_class_by_name(). Turn -cpu host into its own subclass. This requires to move the kvm_enabled() check in ppc_cpu_class_by_name() to avoid the class being found via the normal name lookup in the !kvm_enabled() case. Turn kvmppc_host_cpu_def() into the class_init and add an initfn that asserts KVM is in fact enabled. Implement -cpu ? and the QMP equivalent in terms of subclasses. This newly exposes -cpu host to the user, ordered last for -cpu ?. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 3 +- target-ppc/cpu-qom.h | 5 + target-ppc/cpu.h | 4 - target-ppc/helper.c | 50 ----- target-ppc/kvm.c | 37 +++- target-ppc/kvm_ppc.h | 8 +- target-ppc/translate_init.c | 353 ++++++++++++++++++++++++------------ 7 files changed, 280 insertions(+), 180 deletions(-) delete mode 100644 target-ppc/helper.c diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index 6c11ef84b7..a028dcdcd0 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -1,7 +1,6 @@ -obj-y += translate.o helper.o +obj-y += translate.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o -obj-y += helper.o obj-y += excp_helper.o obj-y += fpu_helper.o obj-y += int_helper.o diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index fb6b5a4119..b338f8fb56 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -50,6 +50,9 @@ typedef struct PowerPCCPUClass { /*< public >*/ void (*parent_reset)(CPUState *cpu); + + /* TODO inline fields here */ + ppc_def_t *info; } PowerPCCPUClass; /** @@ -73,5 +76,7 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) #define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e)) +PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); + #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index dc5145bf39..953146eeba 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1158,10 +1158,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value); void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr); -const ppc_def_t *cpu_ppc_find_by_name (const char *name); -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); - /* Time-base and decrementer management */ #ifndef NO_CPU_IO_DEFS uint64_t cpu_ppc_load_tbl (CPUPPCState *env); diff --git a/target-ppc/helper.c b/target-ppc/helper.c deleted file mode 100644 index 103855afe0..0000000000 --- a/target-ppc/helper.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * PowerPC emulation helpers for QEMU. - * - * Copyright (c) 2003-2007 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "cpu.h" -#include "helper_regs.h" -#include "sysemu/kvm.h" -#include "kvm_ppc.h" -#include "sysemu/cpus.h" - -PowerPCCPU *cpu_ppc_init(const char *cpu_model) -{ - PowerPCCPU *cpu; - CPUPPCState *env; - const ppc_def_t *def; - - def = cpu_ppc_find_by_name(cpu_model); - if (!def) { - return NULL; - } - - cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU)); - env = &cpu->env; - - if (tcg_enabled()) { - ppc_translate_init(); - } - - env->cpu_model_str = cpu_model; - cpu_ppc_register_internal(env, def); - - qemu_init_vcpu(env); - - return cpu; -} diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 9fe949fbec..ce7d69b403 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1230,18 +1230,29 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on) } } -const ppc_def_t *kvmppc_host_cpu_def(void) +static void kvmppc_host_cpu_initfn(Object *obj) { + assert(kvm_enabled()); +} + +static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); uint32_t host_pvr = mfpvr(); - const ppc_def_t *base_spec; + PowerPCCPUClass *pvr_pcc; ppc_def_t *spec; uint32_t vmx = kvmppc_get_vmx(); uint32_t dfp = kvmppc_get_dfp(); - base_spec = ppc_find_by_pvr(host_pvr); - spec = g_malloc0(sizeof(*spec)); - memcpy(spec, base_spec, sizeof(*spec)); + + pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); + if (pvr_pcc != NULL) { + memcpy(spec, pvr_pcc->info, sizeof(*spec)); + } + pcc->info = spec; + /* Override the display name for -cpu ? and QMP */ + pcc->info->name = "host"; /* Now fix up the spec with information we can query from the host */ @@ -1254,8 +1265,6 @@ const ppc_def_t *kvmppc_host_cpu_def(void) /* Only override when we know what the host supports */ alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); } - - return spec; } int kvmppc_fixup_cpu(CPUPPCState *env) @@ -1285,3 +1294,17 @@ int kvm_arch_on_sigbus(int code, void *addr) { return 1; } + +static const TypeInfo kvm_host_cpu_type_info = { + .name = TYPE_HOST_POWERPC_CPU, + .parent = TYPE_POWERPC_CPU, + .instance_init = kvmppc_host_cpu_initfn, + .class_init = kvmppc_host_cpu_class_init, +}; + +static void kvm_ppc_register_types(void) +{ + type_register_static(&kvm_host_cpu_type_info); +} + +type_init(kvm_ppc_register_types) diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 9b0d500b50..4b2172360a 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -11,6 +11,8 @@ #include "exec/memory.h" +#define TYPE_HOST_POWERPC_CPU "host-" TYPE_POWERPC_CPU + void kvmppc_init(void); #ifdef CONFIG_KVM @@ -31,7 +33,6 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); int kvmppc_reset_htab(int shift_hint); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ -const ppc_def_t *kvmppc_host_cpu_def(void); int kvmppc_fixup_cpu(CPUPPCState *env); #else @@ -121,11 +122,6 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env) #endif /* !CONFIG_USER_ONLY */ -static inline const ppc_def_t *kvmppc_host_cpu_def(void) -{ - return NULL; -} - static inline int kvmppc_fixup_cpu(CPUPPCState *env) { return -1; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index e2eeb87650..2b03756ee1 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9792,8 +9792,11 @@ static void fix_opcode_tables (opc_handler_t **ppc_opcodes) } /*****************************************************************************/ -static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) +static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; + const ppc_def_t *def = pcc->info; opcode_t *opc; fill_new_table(env->opcodes, 0x40); @@ -9801,18 +9804,16 @@ static int create_ppc_opcodes (CPUPPCState *env, const ppc_def_t *def) if (((opc->handler.type & def->insns_flags) != 0) || ((opc->handler.type2 & def->insns_flags2) != 0)) { if (register_insn(env->opcodes, opc) < 0) { - printf("*** ERROR initializing PowerPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, - opc->opc3); - return -1; + error_setg(errp, "ERROR initializing PowerPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); + return; } } } fix_opcode_tables(env->opcodes); fflush(stdout); fflush(stderr); - - return 0; } #if defined(PPC_DUMP_CPU) @@ -10026,53 +10027,31 @@ static int ppc_fixup_cpu(CPUPPCState *env) return 0; } -int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) +static void ppc_cpu_realize(Object *obj, Error **errp) { - env->msr_mask = def->msr_mask; - env->mmu_model = def->mmu_model; - env->excp_model = def->excp_model; - env->bus_model = def->bus_model; - env->insns_flags = def->insns_flags; - env->insns_flags2 = def->insns_flags2; - env->flags = def->flags; - env->bfd_mach = def->bfd_mach; - env->check_pow = def->check_pow; - -#if defined(TARGET_PPC64) - if (def->sps) - env->sps = *def->sps; - else if (env->mmu_model & POWERPC_MMU_64) { - /* Use default sets of page sizes */ - static const struct ppc_segment_page_sizes defsps = { - .sps = { - { .page_shift = 12, /* 4K */ - .slb_enc = 0, - .enc = { { .page_shift = 12, .pte_enc = 0 } } - }, - { .page_shift = 24, /* 16M */ - .slb_enc = 0x100, - .enc = { { .page_shift = 24, .pte_enc = 0 } } - }, - }, - }; - env->sps = defsps; - } -#endif /* defined(TARGET_PPC64) */ + PowerPCCPU *cpu = POWERPC_CPU(obj); + CPUPPCState *env = &cpu->env; + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + ppc_def_t *def = pcc->info; + Error *local_err = NULL; if (kvm_enabled()) { if (kvmppc_fixup_cpu(env) != 0) { - fprintf(stderr, "Unable to virtualize selected CPU with KVM\n"); - exit(1); + error_setg(errp, "Unable to virtualize selected CPU with KVM"); + return; } } else { if (ppc_fixup_cpu(env) != 0) { - fprintf(stderr, "Unable to emulate selected CPU with TCG\n"); - exit(1); + error_setg(errp, "Unable to emulate selected CPU with TCG"); + return; } } - if (create_ppc_opcodes(env, def) < 0) - return -1; + create_ppc_opcodes(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } init_ppc_proc(env, def); if (def->insns_flags & PPC_FLOAT) { @@ -10088,6 +10067,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) 34, "power-spe.xml", 0); } + qemu_init_vcpu(env); + #if defined(PPC_DUMP_CPU) { const char *mmu_model, *excp_model, *bus_model; @@ -10249,50 +10230,65 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) dump_ppc_sprs(env); fflush(stdout); #endif - - return 0; } -static bool ppc_cpu_usable(const ppc_def_t *def) +static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) { -#if defined(TARGET_PPCEMB) - /* When using the ppcemb target, we only support 440 style cores */ - if (def->mmu_model != POWERPC_MMU_BOOKE) { - return false; - } -#endif + ObjectClass *oc = (ObjectClass *)a; + uint32_t pvr = *(uint32_t *)b; + PowerPCCPUClass *pcc = (PowerPCCPUClass *)a; - return true; + /* -cpu host does a PVR lookup during construction */ + if (unlikely(strcmp(object_class_get_name(oc), + TYPE_HOST_POWERPC_CPU) == 0)) { + return -1; + } + + return pcc->info->pvr == pvr ? 0 : -1; } -const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) +PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr) { - int i; + GSList *list, *item; + PowerPCCPUClass *pcc = NULL; - for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } - - /* If we have an exact match, we're done */ - if (pvr == ppc_defs[i].pvr) { - return &ppc_defs[i]; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + item = g_slist_find_custom(list, &pvr, ppc_cpu_compare_class_pvr); + if (item != NULL) { + pcc = POWERPC_CPU_CLASS(item->data); } + g_slist_free(list); - return NULL; + return pcc; +} + +static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc = (ObjectClass *)a; + const char *name = b; + + if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 && + strcmp(object_class_get_name(oc) + strlen(name), + "-" TYPE_POWERPC_CPU) == 0) { + return 0; + } + return -1; } #include -const ppc_def_t *cpu_ppc_find_by_name (const char *name) +static ObjectClass *ppc_cpu_class_by_name(const char *name) { - const ppc_def_t *ret; + GSList *list, *item; + ObjectClass *ret = NULL; const char *p; - int i, max, len; + int i, len; - if (kvm_enabled() && (strcasecmp(name, "host") == 0)) { - return kvmppc_host_cpu_def(); + if (strcasecmp(name, "host") == 0) { + if (kvm_enabled()) { + ret = object_class_by_name(TYPE_HOST_POWERPC_CPU); + } + return ret; } /* Check if the given name is a PVR */ @@ -10307,65 +10303,154 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) if (!qemu_isxdigit(*p++)) break; } - if (i == 8) - return ppc_find_by_pvr(strtoul(name, NULL, 16)); - } - ret = NULL; - max = ARRAY_SIZE(ppc_defs); - for (i = 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; + if (i == 8) { + ret = OBJECT_CLASS(ppc_cpu_class_by_pvr(strtoul(name, NULL, 16))); + return ret; } + } - if (strcasecmp(name, ppc_defs[i].name) == 0) { - ret = &ppc_defs[i]; - break; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name); + if (item != NULL) { + ret = OBJECT_CLASS(item->data); } + g_slist_free(list); return ret; } -void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) +PowerPCCPU *cpu_ppc_init(const char *cpu_model) { - int i, max; + PowerPCCPU *cpu; + CPUPPCState *env; + ObjectClass *oc; + Error *err = NULL; - max = ARRAY_SIZE(ppc_defs); - for (i = 0; i < max; i++) { - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } - - (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", - ppc_defs[i].name, ppc_defs[i].pvr); + oc = ppc_cpu_class_by_name(cpu_model); + if (oc == NULL) { + return NULL; } + + cpu = POWERPC_CPU(object_new(object_class_get_name(oc))); + env = &cpu->env; + + if (tcg_enabled()) { + ppc_translate_init(); + } + + env->cpu_model_str = cpu_model; + + ppc_cpu_realize(OBJECT(cpu), &err); + if (err != NULL) { + fprintf(stderr, "%s\n", error_get_pretty(err)); + error_free(err); + object_delete(OBJECT(cpu)); + return NULL; + } + + return cpu; +} + +/* Sort by PVR, ordering special case "host" last. */ +static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *oc_a = (ObjectClass *)a; + ObjectClass *oc_b = (ObjectClass *)b; + PowerPCCPUClass *pcc_a = POWERPC_CPU_CLASS(oc_a); + PowerPCCPUClass *pcc_b = POWERPC_CPU_CLASS(oc_b); + const char *name_a = object_class_get_name(oc_a); + const char *name_b = object_class_get_name(oc_b); + + if (strcmp(name_a, TYPE_HOST_POWERPC_CPU) == 0) { + return 1; + } else if (strcmp(name_b, TYPE_HOST_POWERPC_CPU) == 0) { + return -1; + } else { + /* Avoid an integer overflow during subtraction */ + if (pcc_a->info->pvr < pcc_b->info->pvr) { + return -1; + } else if (pcc_a->info->pvr > pcc_b->info->pvr) { + return 1; + } else { + return 0; + } + } +} + +static void ppc_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CPUListState *s = user_data; + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", + pcc->info->name, pcc->info->pvr); +} + +void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_POWERPC_CPU, false); + list = g_slist_sort(list, ppc_cpu_list_compare); + g_slist_foreach(list, ppc_cpu_list_entry, &s); + g_slist_free(list); +} + +static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **first = user_data; + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(pcc->info->name); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = *first; + *first = entry; } CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) { CpuDefinitionInfoList *cpu_list = NULL; - int i; + GSList *list; - for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { - CpuDefinitionInfoList *entry; - CpuDefinitionInfo *info; - - if (!ppc_cpu_usable(&ppc_defs[i])) { - continue; - } - - info = g_malloc0(sizeof(*info)); - info->name = g_strdup(ppc_defs[i].name); - - entry = g_malloc0(sizeof(*entry)); - entry->value = info; - entry->next = cpu_list; - cpu_list = entry; - } + list = object_class_get_list(TYPE_POWERPC_CPU, false); + g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list); + g_slist_free(list); return cpu_list; } +static void ppc_cpu_def_class_init(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + ppc_def_t *info = data; + + pcc->info = info; +} + +static void ppc_cpu_register_model(const ppc_def_t *def) +{ + TypeInfo type_info = { + .parent = TYPE_POWERPC_CPU, + .class_init = ppc_cpu_def_class_init, + .class_data = (void *)def, + }; + + type_info.name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, def->name), + type_register(&type_info); + g_free((gpointer)type_info.name); +} + /* CPUClass::reset() */ static void ppc_cpu_reset(CPUState *s) { @@ -10434,9 +10519,42 @@ static void ppc_cpu_reset(CPUState *s) static void ppc_cpu_initfn(Object *obj) { PowerPCCPU *cpu = POWERPC_CPU(obj); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; + ppc_def_t *def = pcc->info; cpu_exec_init(env); + + env->msr_mask = def->msr_mask; + env->mmu_model = def->mmu_model; + env->excp_model = def->excp_model; + env->bus_model = def->bus_model; + env->insns_flags = def->insns_flags; + env->insns_flags2 = def->insns_flags2; + env->flags = def->flags; + env->bfd_mach = def->bfd_mach; + env->check_pow = def->check_pow; + +#if defined(TARGET_PPC64) + if (def->sps) { + env->sps = *def->sps; + } else if (env->mmu_model & POWERPC_MMU_64) { + /* Use default sets of page sizes */ + static const struct ppc_segment_page_sizes defsps = { + .sps = { + { .page_shift = 12, /* 4K */ + .slb_enc = 0, + .enc = { { .page_shift = 12, .pte_enc = 0 } } + }, + { .page_shift = 24, /* 16M */ + .slb_enc = 0x100, + .enc = { { .page_shift = 24, .pte_enc = 0 } } + }, + }, + }; + env->sps = defsps; + } +#endif /* defined(TARGET_PPC64) */ } static void ppc_cpu_class_init(ObjectClass *oc, void *data) @@ -10453,14 +10571,27 @@ static const TypeInfo ppc_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(PowerPCCPU), .instance_init = ppc_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(PowerPCCPUClass), .class_init = ppc_cpu_class_init, }; static void ppc_cpu_register_types(void) { + int i; + type_register_static(&ppc_cpu_type_info); + + for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + const ppc_def_t *def = &ppc_defs[i]; +#if defined(TARGET_PPCEMB) + /* When using the ppcemb target, we only support 440 style cores */ + if (def->mmu_model != POWERPC_MMU_BOOKE) { + continue; + } +#endif + ppc_cpu_register_model(def); + } } type_init(ppc_cpu_register_types) From 1b7ce68fb45b97a9eaf71eeb81d2b4f4ea6bf4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 6 Jan 2013 08:31:31 +0000 Subject: [PATCH 0309/1634] target-ppc: Error out for -cpu host on unknown PVR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we silently exited, with subclasses we got an opcode warning. Instead, explicitly tell the user what's wrong. An indication for this is -cpu ? showing "host" with an all-zero PVR. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index ce7d69b403..4846acfc0d 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1232,7 +1232,15 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on) static void kvmppc_host_cpu_initfn(Object *obj) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(obj); + assert(kvm_enabled()); + + if (pcc->info->pvr != mfpvr()) { + fprintf(stderr, "Your host CPU is unsupported.\n" + "Please choose a supported model instead, see -cpu ?.\n"); + exit(1); + } } static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) From 61993a67128095946ed5df51c3c20748182d8efc Mon Sep 17 00:00:00 2001 From: Samuel Seay Date: Fri, 4 Jan 2013 14:35:48 +0000 Subject: [PATCH 0310/1634] PPC: linux-user: Calculate context pointer explicitly Peter Maydell recommended the change to be more proper. The result was tested and shows coming up with the same proper value. Signed-off-by: Samuel Seay [agraf: change subject] Signed-off-by: Alexander Graf --- linux-user/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index c43b8ac30a..bb08a9354e 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4614,7 +4614,7 @@ static void setup_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler. */ env->gpr[1] = newsp; env->gpr[3] = signal; - env->gpr[4] = (target_ulong) h2g(sc); + env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx); env->nip = (target_ulong) ka->_sa_handler; /* Signal handlers are entered in big-endian mode. */ env->msr &= ~MSR_LE; From 2d620f593d9395abd9aa453f8ae0861a51d674d8 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 20 Dec 2012 14:28:58 +0200 Subject: [PATCH 0311/1634] virtio: don't waste irqfds on control vqs Pass nvqs to set_guest_notifiers. This makes it possible to save on irqfds by not allocating one for the control vq for virtio-net. Signed-off-by: Michael S. Tsirkin --- hw/vhost.c | 10 +++++++--- hw/virtio-pci.c | 19 ++++++++++++++----- hw/virtio-pci.h | 1 + hw/virtio.h | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index 4e1cb47418..b6d73ca05f 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -879,7 +879,9 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail; } - r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, true); + r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, + hdev->nvqs, + true); if (r < 0) { fprintf(stderr, "Error binding guest notifier: %d\n", -r); goto fail_notifiers; @@ -929,7 +931,7 @@ fail_vq: } fail_mem: fail_features: - vdev->binding->set_guest_notifiers(vdev->binding_opaque, false); + vdev->binding->set_guest_notifiers(vdev->binding_opaque, hdev->nvqs, false); fail_notifiers: fail: return r; @@ -950,7 +952,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i], 0, (hwaddr)~0x0ull); } - r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, false); + r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, + hdev->nvqs, + false); if (r < 0) { fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); fflush(stderr); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index c7f0c4d4ed..65a563bdb2 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -535,7 +535,7 @@ static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector, VirtIODevice *vdev = proxy->vdev; int ret, queue_no; - for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) { + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { if (!virtio_queue_get_num(vdev, queue_no)) { break; } @@ -565,7 +565,7 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) VirtIODevice *vdev = proxy->vdev; int queue_no; - for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) { + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { if (!virtio_queue_get_num(vdev, queue_no)) { break; } @@ -587,7 +587,7 @@ static void kvm_virtio_pci_vector_poll(PCIDevice *dev, EventNotifier *notifier; VirtQueue *vq; - for (queue_no = 0; queue_no < VIRTIO_PCI_QUEUE_MAX; queue_no++) { + for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { if (!virtio_queue_get_num(vdev, queue_no)) { break; } @@ -631,7 +631,7 @@ static bool virtio_pci_query_guest_notifiers(DeviceState *d) return msix_enabled(&proxy->pci_dev); } -static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) +static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = proxy->vdev; @@ -639,6 +639,15 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) bool with_irqfd = msix_enabled(&proxy->pci_dev) && kvm_msi_via_irqfd_enabled(); + nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX); + + /* When deassigning, pass a consistent nvqs value + * to avoid leaking notifiers. + */ + assert(assign || nvqs == proxy->nvqs_with_notifiers); + + proxy->nvqs_with_notifiers = nvqs; + /* Must unset vector notifier while guest notifier is still assigned */ if (proxy->vector_irqfd && !assign) { msix_unset_vector_notifiers(&proxy->pci_dev); @@ -646,7 +655,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) proxy->vector_irqfd = NULL; } - for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { + for (n = 0; n < nvqs; n++) { if (!virtio_queue_get_num(vdev, n)) { break; } diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index b58d9a2d19..b0f17e2b16 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -51,6 +51,7 @@ typedef struct { bool ioeventfd_disabled; bool ioeventfd_started; VirtIOIRQFD *vector_irqfd; + int nvqs_with_notifiers; } VirtIOPCIProxy; void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev); diff --git a/hw/virtio.h b/hw/virtio.h index 1dec9dce07..329b426fc0 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -99,7 +99,7 @@ typedef struct { int (*load_done)(DeviceState *d, QEMUFile *f); unsigned (*get_features)(DeviceState *d); bool (*query_guest_notifiers)(DeviceState *d); - int (*set_guest_notifiers)(DeviceState *d, bool assigned); + int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assigned); int (*set_host_notifier)(DeviceState *d, int n, bool assigned); void (*vmstate_change)(DeviceState *d, bool running); } VirtIOBindings; From 4c93bfa9c9f00104b5c7e837da697f9506cb70c7 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 21 Dec 2012 00:27:02 +0200 Subject: [PATCH 0312/1634] msix: add api to access msix message Will be used by virtio pci. Signed-off-by: Michael S. Tsirkin --- hw/pci/msix.c | 2 +- hw/pci/msix.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 9eee6570c2..e231a0dc4b 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -27,7 +27,7 @@ #define MSIX_ENABLE_MASK (PCI_MSIX_FLAGS_ENABLE >> 8) #define MSIX_MASKALL_MASK (PCI_MSIX_FLAGS_MASKALL >> 8) -static MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) +MSIMessage msix_get_message(PCIDevice *dev, unsigned vector) { uint8_t *table_entry = dev->msix_table + vector * PCI_MSIX_ENTRY_SIZE; MSIMessage msg; diff --git a/hw/pci/msix.h b/hw/pci/msix.h index d0c4429843..e648410535 100644 --- a/hw/pci/msix.h +++ b/hw/pci/msix.h @@ -5,6 +5,7 @@ #include "hw/pci/pci.h" void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg); +MSIMessage msix_get_message(PCIDevice *dev, unsigned int vector); int msix_init(PCIDevice *dev, unsigned short nentries, MemoryRegion *table_bar, uint8_t table_bar_nr, unsigned table_offset, MemoryRegion *pba_bar, From 078bbb504031dc89616d4b67adcf2ce884cb880b Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 21 Dec 2012 00:47:46 +0200 Subject: [PATCH 0313/1634] kvm: add stub for update msi route Will be used by virtio-pci. Signed-off-by: Michael S. Tsirkin --- kvm-stub.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kvm-stub.c b/kvm-stub.c index 5b971521cd..81f8967180 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -131,6 +131,11 @@ void kvm_irqchip_release_virq(KVMState *s, int virq) { } +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) +{ + return -ENOSYS; +} + int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) { return -ENOSYS; From 774345f981854b026e24aeb0833311183a8e8067 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 21 Dec 2012 00:27:54 +0200 Subject: [PATCH 0314/1634] virtio-pci: cache msix messages Some guests mask a vector then unmask without changing it. Store vectors to avoid kvm system calls in this case. Signed-off-by: Michael S. Tsirkin --- hw/virtio-pci.c | 125 +++++++++++++++++++++++++++++++++++++++--------- hw/virtio-pci.h | 1 + 2 files changed, 103 insertions(+), 23 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 65a563bdb2..6b6f25bd06 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -487,8 +487,6 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, unsigned int vector, MSIMessage msg) { - VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); - EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; int ret; @@ -500,18 +498,94 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, irqfd->virq = ret; } irqfd->users++; - - ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); - if (ret < 0) { - if (--irqfd->users == 0) { - kvm_irqchip_release_virq(kvm_state, irqfd->virq); - } - return ret; - } return 0; } static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, + unsigned int vector) +{ + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + if (--irqfd->users == 0) { + kvm_irqchip_release_virq(kvm_state, irqfd->virq); + } +} + +static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) +{ + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = proxy->vdev; + unsigned int vector; + int ret, queue_no; + MSIMessage msg; + + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } + vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } + msg = msix_get_message(dev, vector); + ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg); + if (ret < 0) { + goto undo; + } + } + return 0; + +undo: + while (--queue_no >= 0) { + vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } + return ret; +} + +static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) +{ + PCIDevice *dev = &proxy->pci_dev; + VirtIODevice *vdev = proxy->vdev; + unsigned int vector; + int queue_no; + + for (queue_no = 0; queue_no < nvqs; queue_no++) { + if (!virtio_queue_get_num(vdev, queue_no)) { + break; + } + vector = virtio_queue_vector(vdev, queue_no); + if (vector >= msix_nr_vectors_allocated(dev)) { + continue; + } + kvm_virtio_pci_vq_vector_release(proxy, vector); + } +} + +static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector, + MSIMessage msg) +{ + VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) { + ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg); + if (ret < 0) { + return ret; + } + } + + ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); + return ret; +} + +static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, unsigned int queue_no, unsigned int vector) { @@ -522,13 +596,9 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); assert(ret == 0); - - if (--irqfd->users == 0) { - kvm_irqchip_release_virq(kvm_state, irqfd->virq); - } } -static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector, +static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, MSIMessage msg) { VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); @@ -542,7 +612,7 @@ static int kvm_virtio_pci_vector_use(PCIDevice *dev, unsigned vector, if (virtio_queue_vector(vdev, queue_no) != vector) { continue; } - ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg); + ret = kvm_virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg); if (ret < 0) { goto undo; } @@ -554,12 +624,12 @@ undo: if (virtio_queue_vector(vdev, queue_no) != vector) { continue; } - kvm_virtio_pci_vq_vector_release(proxy, queue_no, vector); + kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector); } return ret; } -static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) +static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) { VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIODevice *vdev = proxy->vdev; @@ -572,7 +642,7 @@ static void kvm_virtio_pci_vector_release(PCIDevice *dev, unsigned vector) if (virtio_queue_vector(vdev, queue_no) != vector) { continue; } - kvm_virtio_pci_vq_vector_release(proxy, queue_no, vector); + kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector); } } @@ -651,6 +721,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) /* Must unset vector notifier while guest notifier is still assigned */ if (proxy->vector_irqfd && !assign) { msix_unset_vector_notifiers(&proxy->pci_dev); + kvm_virtio_pci_vector_release(proxy, nvqs); g_free(proxy->vector_irqfd); proxy->vector_irqfd = NULL; } @@ -672,17 +743,25 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) proxy->vector_irqfd = g_malloc0(sizeof(*proxy->vector_irqfd) * msix_nr_vectors_allocated(&proxy->pci_dev)); - r = msix_set_vector_notifiers(&proxy->pci_dev, - kvm_virtio_pci_vector_use, - kvm_virtio_pci_vector_release, - kvm_virtio_pci_vector_poll); + r = kvm_virtio_pci_vector_use(proxy, nvqs); if (r < 0) { goto assign_error; } + r = msix_set_vector_notifiers(&proxy->pci_dev, + kvm_virtio_pci_vector_unmask, + kvm_virtio_pci_vector_mask, + kvm_virtio_pci_vector_poll); + if (r < 0) { + goto notifiers_error; + } } return 0; +notifiers_error: + assert(assign); + kvm_virtio_pci_vector_release(proxy, nvqs); + assign_error: /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ assert(assign); diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index b0f17e2b16..9ff3139fe9 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -27,6 +27,7 @@ #define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT) typedef struct { + MSIMessage msg; int virq; unsigned int users; } VirtIOIRQFD; From f1d0f15a6d46bd47e7658e44a004c8898c8cb91e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 24 Dec 2012 17:35:27 +0200 Subject: [PATCH 0315/1634] virtio: backend virtqueue notifier masking some backends (notably vhost) can mask events at their source in a way that is more efficient than masking through kvm. Specifically - masking in kvm uses rcu write side so it has high latency - in kvm on unmask we always send an interrupt masking at source does not have these issues. Add such support in virtio.h and use in virtio-pci. Signed-off-by: Michael S. Tsirkin --- hw/virtio-pci.c | 79 +++++++++++++++++++++++++++++++++++++++++++------ hw/virtio.h | 13 ++++++++ 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 6b6f25bd06..1f35922f65 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -510,6 +510,31 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, } } +static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector) +{ + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); + int ret; + ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); + return ret; +} + +static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector) +{ + VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); + assert(ret == 0); +} + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) { PCIDevice *dev = &proxy->pci_dev; @@ -531,6 +556,16 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) if (ret < 0) { goto undo; } + /* If guest supports masking, set up irqfd now. + * Otherwise, delay until unmasked in the frontend. + */ + if (proxy->vdev->guest_notifier_mask) { + ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } + } } return 0; @@ -540,6 +575,9 @@ undo: if (vector >= msix_nr_vectors_allocated(dev)) { continue; } + if (proxy->vdev->guest_notifier_mask) { + kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + } kvm_virtio_pci_vq_vector_release(proxy, vector); } return ret; @@ -560,6 +598,12 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) if (vector >= msix_nr_vectors_allocated(dev)) { continue; } + /* If guest supports masking, clean up irqfd now. + * Otherwise, it was cleaned when masked in the frontend. + */ + if (proxy->vdev->guest_notifier_mask) { + kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + } kvm_virtio_pci_vq_vector_release(proxy, vector); } } @@ -581,7 +625,19 @@ static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, } } - ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); + /* If guest supports masking, irqfd is already setup, unmask it. + * Otherwise, set it up now. + */ + if (proxy->vdev->guest_notifier_mask) { + proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false); + /* Test after unmasking to avoid losing events. */ + if (proxy->vdev->guest_notifier_pending && + proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) { + event_notifier_set(n); + } + } else { + ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + } return ret; } @@ -589,13 +645,14 @@ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, unsigned int queue_no, unsigned int vector) { - VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); - EventNotifier *n = virtio_queue_get_guest_notifier(vq); - VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; - int ret; - - ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); - assert(ret == 0); + /* If guest supports masking, keep irqfd but mask it. + * Otherwise, clean it up now. + */ + if (proxy->vdev->guest_notifier_mask) { + proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true); + } else { + kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + } } static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, @@ -668,7 +725,11 @@ static void kvm_virtio_pci_vector_poll(PCIDevice *dev, } vq = virtio_get_queue(vdev, queue_no); notifier = virtio_queue_get_guest_notifier(vq); - if (event_notifier_test_and_clear(notifier)) { + if (vdev->guest_notifier_pending) { + if (vdev->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); + } + } else if (event_notifier_test_and_clear(notifier)) { msix_set_pending(dev, vector); } } diff --git a/hw/virtio.h b/hw/virtio.h index 329b426fc0..b9f1873fd6 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -126,6 +126,19 @@ struct VirtIODevice void (*set_config)(VirtIODevice *vdev, const uint8_t *config); void (*reset)(VirtIODevice *vdev); void (*set_status)(VirtIODevice *vdev, uint8_t val); + /* Test and clear event pending status. + * Should be called after unmask to avoid losing events. + * If backend does not support masking, + * must check in frontend instead. + */ + bool (*guest_notifier_pending)(VirtIODevice *vdev, int n); + /* Mask/unmask events from this vq. Any events reported + * while masked will become pending. + * If backend does not support masking, + * must mask in frontend instead. + */ + void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); + VirtQueue *vq; const VirtIOBindings *binding; DeviceState *binding_opaque; From 1830b80ff29dbd9d149f7f3cb565a690b5d5994c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 25 Dec 2012 17:38:59 +0200 Subject: [PATCH 0316/1634] virtio-net: set/clear vhost_started in reverse order As vhost started is cleared last thing on stop, set it first things on start. This makes it possible to use vhost_started while start is in progress which is used by follow-up patches. Signed-off-by: Michael S. Tsirkin --- hw/virtio-net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 5d03b31c1b..b756d57b1a 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -126,12 +126,12 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) if (!vhost_net_query(tap_get_vhost_net(n->nic->nc.peer), &n->vdev)) { return; } + n->vhost_started = 1; r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev); if (r < 0) { error_report("unable to start vhost net: %d: " "falling back on userspace virtio", -r); - } else { - n->vhost_started = 1; + n->vhost_started = 0; } } else { vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev); From 24f4fe345c1b80bab1ee18573914123d8028a9e6 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 25 Dec 2012 17:41:07 +0200 Subject: [PATCH 0317/1634] vhost: set started flag while start is in progress This makes it possible to use started flag for sanity checking of callbacks that happen during start/stop. Signed-off-by: Michael S. Tsirkin --- hw/vhost.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index b6d73ca05f..4fa5007d09 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -873,6 +873,9 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) { int i, r; + + hdev->started = true; + if (!vdev->binding->set_guest_notifiers) { fprintf(stderr, "binding does not support guest notifiers\n"); r = -ENOSYS; @@ -918,8 +921,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) } } - hdev->started = true; - return 0; fail_log: fail_vq: @@ -934,6 +935,8 @@ fail_features: vdev->binding->set_guest_notifiers(vdev->binding_opaque, hdev->nvqs, false); fail_notifiers: fail: + + hdev->started = false; return r; } From f56a12475ff1b8aa61210d08522c3c8aaf0e2648 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 24 Dec 2012 17:37:01 +0200 Subject: [PATCH 0318/1634] vhost: backend masking support Support backend guest notifier masking in vhost-net: create eventfd at device init, when masked, make vhost use that as eventfd instead of sending an interrupt. Signed-off-by: Michael S. Tsirkin --- hw/vhost.c | 95 ++++++++++++++++++++++++++++++++++++++++++------- hw/vhost.h | 10 ++++++ hw/vhost_net.c | 27 ++++++++++++-- hw/vhost_net.h | 3 ++ hw/virtio-net.c | 18 ++++++++++ 5 files changed, 137 insertions(+), 16 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index 4fa5007d09..cee8aad4a1 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -612,7 +612,7 @@ static void vhost_log_stop(MemoryListener *listener, /* FIXME: implement */ } -static int vhost_virtqueue_init(struct vhost_dev *dev, +static int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev, struct vhost_virtqueue *vq, unsigned idx) @@ -681,16 +681,11 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, goto fail_kick; } - file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq)); - r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file); - if (r) { - r = -errno; - goto fail_call; - } + /* Clear and discard previous events if any. */ + event_notifier_test_and_clear(&vq->masked_notifier); return 0; -fail_call: fail_kick: fail_alloc: cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx), @@ -708,7 +703,7 @@ fail_alloc_desc: return r; } -static void vhost_virtqueue_cleanup(struct vhost_dev *dev, +static void vhost_virtqueue_stop(struct vhost_dev *dev, struct VirtIODevice *vdev, struct vhost_virtqueue *vq, unsigned idx) @@ -746,11 +741,39 @@ static void vhost_eventfd_del(MemoryListener *listener, { } +static int vhost_virtqueue_init(struct vhost_dev *dev, + struct vhost_virtqueue *vq, int n) +{ + struct vhost_vring_file file = { + .index = n, + }; + int r = event_notifier_init(&vq->masked_notifier, 0); + if (r < 0) { + return r; + } + + file.fd = event_notifier_get_fd(&vq->masked_notifier); + r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file); + if (r) { + r = -errno; + goto fail_call; + } + return 0; +fail_call: + event_notifier_cleanup(&vq->masked_notifier); + return r; +} + +static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq) +{ + event_notifier_cleanup(&vq->masked_notifier); +} + int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, bool force) { uint64_t features; - int r; + int i, r; if (devfd >= 0) { hdev->control = devfd; } else { @@ -768,6 +791,13 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, if (r < 0) { goto fail; } + + for (i = 0; i < hdev->nvqs; ++i) { + r = vhost_virtqueue_init(hdev, hdev->vqs + i, i); + if (r < 0) { + goto fail_vq; + } + } hdev->features = features; hdev->memory_listener = (MemoryListener) { @@ -795,6 +825,10 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath, memory_listener_register(&hdev->memory_listener, &address_space_memory); hdev->force = force; return 0; +fail_vq: + while (--i >= 0) { + vhost_virtqueue_cleanup(hdev->vqs + i); + } fail: r = -errno; close(hdev->control); @@ -803,6 +837,10 @@ fail: void vhost_dev_cleanup(struct vhost_dev *hdev) { + int i; + for (i = 0; i < hdev->nvqs; ++i) { + vhost_virtqueue_cleanup(hdev->vqs + i); + } memory_listener_unregister(&hdev->memory_listener); g_free(hdev->mem); g_free(hdev->mem_sections); @@ -869,6 +907,37 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) } } +/* Test and clear event pending status. + * Should be called after unmask to avoid losing events. + */ +bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n) +{ + struct vhost_virtqueue *vq = hdev->vqs + n; + assert(hdev->started); + return event_notifier_test_and_clear(&vq->masked_notifier); +} + +/* Mask/unmask events from this vq. */ +void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + bool mask) +{ + struct VirtQueue *vvq = virtio_get_queue(vdev, n); + int r; + + assert(hdev->started); + + struct vhost_vring_file file = { + .index = n, + }; + if (mask) { + file.fd = event_notifier_get_fd(&hdev->vqs[n].masked_notifier); + } else { + file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq)); + } + r = ioctl(hdev->control, VHOST_SET_VRING_CALL, &file); + assert(r >= 0); +} + /* Host notifiers must be enabled at this point. */ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) { @@ -900,7 +969,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail_mem; } for (i = 0; i < hdev->nvqs; ++i) { - r = vhost_virtqueue_init(hdev, + r = vhost_virtqueue_start(hdev, vdev, hdev->vqs + i, i); @@ -925,7 +994,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) fail_log: fail_vq: while (--i >= 0) { - vhost_virtqueue_cleanup(hdev, + vhost_virtqueue_stop(hdev, vdev, hdev->vqs + i, i); @@ -946,7 +1015,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) int i, r; for (i = 0; i < hdev->nvqs; ++i) { - vhost_virtqueue_cleanup(hdev, + vhost_virtqueue_stop(hdev, vdev, hdev->vqs + i, i); diff --git a/hw/vhost.h b/hw/vhost.h index 6f6a906f4f..44c61a5877 100644 --- a/hw/vhost.h +++ b/hw/vhost.h @@ -18,6 +18,7 @@ struct vhost_virtqueue { void *ring; unsigned long long ring_phys; unsigned ring_size; + EventNotifier masked_notifier; }; typedef unsigned long vhost_log_chunk_t; @@ -53,4 +54,13 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev); int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev); +/* Test and clear masked event pending status. + * Should be called after unmask to avoid losing events. + */ +bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n); + +/* Mask/unmask events from this vq. + */ +void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, + bool mask); #endif diff --git a/hw/vhost_net.c b/hw/vhost_net.c index ae2785d83f..d3a04caef6 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -109,6 +109,9 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, (1 << VHOST_NET_F_VIRTIO_NET_HDR); net->backend = r; + net->dev.nvqs = 2; + net->dev.vqs = net->vqs; + r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force); if (r < 0) { goto fail; @@ -143,9 +146,6 @@ int vhost_net_start(struct vhost_net *net, struct vhost_vring_file file = { }; int r; - net->dev.nvqs = 2; - net->dev.vqs = net->vqs; - r = vhost_dev_enable_notifiers(&net->dev, dev); if (r < 0) { goto fail_notifiers; @@ -200,6 +200,17 @@ void vhost_net_cleanup(struct vhost_net *net) vhost_dev_cleanup(&net->dev); g_free(net); } + +bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) +{ + return vhost_virtqueue_pending(&net->dev, idx); +} + +void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask) +{ + vhost_virtqueue_mask(&net->dev, dev, idx, mask); +} #else struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, bool force) @@ -234,4 +245,14 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features) void vhost_net_ack_features(struct vhost_net *net, unsigned features) { } + +bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) +{ + return -ENOSYS; +} + +void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask) +{ +} #endif diff --git a/hw/vhost_net.h b/hw/vhost_net.h index 012aba4148..88912b85fd 100644 --- a/hw/vhost_net.h +++ b/hw/vhost_net.h @@ -17,4 +17,7 @@ void vhost_net_cleanup(VHostNetState *net); unsigned vhost_net_get_features(VHostNetState *net, unsigned features); void vhost_net_ack_features(VHostNetState *net, unsigned features); +bool vhost_net_virtqueue_pending(VHostNetState *net, int n); +void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev, + int idx, bool mask); #endif diff --git a/hw/virtio-net.c b/hw/virtio-net.c index b756d57b1a..3bb01b1037 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1010,6 +1010,22 @@ static NetClientInfo net_virtio_info = { .link_status_changed = virtio_net_set_link_status, }; +static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) +{ + VirtIONet *n = to_virtio_net(vdev); + assert(n->vhost_started); + return vhost_net_virtqueue_pending(tap_get_vhost_net(n->nic->nc.peer), idx); +} + +static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, + bool mask) +{ + VirtIONet *n = to_virtio_net(vdev); + assert(n->vhost_started); + vhost_net_virtqueue_mask(tap_get_vhost_net(n->nic->nc.peer), + vdev, idx, mask); +} + VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, virtio_net_conf *net) { @@ -1026,6 +1042,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->vdev.bad_features = virtio_net_bad_features; n->vdev.reset = virtio_net_reset; n->vdev.set_status = virtio_net_set_status; + n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask; + n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending; n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) { From 7682e8580722f951559f372ba3d2b6170fdbe734 Mon Sep 17 00:00:00 2001 From: Nickolai Zeldovich Date: Mon, 7 Jan 2013 15:38:39 -0500 Subject: [PATCH 0319/1634] readline: avoid memcpy() of overlapping regions memcpy() for overlapping regions is undefined behavior; use memmove() instead in readline_hist_add(). [Keep tab characters since surrounding code still uses them -- Stefan] Signed-off-by: Nickolai Zeldovich Reviewed-by: Richard Henderson Signed-off-by: Stefan Hajnoczi --- readline.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readline.c b/readline.c index 5fc9643c2b..a0c9638e4d 100644 --- a/readline.c +++ b/readline.c @@ -248,8 +248,8 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline) if (idx == READLINE_MAX_CMDS) { /* Need to get one free slot */ free(rs->history[0]); - memcpy(rs->history, &rs->history[1], - (READLINE_MAX_CMDS - 1) * sizeof(char *)); + memmove(rs->history, &rs->history[1], + (READLINE_MAX_CMDS - 1) * sizeof(char *)); rs->history[READLINE_MAX_CMDS - 1] = NULL; idx = READLINE_MAX_CMDS - 1; } From b2d1fe67d09d2b6c7da647fbcea6ca0148c206d3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 19 Dec 2012 15:08:33 +0100 Subject: [PATCH 0320/1634] usbredir: Add support for buffered bulk input (v2) Buffered bulk mode is intended for bulk *input* endpoints, where the data is of a streaming nature (not part of a command-response protocol). These endpoints' input buffer may overflow if data is not read quickly enough. So in buffered bulk mode the usb-host takes care of the submitting and re-submitting of bulk transfers. Buffered bulk mode is necessary for reliable operation with the bulk in endpoints of usb to serial convertors. Unfortunatelty buffered bulk input mode will only work with certain devices, therefor this patch also adds a usb-id table to enable it for devices which need it, while leaving the bulk ep handling for other devices unmodified. Note that the bumping of the required usbredir from 0.5.3 to 0.6 does not mean that we will now need a newer usbredir release then qemu-1.3, .pc files reporting 0.5.3 have only ever existed in usbredir builds directly from git, so qemu-1.3 needs the 0.6 release too. Changes in v2: -Split of quirk handling into quirks.c Signed-off-by: Hans de Goede --- configure | 2 +- hw/usb.h | 12 +- hw/usb/Makefile.objs | 2 +- hw/usb/quirks-ftdi-ids.h | 1255 ++++++++++++++++++++++++++++++++++++ hw/usb/quirks-pl2303-ids.h | 150 +++++ hw/usb/quirks.c | 53 ++ hw/usb/quirks.h | 910 ++++++++++++++++++++++++++ hw/usb/redirect.c | 355 +++++++++- 8 files changed, 2718 insertions(+), 21 deletions(-) create mode 100644 hw/usb/quirks-ftdi-ids.h create mode 100644 hw/usb/quirks-pl2303-ids.h create mode 100644 hw/usb/quirks.c create mode 100644 hw/usb/quirks.h diff --git a/configure b/configure index fe18ed2b25..82f6e71700 100755 --- a/configure +++ b/configure @@ -2851,7 +2851,7 @@ fi # check for usbredirparser for usb network redirection support if test "$usb_redir" != "no" ; then - if $pkg_config --atleast-version=0.5.3 libusbredirparser-0.5 >/dev/null 2>&1 ; then + if $pkg_config --atleast-version=0.6 libusbredirparser-0.5 >/dev/null 2>&1 ; then usb_redir="yes" usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null) usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null) diff --git a/hw/usb.h b/hw/usb.h index aca8ff6950..50c297f341 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -553,5 +553,15 @@ const USBDesc *usb_device_get_usb_desc(USBDevice *dev); int ehci_create_ich9_with_companions(PCIBus *bus, int slot); -#endif +/* quirks.c */ +/* In bulk endpoints are streaming data sources (iow behave like isoc eps) */ +#define USB_QUIRK_BUFFER_BULK_IN 0x01 +/* Bulk pkts in FTDI format, need special handling when combining packets */ +#define USB_QUIRK_IS_FTDI 0x02 + +int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol); + +#endif diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 5a4eeb6d13..dad4cb9f3c 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -5,7 +5,7 @@ common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o common-obj-y += libhw.o common-obj-$(CONFIG_SMARTCARD) += dev-smartcard-reader.o -common-obj-$(CONFIG_USB_REDIR) += redirect.o +common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o common-obj-y += host-$(HOST_USB).o dev-bluetooth.o diff --git a/hw/usb/quirks-ftdi-ids.h b/hw/usb/quirks-ftdi-ids.h new file mode 100644 index 0000000000..57c12ef662 --- /dev/null +++ b/hw/usb/quirks-ftdi-ids.h @@ -0,0 +1,1255 @@ +/* + * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters. + * Please keep numerically sorted within individual areas, thanks! + * + * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais + * from Rudolf Gugler + * + */ + + +/**********************************/ +/***** devices using FTDI VID *****/ +/**********************************/ + + +#define FTDI_VID 0x0403 /* Vendor Id */ + + +/*** "original" FTDI device PIDs ***/ + +#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ +#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ +#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ +#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ +#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ +#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ +#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ +#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ + + +/*** third-party PIDs (using FTDI_VID) ***/ + +#define FTDI_LUMEL_PD12_PID 0x6002 + +/* + * Marvell OpenRD Base, Client + * http://www.open-rd.org + * OpenRD Base, Client use VID 0x0403 + */ +#define MARVELL_OPENRD_PID 0x9e90 + +/* www.candapter.com Ewert Energy Systems CANdapter device */ +#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ + +/* + * Texas Instruments XDS100v2 JTAG / BeagleBone A3 + * http://processors.wiki.ti.com/index.php/XDS100 + * http://beagleboard.org/bone + */ +#define TI_XDS100V2_PID 0xa6d0 + +#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ + +/* US Interface Navigator (http://www.usinterface.com/) */ +#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */ +#define FTDI_USINT_WKEY_PID 0xb811 /* Navigator WKEY and FSK lines */ +#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */ + +/* OOCDlink by Joern Kaipf + * (http://www.joernonline.de/) */ +#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ + +/* Luminary Micro Stellaris Boards, VID = FTDI_VID */ +/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */ +#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8 +#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 +#define LMI_LM3S_ICDI_BOARD_PID 0xbcda + +#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ + +/* OpenDCC (www.opendcc.de) product id */ +#define FTDI_OPENDCC_PID 0xBFD8 +#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9 +#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA +#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB +#define FTDI_OPENDCC_GBM_PID 0xBFDC + +/* NZR SEM 16+ USB (http://www.nzr.de) */ +#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ + +/* + * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) + */ +#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */ + +/* DMX4ALL DMX Interfaces */ +#define FTDI_DMX4ALL 0xC850 + +/* + * ASK.fr devices + */ +#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ + +/* www.starting-point-systems.com µChameleon device */ +#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */ + +/* + * Tactrix OpenPort (ECU) devices. + * OpenPort 1.3M submitted by Donour Sizemore. + * OpenPort 1.3S and 1.3U submitted by Ian Abbott. + */ +#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */ +#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ +#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ + +#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8 + +/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */ +/* the VID is the standard ftdi vid (FTDI_VID) */ +#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */ +#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */ +#define FTDI_SCS_DEVICE_2_PID 0xD012 +#define FTDI_SCS_DEVICE_3_PID 0xD013 +#define FTDI_SCS_DEVICE_4_PID 0xD014 +#define FTDI_SCS_DEVICE_5_PID 0xD015 +#define FTDI_SCS_DEVICE_6_PID 0xD016 +#define FTDI_SCS_DEVICE_7_PID 0xD017 + +/* iPlus device */ +#define FTDI_IPLUS_PID 0xD070 /* Product Id */ +#define FTDI_IPLUS2_PID 0xD071 /* Product Id */ + +/* + * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com. + */ +#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */ + +/* Propox devices */ +#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 + +/* Lenz LI-USB Computer Interface. */ +#define FTDI_LENZ_LIUSB_PID 0xD780 + +/* Vardaan Enterprises Serial Interface VEUSB422R3 */ +#define FTDI_VARDAAN_PID 0xF070 + +/* + * Xsens Technologies BV products (http://www.xsens.com). + */ +#define XSENS_CONVERTER_0_PID 0xD388 +#define XSENS_CONVERTER_1_PID 0xD389 +#define XSENS_CONVERTER_2_PID 0xD38A +#define XSENS_CONVERTER_3_PID 0xD38B +#define XSENS_CONVERTER_4_PID 0xD38C +#define XSENS_CONVERTER_5_PID 0xD38D +#define XSENS_CONVERTER_6_PID 0xD38E +#define XSENS_CONVERTER_7_PID 0xD38F + +/* + * NDI (www.ndigital.com) product ids + */ +#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */ +#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */ +#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */ +#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ +#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ + +/* + * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs + */ +#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8 +#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9 +#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA +#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB +#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC +#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD +#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE +#define FTDI_CHAMSYS_WING_PID 0xDAFF + +/* + * Westrex International devices submitted by Cory Lee + */ +#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */ +#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */ + +/* + * ACG Identification Technologies GmbH products (http://www.acg.de/). + * Submitted by anton -at- goto10 -dot- org. + */ +#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ + +/* + * Definitions for Artemis astronomical USB based cameras + * Check it at http://www.artemisccd.co.uk/ + */ +#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */ + +/* + * Definitions for ATIK Instruments astronomical USB based cameras + * Check it at http://www.atik-instruments.com/ + */ +#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */ +#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */ +#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */ +#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */ +#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */ + +/* + * Yost Engineering, Inc. products (www.yostengineering.com). + * PID 0xE050 submitted by Aaron Prose. + */ +#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */ + +/* + * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). + * All of these devices use FTDI's vendor ID (0x0403). + * Further IDs taken from ELV Windows .inf file. + * + * The previously included PID for the UO 100 module was incorrect. + * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58). + * + * Armin Laeuger originally sent the PID for the UM 100 module. + */ +#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */ +#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */ +#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */ +#define FTDI_ELV_WS550_PID 0xE004 /* WS 550 */ +#define FTDI_ELV_EC3000_PID 0xE006 /* ENERGY CONTROL 3000 USB */ +#define FTDI_ELV_WS888_PID 0xE008 /* WS 888 */ +#define FTDI_ELV_TWS550_PID 0xE009 /* Technoline WS 550 */ +#define FTDI_ELV_FEM_PID 0xE00A /* Funk Energie Monitor */ +#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */ +#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */ +#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */ +#define FTDI_ELV_UMS100_PID 0xE0EB /* ELV USB Master-Slave Schaltsteckdose UMS 100 */ +#define FTDI_ELV_TFD128_PID 0xE0EC /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */ +#define FTDI_ELV_FM3RX_PID 0xE0ED /* ELV Messwertuebertragung FM3 RX */ +#define FTDI_ELV_WS777_PID 0xE0EE /* Conrad WS 777 */ +#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Energy monitor EM 1010 PC */ +#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */ +#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */ +#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */ +#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */ +#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */ +#define FTDI_ELV_UTP8_PID 0xE0F5 /* ELV UTP 8 */ +#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */ +#define FTDI_ELV_WS444PC_PID 0xE0F7 /* Conrad WS 444 PC */ +#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */ +#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */ +#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */ +#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */ +#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */ +#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */ +#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */ +#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */ +#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */ +#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */ +#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */ +#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */ +/* Additional ELV PIDs that default to using the FTDI D2XX drivers on + * MS Windows, rather than the FTDI Virtual Com Port drivers. + * Maybe these will be easier to use with the libftdi/libusb user-space + * drivers, or possibly the Comedi drivers in some cases. */ +#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */ +#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */ +#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperatur-Feuchte-Messgeraet (TFM 100) */ +#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */ +#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */ + +/* + * EVER Eco Pro UPS (http://www.ever.com.pl/) + */ + +#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */ + +/* + * Active Robots product ids. + */ +#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */ + +/* Pyramid Computer GmbH */ +#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */ + +/* www.elsterelectricity.com Elster Unicom III Optical Probe */ +#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */ + +/* + * Gude Analog- und Digitalsysteme GmbH + */ +#define FTDI_GUDEADS_E808_PID 0xE808 +#define FTDI_GUDEADS_E809_PID 0xE809 +#define FTDI_GUDEADS_E80A_PID 0xE80A +#define FTDI_GUDEADS_E80B_PID 0xE80B +#define FTDI_GUDEADS_E80C_PID 0xE80C +#define FTDI_GUDEADS_E80D_PID 0xE80D +#define FTDI_GUDEADS_E80E_PID 0xE80E +#define FTDI_GUDEADS_E80F_PID 0xE80F +#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */ +#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */ +#define FTDI_GUDEADS_E88A_PID 0xE88A +#define FTDI_GUDEADS_E88B_PID 0xE88B +#define FTDI_GUDEADS_E88C_PID 0xE88C +#define FTDI_GUDEADS_E88D_PID 0xE88D +#define FTDI_GUDEADS_E88E_PID 0xE88E +#define FTDI_GUDEADS_E88F_PID 0xE88F + +/* + * Eclo (http://www.eclo.pt/) product IDs. + * PID 0xEA90 submitted by Martin Grill. + */ +#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */ + +/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */ +#define FTDI_TNC_X_PID 0xEBE0 + +/* + * Teratronik product ids. + * Submitted by O. Wölfelschneider. + */ +#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */ +#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */ + +/* Rig Expert Ukraine devices */ +#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */ + +/* + * Hameg HO820 and HO870 interface (using VID 0x0403) + */ +#define HAMEG_HO820_PID 0xed74 +#define HAMEG_HO730_PID 0xed73 +#define HAMEG_HO720_PID 0xed72 +#define HAMEG_HO870_PID 0xed71 + +/* + * MaxStream devices www.maxstream.net + */ +#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */ + +/* + * microHAM product IDs (http://www.microham.com). + * Submitted by Justin Burket (KL1RL) + * and Mike Studer (K6EEP) . + * Ian Abbott added a few more from the driver INF file. + */ +#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */ +#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */ +#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */ +#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */ +#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */ +#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */ +#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */ +#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */ + +/* Domintell products http://www.domintell.com */ +#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */ +#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */ + +/* + * The following are the values for the Perle Systems + * UltraPort USB serial converters + */ +#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */ + +/* Sprog II (Andrew Crosland's SprogII DCC interface) */ +#define FTDI_SPROG_II 0xF0C8 + +/* an infrared receiver for user access control with IR tags */ +#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ + +/* ACT Solutions HomePro ZWave interface + (http://www.act-solutions.com/HomePro-Product-Matrix.html) */ +#define FTDI_ACTZWAVE_PID 0xF2D0 + +/* + * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485, + * USB-TTY aktiv, USB-TTY passiv. Some PIDs are used by several devices + * and I'm not entirely sure which are used by which. + */ +#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 +#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 +#define FTDI_4N_GALAXY_DE_3_PID 0xF3C2 + +/* + * Linx Technologies product ids + */ +#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */ +#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */ +#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */ +#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ +#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ + +/* + * Oceanic product ids + */ +#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */ + +/* + * SUUNTO product ids + */ +#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */ + +/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */ +/* http://www.usbuirt.com/ */ +#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ + +/* CCS Inc. ICDU/ICDU40 product ID - + * the FT232BM is used in an in-circuit-debugger unit for PIC16's/PIC18's */ +#define FTDI_CCSICDU20_0_PID 0xF9D0 +#define FTDI_CCSICDU40_1_PID 0xF9D1 +#define FTDI_CCSMACHX_2_PID 0xF9D2 +#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3 +#define FTDI_CCSICDU64_4_PID 0xF9D4 +#define FTDI_CCSPRIME8_5_PID 0xF9D5 + +/* + * The following are the values for the Matrix Orbital LCD displays, + * which are the FT232BM ( similar to the 8U232AM ) + */ +#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ +#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ + +/* + * Home Electronics (www.home-electro.com) USB gadgets + */ +#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */ + +/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */ +#define INSIDE_ACCESSO 0xFAD0 + +/* + * ThorLabs USB motor drivers + */ +#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */ + +/* + * Protego product ids + */ +#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */ +#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */ +#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ +#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ + +/* + * Sony Ericsson product ids + */ +#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */ +#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */ +#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */ + +/* www.irtrans.de device */ +#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ + +/* + * RM Michaelides CANview USB (http://www.rmcan.com) (FTDI_VID) + * CAN fieldbus interface adapter, added by port GmbH www.port.de) + * Ian Abbott changed the macro names for consistency. + */ +#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */ +/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */ +#define FTDI_TTUSB_PID 0xFF20 /* Product Id */ + +#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 (FTDI_VID) */ + +#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ + +/* + * PCDJ use ftdi based dj-controllers. The following PID is + * for their DAC-2 device http://www.pcdjhardware.com/DAC2.asp + * (the VID is the standard ftdi vid (FTDI_VID), PID sent by Wouter Paesen) + */ +#define FTDI_PCDJ_DAC2_PID 0xFA88 + +#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG (FTDI_VID) */ + +/* + * DIEBOLD BCS SE923 (FTDI_VID) + */ +#define DIEBOLD_BCS_SE923_PID 0xfb99 + +/* www.crystalfontz.com devices + * - thanx for providing free devices for evaluation ! + * they use the ftdi chipset for the USB interface + * and the vendor id is the same + */ +#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */ +#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */ +#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */ +#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */ +#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */ +#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */ +#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */ +#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */ + +/* + * Video Networks Limited / Homechoice in the UK use an ftdi-based device + * for their 1Mb broadband internet service. The following PID is exhibited + * by the usb device supplied (the VID is the standard ftdi vid (FTDI_VID) + */ +#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */ + +/* AlphaMicro Components AMC-232USB01 device (FTDI_VID) */ +#define FTDI_AMC232_PID 0xFF00 /* Product Id */ + +/* + * IBS elektronik product ids (FTDI_VID) + * Submitted by Thomas Schleusener + */ +#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */ +#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */ +#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */ +#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */ +#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */ +#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */ +#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */ +#define FTDI_IBS_PROD_PID 0xff3f /* future device */ +/* www.canusb.com Lawicel CANUSB device (FTDI_VID) */ +#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ + +/* + * TavIR AVR product ids (FTDI_VID) + */ +#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ + +/* + * TIAO product ids (FTDI_VID) + * http://www.tiaowiki.com/w/Main_Page + */ +#define FTDI_TIAO_UMPA_PID 0x8a98 /* TIAO/DIYGADGET USB Multi-Protocol Adapter */ + + +/********************************/ +/** third-party VID/PID combos **/ +/********************************/ + + + +/* + * Atmel STK541 + */ +#define ATMEL_VID 0x03eb /* Vendor ID */ +#define STK541_PID 0x2109 /* Zigbee Controller */ + +/* + * Blackfin gnICE JTAG + * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice + */ +#define ADI_VID 0x0456 +#define ADI_GNICE_PID 0xF000 +#define ADI_GNICEPLUS_PID 0xF001 + +/* + * Microchip Technology, Inc. + * + * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are + * used by single function CDC ACM class based firmware demo + * applications. The VID/PID has also been used in firmware + * emulating FTDI serial chips by: + * Hornby Elite - Digital Command Control Console + * http://www.hornby.com/hornby-dcc/controllers/ + */ +#define MICROCHIP_VID 0x04D8 +#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */ + +/* + * RATOC REX-USB60F + */ +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID_USB60F 0xb020 + +/* + * Acton Research Corp. + */ +#define ACTON_VID 0x0647 /* Vendor ID */ +#define ACTON_SPECTRAPRO_PID 0x0100 + +/* + * Contec products (http://www.contec.com) + * Submitted by Daniel Sangorrin + */ +#define CONTEC_VID 0x06CE /* Vendor ID */ +#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ + +/* + * Definitions for B&B Electronics products. + */ +#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ +#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */ +#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */ +#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */ +#define BANDB_USOPTL4_PID 0xAC11 +#define BANDB_USPTL4_PID 0xAC12 +#define BANDB_USO9ML2DR_2_PID 0xAC16 +#define BANDB_USO9ML2DR_PID 0xAC17 +#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */ +#define BANDB_USOPTL4DR_PID 0xAC19 +#define BANDB_485USB9F_2W_PID 0xAC25 +#define BANDB_485USB9F_4W_PID 0xAC26 +#define BANDB_232USB9M_PID 0xAC27 +#define BANDB_485USBTB_2W_PID 0xAC33 +#define BANDB_485USBTB_4W_PID 0xAC34 +#define BANDB_TTL5USB9M_PID 0xAC49 +#define BANDB_TTL3USB9M_PID 0xAC50 +#define BANDB_ZZ_PROG1_USB_PID 0xBA02 + +/* + * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI + */ +#define INTREPID_VID 0x093C +#define INTREPID_VALUECAN_PID 0x0601 +#define INTREPID_NEOVI_PID 0x0701 + +/* + * Definitions for ID TECH (www.idt-net.com) devices + */ +#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */ +#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */ + +/* + * Definitions for Omnidirectional Control Technology, Inc. devices + */ +#define OCT_VID 0x0B39 /* OCT vendor ID */ +/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */ +/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */ +/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */ +#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */ +#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ + +/* + * Definitions for Icom Inc. devices + */ +#define ICOM_VID 0x0C26 /* Icom vendor ID */ +/* Note: ID-1 is a communications tranceiver for HAM-radio operators */ +#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */ +/* Note: OPC is an Optional cable to connect an Icom Tranceiver */ +#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */ +/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */ +#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */ +#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */ +#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/ +#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */ +#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */ +#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */ +#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */ +#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */ +#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */ + +/* + * GN Otometrics (http://www.otometrics.com) + * Submitted by Ville Sundberg. + */ +#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */ +#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */ + +/* + * The following are the values for the Sealevel SeaLINK+ adapters. + * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and + * removed some PIDs that don't seem to match any existing products.) + */ +#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */ +#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */ +#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */ +#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */ +#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */ +#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */ +#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */ +#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */ +#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */ +#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */ +#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */ +#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */ +#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */ +#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */ +#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */ +#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */ +#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */ +#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */ +#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */ +#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */ +#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */ +#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */ +#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */ +#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */ +#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */ +#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */ +#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */ +#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */ +#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */ +#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */ +#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */ +#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */ +#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */ +#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */ +#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */ +#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */ +#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */ +#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */ +#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */ +#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */ +#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */ +#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */ +#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */ +#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */ +#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */ +#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ +#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ +#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ +#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */ +#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */ +#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */ +#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */ + +/* + * JETI SPECTROMETER SPECBOS 1201 + * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101 + */ +#define JETI_VID 0x0c6c +#define JETI_SPC1201_PID 0x04b2 + +/* + * FTDI USB UART chips used in construction projects from the + * Elektor Electronics magazine (http://www.elektor.com/) + */ +#define ELEKTOR_VID 0x0C7D +#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */ + +/* + * Posiflex inc retail equipment (http://www.posiflex.com.tw) + */ +#define POSIFLEX_VID 0x0d3a /* Vendor ID */ +#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */ + +/* + * The following are the values for two KOBIL chipcard terminals. + */ +#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */ +#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */ +#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */ + +#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ +#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ + +/* + * Falcom Wireless Communications GmbH + */ +#define FALCOM_VID 0x0F94 /* Vendor Id */ +#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */ +#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */ + +/* Larsen and Brusgaard AltiTrack/USBtrack */ +#define LARSENBRUSGAARD_VID 0x0FD8 +#define LB_ALTITRACK_PID 0x0001 + +/* + * TTi (Thurlby Thandar Instruments) + */ +#define TTI_VID 0x103E /* Vendor Id */ +#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */ + +/* Interbiometrics USB I/O Board */ +/* Developed for Interbiometrics by Rudolf Gugler */ +#define INTERBIOMETRICS_VID 0x1209 +#define INTERBIOMETRICS_IOBOARD_PID 0x1002 +#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006 + +/* + * Testo products (http://www.testo.com/) + * Submitted by Colin Leroy + */ +#define TESTO_VID 0x128D +#define TESTO_USB_INTERFACE_PID 0x0001 + +/* + * Mobility Electronics products. + */ +#define MOBILITY_VID 0x1342 +#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */ + +/* + * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 + * Submitted by Harald Welte + */ +#define FIC_VID 0x1457 +#define FIC_NEO1973_DEBUG_PID 0x5118 + +/* Olimex */ +#define OLIMEX_VID 0x15BA +#define OLIMEX_ARM_USB_OCD_PID 0x0003 +#define OLIMEX_ARM_USB_OCD_H_PID 0x002b + +/* + * Telldus Technologies + */ +#define TELLDUS_VID 0x1781 /* Vendor ID */ +#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */ + +/* + * RT Systems programming cables for various ham radios + */ +#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ +#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ +#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ +#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */ + + +/* + * Physik Instrumente + * http://www.physikinstrumente.com/en/products/ + */ +/* These two devices use the VID of FTDI */ +#define PI_C865_PID 0xe0a0 /* PI C-865 Piezomotor Controller */ +#define PI_C857_PID 0xe0a1 /* PI Encoder Trigger Box */ + +#define PI_VID 0x1a72 /* Vendor ID */ +#define PI_C866_PID 0x1000 /* PI C-866 Piezomotor Controller */ +#define PI_C663_PID 0x1001 /* PI C-663 Mercury-Step */ +#define PI_C725_PID 0x1002 /* PI C-725 Piezomotor Controller */ +#define PI_E517_PID 0x1005 /* PI E-517 Digital Piezo Controller Operation Module */ +#define PI_C863_PID 0x1007 /* PI C-863 */ +#define PI_E861_PID 0x1008 /* PI E-861 Piezomotor Controller */ +#define PI_C867_PID 0x1009 /* PI C-867 Piezomotor Controller */ +#define PI_E609_PID 0x100D /* PI E-609 Digital Piezo Controller */ +#define PI_E709_PID 0x100E /* PI E-709 Digital Piezo Controller */ +#define PI_100F_PID 0x100F /* PI Digital Piezo Controller */ +#define PI_1011_PID 0x1011 /* PI Digital Piezo Controller */ +#define PI_1012_PID 0x1012 /* PI Motion Controller */ +#define PI_1013_PID 0x1013 /* PI Motion Controller */ +#define PI_1014_PID 0x1014 /* PI Device */ +#define PI_1015_PID 0x1015 /* PI Device */ +#define PI_1016_PID 0x1016 /* PI Digital Servo Module */ + +/* + * Kondo Kagaku Co.Ltd. + * http://www.kondo-robot.com/EN + */ +#define KONDO_VID 0x165c +#define KONDO_USB_SERIAL_PID 0x0002 + +/* + * Bayer Ascensia Contour blood glucose meter USB-converter cable. + * http://winglucofacts.com/cables/ + */ +#define BAYER_VID 0x1A79 +#define BAYER_CONTOUR_CABLE_PID 0x6001 + +/* + * The following are the values for the Matrix Orbital FTDI Range + * Anything in this range will use an FT232RL. + */ +#define MTXORB_VID 0x1B3D +#define MTXORB_FTDI_RANGE_0100_PID 0x0100 +#define MTXORB_FTDI_RANGE_0101_PID 0x0101 +#define MTXORB_FTDI_RANGE_0102_PID 0x0102 +#define MTXORB_FTDI_RANGE_0103_PID 0x0103 +#define MTXORB_FTDI_RANGE_0104_PID 0x0104 +#define MTXORB_FTDI_RANGE_0105_PID 0x0105 +#define MTXORB_FTDI_RANGE_0106_PID 0x0106 +#define MTXORB_FTDI_RANGE_0107_PID 0x0107 +#define MTXORB_FTDI_RANGE_0108_PID 0x0108 +#define MTXORB_FTDI_RANGE_0109_PID 0x0109 +#define MTXORB_FTDI_RANGE_010A_PID 0x010A +#define MTXORB_FTDI_RANGE_010B_PID 0x010B +#define MTXORB_FTDI_RANGE_010C_PID 0x010C +#define MTXORB_FTDI_RANGE_010D_PID 0x010D +#define MTXORB_FTDI_RANGE_010E_PID 0x010E +#define MTXORB_FTDI_RANGE_010F_PID 0x010F +#define MTXORB_FTDI_RANGE_0110_PID 0x0110 +#define MTXORB_FTDI_RANGE_0111_PID 0x0111 +#define MTXORB_FTDI_RANGE_0112_PID 0x0112 +#define MTXORB_FTDI_RANGE_0113_PID 0x0113 +#define MTXORB_FTDI_RANGE_0114_PID 0x0114 +#define MTXORB_FTDI_RANGE_0115_PID 0x0115 +#define MTXORB_FTDI_RANGE_0116_PID 0x0116 +#define MTXORB_FTDI_RANGE_0117_PID 0x0117 +#define MTXORB_FTDI_RANGE_0118_PID 0x0118 +#define MTXORB_FTDI_RANGE_0119_PID 0x0119 +#define MTXORB_FTDI_RANGE_011A_PID 0x011A +#define MTXORB_FTDI_RANGE_011B_PID 0x011B +#define MTXORB_FTDI_RANGE_011C_PID 0x011C +#define MTXORB_FTDI_RANGE_011D_PID 0x011D +#define MTXORB_FTDI_RANGE_011E_PID 0x011E +#define MTXORB_FTDI_RANGE_011F_PID 0x011F +#define MTXORB_FTDI_RANGE_0120_PID 0x0120 +#define MTXORB_FTDI_RANGE_0121_PID 0x0121 +#define MTXORB_FTDI_RANGE_0122_PID 0x0122 +#define MTXORB_FTDI_RANGE_0123_PID 0x0123 +#define MTXORB_FTDI_RANGE_0124_PID 0x0124 +#define MTXORB_FTDI_RANGE_0125_PID 0x0125 +#define MTXORB_FTDI_RANGE_0126_PID 0x0126 +#define MTXORB_FTDI_RANGE_0127_PID 0x0127 +#define MTXORB_FTDI_RANGE_0128_PID 0x0128 +#define MTXORB_FTDI_RANGE_0129_PID 0x0129 +#define MTXORB_FTDI_RANGE_012A_PID 0x012A +#define MTXORB_FTDI_RANGE_012B_PID 0x012B +#define MTXORB_FTDI_RANGE_012C_PID 0x012C +#define MTXORB_FTDI_RANGE_012D_PID 0x012D +#define MTXORB_FTDI_RANGE_012E_PID 0x012E +#define MTXORB_FTDI_RANGE_012F_PID 0x012F +#define MTXORB_FTDI_RANGE_0130_PID 0x0130 +#define MTXORB_FTDI_RANGE_0131_PID 0x0131 +#define MTXORB_FTDI_RANGE_0132_PID 0x0132 +#define MTXORB_FTDI_RANGE_0133_PID 0x0133 +#define MTXORB_FTDI_RANGE_0134_PID 0x0134 +#define MTXORB_FTDI_RANGE_0135_PID 0x0135 +#define MTXORB_FTDI_RANGE_0136_PID 0x0136 +#define MTXORB_FTDI_RANGE_0137_PID 0x0137 +#define MTXORB_FTDI_RANGE_0138_PID 0x0138 +#define MTXORB_FTDI_RANGE_0139_PID 0x0139 +#define MTXORB_FTDI_RANGE_013A_PID 0x013A +#define MTXORB_FTDI_RANGE_013B_PID 0x013B +#define MTXORB_FTDI_RANGE_013C_PID 0x013C +#define MTXORB_FTDI_RANGE_013D_PID 0x013D +#define MTXORB_FTDI_RANGE_013E_PID 0x013E +#define MTXORB_FTDI_RANGE_013F_PID 0x013F +#define MTXORB_FTDI_RANGE_0140_PID 0x0140 +#define MTXORB_FTDI_RANGE_0141_PID 0x0141 +#define MTXORB_FTDI_RANGE_0142_PID 0x0142 +#define MTXORB_FTDI_RANGE_0143_PID 0x0143 +#define MTXORB_FTDI_RANGE_0144_PID 0x0144 +#define MTXORB_FTDI_RANGE_0145_PID 0x0145 +#define MTXORB_FTDI_RANGE_0146_PID 0x0146 +#define MTXORB_FTDI_RANGE_0147_PID 0x0147 +#define MTXORB_FTDI_RANGE_0148_PID 0x0148 +#define MTXORB_FTDI_RANGE_0149_PID 0x0149 +#define MTXORB_FTDI_RANGE_014A_PID 0x014A +#define MTXORB_FTDI_RANGE_014B_PID 0x014B +#define MTXORB_FTDI_RANGE_014C_PID 0x014C +#define MTXORB_FTDI_RANGE_014D_PID 0x014D +#define MTXORB_FTDI_RANGE_014E_PID 0x014E +#define MTXORB_FTDI_RANGE_014F_PID 0x014F +#define MTXORB_FTDI_RANGE_0150_PID 0x0150 +#define MTXORB_FTDI_RANGE_0151_PID 0x0151 +#define MTXORB_FTDI_RANGE_0152_PID 0x0152 +#define MTXORB_FTDI_RANGE_0153_PID 0x0153 +#define MTXORB_FTDI_RANGE_0154_PID 0x0154 +#define MTXORB_FTDI_RANGE_0155_PID 0x0155 +#define MTXORB_FTDI_RANGE_0156_PID 0x0156 +#define MTXORB_FTDI_RANGE_0157_PID 0x0157 +#define MTXORB_FTDI_RANGE_0158_PID 0x0158 +#define MTXORB_FTDI_RANGE_0159_PID 0x0159 +#define MTXORB_FTDI_RANGE_015A_PID 0x015A +#define MTXORB_FTDI_RANGE_015B_PID 0x015B +#define MTXORB_FTDI_RANGE_015C_PID 0x015C +#define MTXORB_FTDI_RANGE_015D_PID 0x015D +#define MTXORB_FTDI_RANGE_015E_PID 0x015E +#define MTXORB_FTDI_RANGE_015F_PID 0x015F +#define MTXORB_FTDI_RANGE_0160_PID 0x0160 +#define MTXORB_FTDI_RANGE_0161_PID 0x0161 +#define MTXORB_FTDI_RANGE_0162_PID 0x0162 +#define MTXORB_FTDI_RANGE_0163_PID 0x0163 +#define MTXORB_FTDI_RANGE_0164_PID 0x0164 +#define MTXORB_FTDI_RANGE_0165_PID 0x0165 +#define MTXORB_FTDI_RANGE_0166_PID 0x0166 +#define MTXORB_FTDI_RANGE_0167_PID 0x0167 +#define MTXORB_FTDI_RANGE_0168_PID 0x0168 +#define MTXORB_FTDI_RANGE_0169_PID 0x0169 +#define MTXORB_FTDI_RANGE_016A_PID 0x016A +#define MTXORB_FTDI_RANGE_016B_PID 0x016B +#define MTXORB_FTDI_RANGE_016C_PID 0x016C +#define MTXORB_FTDI_RANGE_016D_PID 0x016D +#define MTXORB_FTDI_RANGE_016E_PID 0x016E +#define MTXORB_FTDI_RANGE_016F_PID 0x016F +#define MTXORB_FTDI_RANGE_0170_PID 0x0170 +#define MTXORB_FTDI_RANGE_0171_PID 0x0171 +#define MTXORB_FTDI_RANGE_0172_PID 0x0172 +#define MTXORB_FTDI_RANGE_0173_PID 0x0173 +#define MTXORB_FTDI_RANGE_0174_PID 0x0174 +#define MTXORB_FTDI_RANGE_0175_PID 0x0175 +#define MTXORB_FTDI_RANGE_0176_PID 0x0176 +#define MTXORB_FTDI_RANGE_0177_PID 0x0177 +#define MTXORB_FTDI_RANGE_0178_PID 0x0178 +#define MTXORB_FTDI_RANGE_0179_PID 0x0179 +#define MTXORB_FTDI_RANGE_017A_PID 0x017A +#define MTXORB_FTDI_RANGE_017B_PID 0x017B +#define MTXORB_FTDI_RANGE_017C_PID 0x017C +#define MTXORB_FTDI_RANGE_017D_PID 0x017D +#define MTXORB_FTDI_RANGE_017E_PID 0x017E +#define MTXORB_FTDI_RANGE_017F_PID 0x017F +#define MTXORB_FTDI_RANGE_0180_PID 0x0180 +#define MTXORB_FTDI_RANGE_0181_PID 0x0181 +#define MTXORB_FTDI_RANGE_0182_PID 0x0182 +#define MTXORB_FTDI_RANGE_0183_PID 0x0183 +#define MTXORB_FTDI_RANGE_0184_PID 0x0184 +#define MTXORB_FTDI_RANGE_0185_PID 0x0185 +#define MTXORB_FTDI_RANGE_0186_PID 0x0186 +#define MTXORB_FTDI_RANGE_0187_PID 0x0187 +#define MTXORB_FTDI_RANGE_0188_PID 0x0188 +#define MTXORB_FTDI_RANGE_0189_PID 0x0189 +#define MTXORB_FTDI_RANGE_018A_PID 0x018A +#define MTXORB_FTDI_RANGE_018B_PID 0x018B +#define MTXORB_FTDI_RANGE_018C_PID 0x018C +#define MTXORB_FTDI_RANGE_018D_PID 0x018D +#define MTXORB_FTDI_RANGE_018E_PID 0x018E +#define MTXORB_FTDI_RANGE_018F_PID 0x018F +#define MTXORB_FTDI_RANGE_0190_PID 0x0190 +#define MTXORB_FTDI_RANGE_0191_PID 0x0191 +#define MTXORB_FTDI_RANGE_0192_PID 0x0192 +#define MTXORB_FTDI_RANGE_0193_PID 0x0193 +#define MTXORB_FTDI_RANGE_0194_PID 0x0194 +#define MTXORB_FTDI_RANGE_0195_PID 0x0195 +#define MTXORB_FTDI_RANGE_0196_PID 0x0196 +#define MTXORB_FTDI_RANGE_0197_PID 0x0197 +#define MTXORB_FTDI_RANGE_0198_PID 0x0198 +#define MTXORB_FTDI_RANGE_0199_PID 0x0199 +#define MTXORB_FTDI_RANGE_019A_PID 0x019A +#define MTXORB_FTDI_RANGE_019B_PID 0x019B +#define MTXORB_FTDI_RANGE_019C_PID 0x019C +#define MTXORB_FTDI_RANGE_019D_PID 0x019D +#define MTXORB_FTDI_RANGE_019E_PID 0x019E +#define MTXORB_FTDI_RANGE_019F_PID 0x019F +#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0 +#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1 +#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2 +#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3 +#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4 +#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5 +#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6 +#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7 +#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8 +#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9 +#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA +#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB +#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC +#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD +#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE +#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF +#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0 +#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1 +#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2 +#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3 +#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4 +#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5 +#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6 +#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7 +#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8 +#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9 +#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA +#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB +#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC +#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD +#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE +#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF +#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0 +#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1 +#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2 +#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3 +#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4 +#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5 +#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6 +#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7 +#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8 +#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9 +#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA +#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB +#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC +#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD +#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE +#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF +#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0 +#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1 +#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2 +#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3 +#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4 +#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5 +#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6 +#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7 +#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8 +#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9 +#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA +#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB +#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC +#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD +#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE +#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF +#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0 +#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1 +#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2 +#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3 +#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4 +#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5 +#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6 +#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7 +#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8 +#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9 +#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA +#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB +#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC +#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED +#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE +#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF +#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0 +#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1 +#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2 +#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3 +#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4 +#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5 +#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6 +#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7 +#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8 +#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9 +#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA +#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB +#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC +#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD +#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE +#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF + + + +/* + * The Mobility Lab (TML) + * Submitted by Pierre Castella + */ +#define TML_VID 0x1B91 /* Vendor ID */ +#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */ + +/* Alti-2 products http://www.alti-2.com */ +#define ALTI2_VID 0x1BC9 +#define ALTI2_N3_PID 0x6001 /* Neptune 3 */ + +/* + * Ionics PlugComputer + */ +#define IONICS_VID 0x1c0c +#define IONICS_PLUGCOMPUTER_PID 0x0102 + +/* + * Dresden Elektronik Sensor Terminal Board + */ +#define DE_VID 0x1cf1 /* Vendor ID */ +#define STB_PID 0x0001 /* Sensor Terminal Board */ +#define WHT_PID 0x0004 /* Wireless Handheld Terminal */ + +/* + * STMicroelectonics + */ +#define ST_VID 0x0483 +#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */ + +/* + * Papouch products (http://www.papouch.com/) + * Submitted by Folkert van Heusden + */ + +#define PAPOUCH_VID 0x5050 /* Vendor ID */ +#define PAPOUCH_SB485_PID 0x0100 /* Papouch SB485 USB-485/422 Converter */ +#define PAPOUCH_AP485_PID 0x0101 /* AP485 USB-RS485 Converter */ +#define PAPOUCH_SB422_PID 0x0102 /* Papouch SB422 USB-RS422 Converter */ +#define PAPOUCH_SB485_2_PID 0x0103 /* Papouch SB485 USB-485/422 Converter */ +#define PAPOUCH_AP485_2_PID 0x0104 /* AP485 USB-RS485 Converter */ +#define PAPOUCH_SB422_2_PID 0x0105 /* Papouch SB422 USB-RS422 Converter */ +#define PAPOUCH_SB485S_PID 0x0106 /* Papouch SB485S USB-485/422 Converter */ +#define PAPOUCH_SB485C_PID 0x0107 /* Papouch SB485C USB-485/422 Converter */ +#define PAPOUCH_LEC_PID 0x0300 /* LEC USB Converter */ +#define PAPOUCH_SB232_PID 0x0301 /* Papouch SB232 USB-RS232 Converter */ +#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ +#define PAPOUCH_IRAMP_PID 0x0500 /* Papouch IRAmp Duplex */ +#define PAPOUCH_DRAK5_PID 0x0700 /* Papouch DRAK5 */ +#define PAPOUCH_QUIDO8x8_PID 0x0800 /* Papouch Quido 8/8 Module */ +#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Papouch Quido 4/4 Module */ +#define PAPOUCH_QUIDO2x2_PID 0x0a00 /* Papouch Quido 2/2 Module */ +#define PAPOUCH_QUIDO10x1_PID 0x0b00 /* Papouch Quido 10/1 Module */ +#define PAPOUCH_QUIDO30x3_PID 0x0c00 /* Papouch Quido 30/3 Module */ +#define PAPOUCH_QUIDO60x3_PID 0x0d00 /* Papouch Quido 60(100)/3 Module */ +#define PAPOUCH_QUIDO2x16_PID 0x0e00 /* Papouch Quido 2/16 Module */ +#define PAPOUCH_QUIDO3x32_PID 0x0f00 /* Papouch Quido 3/32 Module */ +#define PAPOUCH_DRAK6_PID 0x1000 /* Papouch DRAK6 */ +#define PAPOUCH_UPSUSB_PID 0x8000 /* Papouch UPS-USB adapter */ +#define PAPOUCH_MU_PID 0x8001 /* MU controller */ +#define PAPOUCH_SIMUKEY_PID 0x8002 /* Papouch SimuKey */ +#define PAPOUCH_AD4USB_PID 0x8003 /* AD4USB Measurement Module */ +#define PAPOUCH_GMUX_PID 0x8004 /* Papouch GOLIATH MUX */ +#define PAPOUCH_GMSR_PID 0x8005 /* Papouch GOLIATH MSR */ + +/* + * Marvell SheevaPlug + */ +#define MARVELL_VID 0x9e88 +#define MARVELL_SHEEVAPLUG_PID 0x9e8f + +/* + * Evolution Robotics products (http://www.evolution.com/). + * Submitted by Shawn M. Lavelle. + */ +#define EVOLUTION_VID 0xDEEE /* Vendor ID */ +#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ +#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/ +#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/ +#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */ + +/* + * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403) + */ +#define MJSG_GENERIC_PID 0x9378 +#define MJSG_SR_RADIO_PID 0x9379 +#define MJSG_XM_RADIO_PID 0x937A +#define MJSG_HD_RADIO_PID 0x937C + +/* + * D.O.Tec products (http://www.directout.eu) + */ +#define FTDI_DOTEC_PID 0x9868 + +/* + * Xverve Signalyzer tools (http://www.signalyzer.com/) + */ +#define XVERVE_SIGNALYZER_ST_PID 0xBCA0 +#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1 +#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2 +#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4 + +/* + * Segway Robotic Mobility Platform USB interface (using VID 0x0403) + * Submitted by John G. Rogers + */ +#define SEGWAY_RMP200_PID 0xe729 + + +/* + * Accesio USB Data Acquisition products (http://www.accesio.com/) + */ +#define ACCESIO_COM4SM_PID 0xD578 + +/* www.sciencescope.co.uk educational dataloggers */ +#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18 +#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C +#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D + +/* + * Milkymist One JTAG/Serial + */ +#define QIHARDWARE_VID 0x20B7 +#define MILKYMISTONE_JTAGSERIAL_PID 0x0713 + +/* + * CTI GmbH RS485 Converter http://www.cti-lean.com/ + */ +/* USB-485-Mini*/ +#define FTDI_CTI_MINI_PID 0xF608 +/* USB-Nano-485*/ +#define FTDI_CTI_NANO_PID 0xF60B + +/* + * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + */ +/* TagTracer MIFARE*/ +#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 + +/* + * Rainforest Automation + */ +/* ZigBee controller */ +#define FTDI_RF_R106 0x8A28 + +/* + * Product: HCP HIT GPRS modem + * Manufacturer: HCP d.o.o. + * ATI command output: Cinterion MC55i + */ +#define FTDI_CINTERION_MC55I_PID 0xA951 diff --git a/hw/usb/quirks-pl2303-ids.h b/hw/usb/quirks-pl2303-ids.h new file mode 100644 index 0000000000..8dbdb46ffe --- /dev/null +++ b/hw/usb/quirks-pl2303-ids.h @@ -0,0 +1,150 @@ +/* + * Prolific PL2303 USB to serial adaptor driver header file + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#define BENQ_VENDOR_ID 0x04a5 +#define BENQ_PRODUCT_ID_S81 0x4027 + +#define PL2303_VENDOR_ID 0x067b +#define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_RSAQ2 0x04bb +#define PL2303_PRODUCT_ID_DCU11 0x1234 +#define PL2303_PRODUCT_ID_PHAROS 0xaaa0 +#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 +#define PL2303_PRODUCT_ID_ALDIGA 0x0611 +#define PL2303_PRODUCT_ID_MMX 0x0612 +#define PL2303_PRODUCT_ID_GPRS 0x0609 +#define PL2303_PRODUCT_ID_HCR331 0x331a +#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 + +#define ATEN_VENDOR_ID 0x0557 +#define ATEN_VENDOR_ID2 0x0547 +#define ATEN_PRODUCT_ID 0x2008 + +#define IODATA_VENDOR_ID 0x04bb +#define IODATA_PRODUCT_ID 0x0a03 +#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e + +#define ELCOM_VENDOR_ID 0x056e +#define ELCOM_PRODUCT_ID 0x5003 +#define ELCOM_PRODUCT_ID_UCSGT 0x5004 + +#define ITEGNO_VENDOR_ID 0x0eba +#define ITEGNO_PRODUCT_ID 0x1080 +#define ITEGNO_PRODUCT_ID_2080 0x2080 + +#define MA620_VENDOR_ID 0x0df7 +#define MA620_PRODUCT_ID 0x0620 + +#define RATOC_VENDOR_ID 0x0584 +#define RATOC_PRODUCT_ID 0xb000 + +#define TRIPP_VENDOR_ID 0x2478 +#define TRIPP_PRODUCT_ID 0x2008 + +#define RADIOSHACK_VENDOR_ID 0x1453 +#define RADIOSHACK_PRODUCT_ID 0x4026 + +#define DCU10_VENDOR_ID 0x0731 +#define DCU10_PRODUCT_ID 0x0528 + +#define SITECOM_VENDOR_ID 0x6189 +#define SITECOM_PRODUCT_ID 0x2068 + +/* Alcatel OT535/735 USB cable */ +#define ALCATEL_VENDOR_ID 0x11f7 +#define ALCATEL_PRODUCT_ID 0x02df + +/* Samsung I330 phone cradle */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_ID 0x8001 + +#define SIEMENS_VENDOR_ID 0x11f5 +#define SIEMENS_PRODUCT_ID_SX1 0x0001 +#define SIEMENS_PRODUCT_ID_X65 0x0003 +#define SIEMENS_PRODUCT_ID_X75 0x0004 +#define SIEMENS_PRODUCT_ID_EF81 0x0005 + +#define SYNTECH_VENDOR_ID 0x0745 +#define SYNTECH_PRODUCT_ID 0x0001 + +/* Nokia CA-42 Cable */ +#define NOKIA_CA42_VENDOR_ID 0x078b +#define NOKIA_CA42_PRODUCT_ID 0x1234 + +/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ +#define CA_42_CA42_VENDOR_ID 0x10b5 +#define CA_42_CA42_PRODUCT_ID 0xac70 + +#define SAGEM_VENDOR_ID 0x079b +#define SAGEM_PRODUCT_ID 0x0027 + +/* Leadtek GPS 9531 (ID 0413:2101) */ +#define LEADTEK_VENDOR_ID 0x0413 +#define LEADTEK_9531_PRODUCT_ID 0x2101 + +/* USB GSM cable from Speed Dragon Multimedia, Ltd */ +#define SPEEDDRAGON_VENDOR_ID 0x0e55 +#define SPEEDDRAGON_PRODUCT_ID 0x110b + +/* DATAPILOT Universal-2 Phone Cable */ +#define DATAPILOT_U2_VENDOR_ID 0x0731 +#define DATAPILOT_U2_PRODUCT_ID 0x2003 + +/* Belkin "F5U257" Serial Adapter */ +#define BELKIN_VENDOR_ID 0x050d +#define BELKIN_PRODUCT_ID 0x0257 + +/* Alcor Micro Corp. USB 2.0 TO RS-232 */ +#define ALCOR_VENDOR_ID 0x058F +#define ALCOR_PRODUCT_ID 0x9720 + +/* Willcom WS002IN Data Driver (by NetIndex Inc.) */ +#define WS002IN_VENDOR_ID 0x11f6 +#define WS002IN_PRODUCT_ID 0x2001 + +/* Corega CG-USBRS232R Serial Adapter */ +#define COREGA_VENDOR_ID 0x07aa +#define COREGA_PRODUCT_ID 0x002a + +/* Y.C. Cable U.S.A., Inc - USB to RS-232 */ +#define YCCABLE_VENDOR_ID 0x05ad +#define YCCABLE_PRODUCT_ID 0x0fba + +/* "Superial" USB - Serial */ +#define SUPERIAL_VENDOR_ID 0x5372 +#define SUPERIAL_PRODUCT_ID 0x2303 + +/* Hewlett-Packard LD220-HP POS Pole Display */ +#define HP_VENDOR_ID 0x03f0 +#define HP_LD220_PRODUCT_ID 0x3524 + +/* Cressi Edy (diving computer) PC interface */ +#define CRESSI_VENDOR_ID 0x04b8 +#define CRESSI_EDY_PRODUCT_ID 0x0521 + +/* Zeagle dive computer interface */ +#define ZEAGLE_VENDOR_ID 0x04b8 +#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 + +/* Sony, USB data cable for CMD-Jxx mobile phones */ +#define SONY_VENDOR_ID 0x054c +#define SONY_QN3USB_PRODUCT_ID 0x0437 + +/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ +#define SANWA_VENDOR_ID 0x11ad +#define SANWA_PRODUCT_ID 0x0001 + +/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ +#define ADLINK_VENDOR_ID 0x0b63 +#define ADLINK_ND6530_PRODUCT_ID 0x6530 + +/* SMART USB Serial Adapter */ +#define SMART_VENDOR_ID 0x0b8c +#define SMART_PRODUCT_ID 0x2303 diff --git a/hw/usb/quirks.c b/hw/usb/quirks.c new file mode 100644 index 0000000000..a761a96032 --- /dev/null +++ b/hw/usb/quirks.c @@ -0,0 +1,53 @@ +/* + * USB quirk handling + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "quirks.h" +#include "hw/usb.h" + +static bool usb_id_match(const struct usb_device_id *ids, + uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol) { + int i; + + for (i = 0; ids[i].vendor_id != -1; i++) { + if (ids[i].vendor_id == vendor_id && + ids[i].product_id == product_id && + (ids[i].interface_class == -1 || + (ids[i].interface_class == interface_class && + ids[i].interface_subclass == interface_subclass && + ids[i].interface_protocol == interface_protocol))) { + return true; + } + } + return false; +} + +int usb_get_quirks(uint16_t vendor_id, uint16_t product_id, + uint8_t interface_class, uint8_t interface_subclass, + uint8_t interface_protocol) +{ + int quirks = 0; + + if (usb_id_match(usbredir_raw_serial_ids, vendor_id, product_id, + interface_class, interface_subclass, interface_protocol)) { + quirks |= USB_QUIRK_BUFFER_BULK_IN; + } + if (usb_id_match(usbredir_ftdi_serial_ids, vendor_id, product_id, + interface_class, interface_subclass, interface_protocol)) { + quirks |= USB_QUIRK_BUFFER_BULK_IN | USB_QUIRK_IS_FTDI; + } + + return quirks; +} diff --git a/hw/usb/quirks.h b/hw/usb/quirks.h new file mode 100644 index 0000000000..8dc6065527 --- /dev/null +++ b/hw/usb/quirks.h @@ -0,0 +1,910 @@ +/* + * USB quirk handling + * + * Copyright (c) 2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* 1 on 1 copy of linux/drivers/usb/serial/ftdi_sio_ids.h */ +#include "quirks-ftdi-ids.h" +/* 1 on 1 copy of linux/drivers/usb/serial/pl2303.h */ +#include "quirks-pl2303-ids.h" + +struct usb_device_id { + int vendor_id; + int product_id; + int interface_class; + int interface_subclass; + int interface_protocol; +}; + +#define USB_DEVICE(vendor, product) \ + .vendor_id = vendor, .product_id = product, .interface_class = -1, + +#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, iclass, isubclass, iproto) \ + .vendor_id = vend, .product_id = prod, .interface_class = iclass, \ + .interface_subclass = isubclass, .interface_protocol = iproto + +static const struct usb_device_id usbredir_raw_serial_ids[] = { + /* + * Silicon Laboratories CP210x USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/cp210x.c + * + * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk) + */ + { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ + { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ + { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ + { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ + { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ + { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ + { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ + { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ + { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ + { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ + { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ + { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ + { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */ + { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */ + { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */ + { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ + { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ + { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */ + { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */ + { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ + { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ + { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ + { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ + { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ + { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */ + { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ + { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ + { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ + { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ + { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ + { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ + { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ + { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ + { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ + { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ + { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ + { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ + { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ + { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ + { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ + { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ + { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ + { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ + { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ + { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */ + { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ + { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ + { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ + { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ + { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ + { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ + { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ + { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ + { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ + { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ + { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ + { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ + { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ + { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ + { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ + { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ + { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ + { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ + { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ + { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ + { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ + { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ + { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ + { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ + { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ + { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ + { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ + { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */ + { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ + { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ + { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ + { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ + { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ + { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ + { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ + { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ + { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ + { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ + { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ + { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ + { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ + { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ + + /* + * Prolific pl2303 USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/pl2303.c + * + * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2003 IBM Corp. + */ + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, + { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, + { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, + { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, + { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, + { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, + { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, + { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, + { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, + { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, + { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, + { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, + { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, + { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ + { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, + { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, + { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, + { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, + { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, + { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, + { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, + { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, + { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, + { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, + { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, + { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, + { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, + { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, + { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, + { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, + { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, + + { USB_DEVICE(-1, -1) } /* Terminating Entry */ +}; + +static const struct usb_device_id usbredir_ftdi_serial_ids[] = { + /* + * FTDI USB to RS232 serial adapter ids + * copied from linux/drivers/usb/serial/ftdi_sio.c + * + * Copyright (C) 2009 - 2010 + * Johan Hovold (jhovold@gmail.com) + * Copyright (C) 1999 - 2001 + * Greg Kroah-Hartman (greg@kroah.com) + * Bill Ryder (bryder@sgi.com) + * Copyright (C) 2002 + * Kuba Ober (kuba@mareimbrium.org) + */ + { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) }, + { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, + { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, + { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) }, + { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) }, + { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, + { USB_DEVICE(OCT_VID, OCT_US101_PID) }, + { USB_DEVICE(OCT_VID, OCT_DK201_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) }, + { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, + { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID) }, + /* + * ELV devices: + */ + { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) }, + { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, + { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, + { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, + { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) }, + { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) }, + { USB_DEVICE(TTI_VID, TTI_QL355P_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, + { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, + { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) }, + { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, + { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, + { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) }, + { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) }, + { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) }, + { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, + { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) }, + { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, + { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, + { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID) }, + { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, + { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, + { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID) }, + { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID) }, + { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID) }, + { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, + { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, + + /* Papouch devices based on FTDI chip */ + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) }, + + { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) }, + { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) }, + { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) }, + { USB_DEVICE(ATMEL_VID, STK541_PID) }, + { USB_DEVICE(DE_VID, STB_PID) }, + { USB_DEVICE(DE_VID, WHT_PID) }, + { USB_DEVICE(ADI_VID, ADI_GNICE_PID) }, + { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID) }, + { USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID, + 0xff, 0xff, 0x00) }, + { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, + { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID) }, + { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, + { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(FTDI_VID, PI_C865_PID) }, + { USB_DEVICE(FTDI_VID, PI_C857_PID) }, + { USB_DEVICE(PI_VID, PI_C866_PID) }, + { USB_DEVICE(PI_VID, PI_C663_PID) }, + { USB_DEVICE(PI_VID, PI_C725_PID) }, + { USB_DEVICE(PI_VID, PI_E517_PID) }, + { USB_DEVICE(PI_VID, PI_C863_PID) }, + { USB_DEVICE(PI_VID, PI_E861_PID) }, + { USB_DEVICE(PI_VID, PI_C867_PID) }, + { USB_DEVICE(PI_VID, PI_E609_PID) }, + { USB_DEVICE(PI_VID, PI_E709_PID) }, + { USB_DEVICE(PI_VID, PI_100F_PID) }, + { USB_DEVICE(PI_VID, PI_1011_PID) }, + { USB_DEVICE(PI_VID, PI_1012_PID) }, + { USB_DEVICE(PI_VID, PI_1013_PID) }, + { USB_DEVICE(PI_VID, PI_1014_PID) }, + { USB_DEVICE(PI_VID, PI_1015_PID) }, + { USB_DEVICE(PI_VID, PI_1016_PID) }, + { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) }, + { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, + { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID) }, + { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID) }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID) }, + { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, + { USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) }, + { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, + { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) }, + { USB_DEVICE(ST_VID, ST_STMCLT1030_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, + { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, + + { USB_DEVICE(-1, -1) } /* Terminating Entry */ +}; + +#undef USB_DEVICE +#undef USB_DEVICE_AND_INTERFACE_INFO diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index f15dc914ab..f1bf84c987 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -52,11 +52,13 @@ typedef struct USBRedirDevice USBRedirDevice; -/* Struct to hold buffered packets (iso or int input packets) */ +/* Struct to hold buffered packets */ struct buf_packet { uint8_t *data; - int len; - int status; + void *free_on_destroy; + uint16_t len; + uint16_t offset; + uint8_t status; QTAILQ_ENTRY(buf_packet)next; }; @@ -70,11 +72,14 @@ struct endp_data { uint8_t iso_error; /* For reporting iso errors to the HC */ uint8_t interrupt_started; uint8_t interrupt_error; + uint8_t bulk_receiving_enabled; + uint8_t bulk_receiving_started; uint8_t bufpq_prefilled; uint8_t bufpq_dropping_packets; QTAILQ_HEAD(, buf_packet) bufpq; int32_t bufpq_size; int32_t bufpq_target_size; + USBPacket *pending_async_packet; }; struct PacketIdQueueEntry { @@ -108,6 +113,7 @@ struct USBRedirDevice { struct endp_data endpoint[MAX_ENDPOINTS]; struct PacketIdQueue cancelled; struct PacketIdQueue already_in_flight; + void (*buffered_bulk_in_complete)(USBRedirDevice *, USBPacket *, uint8_t); /* Data for device filtering */ struct usb_redir_device_connect_header device_info; struct usb_redir_interface_info_header interface_info; @@ -135,6 +141,8 @@ static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, *interrupt_receiving_status); static void usbredir_bulk_streams_status(void *priv, uint64_t id, struct usb_redir_bulk_streams_status_header *bulk_streams_status); +static void usbredir_bulk_receiving_status(void *priv, uint64_t id, + struct usb_redir_bulk_receiving_status_header *bulk_receiving_status); static void usbredir_control_packet(void *priv, uint64_t id, struct usb_redir_control_packet_header *control_packet, uint8_t *data, int data_len); @@ -147,6 +155,9 @@ static void usbredir_iso_packet(void *priv, uint64_t id, static void usbredir_interrupt_packet(void *priv, uint64_t id, struct usb_redir_interrupt_packet_header *interrupt_header, uint8_t *data, int data_len); +static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, + struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet, + uint8_t *data, int data_len); static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p, int status); @@ -320,12 +331,19 @@ static void packet_id_queue_empty(struct PacketIdQueue *q) static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) { USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + int i = USBEP2I(p->ep); if (p->combined) { usb_combined_packet_cancel(udev, p); return; } + if (dev->endpoint[i].pending_async_packet) { + assert(dev->endpoint[i].pending_async_packet == p); + dev->endpoint[i].pending_async_packet = NULL; + return; + } + packet_id_queue_add(&dev->cancelled, p->id); usbredirparser_send_cancel_data_packet(dev->parser, p->id); usbredirparser_do_write(dev->parser); @@ -344,6 +362,11 @@ static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, { static USBPacket *p; + /* async handled packets for bulk receiving eps do not count as inflight */ + if (dev->endpoint[USBEP2I(ep)].bulk_receiving_started) { + return; + } + QTAILQ_FOREACH(p, &ep->queue, queue) { /* Skip combined packets, except for the first */ if (p->combined && p != p->combined->first) { @@ -391,8 +414,8 @@ static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, return p; } -static void bufp_alloc(USBRedirDevice *dev, - uint8_t *data, int len, int status, uint8_t ep) +static void bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len, + uint8_t status, uint8_t ep, void *free_on_destroy) { struct buf_packet *bufp; @@ -416,7 +439,9 @@ static void bufp_alloc(USBRedirDevice *dev, bufp = g_malloc(sizeof(struct buf_packet)); bufp->data = data; bufp->len = len; + bufp->offset = 0; bufp->status = status; + bufp->free_on_destroy = free_on_destroy; QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); dev->endpoint[EP2I(ep)].bufpq_size++; } @@ -426,7 +451,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, { QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); dev->endpoint[EP2I(ep)].bufpq_size--; - free(bufp->data); + free(bufp->free_on_destroy); g_free(bufp); } @@ -577,19 +602,162 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) usbredir_free_bufpq(dev, ep); } +/* + * The usb-host may poll the endpoint faster then our guest, resulting in lots + * of smaller bulkp-s. The below buffered_bulk_in_complete* functions combine + * data from multiple bulkp-s into a single packet, avoiding bufpq overflows. + */ +static void usbredir_buffered_bulk_add_data_to_packet(USBRedirDevice *dev, + struct buf_packet *bulkp, int count, USBPacket *p, uint8_t ep) +{ + usb_packet_copy(p, bulkp->data + bulkp->offset, count); + bulkp->offset += count; + if (bulkp->offset == bulkp->len) { + /* Store status in the last packet with data from this bulkp */ + usbredir_handle_status(dev, p, bulkp->status); + bufp_free(dev, bulkp, ep); + } +} + +static void usbredir_buffered_bulk_in_complete_raw(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + struct buf_packet *bulkp; + int count; + + while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) && + p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { + count = bulkp->len - bulkp->offset; + if (count > (p->iov.size - p->actual_length)) { + count = p->iov.size - p->actual_length; + } + usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); + } +} + +static void usbredir_buffered_bulk_in_complete_ftdi(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; + uint8_t header[2] = { 0, 0 }; + struct buf_packet *bulkp; + int count; + + while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) && + p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) { + if (bulkp->len < 2) { + WARNING("malformed ftdi bulk in packet\n"); + bufp_free(dev, bulkp, ep); + continue; + } + + if ((p->actual_length % maxp) == 0) { + usb_packet_copy(p, bulkp->data, 2); + memcpy(header, bulkp->data, 2); + } else { + if (bulkp->data[0] != header[0] || bulkp->data[1] != header[1]) { + break; /* Different header, add to next packet */ + } + } + + if (bulkp->offset == 0) { + bulkp->offset = 2; /* Skip header */ + } + count = bulkp->len - bulkp->offset; + /* Must repeat the header at maxp interval */ + if (count > (maxp - (p->actual_length % maxp))) { + count = maxp - (p->actual_length % maxp); + } + usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep); + } +} + +static void usbredir_buffered_bulk_in_complete(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + dev->buffered_bulk_in_complete(dev, p, ep); + DPRINTF("bulk-token-in ep %02X status %d len %d id %"PRIu64"\n", + ep, p->status, p->actual_length, p->id); +} + +static void usbredir_handle_buffered_bulk_in_data(USBRedirDevice *dev, + USBPacket *p, uint8_t ep) +{ + /* Input bulk endpoint, buffered packet input */ + if (!dev->endpoint[EP2I(ep)].bulk_receiving_started) { + int bpt; + struct usb_redir_start_bulk_receiving_header start = { + .endpoint = ep, + .stream_id = 0, + .no_transfers = 5, + }; + /* Round bytes_per_transfer up to a multiple of max_packet_size */ + bpt = 512 + dev->endpoint[EP2I(ep)].max_packet_size - 1; + bpt /= dev->endpoint[EP2I(ep)].max_packet_size; + bpt *= dev->endpoint[EP2I(ep)].max_packet_size; + start.bytes_per_transfer = bpt; + /* No id, we look at the ep when receiving a status back */ + usbredirparser_send_start_bulk_receiving(dev->parser, 0, &start); + usbredirparser_do_write(dev->parser); + DPRINTF("bulk receiving started bytes/transfer %u count %d ep %02X\n", + start.bytes_per_transfer, start.no_transfers, ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 1; + /* We don't really want to drop bulk packets ever, but + having some upper limit to how much we buffer is good. */ + dev->endpoint[EP2I(ep)].bufpq_target_size = 5000; + dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; + } + + if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { + DPRINTF("bulk-token-in ep %02X, no bulkp\n", ep); + assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL); + dev->endpoint[EP2I(ep)].pending_async_packet = p; + p->status = USB_RET_ASYNC; + return; + } + usbredir_buffered_bulk_in_complete(dev, p, ep); +} + +static void usbredir_stop_bulk_receiving(USBRedirDevice *dev, uint8_t ep) +{ + struct usb_redir_stop_bulk_receiving_header stop_bulk = { + .endpoint = ep, + .stream_id = 0, + }; + if (dev->endpoint[EP2I(ep)].bulk_receiving_started) { + usbredirparser_send_stop_bulk_receiving(dev->parser, 0, &stop_bulk); + DPRINTF("bulk receiving stopped ep %02X\n", ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 0; + } + usbredir_free_bufpq(dev, ep); +} + static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { struct usb_redir_bulk_packet_header bulk_packet; size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; - - DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); + const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; if (usbredir_already_in_flight(dev, p->id)) { p->status = USB_RET_ASYNC; return; } + if (dev->endpoint[EP2I(ep)].bulk_receiving_enabled) { + if (size != 0 && (size % maxp) == 0) { + usbredir_handle_buffered_bulk_in_data(dev, p, ep); + return; + } + WARNING("bulk recv invalid size %zd ep %02x, disabling\n", size, ep); + assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL); + usbredir_stop_bulk_receiving(dev, ep); + dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0; + } + + DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id); + bulk_packet.endpoint = ep; bulk_packet.length = size; bulk_packet.stream_id = 0; @@ -726,9 +894,6 @@ static void usbredir_handle_data(USBDevice *udev, USBPacket *p) ERROR("handle_data called for control transfer on ep %02X\n", ep); p->status = USB_RET_NAK; break; - case USB_ENDPOINT_XFER_ISOC: - usbredir_handle_iso_data(dev, p, ep); - break; case USB_ENDPOINT_XFER_BULK: if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN && p->ep->pipeline) { @@ -737,6 +902,9 @@ static void usbredir_handle_data(USBDevice *udev, USBPacket *p) } usbredir_handle_bulk_data(dev, p, ep); break; + case USB_ENDPOINT_XFER_ISOC: + usbredir_handle_iso_data(dev, p, ep); + break; case USB_ENDPOINT_XFER_INT: if (ep & USB_DIR_IN) { usbredir_handle_interrupt_in_data(dev, p, ep); @@ -763,6 +931,11 @@ static void usbredir_stop_ep(USBRedirDevice *dev, int i) uint8_t ep = I2EP(i); switch (dev->endpoint[i].type) { + case USB_ENDPOINT_XFER_BULK: + if (ep & USB_DIR_IN) { + usbredir_stop_bulk_receiving(dev, ep); + } + break; case USB_ENDPOINT_XFER_ISOC: usbredir_stop_iso_stream(dev, ep); break; @@ -942,10 +1115,12 @@ static void usbredir_create_parser(USBRedirDevice *dev) dev->parser->interrupt_receiving_status_func = usbredir_interrupt_receiving_status; dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; + dev->parser->bulk_receiving_status_func = usbredir_bulk_receiving_status; dev->parser->control_packet_func = usbredir_control_packet; dev->parser->bulk_packet_func = usbredir_bulk_packet; dev->parser->iso_packet_func = usbredir_iso_packet; dev->parser->interrupt_packet_func = usbredir_interrupt_packet; + dev->parser->buffered_bulk_packet_func = usbredir_buffered_bulk_packet; dev->read_buf = NULL; dev->read_buf_size = 0; @@ -954,6 +1129,7 @@ static void usbredir_create_parser(USBRedirDevice *dev) usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); if (runstate_check(RUN_STATE_INMIGRATE)) { flags |= usbredirparser_fl_no_hello; @@ -1192,6 +1368,52 @@ error: return -1; } +static void usbredir_check_bulk_receiving(USBRedirDevice *dev) +{ + int i, j, quirks; + + if (!usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_bulk_receiving)) { + return; + } + + for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) { + dev->endpoint[i].bulk_receiving_enabled = 0; + } + for (i = 0; i < dev->interface_info.interface_count; i++) { + quirks = usb_get_quirks(dev->device_info.vendor_id, + dev->device_info.product_id, + dev->interface_info.interface_class[i], + dev->interface_info.interface_subclass[i], + dev->interface_info.interface_protocol[i]); + if (!(quirks & USB_QUIRK_BUFFER_BULK_IN)) { + continue; + } + if (quirks & USB_QUIRK_IS_FTDI) { + dev->buffered_bulk_in_complete = + usbredir_buffered_bulk_in_complete_ftdi; + } else { + dev->buffered_bulk_in_complete = + usbredir_buffered_bulk_in_complete_raw; + } + + for (j = EP2I(USB_DIR_IN); j < MAX_ENDPOINTS; j++) { + if (dev->endpoint[j].interface == + dev->interface_info.interface[i] && + dev->endpoint[j].type == USB_ENDPOINT_XFER_BULK && + dev->endpoint[j].max_packet_size != 0) { + dev->endpoint[j].bulk_receiving_enabled = 1; + /* + * With buffering pipelining is not necessary. Also packet + * combining and bulk in buffering don't play nice together! + */ + I2USBEP(dev, j)->pipeline = false; + break; /* Only buffer for the first ep of each intf */ + } + } + } +} + /* * usbredirparser packet complete callbacks */ @@ -1300,6 +1522,7 @@ static void usbredir_device_connect(void *priv, return; } + usbredir_check_bulk_receiving(dev); qemu_mod_timer(dev->attach_timer, dev->next_attach_time); } @@ -1338,9 +1561,10 @@ static void usbredir_interface_info(void *priv, /* * If we receive interface info after the device has already been - * connected (ie on a set_config), re-check the filter. + * connected (ie on a set_config), re-check interface dependent things. */ if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { + usbredir_check_bulk_receiving(dev); if (usbredir_check_filter(dev)) { ERROR("Device no longer matches filter after interface info " "change, disconnecting!\n"); @@ -1441,6 +1665,7 @@ static void usbredir_ep_info(void *priv, return; } usbredir_setup_usb_eps(dev); + usbredir_check_bulk_receiving(dev); } static void usbredir_configuration_status(void *priv, uint64_t id, @@ -1531,6 +1756,25 @@ static void usbredir_bulk_streams_status(void *priv, uint64_t id, { } +static void usbredir_bulk_receiving_status(void *priv, uint64_t id, + struct usb_redir_bulk_receiving_status_header *bulk_receiving_status) +{ + USBRedirDevice *dev = priv; + uint8_t ep = bulk_receiving_status->endpoint; + + DPRINTF("bulk recv status %d ep %02X id %"PRIu64"\n", + bulk_receiving_status->status, ep, id); + + if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].bulk_receiving_started) { + return; + } + + if (bulk_receiving_status->status == usb_redir_stall) { + DPRINTF("bulk receiving stopped by peer ep %02X\n", ep); + dev->endpoint[EP2I(ep)].bulk_receiving_started = 0; + } +} + static void usbredir_control_packet(void *priv, uint64_t id, struct usb_redir_control_packet_header *control_packet, uint8_t *data, int data_len) @@ -1636,7 +1880,7 @@ static void usbredir_iso_packet(void *priv, uint64_t id, } /* bufp_alloc also adds the packet to the ep queue */ - bufp_alloc(dev, data, data_len, iso_packet->status, ep); + bufp_alloc(dev, data, data_len, iso_packet->status, ep, data); } static void usbredir_interrupt_packet(void *priv, uint64_t id, @@ -1667,7 +1911,7 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } /* bufp_alloc also adds the packet to the ep queue */ - bufp_alloc(dev, data, data_len, interrupt_packet->status, ep); + bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data); } else { /* * We report output interrupt packets as completed directly upon @@ -1680,6 +1924,52 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } } +static void usbredir_buffered_bulk_packet(void *priv, uint64_t id, + struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet, + uint8_t *data, int data_len) +{ + USBRedirDevice *dev = priv; + uint8_t status, ep = buffered_bulk_packet->endpoint; + void *free_on_destroy; + int i, len; + + DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n", + buffered_bulk_packet->status, ep, data_len, id); + + if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_BULK) { + ERROR("received buffered-bulk packet for non bulk ep %02X\n", ep); + free(data); + return; + } + + if (dev->endpoint[EP2I(ep)].bulk_receiving_started == 0) { + DPRINTF("received buffered-bulk packet on not started ep %02X\n", ep); + free(data); + return; + } + + /* Data must be in maxp chunks for buffered_bulk_add_*_data_to_packet */ + len = dev->endpoint[EP2I(ep)].max_packet_size; + status = usb_redir_success; + free_on_destroy = NULL; + for (i = 0; i < data_len; i += len) { + if (len >= (data_len - i)) { + len = data_len - i; + status = buffered_bulk_packet->status; + free_on_destroy = data; + } + /* bufp_alloc also adds the packet to the ep queue */ + bufp_alloc(dev, data + i, len, status, ep, free_on_destroy); + } + + if (dev->endpoint[EP2I(ep)].pending_async_packet) { + USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet; + dev->endpoint[EP2I(ep)].pending_async_packet = NULL; + usbredir_buffered_bulk_in_complete(dev, p, ep); + usb_packet_complete(&dev->dev, p); + } +} + /* * Migration code */ @@ -1714,6 +2004,7 @@ static int usbredir_post_load(void *priv, int version_id) dev->dev.speedmask = (1 << dev->dev.speed); usbredir_setup_usb_eps(dev); + usbredir_check_bulk_receiving(dev); return 0; } @@ -1787,15 +2078,16 @@ static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) struct endp_data *endp = priv; USBRedirDevice *dev = endp->dev; struct buf_packet *bufp; - int i = 0; + int len, i = 0; qemu_put_be32(f, endp->bufpq_size); QTAILQ_FOREACH(bufp, &endp->bufpq, next) { + len = bufp->len - bufp->offset; DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, - bufp->len, bufp->status); - qemu_put_be32(f, bufp->len); + len, bufp->status); + qemu_put_be32(f, len); qemu_put_be32(f, bufp->status); - qemu_put_buffer(f, bufp->data, bufp->len); + qemu_put_buffer(f, bufp->data + bufp->offset, len); i++; } assert(i == endp->bufpq_size); @@ -1813,7 +2105,9 @@ static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) bufp = g_malloc(sizeof(struct buf_packet)); bufp->len = qemu_get_be32(f); bufp->status = qemu_get_be32(f); + bufp->offset = 0; bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ + bufp->free_on_destroy = bufp->data; qemu_get_buffer(f, bufp->data, bufp->len); QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size, @@ -1830,6 +2124,23 @@ static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { /* For endp_data migration */ +static const VMStateDescription usbredir_bulk_receiving_vmstate = { + .name = "usb-redir-ep/bulk-receiving", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(bulk_receiving_started, struct endp_data), + VMSTATE_END_OF_LIST() + } +}; + +static bool usbredir_bulk_receiving_needed(void *priv) +{ + struct endp_data *endp = priv; + + return endp->bulk_receiving_started; +} + static const VMStateDescription usbredir_ep_vmstate = { .name = "usb-redir-ep", .version_id = 1, @@ -1856,6 +2167,14 @@ static const VMStateDescription usbredir_ep_vmstate = { }, VMSTATE_INT32(bufpq_target_size, struct endp_data), VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &usbredir_bulk_receiving_vmstate, + .needed = usbredir_bulk_receiving_needed, + }, { + /* empty */ + } } }; From 89eb147c2cfd2c797d3662aa2f55254441f0595a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 3 Jan 2013 12:29:41 +0100 Subject: [PATCH 0321/1634] uhci: stop using portio lists Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-uhci.c | 106 +++++++++++++--------------------------------- trace-events | 2 - 2 files changed, 30 insertions(+), 78 deletions(-) diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 0cd68cf355..60645aa21f 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -461,40 +461,11 @@ static const VMStateDescription vmstate_uhci = { } }; -static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void uhci_port_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { UHCIState *s = opaque; - addr &= 0x1f; - switch(addr) { - case 0x0c: - s->sof_timing = val; - break; - } -} - -static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x0c: - val = s->sof_timing; - break; - default: - val = 0xff; - break; - } - return val; -} - -static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; trace_usb_uhci_mmio_writew(addr, val); switch(addr) { @@ -543,6 +514,17 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) if (s->status & UHCI_STS_HCHALTED) s->frnum = val & 0x7ff; break; + case 0x08: + s->fl_base_addr &= 0xffff0000; + s->fl_base_addr |= val & ~0xfff; + break; + case 0x0a: + s->fl_base_addr &= 0x0000ffff; + s->fl_base_addr |= (val << 16); + break; + case 0x0c: + s->sof_timing = val & 0xff; + break; case 0x10 ... 0x1f: { UHCIPort *port; @@ -574,12 +556,11 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) +static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size) { UHCIState *s = opaque; uint32_t val; - addr &= 0x1f; switch(addr) { case 0x00: val = s->cmd; @@ -593,6 +574,15 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) case 0x06: val = s->frnum; break; + case 0x08: + val = s->fl_base_addr & 0xffff; + break; + case 0x0a: + val = (s->fl_base_addr >> 16) & 0xffff; + break; + case 0x0c: + val = s->sof_timing; + break; case 0x10 ... 0x1f: { UHCIPort *port; @@ -615,38 +605,6 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) return val; } -static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; - trace_usb_uhci_mmio_writel(addr, val); - - switch(addr) { - case 0x08: - s->fl_base_addr = val & ~0xfff; - break; - } -} - -static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x08: - val = s->fl_base_addr; - break; - default: - val = 0xffffffff; - break; - } - trace_usb_uhci_mmio_readl(addr, val); - return val; -} - /* signal resume if controller suspended */ static void uhci_resume (void *opaque) { @@ -1236,18 +1194,14 @@ static void uhci_frame_timer(void *opaque) qemu_mod_timer(s->frame_timer, t_now + frame_t); } -static const MemoryRegionPortio uhci_portio[] = { - { 0, 32, 2, .write = uhci_ioport_writew, }, - { 0, 32, 2, .read = uhci_ioport_readw, }, - { 0, 32, 4, .write = uhci_ioport_writel, }, - { 0, 32, 4, .read = uhci_ioport_readl, }, - { 0, 32, 1, .write = uhci_ioport_writeb, }, - { 0, 32, 1, .read = uhci_ioport_readb, }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps uhci_ioport_ops = { - .old_portio = uhci_portio, + .read = uhci_port_read, + .write = uhci_port_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_LITTLE_ENDIAN, }; static USBPortOps uhci_port_ops = { diff --git a/trace-events b/trace-events index 4023a4c094..2183183214 100644 --- a/trace-events +++ b/trace-events @@ -307,8 +307,6 @@ usb_uhci_frame_loop_stop_idle(void) "" usb_uhci_frame_loop_continue(void) "" usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%04x" usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x" -usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x" -usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x" usb_uhci_queue_add(uint32_t token) "token 0x%x" usb_uhci_queue_del(uint32_t token, const char *reason) "token 0x%x: %s" usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" From 314992b1a48a5a2a0f2b14195f959ad2c3f5b3ff Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 3 Jan 2013 14:17:18 +0100 Subject: [PATCH 0322/1634] linux-user: fix mips 32-on-64 prealloc case MIPS only supports 31 bits of virtual address space for user space, so let's make sure we stay within that limit with our preallocated memory block. This fixes the MIPS user space targets when executed without command line option. Signed-off-by: Alexander Graf Signed-off-by: Aurelien Jarno --- linux-user/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index f6c4c8d7a3..9ade1bfabd 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -57,7 +57,12 @@ int have_guest_base; * This way we will never overlap with our own libraries or binaries or stack * or anything else that QEMU maps. */ +# ifdef TARGET_MIPS +/* MIPS only supports 31 bits of virtual address space for user space */ +unsigned long reserved_va = 0x77000000; +# else unsigned long reserved_va = 0xf7000000; +# endif #else unsigned long reserved_va; #endif From e1a4019cf13ddf2441496c2e613faba3a891cddf Mon Sep 17 00:00:00 2001 From: Eric Johnson Date: Mon, 7 Jan 2013 22:26:44 -0800 Subject: [PATCH 0323/1634] target-mips: Allow DSP access to be disabled once enabled. Clear the DSP hflags at the start of compute_hflags. Otherwise access is not properly disabled once enabled. Signed-off-by: Eric Johnson Signed-off-by: Aurelien Jarno --- target-mips/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 31602ac8ed..5963d62973 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -751,7 +751,7 @@ static inline void compute_hflags(CPUMIPSState *env) { env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | - MIPS_HFLAG_UX); + MIPS_HFLAG_UX | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { From e320d05a531ed4991a87cfe0a4c280563fb88788 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 1 Jan 2013 19:44:31 +0100 Subject: [PATCH 0324/1634] target-mips: Replace macros by inline functions The macros RESTORE_ROUNDING_MODE and RESTORE_FLUSH_MODE silently used variable env from their callers. Using inline functions with env passed as a function argument is more transparent. This modification was proposed by Peter Maydell. Cc: Peter Maydell Signed-off-by: Stefan Weil Reviewed-by: Eric Johnson Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d833d78b4f..d5c61e8a84 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2170,11 +2170,17 @@ static unsigned int ieee_rm[] = { float_round_down }; -#define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status) +static inline void restore_rounding_mode(CPUMIPSState *env) +{ + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], + &env->active_fpu.fp_status); +} -#define RESTORE_FLUSH_MODE \ - set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status) +static inline void restore_flush_mode(CPUMIPSState *env) +{ + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, + &env->active_fpu.fp_status); +} target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) { @@ -2230,9 +2236,9 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t reg) return; } /* set rounding mode */ - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); /* set flush-to-zero mode */ - RESTORE_FLUSH_MODE; + restore_flush_mode(env); set_float_exception_flags(0, &env->active_fpu.fp_status); if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31)) do_raise_exception(env, EXCP_FPE, GETPC()); @@ -2464,7 +2470,7 @@ uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2479,7 +2485,7 @@ uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2494,7 +2500,7 @@ uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2509,7 +2515,7 @@ uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2576,7 +2582,7 @@ uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2591,7 +2597,7 @@ uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2606,7 +2612,7 @@ uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2621,7 +2627,7 @@ uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2636,7 +2642,7 @@ uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2651,7 +2657,7 @@ uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { dt2 = FP_TO_INT64_OVERFLOW; @@ -2666,7 +2672,7 @@ uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; @@ -2681,7 +2687,7 @@ uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0) set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; From da1a4cef9e125a866f4ef9a39b342c2913727f70 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Wed, 2 Jan 2013 05:08:48 +0100 Subject: [PATCH 0325/1634] target-mips: Fix helper and tests for dot/cross-dot product instructions Helper function for dpa_w_ph, dpax_w_ph, dps_w_ph and dpsx_w_ph incorrectly defines halfword vector elements as unsigned values. This results in wrong output which is not triggered in the tests as they also follow this logic. Signed-off-by: Petar Jovanovic Reviewed-by: Eric Johnson Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 2 +- tests/tcg/mips/mips32-dspr2/dpa_w_ph.c | 4 ++-- tests/tcg/mips/mips32-dspr2/dpax_w_ph.c | 17 +++++++++++++++++ tests/tcg/mips/mips32-dspr2/dps_w_ph.c | 17 +++++++++++++++++ tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c | 4 ++-- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index a33e2bf9fd..4870e3dbbc 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -2473,7 +2473,7 @@ DP_OB(dpsu_h_obr, 0, 24, 16, 8, 0, 24, 16, 8, 0); void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \ CPUMIPSState *env) \ { \ - uint16_t rsB, rsA, rtB, rtA; \ + int16_t rsB, rsA, rtB, rtA; \ int32_t tempA, tempB; \ int64_t acc; \ \ diff --git a/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c index 1cfbdb080f..fae49f10eb 100644 --- a/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c @@ -26,8 +26,8 @@ int main() ach = 6, acl = 7; rs = 0xFFFF00FF; rt = 0xFFFF0002; - resulth = 0x05; - resultl = 0xfffe0206; + resulth = 0x06; + resultl = 0x206; __asm ("mthi %0, $ac1\n\t" "mtlo %1, $ac1\n\t" diff --git a/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c index f75699755c..514797cfd1 100644 --- a/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c @@ -23,5 +23,22 @@ int main() assert(ach == resulth); assert(acl == resultl); + ach = 6, acl = 7; + rs = 0xFFFF00FF; + rt = 0xFFFF0002; + resulth = 0x05; + resultl = 0xFFFFFF06; + __asm + ("mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "dpax.w.ph $ac1, %2, %3\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + : "+r"(ach), "+r"(acl) + : "r"(rs), "r"(rt) + ); + assert(ach == resulth); + assert(acl == resultl); + return 0; } diff --git a/tests/tcg/mips/mips32-dspr2/dps_w_ph.c b/tests/tcg/mips/mips32-dspr2/dps_w_ph.c index 8303643d18..f51f9b9d13 100644 --- a/tests/tcg/mips/mips32-dspr2/dps_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dps_w_ph.c @@ -23,5 +23,22 @@ int main() assert(ach == resulth); assert(acl == resultl); + ach = 6, acl = 7; + rs = 0xFFFF00FF; + rt = 0xFFFF0002; + resulth = 0x05; + resultl = 0xFFFFFE08; + __asm + ("mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "dps.w.ph $ac1, %2, %3\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + : "+r"(ach), "+r"(acl) + : "r"(rs), "r"(rt) + ); + assert(ach == resulth); + assert(acl == resultl); + return 0; } diff --git a/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c index 6db59a4ccd..bb49a4031d 100644 --- a/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c +++ b/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c @@ -9,8 +9,8 @@ int main() rs = 0xBC0123AD; rt = 0x01643721; - resulth = 0x04; - resultl = 0xD751F050; + resulth = 0x05; + resultl = 0xE72F050; __asm ("mthi %0, $ac1\n\t" "mtlo %1, $ac1\n\t" From 28e7a650691fac674b3aa8697353e27f9c165b1b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Dec 2012 10:19:34 +0100 Subject: [PATCH 0326/1634] docs: move pci-ids.txt to docs/specs/ Signed-off-by: Paolo Bonzini Signed-off-by: Michael S. Tsirkin --- pci-ids.txt => docs/specs/pci-ids.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pci-ids.txt => docs/specs/pci-ids.txt (100%) diff --git a/pci-ids.txt b/docs/specs/pci-ids.txt similarity index 100% rename from pci-ids.txt rename to docs/specs/pci-ids.txt From 4ea9296c0738e7885e27f463bb6bcbab32b6ef7a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Dec 2012 10:19:35 +0100 Subject: [PATCH 0327/1634] reorganize pci-ids.txt Some devices were missing, and we're using two PCI vendor ids. This patch only adds devices that are already documented in hw/pci/pci.h. Signed-off-by: Paolo Bonzini Signed-off-by: Michael S. Tsirkin --- docs/specs/pci-ids.txt | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index 73125a8bd7..df2527fe4c 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -3,29 +3,30 @@ PCI IDs for qemu ================ Red Hat, Inc. donates a part of its device ID range to qemu, to be used for -virtual devices. The vendor ID is 1af4 (formerly Qumranet ID). +virtual devices. The vendor IDs are 1af4 (formerly Qumranet ID) and 1b36. -The 1000 -> 10ff device ID range is used for VirtIO devices. +Contact Gerd Hoffmann to get a device ID assigned +for your devices. -The 1100 device ID is used as PCI Subsystem ID for existing hardware -devices emulated by qemu. +1af4 vendor ID +-------------- -All other device IDs are reserved. - - -VirtIO Device IDs ------------------ +The 1000 -> 10ff device ID range is used as follows for virtio-pci devices. +Note that this allocation separate from the virtio device IDs, which are +maintained as part of the virtio specification. 1af4:1000 network device 1af4:1001 block device 1af4:1002 balloon device 1af4:1003 console device - -1af4:1004 Reserved. - to Contact Gerd Hoffmann to get a -1af4:10ef device ID assigned for your new virtio device. +1af4:1004 SCSI host bus adapter device +1af4:1005 entropy generator device 1af4:10f0 Available for experimental usage without registration. Must get to official ID when the code leaves the test lab (i.e. when seeking 1af4:10ff upstream merge or shipping a distro/product) to avoid conflicts. +1af4:1100 Used as PCI Subsystem ID for existing hardware devices emulated + by qemu. + +All other device IDs are reserved. From 13744bd0a054bc7a4b1432cc8facd23d41a9806e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Dec 2012 10:19:36 +0100 Subject: [PATCH 0328/1634] virtio-9p: use symbolic constant, add to pci-ids.txt Signed-off-by: Paolo Bonzini Signed-off-by: Michael S. Tsirkin --- docs/specs/pci-ids.txt | 1 + hw/9pfs/virtio-9p-device.c | 2 +- hw/pci/pci.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index df2527fe4c..2d5329af49 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -21,6 +21,7 @@ maintained as part of the virtio specification. 1af4:1003 console device 1af4:1004 SCSI host bus adapter device 1af4:1005 entropy generator device +1af4:1009 9p filesystem device 1af4:10f0 Available for experimental usage without registration. Must get to official ID when the code leaves the test lab (i.e. when seeking diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 6761bce9dc..f16ccfbed1 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -170,7 +170,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) k->init = virtio_9p_init_pci; k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = 0x1009; + k->device_id = PCI_DEVICE_ID_VIRTIO_9P; k->revision = VIRTIO_PCI_ABI_VERSION; k->class_id = 0x2; dc->props = virtio_9p_properties; diff --git a/hw/pci/pci.h b/hw/pci/pci.h index 72927e3149..ed098ced6b 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -77,6 +77,7 @@ #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 #define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 +#define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define FMT_PCIBUS PRIx64 From b8ef62a9b746f2d7078d97c7ee5d1c7a31b42d5d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Dec 2012 10:19:37 +0100 Subject: [PATCH 0329/1634] ivshmem: use symbolic constant for PCI ID, add to pci-ids.txt Due to disagreement on a name that is generic enough for hw/pci/pci.h, the symbolic constants are placed in the .c files. Signed-off-by: Paolo Bonzini Signed-off-by: Michael S. Tsirkin --- docs/specs/pci-ids.txt | 2 ++ hw/ivshmem.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index 2d5329af49..e76b196eb5 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -30,4 +30,6 @@ maintained as part of the virtio specification. 1af4:1100 Used as PCI Subsystem ID for existing hardware devices emulated by qemu. +1af4:1110 ivshmem device (shared memory, docs/specs/ivshmem_device_spec.txt) + All other device IDs are reserved. diff --git a/hw/ivshmem.c b/hw/ivshmem.c index fcf5d05bae..c86fddd0b3 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -29,6 +29,9 @@ #include #include +#define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET +#define PCI_DEVICE_ID_IVSHMEM 0x1110 + #define IVSHMEM_IOEVENTFD 0 #define IVSHMEM_MSI 1 @@ -800,8 +803,8 @@ static void ivshmem_class_init(ObjectClass *klass, void *data) k->init = pci_ivshmem_init; k->exit = pci_ivshmem_uninit; - k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = 0x1110; + k->vendor_id = PCI_VENDOR_ID_IVSHMEM; + k->device_id = PCI_DEVICE_ID_IVSHMEM; k->class_id = PCI_CLASS_MEMORY_RAM; dc->reset = ivshmem_reset; dc->props = ivshmem_properties; From 41c6bcd912d1a2461313040566077b86e48eea31 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Dec 2012 14:49:07 -0200 Subject: [PATCH 0330/1634] libqemustub: Add qemu_[un]register_reset() stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be useful for code that don't call qemu_devices_reset() (e.g. *-user). If qemu_devices_reset() is never called, it means we don't need to keep track of the reset handler list. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- stubs/Makefile.objs | 1 + stubs/reset.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 stubs/reset.c diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 035b29a1f3..00f0b641d6 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -5,4 +5,5 @@ stub-obj-y += fdset-get-fd.o stub-obj-y += fdset-remove-fd.o stub-obj-y += get-fd.o stub-obj-y += set-fd-handler.o +stub-obj-y += reset.o stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/reset.c b/stubs/reset.c new file mode 100644 index 0000000000..ad287251ed --- /dev/null +++ b/stubs/reset.c @@ -0,0 +1,13 @@ +#include "hw/hw.h" + +/* Stub functions for binaries that never call qemu_devices_reset(), + * and don't need to keep track of the reset handler list. + */ + +void qemu_register_reset(QEMUResetHandler *func, void *opaque) +{ +} + +void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) +{ +} From 083a5f8731bb3c7e0eae99dcdb1209027d770aaf Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Dec 2012 14:49:08 -0200 Subject: [PATCH 0331/1634] libqemustub: vmstate register/unregister stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vmstate stub functions, so that qdev.o can be used without savevm.o when vmstate support is not necessary (i.e. by *-user). Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- stubs/Makefile.objs | 1 + stubs/vmstate.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 stubs/vmstate.c diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 00f0b641d6..ca2197e6fb 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -6,4 +6,5 @@ stub-obj-y += fdset-remove-fd.o stub-obj-y += get-fd.o stub-obj-y += set-fd-handler.o stub-obj-y += reset.o +stub-obj-y += vmstate.o stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/vmstate.c b/stubs/vmstate.c new file mode 100644 index 0000000000..3682af599e --- /dev/null +++ b/stubs/vmstate.c @@ -0,0 +1,17 @@ +#include "qemu-common.h" +#include "migration/vmstate.h" + +int vmstate_register_with_alias_id(DeviceState *dev, + int instance_id, + const VMStateDescription *vmsd, + void *base, int alias_id, + int required_for_version) +{ + return 0; +} + +void vmstate_unregister(DeviceState *dev, + const VMStateDescription *vmsd, + void *opaque) +{ +} From 906709a151344805df4ff493a7d3a81fbce46fbe Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Dec 2012 14:49:09 -0200 Subject: [PATCH 0332/1634] libqemustub: sysbus_get_default() stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stub will be used on cases where sysbus.c is not compiled in (e.g. *-user). Note that code that uses NULL as the bus with qdev{_try,}_create() implicitly uses sysbus_get_default() as the bus, and will still require sysbus.c to be compiled in. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- stubs/Makefile.objs | 1 + stubs/sysbus.c | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 stubs/sysbus.c diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index ca2197e6fb..7672c69a29 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -7,4 +7,5 @@ stub-obj-y += get-fd.o stub-obj-y += set-fd-handler.o stub-obj-y += reset.o stub-obj-y += vmstate.o +stub-obj-y += sysbus.o stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/sysbus.c b/stubs/sysbus.c new file mode 100644 index 0000000000..e13496582b --- /dev/null +++ b/stubs/sysbus.c @@ -0,0 +1,6 @@ +#include "hw/qdev-core.h" + +BusState *sysbus_get_default(void) +{ + return NULL; +} From 507066f8a9610c0088df19ce7b3e436f43165ec1 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Dec 2012 14:49:12 -0200 Subject: [PATCH 0333/1634] qdev: Include qdev code into *-user, too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code depends on some functions from qemu-option.o, so add qemu-option.o to universal-obj-y to make sure it's included. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- Makefile.objs | 8 ++++++++ hw/Makefile.objs | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index a3eab4b410..12a314e3fb 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -21,6 +21,13 @@ qom-obj-y = qom/ universal-obj-y += $(qom-obj-y) +####################################################################### +# Core hw code (qdev core) +hw-core-obj-y += hw/ +hw-core-obj-y += qemu-option.o + +universal-obj-y += $(hw-core-obj-y) + ####################################################################### # oslib-obj-y is code depending on the OS (win32 vs posix) oslib-obj-y = osdep.o cutils.o qemu-timer-common.o @@ -182,6 +189,7 @@ nested-vars += \ user-obj-y \ common-obj-y \ universal-obj-y \ + hw-core-obj-y \ extra-obj-y \ trace-obj-y dummy := $(call unnest-vars) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index b8bbed39c1..6b8a68c504 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,3 +1,9 @@ +# core qdev-related obj files, also used by *-user: +hw-core-obj-y += qdev.o qdev-properties.o +# irq.o needed for qdev GPIO handling: +hw-core-obj-y += irq.o + + common-obj-y = usb/ ide/ pci/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o @@ -154,7 +160,6 @@ common-obj-$(CONFIG_SOUND) += $(sound-obj-y) common-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ common-obj-y += usb/ -common-obj-y += irq.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_MAX7310) += max7310.o common-obj-$(CONFIG_WM8750) += wm8750.o @@ -180,7 +185,7 @@ common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += msmouse.o ps2.o -common-obj-y += qdev.o qdev-properties.o qdev-monitor.o +common-obj-y += qdev-monitor.o common-obj-y += qdev-properties-system.o common-obj-$(CONFIG_BRLAPI) += baum.o From 5d5b24d042072fb4d13e7027f6e52e44390a9896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 4 Jan 2013 18:13:00 +0100 Subject: [PATCH 0334/1634] qdev: Don't assume existence of parent bus on unparenting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 667d22d1ae59da46b4c1fbd094ca61145f19b8c3 (qdev: move bus removal to object_unparent) made the assumption that at unparenting time parent_bus is not NULL. This assumption is unjustified since object_unparent() may well be called directly after object_initialize(), without any qdev_set_parent_bus(). This did not cause any issues yet because qdev_[try_]create() does call qdev_set_parent_bus(), falling back to SysBus if unsupplied. While at it, ensure that this new function uses the device_ prefix and make the name more neutral in light of this semantic change. Reported-by: Eduardo Habkost Signed-off-by: Andreas Färber Tested-by: Igor Mammedov --- hw/qdev.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index f2c248451c..e2a5c5735b 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -698,16 +698,18 @@ static void device_class_base_init(ObjectClass *class, void *data) klass->props = NULL; } -static void qdev_remove_from_bus(Object *obj) +static void device_unparent(Object *obj) { DeviceState *dev = DEVICE(obj); - bus_remove_child(dev->parent_bus, dev); + if (dev->parent_bus != NULL) { + bus_remove_child(dev->parent_bus, dev); + } } static void device_class_init(ObjectClass *class, void *data) { - class->unparent = qdev_remove_from_bus; + class->unparent = device_unparent; } void device_reset(DeviceState *dev) From 961f839570f01d60a0b224248e6e56fc1d675793 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 5 Dec 2012 14:49:13 -0200 Subject: [PATCH 0335/1634] cpu: Change parent type to Device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This finally makes the CPU class a subclass of the Device class, allowing us to start using DeviceState properties on CPU subclasses. It has no_user=1, as creating CPUs using -device doesn't work yet. Signed-off-by: Igor Mammedov Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/qom/cpu.h | 6 +++--- qom/cpu.c | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 3e9fc3aca5..fbacb2756b 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -20,7 +20,7 @@ #ifndef QEMU_CPU_H #define QEMU_CPU_H -#include "qom/object.h" +#include "hw/qdev-core.h" #include "qemu/thread.h" /** @@ -46,7 +46,7 @@ typedef struct CPUState CPUState; */ typedef struct CPUClass { /*< private >*/ - ObjectClass parent_class; + DeviceClass parent_class; /*< public >*/ void (*reset)(CPUState *cpu); @@ -66,7 +66,7 @@ struct kvm_run; */ struct CPUState { /*< private >*/ - Object parent_obj; + DeviceState parent_obj; /*< public >*/ struct QemuThread *thread; diff --git a/qom/cpu.c b/qom/cpu.c index d4d436f80a..49e5134ea1 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -36,14 +36,16 @@ static void cpu_common_reset(CPUState *cpu) static void cpu_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); CPUClass *k = CPU_CLASS(klass); k->reset = cpu_common_reset; + dc->no_user = 1; } -static TypeInfo cpu_type_info = { +static const TypeInfo cpu_type_info = { .name = TYPE_CPU, - .parent = TYPE_OBJECT, + .parent = TYPE_DEVICE, .instance_size = sizeof(CPUState), .abstract = true, .class_size = sizeof(CPUClass), From fcb93c036053ca8a5cfc02ca72b1b80dd2062423 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2013 20:01:04 -0200 Subject: [PATCH 0336/1634] target-i386: kvm: -cpu host: Use GET_SUPPORTED_CPUID for SVM features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing -cpu host code simply sets every bit inside svm_features (initializing it to -1), and that makes it impossible to make the enforce/check options work properly when the user asks for SVM features explicitly in the command-line. So, instead of initializing svm_features to -1, use GET_SUPPORTED_CPUID to fill only the bits that are supported by the host (just like we do for all other CPUID feature words inside kvm_cpu_fill_host()). This will keep the existing behavior (as filter_features_for_kvm() already uses GET_SUPPORTED_CPUID to filter svm_features), but will allow us to properly check for KVM features inside kvm_check_features_against_host() later. For example, we will be able to make this: $ qemu-system-x86_64 -cpu ...,+pfthreshold,enforce refuse to start if the SVM "pfthreshold" feature is not supported by the host (after we fix kvm_check_features_against_host() to check SVM flags as well). Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 82685dc3f5..1e30015be9 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -897,13 +897,10 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) } } - /* - * Every SVM feature requires emulation support in KVM - so we can't just - * read the host features here. KVM might even support SVM features not - * available on the host hardware. Just set all bits and mask out the - * unsupported ones later. - */ - x86_cpu_def->svm_features = -1; + /* Other KVM-specific feature fields: */ + x86_cpu_def->svm_features = + kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX); + #endif /* CONFIG_KVM */ } From bd004beff8db09b5790b1bb19fad3974e112f007 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2013 20:01:05 -0200 Subject: [PATCH 0337/1634] target-i386: kvm: Enable all supported KVM features for -cpu host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using -cpu host, we don't need to use the kvm_default_features variable, as the user is explicitly asking QEMU to enable all feature supported by the host. This changes the kvm_cpu_fill_host() code to use GET_SUPPORTED_CPUID to initialize the kvm_features field, so we get all host KVM features enabled. This will also allow us to properly check/enforce KVM features inside kvm_check_features_against_host() later. For example, we will be able to make this: $ qemu-system-x86_64 -cpu ...,+kvm_pv_eoi,enforce refuse to start if kvm_pv_eoi is not supported by the host (after we fix kvm_check_features_against_host() to check KVM flags as well). Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 1e30015be9..2547bfabf1 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -900,6 +900,8 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) /* Other KVM-specific feature fields: */ x86_cpu_def->svm_features = kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX); + x86_cpu_def->kvm_features = + kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX); #endif /* CONFIG_KVM */ } From 8b4beddc6bead9d7c85fe690b62f2621574eb195 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2013 20:01:06 -0200 Subject: [PATCH 0338/1634] target-i386: check/enforce: Fix CPUID leaf numbers on error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The -cpu check/enforce warnings are printing incorrect information about the missing flags. There are no feature flags on CPUID leaves 0 and 0x80000000, but there were references to 0 and 0x80000000 in the table at kvm_check_features_against_host(). This changes the model_features_t struct to contain the register number as well, so the error messages print the correct CPUID leaf+register information, instead of wrong CPUID leaf numbers. This also changes the format of the error messages, so they follow the "CPUID... [bit ]" convention used in Intel documentation. Example output: $ qemu-system-x86_64 -machine pc-1.0,accel=kvm -cpu Opteron_G4,+ia64,enforce warning: host doesn't support requested feature: CPUID.01H:EDX.ia64 [bit 30] warning: host doesn't support requested feature: CPUID.01H:ECX.xsave [bit 26] warning: host doesn't support requested feature: CPUID.01H:ECX.avx [bit 28] warning: host doesn't support requested feature: CPUID.80000001H:ECX.abm [bit 5] warning: host doesn't support requested feature: CPUID.80000001H:ECX.sse4a [bit 6] warning: host doesn't support requested feature: CPUID.80000001H:ECX.misalignsse [bit 7] warning: host doesn't support requested feature: CPUID.80000001H:ECX.3dnowprefetch [bit 8] warning: host doesn't support requested feature: CPUID.80000001H:ECX.xop [bit 11] warning: host doesn't support requested feature: CPUID.80000001H:ECX.fma4 [bit 16] Unable to find x86 CPU definition $ Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 42 +++++++++++++++++++++++++++++++++--------- target-i386/cpu.h | 3 +++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 2547bfabf1..ddf70248a0 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -124,6 +124,25 @@ static const char *cpuid_7_0_ebx_feature_name[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; +const char *get_register_name_32(unsigned int reg) +{ + static const char *reg_names[CPU_NB_REGS32] = { + [R_EAX] = "EAX", + [R_ECX] = "ECX", + [R_EDX] = "EDX", + [R_EBX] = "EBX", + [R_ESP] = "ESP", + [R_EBP] = "EBP", + [R_ESI] = "ESI", + [R_EDI] = "EDI", + }; + + if (reg > CPU_NB_REGS32) { + return NULL; + } + return reg_names[reg]; +} + /* collects per-function cpuid data */ typedef struct model_features_t { @@ -132,7 +151,8 @@ typedef struct model_features_t { uint32_t check_feat; const char **flag_names; uint32_t cpuid; - } model_features_t; + int reg; +} model_features_t; int check_cpuid = 0; int enforce_cpuid = 0; @@ -912,10 +932,13 @@ static int unavailable_host_feature(struct model_features_t *f, uint32_t mask) for (i = 0; i < 32; ++i) if (1 << i & mask) { - fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested" - " flag '%s' [0x%08x]\n", - f->cpuid >> 16, f->cpuid & 0xffff, - f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask); + const char *reg = get_register_name_32(f->reg); + assert(reg); + fprintf(stderr, "warning: host doesn't support requested feature: " + "CPUID.%02XH:%s%s%s [bit %d]\n", + f->cpuid, reg, + f->flag_names[i] ? "." : "", + f->flag_names[i] ? f->flag_names[i] : "", i); break; } return 0; @@ -934,13 +957,14 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) int rv, i; struct model_features_t ft[] = { {&guest_def->features, &host_def.features, - ~0, feature_name, 0x00000000}, + ~0, feature_name, 0x00000001, R_EDX}, {&guest_def->ext_features, &host_def.ext_features, - ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001}, + ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001, R_ECX}, {&guest_def->ext2_features, &host_def.ext2_features, - ~PPRO_FEATURES, ext2_feature_name, 0x80000000}, + ~PPRO_FEATURES, ext2_feature_name, 0x80000001, R_EDX}, {&guest_def->ext3_features, &host_def.ext3_features, - ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}}; + ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001, R_ECX} + }; assert(kvm_enabled()); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1283537108..e56921bbe3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1220,4 +1220,7 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); void enable_kvm_pv_eoi(void); +/* Return name of 32-bit register, from a R_* constant */ +const char *get_register_name_32(unsigned int reg); + #endif /* CPU_I386_H */ From 54830ff84df5d1fb182e91bf40e3d7c66c2559a4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2013 20:01:07 -0200 Subject: [PATCH 0339/1634] target-i386: check/enforce: Do not ignore "hypervisor" flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need any hack to ignore CPUID_EXT_HYPERVISOR anymore, because kvm_arch_get_supported_cpuid() now sets CPUID_EXT_HYPERVISOR properly. So, this shouldn't introduce any behavior change, but it makes the code simpler. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index ddf70248a0..a3d104d7dc 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -959,7 +959,7 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) {&guest_def->features, &host_def.features, ~0, feature_name, 0x00000001, R_EDX}, {&guest_def->ext_features, &host_def.ext_features, - ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001, R_ECX}, + ~0, ext_feature_name, 0x00000001, R_ECX}, {&guest_def->ext2_features, &host_def.ext2_features, ~PPRO_FEATURES, ext2_feature_name, 0x80000001, R_EDX}, {&guest_def->ext3_features, &host_def.ext3_features, From 227146259e8deb14b7b30e7718e61512e0f524a9 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2013 20:01:08 -0200 Subject: [PATCH 0340/1634] target-i386: check/enforce: Check all CPUID.80000001H.EDX bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have no idea why PPRO_FEATURES was being ignored on the check of the CPUID.80000001H.EDX bits. I believe it was a mistake, and it was supposed to be ~(PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) or just ~CPUID_EXT2_AMD_ALIASES, because some time ago kvm_cpu_fill_host() used the CPUID instruction directly (instead of kvm_arch_get_supported_cpuid()). But now kvm_cpu_fill_host() uses kvm_arch_get_supported_cpuid(), and kvm_arch_get_supported_cpuid() returns all supported bits for CPUID.80000001H.EDX, even the AMD aliases (that are explicitly copied from CPUID.01H.EDX), so we can make the code check/enforce all the CPUID.80000001H.EDX bits. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index a3d104d7dc..a2971d27eb 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -961,7 +961,7 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) {&guest_def->ext_features, &host_def.ext_features, ~0, ext_feature_name, 0x00000001, R_ECX}, {&guest_def->ext2_features, &host_def.ext2_features, - ~PPRO_FEATURES, ext2_feature_name, 0x80000001, R_EDX}, + ~0, ext2_feature_name, 0x80000001, R_EDX}, {&guest_def->ext3_features, &host_def.ext3_features, ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001, R_ECX} }; From 396d2cfccdc1a46a8c66d9d9baaa59071a553b1c Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2013 20:01:09 -0200 Subject: [PATCH 0341/1634] target-i386: check/enforce: Check SVM flag support as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When nested SVM is supported, the kernel returns the SVM flag on GET_SUPPORTED_CPUID[1], so we can check the SVM flag safely in kvm_check_features_against_host(). I don't know why the original code ignored the SVM flag. Maybe it was because kvm_cpu_fill_host() used the CPUID instruction directly instead of GET_SUPPORTED_CPUID [1] Older kernels (before v2.6.37) returned the SVM flag even if nested SVM was _not_ supported. So the only cases where this patch should change behavior is when SVM is being requested by the user or the CPU model, but not supported by the host. And on these cases we really want QEMU to abort if the "enforce" option is set. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index a2971d27eb..535cd52d17 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -963,7 +963,7 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) {&guest_def->ext2_features, &host_def.ext2_features, ~0, ext2_feature_name, 0x80000001, R_EDX}, {&guest_def->ext3_features, &host_def.ext3_features, - ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001, R_ECX} + ~0, ext3_feature_name, 0x80000001, R_ECX} }; assert(kvm_enabled()); From e8beac00bd26a60e788ab336f38bc12a95b20f0d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 4 Jan 2013 20:01:10 -0200 Subject: [PATCH 0342/1634] target-i386: check/enforce: Eliminate check_feat field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all entries have check_feat=~0 in kvm_check_features_against_host(), we can eliminate check_feat entirely and make the code check all bits. This patch shouldn't introduce any behavior change, as check_feat is set to ~0 on all entries. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 535cd52d17..951e206779 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -148,7 +148,6 @@ const char *get_register_name_32(unsigned int reg) typedef struct model_features_t { uint32_t *guest_feat; uint32_t *host_feat; - uint32_t check_feat; const char **flag_names; uint32_t cpuid; int reg; @@ -945,8 +944,7 @@ static int unavailable_host_feature(struct model_features_t *f, uint32_t mask) } /* best effort attempt to inform user requested cpu flags aren't making - * their way to the guest. Note: ft[].check_feat ideally should be - * specified via a guest_def field to suppress report of extraneous flags. + * their way to the guest. * * This function may be called only if KVM is enabled. */ @@ -957,13 +955,13 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) int rv, i; struct model_features_t ft[] = { {&guest_def->features, &host_def.features, - ~0, feature_name, 0x00000001, R_EDX}, + feature_name, 0x00000001, R_EDX}, {&guest_def->ext_features, &host_def.ext_features, - ~0, ext_feature_name, 0x00000001, R_ECX}, + ext_feature_name, 0x00000001, R_ECX}, {&guest_def->ext2_features, &host_def.ext2_features, - ~0, ext2_feature_name, 0x80000001, R_EDX}, + ext2_feature_name, 0x80000001, R_EDX}, {&guest_def->ext3_features, &host_def.ext3_features, - ~0, ext3_feature_name, 0x80000001, R_ECX} + ext3_feature_name, 0x80000001, R_ECX} }; assert(kvm_enabled()); @@ -971,7 +969,7 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) kvm_cpu_fill_host(&host_def); for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) for (mask = 1; mask; mask <<= 1) - if (ft[i].check_feat & mask && *ft[i].guest_feat & mask && + if (*ft[i].guest_feat & mask && !(*ft[i].host_feat & mask)) { unavailable_host_feature(&ft[i], mask); rv = 1; From 75a192aa68e7801ab8465b3345ac74d6d3cdceca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 14:44:08 +0100 Subject: [PATCH 0343/1634] qemu-common.h: Make qemu_init_vcpu() stub static inline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turn the *-user macro into a no-op inline function to avoid unused-variable warnings and band-aiding #ifdef'ery. This allows to drop an #ifdef for alpha and avoids more for unicore32 and other upcoming trivial realizefn implementations. Suggested-by: Lluís Vilanova Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber Reviewed-by: Eduardo Habkost --- include/qemu-common.h | 4 +++- target-alpha/cpu.c | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/qemu-common.h b/include/qemu-common.h index 2b83de395c..ca464bb367 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -288,7 +288,9 @@ struct qemu_work_item { }; #ifdef CONFIG_USER_ONLY -#define qemu_init_vcpu(env) do { } while (0) +static inline void qemu_init_vcpu(void *env) +{ +} #else void qemu_init_vcpu(void *env); #endif diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 212a6250ba..40e980933f 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -26,11 +26,9 @@ static void alpha_cpu_realize(Object *obj, Error **errp) { -#ifndef CONFIG_USER_ONLY AlphaCPU *cpu = ALPHA_CPU(obj); qemu_init_vcpu(&cpu->env); -#endif } /* Sort alphabetically by type name. */ From 4586f157757acc5c8edcc954289c7aa51661235c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 28 Dec 2012 21:01:16 +0100 Subject: [PATCH 0344/1634] target-i386: Filter out unsupported features at realize time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eduardo Habkost Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 951e206779..a776e1118d 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1571,21 +1571,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) env->cpuid_ext2_features |= (def->features & CPUID_EXT2_AMD_ALIASES); } - if (!kvm_enabled()) { - env->cpuid_features &= TCG_FEATURES; - env->cpuid_ext_features &= TCG_EXT_FEATURES; - env->cpuid_ext2_features &= (TCG_EXT2_FEATURES -#ifdef TARGET_X86_64 - | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM -#endif - ); - env->cpuid_ext3_features &= TCG_EXT3_FEATURES; - env->cpuid_svm_features &= TCG_SVM_FEATURES; - } else { -#ifdef CONFIG_KVM - filter_features_for_kvm(cpu); -#endif - } object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); @@ -2106,6 +2091,22 @@ void x86_cpu_realize(Object *obj, Error **errp) env->cpuid_level = 7; } + if (!kvm_enabled()) { + env->cpuid_features &= TCG_FEATURES; + env->cpuid_ext_features &= TCG_EXT_FEATURES; + env->cpuid_ext2_features &= (TCG_EXT2_FEATURES +#ifdef TARGET_X86_64 + | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM +#endif + ); + env->cpuid_ext3_features &= TCG_EXT3_FEATURES; + env->cpuid_svm_features &= TCG_SVM_FEATURES; + } else { +#ifdef CONFIG_KVM + filter_features_for_kvm(cpu); +#endif + } + #ifndef CONFIG_USER_ONLY qemu_register_reset(x86_cpu_machine_reset_cb, cpu); From 9b15cd9e7a1ab0827f4d01c4be77eb41f195073f Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 28 Dec 2012 21:01:17 +0100 Subject: [PATCH 0345/1634] target-i386: Sanitize AMD's ext2_features at realize time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CPU properties are implemented, ext2_features may change between object_new(CPU) and cpu_realize_fn(). Sanitizing ext2_features for AMD based CPU at realize() time will keep current behavior after CPU features are converted to properties. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index a776e1118d..b40cc37bac 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1561,16 +1561,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000, "tsc-frequency", &error); - /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on - * CPUID[1].EDX. - */ - if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && - env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && - env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) { - env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES; - env->cpuid_ext2_features |= (def->features & CPUID_EXT2_AMD_ALIASES); - } - object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); @@ -2091,6 +2081,17 @@ void x86_cpu_realize(Object *obj, Error **errp) env->cpuid_level = 7; } + /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on + * CPUID[1].EDX. + */ + if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && + env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && + env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) { + env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES; + env->cpuid_ext2_features |= (env->cpuid_features + & CPUID_EXT2_AMD_ALIASES); + } + if (!kvm_enabled()) { env->cpuid_features &= TCG_FEATURES; env->cpuid_ext_features &= TCG_EXT_FEATURES; From ebe8b9c6eb6e425d44805288b6b5dabd69368f46 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 28 Dec 2012 21:01:18 +0100 Subject: [PATCH 0346/1634] target-i386: Explicitly set vendor for each built-in cpudef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since cpudef config is not supported anymore and all remaining sources now always set x86_def_t.vendor[123] fields, remove setting default vendor to simplify future re-factoring. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b40cc37bac..78bd61e18f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -407,6 +407,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "core2duo", .level = 10, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 15, .stepping = 11, @@ -451,6 +454,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "qemu32", .level = 4, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 3, .stepping = 3, @@ -461,6 +467,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "kvm32", .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 15, .model = 6, .stepping = 1, @@ -475,6 +484,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "coreduo", .level = 10, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 14, .stepping = 8, @@ -490,6 +502,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "486", .level = 1, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 4, .model = 0, .stepping = 0, @@ -499,6 +514,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium", .level = 1, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 5, .model = 4, .stepping = 3, @@ -508,6 +526,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium2", .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 5, .stepping = 2, @@ -517,6 +538,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium3", .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 7, .stepping = 3, @@ -542,6 +566,9 @@ static x86_def_t builtin_x86_defs[] = { .name = "n270", /* original is on level 10 */ .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 28, .stepping = 2, @@ -1534,15 +1561,10 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) if (cpu_x86_parse_featurestr(def, features) < 0) { goto error; } - if (def->vendor1) { - env->cpuid_vendor1 = def->vendor1; - env->cpuid_vendor2 = def->vendor2; - env->cpuid_vendor3 = def->vendor3; - } else { - env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1; - env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2; - env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3; - } + assert(def->vendor1); + env->cpuid_vendor1 = def->vendor1; + env->cpuid_vendor2 = def->vendor2; + env->cpuid_vendor3 = def->vendor3; env->cpuid_vendor_override = def->vendor_override; object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); From b0223e29afdc88cc262a764026296414396cd129 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 8 Jan 2013 14:09:03 -0700 Subject: [PATCH 0347/1634] vfio-pci: Make host MSI-X enable track guest Guests typically enable MSI-X with all of the vectors in the MSI-X vector table masked. Only when the vector is enabled does the vector get unmasked, resulting in a vector_use callback. These two points, enable and unmask, correspond to pci_enable_msix() and request_irq() for Linux guests. Some drivers rely on VF/PF or PF/fw communication channels that expect the physical state of the device to match the guest visible state of the device. They don't appreciate lazily enabling MSI-X on the physical device. To solve this, enable MSI-X with a single vector when the MSI-X capability is enabled and immediate disable the vector. This leaves the physical device in exactly the same state between host and guest. Furthermore, the brief gap where we enable vector 0, it fires into userspace, not KVM, so the guest doesn't get spurious interrupts. Ideally we could call VFIO_DEVICE_SET_IRQS with the right parameters to enable MSI-X with zero vectors, but this will currently return an error as the Linux MSI-X interfaces do not allow it. Signed-off-by: Alex Williamson Cc: qemu-stable@nongnu.org --- hw/vfio_pci.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 28c83031d0..8ec1faf27e 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -562,8 +562,8 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix) return ret; } -static int vfio_msix_vector_use(PCIDevice *pdev, - unsigned int nr, MSIMessage msg) +static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, + MSIMessage *msg, IOHandler *handler) { VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); VFIOMSIVector *vector; @@ -587,7 +587,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev, * Attempt to enable route through KVM irqchip, * default to userspace handling if unavailable. */ - vector->virq = kvm_irqchip_add_msi_route(kvm_state, msg); + vector->virq = msg ? kvm_irqchip_add_msi_route(kvm_state, *msg) : -1; if (vector->virq < 0 || kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt, vector->virq) < 0) { @@ -596,7 +596,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev, vector->virq = -1; } qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), - vfio_msi_interrupt, NULL, vector); + handler, NULL, vector); } /* @@ -639,6 +639,12 @@ static int vfio_msix_vector_use(PCIDevice *pdev, return 0; } +static int vfio_msix_vector_use(PCIDevice *pdev, + unsigned int nr, MSIMessage msg) +{ + return vfio_msix_vector_do_use(pdev, nr, &msg, vfio_msi_interrupt); +} + static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) { VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); @@ -697,6 +703,22 @@ static void vfio_enable_msix(VFIODevice *vdev) vdev->interrupt = VFIO_INT_MSIX; + /* + * Some communication channels between VF & PF or PF & fw rely on the + * physical state of the device and expect that enabling MSI-X from the + * guest enables the same on the host. When our guest is Linux, the + * guest driver call to pci_enable_msix() sets the enabling bit in the + * MSI-X capability, but leaves the vector table masked. We therefore + * can't rely on a vector_use callback (from request_irq() in the guest) + * to switch the physical device into MSI-X mode because that may come a + * long time after pci_enable_msix(). This code enables vector 0 with + * triggering to userspace, then immediately release the vector, leaving + * the physical device with no vectors enabled, but MSI-X enabled, just + * like the guest view. + */ + vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL); + vfio_msix_vector_release(&vdev->pdev, 0); + if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, vfio_msix_vector_release, NULL)) { error_report("vfio: msix_set_vector_notifiers failed\n"); From 8fc94e5a8046e349e07976f9bcaffbcd5833f3a2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 8 Jan 2013 14:10:03 -0700 Subject: [PATCH 0348/1634] vfio-pci: Loosen sanity checks to allow future features VFIO_PCI_NUM_REGIONS and VFIO_PCI_NUM_IRQS should never have been used in this manner as it locks a specific kernel implementation. Future features may introduce new regions or interrupt entries (VGA may add legacy ranges, AER might add an IRQ for error signalling). Fix this before it gets us into trouble. Signed-off-by: Alex Williamson Cc: qemu-stable@nongnu.org --- hw/vfio_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 8ec1faf27e..c51ae6761b 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -1837,13 +1837,13 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) error_report("Warning, device %s does not support reset\n", name); } - if (dev_info.num_regions != VFIO_PCI_NUM_REGIONS) { + if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) { error_report("vfio: unexpected number of io regions %u\n", dev_info.num_regions); goto error; } - if (dev_info.num_irqs != VFIO_PCI_NUM_IRQS) { + if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) { error_report("vfio: unexpected number of irqs %u\n", dev_info.num_irqs); goto error; } From a9de6d01df3153b2ac0cade11e26a66d596d7166 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:01:55 -0200 Subject: [PATCH 0349/1634] qemu-ga: guest_file_handle_find(): take an Error argument Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth *Fixed missing space character in error message Signed-off-by: Michael Roth --- qga/commands-posix.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index a657201e7a..bbef66dc6a 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -111,7 +111,7 @@ static void guest_file_handle_add(FILE *fh) QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); } -static GuestFileHandle *guest_file_handle_find(int64_t id) +static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) { GuestFileHandle *gfh; @@ -122,6 +122,7 @@ static GuestFileHandle *guest_file_handle_find(int64_t id) } } + error_setg(err, "handle '%" PRId64 "' has not been found", id); return NULL; } @@ -160,12 +161,11 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E void qmp_guest_file_close(int64_t handle, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); int ret; slog("guest-file-close called, handle: %ld", handle); if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return; } @@ -182,14 +182,13 @@ void qmp_guest_file_close(int64_t handle, Error **err) struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, int64_t count, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); GuestFileRead *read_data = NULL; guchar *buf; FILE *fh; size_t read_count; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return NULL; } @@ -228,11 +227,10 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, guchar *buf; gsize buf_len; int write_count; - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); FILE *fh; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return NULL; } @@ -265,13 +263,12 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, int64_t whence, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); GuestFileSeek *seek_data = NULL; FILE *fh; int ret; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return NULL; } @@ -291,12 +288,11 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, void qmp_guest_file_flush(int64_t handle, Error **err) { - GuestFileHandle *gfh = guest_file_handle_find(handle); + GuestFileHandle *gfh = guest_file_handle_find(handle, err); FILE *fh; int ret; if (!gfh) { - error_set(err, QERR_FD_NOT_FOUND, "handle"); return; } From 3ac4b7c51e3ba181a86983ba2601a595ed8f3b1d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:01:56 -0200 Subject: [PATCH 0350/1634] qemu-ga: qmp_guest_file_close(): fix fclose() error check fclose() returns EOF on error. Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- qga/commands-posix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index bbef66dc6a..ebb58be22e 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -170,7 +170,7 @@ void qmp_guest_file_close(int64_t handle, Error **err) } ret = fclose(gfh->fh); - if (ret == -1) { + if (ret == EOF) { error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed"); return; } From db3edb665549979b44e0376ab9e859f58b89b503 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:01:57 -0200 Subject: [PATCH 0351/1634] qemu-ga: qmp_guest_file_*: improve error reporting Use error_setg_errno() when possible with an improved error description. Signed-off-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/commands-posix.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index ebb58be22e..d5f2dcdc09 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -138,7 +138,8 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E slog("guest-file-open called, filepath: %s, mode: %s", path, mode); fh = fopen(path, mode); if (!fh) { - error_set(err, QERR_OPEN_FILE_FAILED, path); + error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')", + path, mode); return -1; } @@ -149,7 +150,8 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E ret = fcntl(fd, F_GETFL); ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK); if (ret == -1) { - error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed"); + error_setg_errno(err, errno, "failed to make file '%s' non-blocking", + path); fclose(fh); return -1; } @@ -171,7 +173,7 @@ void qmp_guest_file_close(int64_t handle, Error **err) ret = fclose(gfh->fh); if (ret == EOF) { - error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed"); + error_setg_errno(err, errno, "failed to close handle"); return; } @@ -195,7 +197,8 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, if (!has_count) { count = QGA_READ_COUNT_DEFAULT; } else if (count < 0) { - error_set(err, QERR_INVALID_PARAMETER, "count"); + error_setg(err, "value '%" PRId64 "' is invalid for argument count", + count); return NULL; } @@ -203,8 +206,8 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count, buf = g_malloc0(count+1); read_count = fread(buf, 1, count, fh); if (ferror(fh)) { + error_setg_errno(err, errno, "failed to read file"); slog("guest-file-read failed, handle: %ld", handle); - error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed"); } else { buf[read_count] = 0; read_data = g_malloc0(sizeof(GuestFileRead)); @@ -240,15 +243,16 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64, if (!has_count) { count = buf_len; } else if (count < 0 || count > buf_len) { + error_setg(err, "value '%" PRId64 "' is invalid for argument count", + count); g_free(buf); - error_set(err, QERR_INVALID_PARAMETER, "count"); return NULL; } write_count = fwrite(buf, 1, count, fh); if (ferror(fh)) { + error_setg_errno(err, errno, "failed to write to file"); slog("guest-file-write failed, handle: %ld", handle); - error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error"); } else { write_data = g_malloc0(sizeof(GuestFileWrite)); write_data->count = write_count; @@ -275,7 +279,7 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset, fh = gfh->fh; ret = fseek(fh, offset, whence); if (ret == -1) { - error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); + error_setg_errno(err, errno, "failed to seek file"); } else { seek_data = g_malloc0(sizeof(GuestFileRead)); seek_data->position = ftell(fh); @@ -299,7 +303,7 @@ void qmp_guest_file_flush(int64_t handle, Error **err) fh = gfh->fh; ret = fflush(fh); if (ret == EOF) { - error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno)); + error_setg_errno(err, errno, "failed to flush file"); } } From d220a6dfea10655efe70d37748a3c23cf0a00647 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:01:58 -0200 Subject: [PATCH 0352/1634] qemu-ga: qmp_guest_shutdown(): improve error reporting Most errors are QERR_UNDEFINED_ERROR. Also, adds ga_wait_child() as a future commit will use it too. Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- qga/commands-posix.c | 52 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index d5f2dcdc09..247e8dc855 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -46,10 +46,29 @@ extern char **environ; #endif #endif +static void ga_wait_child(pid_t pid, int *status, Error **err) +{ + pid_t rpid; + + *status = 0; + + do { + rpid = waitpid(pid, status, 0); + } while (rpid == -1 && errno == EINTR); + + if (rpid == -1) { + error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid); + return; + } + + g_assert(rpid == pid); +} + void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) { const char *shutdown_flag; - pid_t rpid, pid; + Error *local_err = NULL; + pid_t pid; int status; slog("guest-shutdown called, mode: %s", mode); @@ -60,8 +79,8 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) } else if (strcmp(mode, "reboot") == 0) { shutdown_flag = "-r"; } else { - error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode", - "halt|powerdown|reboot"); + error_setg(err, + "mode is invalid (valid values are: halt|powerdown|reboot"); return; } @@ -77,18 +96,27 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) "hypervisor initiated shutdown", (char*)NULL, environ); _exit(EXIT_FAILURE); } else if (pid < 0) { - goto exit_err; - } - - do { - rpid = waitpid(pid, &status, 0); - } while (rpid == -1 && errno == EINTR); - if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { + error_setg_errno(err, errno, "failed to create child process"); return; } -exit_err: - error_set(err, QERR_UNDEFINED_ERROR); + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return; + } + + if (!WIFEXITED(status)) { + error_setg(err, "child process has terminated abnormally"); + return; + } + + if (WEXITSTATUS(status)) { + error_setg(err, "child process has failed to shutdown"); + return; + } + + /* succeded */ } typedef struct GuestFileHandle { From 261551d1cc3a830e9623971dffa8033b216f1d63 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 29 Nov 2012 15:29:11 -0200 Subject: [PATCH 0353/1634] qemu-ga: build_fs_mount_list(): take an Error argument Signed-off-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/commands-posix.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 247e8dc855..f7b85b284c 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -371,7 +371,7 @@ static void free_fs_mount_list(FsMountList *mounts) /* * Walk the mount table and build a list of local file systems */ -static int build_fs_mount_list(FsMountList *mounts) +static void build_fs_mount_list(FsMountList *mounts, Error **err) { struct mntent *ment; FsMount *mount; @@ -380,8 +380,8 @@ static int build_fs_mount_list(FsMountList *mounts) fp = setmntent(mtab, "r"); if (!fp) { - g_warning("fsfreeze: unable to read mtab"); - return -1; + error_setg(err, "failed to open mtab file: '%s'", mtab); + return; } while ((ment = getmntent(fp))) { @@ -405,8 +405,6 @@ static int build_fs_mount_list(FsMountList *mounts) } endmntent(fp); - - return 0; } #endif @@ -433,15 +431,17 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) int ret = 0, i = 0; FsMountList mounts; struct FsMount *mount; + Error *local_err = NULL; int fd; char err_msg[512]; slog("guest-fsfreeze called"); QTAILQ_INIT(&mounts); - ret = build_fs_mount_list(&mounts); - if (ret < 0) { - return ret; + build_fs_mount_list(&mounts, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return -1; } /* cannot risk guest agent blocking itself on a write in this state */ @@ -498,12 +498,12 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) FsMountList mounts; FsMount *mount; int fd, i = 0, logged; + Error *local_err = NULL; QTAILQ_INIT(&mounts); - ret = build_fs_mount_list(&mounts); - if (ret) { - error_set(err, QERR_QGA_COMMAND_FAILED, - "failed to enumerate filesystems"); + build_fs_mount_list(&mounts, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); return 0; } @@ -568,6 +568,7 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) FsMountList mounts; struct FsMount *mount; int fd; + Error *local_err = NULL; char err_msg[512]; struct fstrim_range r = { .start = 0, @@ -578,8 +579,9 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) slog("guest-fstrim called"); QTAILQ_INIT(&mounts); - ret = build_fs_mount_list(&mounts); - if (ret < 0) { + build_fs_mount_list(&mounts, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); return; } From 617fbbc13219d26dd71d100d83d617ec8acf5e2d Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:02:00 -0200 Subject: [PATCH 0354/1634] qemu-ga: qmp_guest_fsfreeze_*(): get rid of sprintf() + error_set() Convert them to error_setg_errno(). Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- qga/commands-posix.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index f7b85b284c..9ad2891d77 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -433,7 +433,6 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) struct FsMount *mount; Error *local_err = NULL; int fd; - char err_msg[512]; slog("guest-fsfreeze called"); @@ -450,9 +449,7 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) QTAILQ_FOREACH(mount, &mounts, next) { fd = qemu_open(mount->dirname, O_RDONLY); if (fd == -1) { - sprintf(err_msg, "failed to open %s, %s", mount->dirname, - strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to open %s", mount->dirname); goto error; } @@ -468,9 +465,8 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) ret = ioctl(fd, FIFREEZE); if (ret == -1) { if (errno != EOPNOTSUPP) { - sprintf(err_msg, "failed to freeze %s, %s", - mount->dirname, strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to freeze %s", + mount->dirname); close(fd); goto error; } From 071673b09021b60eab268653c6bcfba92eea7603 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:02:01 -0200 Subject: [PATCH 0355/1634] qemu-ga: qmp_guest_fstrim(): get rid of sprintf() + error_set() Convert them to error_setg_errno(). Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- qga/commands-posix.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 9ad2891d77..fa786e53e9 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -565,7 +565,6 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) struct FsMount *mount; int fd; Error *local_err = NULL; - char err_msg[512]; struct fstrim_range r = { .start = 0, .len = -1, @@ -584,9 +583,7 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) QTAILQ_FOREACH(mount, &mounts, next) { fd = qemu_open(mount->dirname, O_RDONLY); if (fd == -1) { - sprintf(err_msg, "failed to open %s, %s", mount->dirname, - strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to open %s", mount->dirname); goto error; } @@ -599,9 +596,8 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) ret = ioctl(fd, FITRIM, &r); if (ret == -1) { if (errno != ENOTTY && errno != EOPNOTSUPP) { - sprintf(err_msg, "failed to trim %s, %s", - mount->dirname, strerror(errno)); - error_set(err, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(err, errno, "failed to trim %s", + mount->dirname); close(fd); goto error; } From 878a0ae0ab3eb8428626e67995c9efad8eb1ba80 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:02:02 -0200 Subject: [PATCH 0356/1634] qemu-ga: qmp_guest_network_get_interfaces(): get rid of snprintf() + error_set() Convert them to error_setg_errno(). Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- qga/commands-posix.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index fa786e53e9..9b6ef17260 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -802,12 +802,9 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) { GuestNetworkInterfaceList *head = NULL, *cur_item = NULL; struct ifaddrs *ifap, *ifa; - char err_msg[512]; if (getifaddrs(&ifap) < 0) { - snprintf(err_msg, sizeof(err_msg), - "getifaddrs failed: %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "getifaddrs failed"); goto error; } @@ -843,20 +840,16 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) /* we haven't obtained HW address yet */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { - snprintf(err_msg, sizeof(err_msg), - "failed to create socket: %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "failed to create socket"); goto error; } memset(&ifr, 0, sizeof(ifr)); pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name); if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) { - snprintf(err_msg, sizeof(err_msg), - "failed to get MAC address of %s: %s", - ifa->ifa_name, - strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, + "failed to get MAC address of %s", + ifa->ifa_name); goto error; } @@ -867,9 +860,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) (int) mac_addr[0], (int) mac_addr[1], (int) mac_addr[2], (int) mac_addr[3], (int) mac_addr[4], (int) mac_addr[5]) == -1) { - snprintf(err_msg, sizeof(err_msg), - "failed to format MAC: %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "failed to format MAC"); goto error; } @@ -884,9 +875,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) address_item->value = g_malloc0(sizeof(*address_item->value)); p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { - snprintf(err_msg, sizeof(err_msg), - "inet_ntop failed : %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "inet_ntop failed"); goto error; } @@ -906,9 +895,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) address_item->value = g_malloc0(sizeof(*address_item->value)); p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { - snprintf(err_msg, sizeof(err_msg), - "inet_ntop failed : %s", strerror(errno)); - error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg); + error_setg_errno(errp, errno, "inet_ntop failed"); goto error; } From 6b26e837a40a7bed14080fb9029ad6c22409f8b3 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:02:03 -0200 Subject: [PATCH 0357/1634] qemu-ga: bios_supports_mode(): improve error reporting Most errors are QERR_UNDEFINED_ERROR today. Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- qga/commands-posix.c | 54 +++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 9b6ef17260..f3ee492633 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -618,8 +618,9 @@ error: static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, const char *sysfile_str, Error **err) { + Error *local_err = NULL; char *pmutils_path; - pid_t pid, rpid; + pid_t pid; int status; pmutils_path = g_find_program_in_path(pmutils_bin); @@ -664,31 +665,38 @@ static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg, } _exit(SUSPEND_NOT_SUPPORTED); + } else if (pid < 0) { + error_setg_errno(err, errno, "failed to create child process"); + goto out; } + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + goto out; + } + + if (!WIFEXITED(status)) { + error_setg(err, "child process has terminated abnormally"); + goto out; + } + + switch (WEXITSTATUS(status)) { + case SUSPEND_SUPPORTED: + goto out; + case SUSPEND_NOT_SUPPORTED: + error_setg(err, + "the requested suspend mode is not supported by the guest"); + goto out; + default: + error_setg(err, + "the helper program '%s' returned an unexpected exit status" + " code (%d)", pmutils_path, WEXITSTATUS(status)); + goto out; + } + +out: g_free(pmutils_path); - - if (pid < 0) { - goto undef_err; - } - - do { - rpid = waitpid(pid, &status, 0); - } while (rpid == -1 && errno == EINTR); - if (rpid == pid && WIFEXITED(status)) { - switch (WEXITSTATUS(status)) { - case SUSPEND_SUPPORTED: - return; - case SUSPEND_NOT_SUPPORTED: - error_set(err, QERR_UNSUPPORTED); - return; - default: - goto undef_err; - } - } - -undef_err: - error_set(err, QERR_UNDEFINED_ERROR); } static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, From 7b3760879bf323a0d9654a5158d5b3ed51882505 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 27 Nov 2012 11:02:04 -0200 Subject: [PATCH 0358/1634] qemu-ga: guest_suspend(): improve error reporting Most errors are QERR_UNDEFINED_ERROR today. Signed-off-by: Luiz Capitulino Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- qga/commands-posix.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index f3ee492633..614a421ffd 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -702,8 +702,9 @@ out: static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, Error **err) { + Error *local_err = NULL; char *pmutils_path; - pid_t rpid, pid; + pid_t pid; int status; pmutils_path = g_find_program_in_path(pmutils_bin); @@ -741,23 +742,29 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str, } _exit(EXIT_SUCCESS); + } else if (pid < 0) { + error_setg_errno(err, errno, "failed to create child process"); + goto out; } + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + goto out; + } + + if (!WIFEXITED(status)) { + error_setg(err, "child process has terminated abnormally"); + goto out; + } + + if (WEXITSTATUS(status)) { + error_setg(err, "child process has failed to suspend"); + goto out; + } + +out: g_free(pmutils_path); - - if (pid < 0) { - goto exit_err; - } - - do { - rpid = waitpid(pid, &status, 0); - } while (rpid == -1 && errno == EINTR); - if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) { - return; - } - -exit_err: - error_set(err, QERR_UNDEFINED_ERROR); } void qmp_guest_suspend_disk(Error **err) From ec0f694c11e8e0958d727e40e0759ab99e5908d6 Mon Sep 17 00:00:00 2001 From: Tomoki Sekiyama Date: Wed, 12 Dec 2012 12:55:55 +0900 Subject: [PATCH 0359/1634] qemu-ga: execute hook to quiesce the guest on fsfreeze-freeze/thaw To use the online disk snapshot for online-backup, application-level consistency of the snapshot image is required. However, currently the guest agent can provide only filesystem-level consistency, and the snapshot may contain dirty data, for example, incomplete transactions. This patch provides the opportunity to quiesce applications before snapshot is taken. If --fsfreeze-hook option is specified, the hook is executed with "freeze" argument before the filesystem is frozen by fsfreeze-freeze command. As for fsfreeze-thaw command, the hook is executed with "thaw" argument after the filesystem is thawed. This patch depends on patchset to improve error reporting by Luiz Capitulino: http://lists.gnu.org/archive/html/qemu-devel/2012-11/msg03016.html Signed-off-by: Tomoki Sekiyama Reviewed-by: Luiz Capitulino *clarified usage in help output Signed-off-by: Michael Roth --- qga/commands-posix.c | 69 ++++++++++++++++++++++++++++++++++++++++++ qga/guest-agent-core.h | 1 + qga/main.c | 48 ++++++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 614a421ffd..77f6ee7d5f 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -410,6 +410,66 @@ static void build_fs_mount_list(FsMountList *mounts, Error **err) #if defined(CONFIG_FSFREEZE) +typedef enum { + FSFREEZE_HOOK_THAW = 0, + FSFREEZE_HOOK_FREEZE, +} FsfreezeHookArg; + +const char *fsfreeze_hook_arg_string[] = { + "thaw", + "freeze", +}; + +static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err) +{ + int status; + pid_t pid; + const char *hook; + const char *arg_str = fsfreeze_hook_arg_string[arg]; + Error *local_err = NULL; + + hook = ga_fsfreeze_hook(ga_state); + if (!hook) { + return; + } + if (access(hook, X_OK) != 0) { + error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook); + return; + } + + slog("executing fsfreeze hook with arg '%s'", arg_str); + pid = fork(); + if (pid == 0) { + setsid(); + reopen_fd_to_null(0); + reopen_fd_to_null(1); + reopen_fd_to_null(2); + + execle(hook, hook, arg_str, NULL, environ); + _exit(EXIT_FAILURE); + } else if (pid < 0) { + error_setg_errno(err, errno, "failed to create child process"); + return; + } + + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return; + } + + if (!WIFEXITED(status)) { + error_setg(err, "fsfreeze hook has terminated abnormally"); + return; + } + + status = WEXITSTATUS(status); + if (status) { + error_setg(err, "fsfreeze hook has failed with status %d", status); + return; + } +} + /* * Return status of freeze/thaw */ @@ -436,6 +496,12 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err) slog("guest-fsfreeze called"); + execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err); + if (error_is_set(&local_err)) { + error_propagate(err, local_err); + return -1; + } + QTAILQ_INIT(&mounts); build_fs_mount_list(&mounts, &local_err); if (error_is_set(&local_err)) { @@ -537,6 +603,9 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) ga_unset_frozen(ga_state); free_fs_mount_list(&mounts); + + execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err); + return i; } diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index 8934163375..3354598362 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -34,6 +34,7 @@ void ga_set_response_delimited(GAState *s); bool ga_is_frozen(GAState *s); void ga_set_frozen(GAState *s); void ga_unset_frozen(GAState *s); +const char *ga_fsfreeze_hook(GAState *s); #ifndef _WIN32 void reopen_fd_to_null(int fd); diff --git a/qga/main.c b/qga/main.c index ba5fa1c778..a9b968c507 100644 --- a/qga/main.c +++ b/qga/main.c @@ -34,6 +34,12 @@ #include "qga/service-win32.h" #include #endif +#ifdef __linux__ +#include +#ifdef FIFREEZE +#define CONFIG_FSFREEZE +#endif +#endif #ifndef _WIN32 #define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0" @@ -42,6 +48,9 @@ #endif #define QGA_STATEDIR_DEFAULT CONFIG_QEMU_LOCALSTATEDIR "/run" #define QGA_PIDFILE_DEFAULT QGA_STATEDIR_DEFAULT "/qemu-ga.pid" +#ifdef CONFIG_FSFREEZE +#define QGA_FSFREEZE_HOOK_DEFAULT CONFIG_QEMU_CONFDIR "/fsfreeze-hook" +#endif #define QGA_SENTINEL_BYTE 0xFF struct GAState { @@ -64,6 +73,9 @@ struct GAState { const char *log_filepath; const char *pid_filepath; } deferred_options; +#ifdef CONFIG_FSFREEZE + const char *fsfreeze_hook; +#endif }; struct GAState *ga_state; @@ -153,6 +165,16 @@ static void usage(const char *cmd) " %s)\n" " -l, --logfile set logfile path, logs to stderr by default\n" " -f, --pidfile specify pidfile (default is %s)\n" +#ifdef CONFIG_FSFREEZE +" -F, --fsfreeze-hook\n" +" enable fsfreeze hook. Accepts an optional argument that\n" +" specifies script to run on freeze/thaw. Script will be\n" +" called with 'freeze'/'thaw' arguments accordingly.\n" +" (default is %s)\n" +" If using -F with an argument, do not follow -F with a\n" +" space.\n" +" (for example: -F/var/run/fsfreezehook.sh)\n" +#endif " -t, --statedir specify dir to store state information (absolute paths\n" " only, default is %s)\n" " -v, --verbose log extra debugging information\n" @@ -167,6 +189,9 @@ static void usage(const char *cmd) "\n" "Report bugs to \n" , cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT, +#ifdef CONFIG_FSFREEZE + QGA_FSFREEZE_HOOK_DEFAULT, +#endif QGA_STATEDIR_DEFAULT); } @@ -401,6 +426,13 @@ void ga_unset_frozen(GAState *s) } } +#ifdef CONFIG_FSFREEZE +const char *ga_fsfreeze_hook(GAState *s) +{ + return s->fsfreeze_hook; +} +#endif + static void become_daemon(const char *pidfile) { #ifndef _WIN32 @@ -678,10 +710,13 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[]) int main(int argc, char **argv) { - const char *sopt = "hVvdm:p:l:f:b:s:t:"; + const char *sopt = "hVvdm:p:l:f:F::b:s:t:"; const char *method = NULL, *path = NULL; const char *log_filepath = NULL; const char *pid_filepath = QGA_PIDFILE_DEFAULT; +#ifdef CONFIG_FSFREEZE + const char *fsfreeze_hook = NULL; +#endif const char *state_dir = QGA_STATEDIR_DEFAULT; #ifdef _WIN32 const char *service = NULL; @@ -691,6 +726,9 @@ int main(int argc, char **argv) { "version", 0, NULL, 'V' }, { "logfile", 1, NULL, 'l' }, { "pidfile", 1, NULL, 'f' }, +#ifdef CONFIG_FSFREEZE + { "fsfreeze-hook", 2, NULL, 'F' }, +#endif { "verbose", 0, NULL, 'v' }, { "method", 1, NULL, 'm' }, { "path", 1, NULL, 'p' }, @@ -723,6 +761,11 @@ int main(int argc, char **argv) case 'f': pid_filepath = optarg; break; +#ifdef CONFIG_FSFREEZE + case 'F': + fsfreeze_hook = optarg ? optarg : QGA_FSFREEZE_HOOK_DEFAULT; + break; +#endif case 't': state_dir = optarg; break; @@ -786,6 +829,9 @@ int main(int argc, char **argv) s = g_malloc0(sizeof(GAState)); s->log_level = log_level; s->log_file = stderr; +#ifdef CONFIG_FSFREEZE + s->fsfreeze_hook = fsfreeze_hook; +#endif g_log_set_default_handler(ga_log, s); g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR); ga_enable_logging(s); From 96610da210697a1f33669d8bec0cb7b944d3a516 Mon Sep 17 00:00:00 2001 From: Tomoki Sekiyama Date: Wed, 12 Dec 2012 12:55:57 +0900 Subject: [PATCH 0360/1634] qemu-ga: sample fsfreeze hooks Adds sample hook scripts for --fsfreeze-hook option of qemu-ga. - fsfreeze-hook : execute scripts in fsfreeze-hook.d/ - fsfreeze-hook.d/mysql-flush.sh.sample : quiesce MySQL before snapshot Signed-off-by: Tomoki Sekiyama Reviewed-by: Michael Roth Signed-off-by: Michael Roth --- .gitignore | 1 + Makefile | 2 +- scripts/qemu-guest-agent/fsfreeze-hook | 33 +++++++++++ .../fsfreeze-hook.d/mysql-flush.sh.sample | 56 +++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100755 scripts/qemu-guest-agent/fsfreeze-hook create mode 100755 scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample diff --git a/.gitignore b/.gitignore index 0e3816918c..5fea65dc14 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ fsdev/virtfs-proxy-helper.pod *.tp *.vr *.d +!scripts/qemu-guest-agent/fsfreeze-hook.d *.o *.lo *.la diff --git a/Makefile b/Makefile index a7ac04b9ae..ee06448e28 100644 --- a/Makefile +++ b/Makefile @@ -232,7 +232,7 @@ clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f qemu-options.def - find . -name '*.[od]' -exec rm -f {} + + find . -name '*.[od]' -type f -exec rm -f {} + rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -Rf .libs rm -f qemu-img-cmds.h diff --git a/scripts/qemu-guest-agent/fsfreeze-hook b/scripts/qemu-guest-agent/fsfreeze-hook new file mode 100755 index 0000000000..c27b29f282 --- /dev/null +++ b/scripts/qemu-guest-agent/fsfreeze-hook @@ -0,0 +1,33 @@ +#!/bin/sh + +# This script is executed when a guest agent receives fsfreeze-freeze and +# fsfreeze-thaw command, if it is specified in --fsfreeze-hook (-F) +# option of qemu-ga or placed in default path (/etc/qemu/fsfreeze-hook). +# When the agent receives fsfreeze-freeze request, this script is issued with +# "freeze" argument before the filesystem is frozen. And for fsfreeze-thaw +# request, it is issued with "thaw" argument after filesystem is thawed. + +LOGFILE=/var/log/qga-fsfreeze-hook.log +FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d + +# Check whether file $1 is a backup or rpm-generated file and should be ignored +is_ignored_file() { + case "$1" in + *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave | *.sample) + return 0 ;; + esac + return 1 +} + +# Iterate executables in directory "fsfreeze-hook.d" with the specified args +[ ! -d "$FSFREEZE_D" ] && exit 0 +for file in "$FSFREEZE_D"/* ; do + is_ignored_file "$file" && continue + [ -x "$file" ] || continue + printf "$(date): execute $file $@\n" >>$LOGFILE + "$file" "$@" >>$LOGFILE 2>&1 + STATUS=$? + printf "$(date): $file finished with status=$STATUS\n" >>$LOGFILE +done + +exit 0 diff --git a/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample b/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample new file mode 100755 index 0000000000..2b4fa3aeb1 --- /dev/null +++ b/scripts/qemu-guest-agent/fsfreeze-hook.d/mysql-flush.sh.sample @@ -0,0 +1,56 @@ +#!/bin/sh + +# Flush MySQL tables to the disk before the filesystem is frozen. +# At the same time, this keeps a read lock in order to avoid write accesses +# from the other clients until the filesystem is thawed. + +MYSQL="/usr/bin/mysql" +MYSQL_OPTS="-uroot" #"-prootpassword" +FIFO=/var/run/mysql-flush.fifo + +# Check mysql is installed and the server running +[ -x "$MYSQL" ] && "$MYSQL" $MYSQL_OPTS < /dev/null || exit 0 + +flush_and_wait() { + printf "FLUSH TABLES WITH READ LOCK \\G\n" + trap 'printf "$(date): $0 is killed\n">&2' HUP INT QUIT ALRM TERM + read < $FIFO + printf "UNLOCK TABLES \\G\n" + rm -f $FIFO +} + +case "$1" in + freeze) + mkfifo $FIFO || exit 1 + flush_and_wait | "$MYSQL" $MYSQL_OPTS & + # wait until every block is flushed + while [ "$(echo 'SHOW STATUS LIKE "Key_blocks_not_flushed"' |\ + "$MYSQL" $MYSQL_OPTS | tail -1 | cut -f 2)" -gt 0 ]; do + sleep 1 + done + # for InnoDB, wait until every log is flushed + INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX) + [ $? -ne 0 ] && exit 2 + trap "rm -f $INNODB_STATUS; exit 1" HUP INT QUIT ALRM TERM + while :; do + printf "SHOW ENGINE INNODB STATUS \\G" |\ + "$MYSQL" $MYSQL_OPTS > $INNODB_STATUS + LOG_CURRENT=$(grep 'Log sequence number' $INNODB_STATUS |\ + tr -s ' ' | cut -d' ' -f4) + LOG_FLUSHED=$(grep 'Log flushed up to' $INNODB_STATUS |\ + tr -s ' ' | cut -d' ' -f5) + [ "$LOG_CURRENT" = "$LOG_FLUSHED" ] && break + sleep 1 + done + rm -f $INNODB_STATUS + ;; + + thaw) + [ ! -p $FIFO ] && exit 1 + echo > $FIFO + ;; + + *) + exit 1 + ;; +esac From 5c03a2542fbe1a275fe3dd7ebd48a6a283b249ed Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Dec 2012 10:19:38 +0100 Subject: [PATCH 0361/1634] pci: use constants for devices under the 1B36 device ID, document them Signed-off-by: Paolo Bonzini Signed-off-by: Michael S. Tsirkin --- docs/specs/pci-ids.txt | 15 +++++++++++++++ hw/pci/pci.h | 7 +++++++ hw/pci_bridge_dev.c | 8 ++------ hw/serial-pci.c | 12 ++++++------ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/docs/specs/pci-ids.txt b/docs/specs/pci-ids.txt index e76b196eb5..3c65e1a6ef 100644 --- a/docs/specs/pci-ids.txt +++ b/docs/specs/pci-ids.txt @@ -33,3 +33,18 @@ maintained as part of the virtio specification. 1af4:1110 ivshmem device (shared memory, docs/specs/ivshmem_device_spec.txt) All other device IDs are reserved. + +1b36 vendor ID +-------------- + +The 0000 -> 00ff device ID range is used as follows for QEMU-specific +PCI devices (other than virtio): + +1b36:0001 PCI-PCI bridge +1b36:0002 PCI serial port (16550A) adapter (docs/specs/pci-serial.txt) +1b36:0003 PCI Dual-port 16550A adapter (docs/specs/pci-serial.txt) +1b36:0004 PCI Quad-port 16550A adapter (docs/specs/pci-serial.txt) + +All these devices are documented in docs/specs. + +The 0100 device ID is used for the QXL video card device. diff --git a/hw/pci/pci.h b/hw/pci/pci.h index ed098ced6b..f340fe57c9 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -79,6 +79,13 @@ #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 +#define PCI_VENDOR_ID_REDHAT 0x1b36 +#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 +#define PCI_DEVICE_ID_REDHAT_SERIAL 0x0002 +#define PCI_DEVICE_ID_REDHAT_SERIAL2 0x0003 +#define PCI_DEVICE_ID_REDHAT_SERIAL4 0x0004 +#define PCI_DEVICE_ID_REDHAT_QXL 0x0100 + #define FMT_PCIBUS PRIx64 typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 7818dcc350..2dd312db35 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -27,10 +27,6 @@ #include "exec/memory.h" #include "pci/pci_bus.h" -#define REDHAT_PCI_VENDOR_ID 0x1b36 -#define PCI_BRIDGE_DEV_VENDOR_ID REDHAT_PCI_VENDOR_ID -#define PCI_BRIDGE_DEV_DEVICE_ID 0x1 - struct PCIBridgeDev { PCIBridge bridge; MemoryRegion bar; @@ -146,8 +142,8 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) k->init = pci_bridge_dev_initfn; k->exit = pci_bridge_dev_exitfn; k->config_write = pci_bridge_dev_write_config; - k->vendor_id = PCI_BRIDGE_DEV_VENDOR_ID; - k->device_id = PCI_BRIDGE_DEV_DEVICE_ID; + k->vendor_id = PCI_VENDOR_ID_REDHAT; + k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; k->class_id = PCI_CLASS_BRIDGE_PCI; k->is_bridge = 1, dc->desc = "Standard PCI Bridge"; diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 6a2548a515..50e8ab7faf 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -185,8 +185,8 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data) PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); pc->init = serial_pci_init; pc->exit = serial_pci_exit; - pc->vendor_id = 0x1b36; /* Red Hat */ - pc->device_id = 0x0002; + pc->vendor_id = PCI_VENDOR_ID_REDHAT; + pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL; pc->revision = 1; pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_serial; @@ -199,8 +199,8 @@ static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); pc->init = multi_serial_pci_init; pc->exit = multi_serial_pci_exit; - pc->vendor_id = 0x1b36; /* Red Hat */ - pc->device_id = 0x0003; + pc->vendor_id = PCI_VENDOR_ID_REDHAT; + pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2; pc->revision = 1; pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_multi_serial; @@ -213,8 +213,8 @@ static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); pc->init = multi_serial_pci_init; pc->exit = multi_serial_pci_exit; - pc->vendor_id = 0x1b36; /* Red Hat */ - pc->device_id = 0x0004; + pc->vendor_id = PCI_VENDOR_ID_REDHAT; + pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4; pc->revision = 1; pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_multi_serial; From feb9a2ab4b0260d8d680a7ffd25063dafc7ec628 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sun, 6 Jan 2013 21:30:31 -0700 Subject: [PATCH 0362/1634] pci-assign: Enable MSIX on device to match guest When a guest enables MSIX on a device we evaluate the MSIX vector table, typically find no unmasked vectors and don't switch the device to MSIX mode. This generally works fine and the device will be switched once the guest enables and therefore unmasks a vector. Unfortunately some drivers enable MSIX, then use interfaces to send commands between VF & PF or PF & firmware that act based on the host state of the device. These therefore may break when MSIX is managed lazily. This change re-enables the previous test used to enable MSIX (see qemu-kvm a6b402c9), which basically guesses whether a vector will be used based on the data field of the vector table. Cc: qemu-stable@nongnu.org Signed-off-by: Alex Williamson Acked-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/kvm/pci-assign.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c index 8ee94287ff..896cfe8a59 100644 --- a/hw/kvm/pci-assign.c +++ b/hw/kvm/pci-assign.c @@ -1031,6 +1031,19 @@ static bool assigned_dev_msix_masked(MSIXTableEntry *entry) return (entry->ctrl & cpu_to_le32(0x1)) != 0; } +/* + * When MSI-X is first enabled the vector table typically has all the + * vectors masked, so we can't use that as the obvious test to figure out + * how many vectors to initially enable. Instead we look at the data field + * because this is what worked for pci-assign for a long time. This makes + * sure the physical MSI-X state tracks the guest's view, which is important + * for some VF/PF and PF/fw communication channels. + */ +static bool assigned_dev_msix_skipped(MSIXTableEntry *entry) +{ + return !entry->data; +} + static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) { AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev); @@ -1041,7 +1054,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) /* Get the usable entry number for allocating */ for (i = 0; i < adev->msix_max; i++, entry++) { - if (assigned_dev_msix_masked(entry)) { + if (assigned_dev_msix_skipped(entry)) { continue; } entries_nr++; @@ -1070,7 +1083,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) for (i = 0; i < adev->msix_max; i++, entry++) { adev->msi_virq[i] = -1; - if (assigned_dev_msix_masked(entry)) { + if (assigned_dev_msix_skipped(entry)) { continue; } From 5e3bc735d93dd23f074b5116fd11e1ad8cd4962f Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Tue, 8 Jan 2013 16:30:56 +0100 Subject: [PATCH 0363/1634] Check return values from g_poll and select The current implementation of os_host_main_loop_wait() on Windows, returns 1 only when a g_poll() event occurs because the return value of select() is overridden. This is wrong as we may skip a socket event, as shown in this example: 1. select() returns 0 2. g_poll() returns 1 (socket event occurs) 3. os_host_main_loop_wait() returns 1 4. qemu_iohandler_poll() sees no socket event because select() has return before the event occurs 5. select() returns 1 6. g_poll() returns 0 (g_poll overrides select's return value) 7. os_host_main_loop_wait() returns 0 8. qemu_iohandler_poll() doesn't check for socket events because the return value of os_host_main_loop_wait() is zero. 9. goto 5 This patch use one variable for each of these return values, so we don't miss a select() event anymore. Also move the call to select() after g_poll(), this will improve latency as we don't have to go through two os_host_main_loop_wait() calls to detect a socket event. Reviewed-by: Paolo Bonzini Signed-off-by: Fabien Chouteau Signed-off-by: Anthony Liguori --- main-loop.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/main-loop.c b/main-loop.c index 54f38ae1ae..6f52ac39bc 100644 --- a/main-loop.c +++ b/main-loop.c @@ -330,7 +330,7 @@ void qemu_fd_register(int fd) static int os_host_main_loop_wait(uint32_t timeout) { GMainContext *context = g_main_context_default(); - int ret, i; + int select_ret, g_poll_ret, ret, i; PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; @@ -345,13 +345,6 @@ static int os_host_main_loop_wait(uint32_t timeout) return ret; } - if (nfds >= 0) { - ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); - if (ret != 0) { - timeout = 0; - } - } - g_main_context_prepare(context, &max_priority); n_poll_fds = g_main_context_query(context, max_priority, &poll_timeout, poll_fds, ARRAY_SIZE(poll_fds)); @@ -367,9 +360,9 @@ static int os_host_main_loop_wait(uint32_t timeout) } qemu_mutex_unlock_iothread(); - ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); + g_poll_ret = g_poll(poll_fds, n_poll_fds + w->num, poll_timeout); qemu_mutex_lock_iothread(); - if (ret > 0) { + if (g_poll_ret > 0) { for (i = 0; i < w->num; i++) { w->revents[i] = poll_fds[n_poll_fds + i].revents; } @@ -384,12 +377,18 @@ static int os_host_main_loop_wait(uint32_t timeout) g_main_context_dispatch(context); } - /* If an edge-triggered socket event occurred, select will return a - * positive result on the next iteration. We do not need to do anything - * here. + /* Call select after g_poll to avoid a useless iteration and therefore + * improve socket latency. */ - return ret; + if (nfds >= 0) { + select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); + if (select_ret != 0) { + timeout = 0; + } + } + + return select_ret || g_poll_ret; } #endif From 6ad53bdf5830bfc30221aee8d4ced9a9eaf8fe03 Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Sat, 22 Dec 2012 15:13:54 +0800 Subject: [PATCH 0364/1634] target-i386: fix bits 39:32 of the final physical address when using 4M page ((pde & 0x1fe000) << 19) is the bits 39:32 of the final physical address, and we shouldn't use unit32_t to calculate it. Convert the type to hwaddr to fix this problem. Signed-off-by: Wen Congyang Reviewed-by: Markus Armbruster Signed-off-by: Luiz Capitulino --- target-i386/arch_memory_mapping.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/target-i386/arch_memory_mapping.c b/target-i386/arch_memory_mapping.c index c6c7874474..844893f44d 100644 --- a/target-i386/arch_memory_mapping.c +++ b/target-i386/arch_memory_mapping.c @@ -115,7 +115,7 @@ static void walk_pde2(MemoryMappingList *list, hwaddr pde_start_addr, int32_t a20_mask, bool pse) { - hwaddr pde_addr, pte_start_addr, start_paddr; + hwaddr pde_addr, pte_start_addr, start_paddr, high_paddr; uint32_t pde; target_ulong line_addr, start_vaddr; int i; @@ -130,8 +130,13 @@ static void walk_pde2(MemoryMappingList *list, line_addr = (((unsigned int)i & 0x3ff) << 22); if ((pde & PG_PSE_MASK) && pse) { - /* 4 MB page */ - start_paddr = (pde & ~0x3fffff) | ((pde & 0x1fe000) << 19); + /* + * 4 MB page: + * bits 39:32 are bits 20:13 of the PDE + * bit3 31:22 are bits 31:22 of the PDE + */ + high_paddr = ((hwaddr)(pde & 0x1fe000) << 19); + start_paddr = (pde & ~0x3fffff) | high_paddr; if (cpu_physical_memory_is_io(start_paddr)) { /* I/O region */ continue; From 4e45deedf57c6cc7113b588282d0c16f89298aff Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 4 Jan 2013 10:37:50 +0100 Subject: [PATCH 0365/1634] rtc-test: skip year-2038 overflow check in case time_t is 32bit only Signed-off-by: Gerd Hoffmann --- tests/rtc-test.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/rtc-test.c b/tests/rtc-test.c index 02edbf5727..e7123cafbc 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -201,6 +201,10 @@ static void set_year_20xx(void) g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11); g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); + if (sizeof(time_t) == 4) { + return; + } + /* Set a date in 2080 to ensure there is no year-2038 overflow. */ cmos_write(RTC_REG_A, 0x76); cmos_write(RTC_YEAR, 0x80); From 067f0691277325dcce8401534d2ffc6164305021 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 4 Jan 2013 17:12:18 +0100 Subject: [PATCH 0366/1634] m48t59-test: don't touch watchdog Signed-off-by: Gerd Hoffmann --- tests/m48t59-test.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c index 5179681ca5..d79f55472d 100644 --- a/tests/m48t59-test.c +++ b/tests/m48t59-test.c @@ -233,6 +233,11 @@ static void fuzz_registers(void) reg = (uint8_t)g_test_rand_int_range(0, 16); val = (uint8_t)g_test_rand_int_range(0, 256); + if (reg == 7) { + /* watchdog setup register, may trigger system reset, skip */ + continue; + } + cmos_write(reg, val); cmos_read(reg); } From 517823449ebe8e3758b86c441cc74968b68e6491 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Jan 2013 14:10:22 +0100 Subject: [PATCH 0367/1634] monitor: assert monitor_puts()'s loop invariant Chiefly to hush up Coverity. Signed-off-by: Markus Armbruster Signed-off-by: Luiz Capitulino --- monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/monitor.c b/monitor.c index 9cf419bb1d..c6eac608a3 100644 --- a/monitor.c +++ b/monitor.c @@ -270,6 +270,7 @@ static void monitor_puts(Monitor *mon, const char *str) char c; for(;;) { + assert(mon->outbuf_index < sizeof(mon->outbuf) - 1); c = *str++; if (c == '\0') break; From 8c43a6f05d5ef3c9484bd2be9d4e818d58e62016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 10 Jan 2013 16:19:07 +0100 Subject: [PATCH 0368/1634] Make all static TypeInfos const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39bffca2030950ef6efe57c2fac8327a45ae1015 (qdev: register all types natively through QEMU Object Model), TypeInfo as used in the common, non-iterative pattern is no longer amended with information and should therefore be const. Fix the documented QOM examples: sed -i 's/static TypeInfo/static const TypeInfo/g' include/qom/object.h Since frequently the wrong examples are being copied by contributors of new devices, fix all types in the tree: sed -i 's/^static TypeInfo/static const TypeInfo/g' */*.c sed -i 's/^static TypeInfo/static const TypeInfo/g' */*/*.c This also avoids to piggy-back these changes onto real functional changes or other refactorings. Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- backends/rng-egd.c | 2 +- backends/rng-random.c | 2 +- backends/rng.c | 2 +- hw/9pfs/virtio-9p-device.c | 2 +- hw/a15mpcore.c | 2 +- hw/a9mpcore.c | 2 +- hw/ac97.c | 2 +- hw/acpi_piix4.c | 2 +- hw/ads7846.c | 2 +- hw/apb_pci.c | 6 +++--- hw/apic.c | 2 +- hw/apic_common.c | 2 +- hw/applesmc.c | 2 +- hw/arm11mpcore.c | 4 ++-- hw/arm_gic.c | 2 +- hw/arm_gic_common.c | 2 +- hw/arm_l2x0.c | 2 +- hw/arm_mptimer.c | 2 +- hw/arm_sysctl.c | 2 +- hw/arm_timer.c | 4 ++-- hw/armv7m.c | 2 +- hw/armv7m_nvic.c | 2 +- hw/bitbang_i2c.c | 2 +- hw/cadence_gem.c | 2 +- hw/cadence_ttc.c | 2 +- hw/cadence_uart.c | 2 +- hw/ccid-card-emulated.c | 2 +- hw/ccid-card-passthru.c | 2 +- hw/cirrus_vga.c | 4 ++-- hw/cs4231.c | 2 +- hw/cs4231a.c | 2 +- hw/debugcon.c | 2 +- hw/debugexit.c | 2 +- hw/ds1225y.c | 2 +- hw/ds1338.c | 2 +- hw/e1000.c | 2 +- hw/eccmemctl.c | 2 +- hw/empty_slot.c | 2 +- hw/es1370.c | 2 +- hw/escc.c | 2 +- hw/etraxfs_eth.c | 2 +- hw/etraxfs_pic.c | 2 +- hw/etraxfs_ser.c | 2 +- hw/etraxfs_timer.c | 2 +- hw/exynos4210_combiner.c | 2 +- hw/exynos4210_fimd.c | 2 +- hw/exynos4210_gic.c | 4 ++-- hw/exynos4210_mct.c | 2 +- hw/exynos4210_pmu.c | 2 +- hw/exynos4210_pwm.c | 2 +- hw/exynos4210_uart.c | 2 +- hw/fdc.c | 6 +++--- hw/fw_cfg.c | 2 +- hw/g364fb.c | 2 +- hw/grlib_apbuart.c | 2 +- hw/grlib_gptimer.c | 2 +- hw/grlib_irqmp.c | 2 +- hw/gus.c | 2 +- hw/hda-audio.c | 6 +++--- hw/highbank.c | 2 +- hw/hpet.c | 2 +- hw/i2c.c | 2 +- hw/i82374.c | 2 +- hw/i82378.c | 2 +- hw/i8254.c | 2 +- hw/i8254_common.c | 2 +- hw/i8259.c | 2 +- hw/i8259_common.c | 2 +- hw/ide/ahci.c | 2 +- hw/ide/cmd646.c | 2 +- hw/ide/ich.c | 2 +- hw/ide/isa.c | 2 +- hw/ide/piix.c | 6 +++--- hw/ide/qdev.c | 8 ++++---- hw/ide/via.c | 2 +- hw/imx_ccm.c | 2 +- hw/imx_serial.c | 2 +- hw/integratorcp.c | 4 ++-- hw/intel-hda.c | 4 ++-- hw/ioapic.c | 2 +- hw/ioapic_common.c | 2 +- hw/ioh3420.c | 2 +- hw/isa-bus.c | 4 ++-- hw/ivshmem.c | 2 +- hw/jazz_led.c | 2 +- hw/kvm/apic.c | 2 +- hw/kvm/clock.c | 2 +- hw/kvm/i8254.c | 2 +- hw/kvm/i8259.c | 2 +- hw/kvm/ioapic.c | 2 +- hw/kvmvapic.c | 2 +- hw/lan9118.c | 2 +- hw/lance.c | 2 +- hw/lm32_juart.c | 2 +- hw/lm32_pic.c | 2 +- hw/lm32_sys.c | 2 +- hw/lm32_timer.c | 2 +- hw/lm32_uart.c | 2 +- hw/lm832x.c | 2 +- hw/lsi53c895a.c | 2 +- hw/m48t59.c | 4 ++-- hw/macio.c | 2 +- hw/marvell_88w8618_audio.c | 2 +- hw/max111x.c | 4 ++-- hw/max7310.c | 2 +- hw/mc146818rtc.c | 2 +- hw/milkymist-ac97.c | 2 +- hw/milkymist-hpdmc.c | 2 +- hw/milkymist-memcard.c | 2 +- hw/milkymist-minimac2.c | 2 +- hw/milkymist-pfpu.c | 2 +- hw/milkymist-softusb.c | 2 +- hw/milkymist-sysctl.c | 2 +- hw/milkymist-tmu2.c | 2 +- hw/milkymist-uart.c | 2 +- hw/milkymist-vgafb.c | 2 +- hw/mips_malta.c | 2 +- hw/mipsnet.c | 2 +- hw/mpc8544_guts.c | 2 +- hw/mst_fpga.c | 2 +- hw/musicpal.c | 16 ++++++++-------- hw/nand.c | 2 +- hw/ne2000-isa.c | 2 +- hw/ne2000.c | 2 +- hw/omap_gpio.c | 4 ++-- hw/omap_i2c.c | 2 +- hw/omap_intc.c | 4 ++-- hw/onenand.c | 2 +- hw/opencores_eth.c | 2 +- hw/openpic.c | 2 +- hw/parallel.c | 2 +- hw/pc-testdev.c | 2 +- hw/pc.c | 2 +- hw/pc_sysfw.c | 2 +- hw/pci/pci.c | 2 +- hw/pci_bridge_dev.c | 2 +- hw/pckbd.c | 2 +- hw/pcnet-pci.c | 2 +- hw/pcspk.c | 2 +- hw/piix4.c | 2 +- hw/pl011.c | 4 ++-- hw/pl022.c | 2 +- hw/pl031.c | 2 +- hw/pl041.c | 2 +- hw/pl050.c | 4 ++-- hw/pl061.c | 4 ++-- hw/pl080.c | 4 ++-- hw/pl110.c | 6 +++--- hw/pl181.c | 2 +- hw/pl190.c | 2 +- hw/ppce500_spin.c | 2 +- hw/pxa2xx.c | 8 ++++---- hw/pxa2xx_dma.c | 2 +- hw/pxa2xx_gpio.c | 2 +- hw/pxa2xx_pic.c | 2 +- hw/pxa2xx_timer.c | 4 ++-- hw/qdev.c | 2 +- hw/qxl.c | 4 ++-- hw/realview_gic.c | 2 +- hw/rtl8139.c | 2 +- hw/s390-virtio-bus.c | 14 +++++++------- hw/s390x/event-facility.c | 4 ++-- hw/s390x/sclp.c | 2 +- hw/s390x/sclpconsole.c | 2 +- hw/s390x/sclpquiesce.c | 2 +- hw/sb16.c | 2 +- hw/sbi.c | 2 +- hw/scsi-bus.c | 2 +- hw/scsi-disk.c | 8 ++++---- hw/scsi-generic.c | 2 +- hw/serial-isa.c | 2 +- hw/serial-pci.c | 6 +++--- hw/sga.c | 2 +- hw/sh_pci.c | 4 ++-- hw/slavio_intctl.c | 2 +- hw/slavio_misc.c | 4 ++-- hw/slavio_timer.c | 2 +- hw/smbus.c | 2 +- hw/smbus_eeprom.c | 2 +- hw/smc91c111.c | 2 +- hw/spapr_llan.c | 2 +- hw/spapr_vio.c | 4 ++-- hw/spapr_vscsi.c | 2 +- hw/spapr_vty.c | 2 +- hw/sparc32_dma.c | 2 +- hw/spitz.c | 8 ++++---- hw/ssd0303.c | 2 +- hw/ssd0323.c | 2 +- hw/ssi-sd.c | 2 +- hw/ssi.c | 2 +- hw/stellaris.c | 6 +++--- hw/stellaris_enet.c | 2 +- hw/stream.c | 2 +- hw/strongarm.c | 12 ++++++------ hw/sun4c_intctl.c | 2 +- hw/sun4m.c | 8 ++++---- hw/sun4m_iommu.c | 2 +- hw/sun4u.c | 6 +++--- hw/sysbus.c | 2 +- hw/tcx.c | 2 +- hw/tmp105.c | 2 +- hw/tosa.c | 4 ++-- hw/tusb6010.c | 2 +- hw/twl92230.c | 2 +- hw/usb/bus.c | 2 +- hw/usb/dev-audio.c | 2 +- hw/usb/dev-bluetooth.c | 2 +- hw/usb/dev-hid.c | 6 +++--- hw/usb/dev-hub.c | 2 +- hw/usb/dev-network.c | 2 +- hw/usb/dev-serial.c | 4 ++-- hw/usb/dev-smartcard-reader.c | 4 ++-- hw/usb/dev-storage.c | 2 +- hw/usb/dev-uas.c | 2 +- hw/usb/dev-wacom.c | 2 +- hw/usb/hcd-ohci.c | 4 ++-- hw/usb/hcd-xhci.c | 2 +- hw/usb/host-bsd.c | 2 +- hw/usb/host-linux.c | 2 +- hw/usb/redirect.c | 2 +- hw/versatile_pci.c | 6 +++--- hw/versatilepb.c | 2 +- hw/vga-isa.c | 2 +- hw/vga-pci.c | 2 +- hw/virtio-console.c | 4 ++-- hw/virtio-pci.c | 12 ++++++------ hw/virtio-serial-bus.c | 2 +- hw/vmmouse.c | 2 +- hw/vmport.c | 2 +- hw/vmware_vga.c | 2 +- hw/vt82c686.c | 8 ++++---- hw/wdt_i6300esb.c | 2 +- hw/wdt_ib700.c | 2 +- hw/wm8750.c | 2 +- hw/xen_apic.c | 2 +- hw/xen_platform.c | 2 +- hw/xen_pt.c | 2 +- hw/xgmac.c | 2 +- hw/xilinx_axidma.c | 2 +- hw/xilinx_axienet.c | 2 +- hw/xilinx_ethlite.c | 2 +- hw/xilinx_intc.c | 2 +- hw/xilinx_spi.c | 2 +- hw/xilinx_timer.c | 2 +- hw/xilinx_uartlite.c | 2 +- hw/xio3130_downstream.c | 2 +- hw/xio3130_upstream.c | 2 +- hw/z2.c | 4 ++-- hw/zaurus.c | 2 +- hw/zynq_slcr.c | 2 +- include/qom/object.h | 6 +++--- qom/container.c | 2 +- 252 files changed, 342 insertions(+), 342 deletions(-) diff --git a/backends/rng-egd.c b/backends/rng-egd.c index fd41b53188..5e012e9e30 100644 --- a/backends/rng-egd.c +++ b/backends/rng-egd.c @@ -207,7 +207,7 @@ static void rng_egd_class_init(ObjectClass *klass, void *data) rbc->opened = rng_egd_opened; } -static TypeInfo rng_egd_info = { +static const TypeInfo rng_egd_info = { .name = TYPE_RNG_EGD, .parent = TYPE_RNG_BACKEND, .instance_size = sizeof(RngEgd), diff --git a/backends/rng-random.c b/backends/rng-random.c index d479ce8c56..0d1108811d 100644 --- a/backends/rng-random.c +++ b/backends/rng-random.c @@ -144,7 +144,7 @@ static void rng_random_class_init(ObjectClass *klass, void *data) rbc->opened = rng_random_opened; } -static TypeInfo rng_random_info = { +static const TypeInfo rng_random_info = { .name = TYPE_RNG_RANDOM, .parent = TYPE_RNG_BACKEND, .instance_size = sizeof(RndRandom), diff --git a/backends/rng.c b/backends/rng.c index 48a5840cd5..3d3389802e 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -76,7 +76,7 @@ static void rng_backend_init(Object *obj) NULL); } -static TypeInfo rng_backend_info = { +static const TypeInfo rng_backend_info = { .name = TYPE_RNG_BACKEND, .parent = TYPE_OBJECT, .instance_size = sizeof(RngBackend), diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 6761bce9dc..2a7c2a3d62 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -177,7 +177,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) dc->reset = virtio_pci_reset; } -static TypeInfo virtio_9p_info = { +static const TypeInfo virtio_9p_info = { .name = "virtio-9p-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index fc0a02ae86..30983efc03 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -93,7 +93,7 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data) /* We currently have no savable state */ } -static TypeInfo a15mp_priv_info = { +static const TypeInfo a15mp_priv_info = { .name = "a15mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(A15MPPrivState), diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index f802de0824..184734f9b1 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -226,7 +226,7 @@ static void a9mp_priv_class_init(ObjectClass *klass, void *data) dc->reset = a9mp_priv_reset; } -static TypeInfo a9mp_priv_info = { +static const TypeInfo a9mp_priv_info = { .name = "a9mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(a9mp_priv_state), diff --git a/hw/ac97.c b/hw/ac97.c index 5cd19c1d02..6c565e755c 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -1423,7 +1423,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) dc->props = ac97_properties; } -static TypeInfo ac97_info = { +static const TypeInfo ac97_info = { .name = "AC97", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (AC97LinkState), diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 06a8aca9cb..2f84b4ed4c 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -487,7 +487,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) dc->props = piix4_pm_properties; } -static TypeInfo piix4_pm_info = { +static const TypeInfo piix4_pm_info = { .name = "PIIX4_PM", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX4PMState), diff --git a/hw/ads7846.c b/hw/ads7846.c index fa137e628e..29e5585d91 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -162,7 +162,7 @@ static void ads7846_class_init(ObjectClass *klass, void *data) k->transfer = ads7846_transfer; } -static TypeInfo ads7846_info = { +static const TypeInfo ads7846_info = { .name = "ads7846", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ADS7846State), diff --git a/hw/apb_pci.c b/hw/apb_pci.c index c22e2b0fc3..b9a7ee6a31 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -486,7 +486,7 @@ static void pbm_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_HOST; } -static TypeInfo pbm_pci_host_info = { +static const TypeInfo pbm_pci_host_info = { .name = "pbm-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -502,7 +502,7 @@ static void pbm_host_class_init(ObjectClass *klass, void *data) dc->reset = pci_pbm_reset; } -static TypeInfo pbm_host_info = { +static const TypeInfo pbm_host_info = { .name = "pbm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(APBState), @@ -525,7 +525,7 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pci_device; } -static TypeInfo pbm_pci_bridge_info = { +static const TypeInfo pbm_pci_bridge_info = { .name = "pbm-bridge", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridge), diff --git a/hw/apic.c b/hw/apic.c index 81b82f694c..fd14b73023 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -895,7 +895,7 @@ static void apic_class_init(ObjectClass *klass, void *data) k->post_load = apic_post_load; } -static TypeInfo apic_info = { +static const TypeInfo apic_info = { .name = "apic", .instance_size = sizeof(APICCommonState), .parent = TYPE_APIC_COMMON, diff --git a/hw/apic_common.c b/hw/apic_common.c index 0658be93c1..6e1b1e0320 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -385,7 +385,7 @@ static void apic_common_class_init(ObjectClass *klass, void *data) sc->init = apic_init_common; } -static TypeInfo apic_common_type = { +static const TypeInfo apic_common_type = { .name = TYPE_APIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(APICCommonState), diff --git a/hw/applesmc.c b/hw/applesmc.c index c564b60c0a..5a8c4ff2d2 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -236,7 +236,7 @@ static void qdev_applesmc_class_init(ObjectClass *klass, void *data) dc->props = applesmc_isa_properties; } -static TypeInfo applesmc_isa_info = { +static const TypeInfo applesmc_isa_info = { .name = "isa-applesmc", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(struct AppleSMCStatus), diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index 093331124a..469f6bfdee 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -222,7 +222,7 @@ static void mpcore_rirq_class_init(ObjectClass *klass, void *data) dc->props = mpcore_rirq_properties; } -static TypeInfo mpcore_rirq_info = { +static const TypeInfo mpcore_rirq_info = { .name = "realview_mpcore", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mpcore_rirq_state), @@ -252,7 +252,7 @@ static void mpcore_priv_class_init(ObjectClass *klass, void *data) dc->props = mpcore_priv_properties; } -static TypeInfo mpcore_priv_info = { +static const TypeInfo mpcore_priv_info = { .name = "arm11mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mpcore_priv_state), diff --git a/hw/arm_gic.c b/hw/arm_gic.c index b6062c4241..466dbf7398 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -703,7 +703,7 @@ static void arm_gic_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo arm_gic_info = { +static const TypeInfo arm_gic_info = { .name = TYPE_ARM_GIC, .parent = TYPE_ARM_GIC_COMMON, .instance_size = sizeof(GICState), diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 73ae331807..41799ad765 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -171,7 +171,7 @@ static void arm_gic_common_class_init(ObjectClass *klass, void *data) sc->init = arm_gic_common_init; } -static TypeInfo arm_gic_common_type = { +static const TypeInfo arm_gic_common_type = { .name = TYPE_ARM_GIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GICState), diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c index 6abf0ee160..ae1e51d009 100644 --- a/hw/arm_l2x0.c +++ b/hw/arm_l2x0.c @@ -179,7 +179,7 @@ static void l2x0_class_init(ObjectClass *klass, void *data) dc->reset = l2x0_priv_reset; } -static TypeInfo l2x0_info = { +static const TypeInfo l2x0_info = { .name = "l2x0", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(l2x0_state), diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 1febaeb7b1..0cd3853a36 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -329,7 +329,7 @@ static void arm_mptimer_class_init(ObjectClass *klass, void *data) dc->props = arm_mptimer_properties; } -static TypeInfo arm_mptimer_info = { +static const TypeInfo arm_mptimer_info = { .name = "arm_mptimer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_mptimer_state), diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index b733617aa0..a196fcc4aa 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -410,7 +410,7 @@ static void arm_sysctl_class_init(ObjectClass *klass, void *data) dc->props = arm_sysctl_properties; } -static TypeInfo arm_sysctl_info = { +static const TypeInfo arm_sysctl_info = { .name = "realview_sysctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_sysctl_state), diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 37e28e993c..c1e56be74e 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -361,7 +361,7 @@ static void icp_pit_class_init(ObjectClass *klass, void *data) sdc->init = icp_pit_init; } -static TypeInfo icp_pit_info = { +static const TypeInfo icp_pit_info = { .name = "integrator_pit", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pit_state), @@ -383,7 +383,7 @@ static void sp804_class_init(ObjectClass *klass, void *data) k->props = sp804_properties; } -static TypeInfo sp804_info = { +static const TypeInfo sp804_info = { .name = "sp804", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(sp804_state), diff --git a/hw/armv7m.c b/hw/armv7m.c index ce2ec9b4dc..98fe483c25 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -269,7 +269,7 @@ static void bitband_class_init(ObjectClass *klass, void *data) dc->props = bitband_properties; } -static TypeInfo bitband_info = { +static const TypeInfo bitband_info = { .name = "ARM,bitband-memory", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BitBandState), diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 0907e42c0c..d5798d0309 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -535,7 +535,7 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data) dc->reset = armv7m_nvic_reset; } -static TypeInfo armv7m_nvic_info = { +static const TypeInfo armv7m_nvic_info = { .name = TYPE_NVIC, .parent = TYPE_ARM_GIC_COMMON, .instance_init = armv7m_nvic_instance_init, diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c index 44ed7f4d61..114508fade 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -230,7 +230,7 @@ static void gpio_i2c_class_init(ObjectClass *klass, void *data) dc->desc = "Virtual GPIO to I2C bridge"; } -static TypeInfo gpio_i2c_info = { +static const TypeInfo gpio_i2c_info = { .name = "gpio_i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GPIOI2CState), diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 40a239973c..2beee6268e 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -1218,7 +1218,7 @@ static void gem_class_init(ObjectClass *klass, void *data) dc->reset = gem_reset; } -static TypeInfo gem_info = { +static const TypeInfo gem_info = { .class_init = gem_class_init, .name = "cadence_gem", .parent = TYPE_SYS_BUS_DEVICE, diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index 9e1cb1f152..2a8fadd810 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -474,7 +474,7 @@ static void cadence_ttc_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_cadence_ttc; } -static TypeInfo cadence_ttc_info = { +static const TypeInfo cadence_ttc_info = { .name = "cadence_ttc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CadenceTTCState), diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c index 7dd2fe54ed..cf2f53c81c 100644 --- a/hw/cadence_uart.c +++ b/hw/cadence_uart.c @@ -501,7 +501,7 @@ static void cadence_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_cadence_uart; } -static TypeInfo cadence_uart_info = { +static const TypeInfo cadence_uart_info = { .name = "cadence_uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(UartState), diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c index 6fd44695ae..c8f8ba3792 100644 --- a/hw/ccid-card-emulated.c +++ b/hw/ccid-card-emulated.c @@ -587,7 +587,7 @@ static void emulated_class_initfn(ObjectClass *klass, void *data) dc->props = emulated_card_properties; } -static TypeInfo emulated_card_info = { +static const TypeInfo emulated_card_info = { .name = EMULATED_DEV_NAME, .parent = TYPE_CCID_CARD, .instance_size = sizeof(EmulatedState), diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c index 4be05471a9..984bd0bf4c 100644 --- a/hw/ccid-card-passthru.c +++ b/hw/ccid-card-passthru.c @@ -336,7 +336,7 @@ static void passthru_class_initfn(ObjectClass *klass, void *data) dc->props = passthru_card_properties; } -static TypeInfo passthru_card_info = { +static const TypeInfo passthru_card_info = { .name = PASSTHRU_DEV_NAME, .parent = TYPE_CCID_CARD, .instance_size = sizeof(PassthruState), diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 80510bc9af..2a2c8dad62 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -2933,7 +2933,7 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) dc->props = isa_vga_cirrus_properties; } -static TypeInfo isa_cirrus_vga_info = { +static const TypeInfo isa_cirrus_vga_info = { .name = "isa-cirrus-vga", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISACirrusVGAState), @@ -3003,7 +3003,7 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data) dc->props = pci_vga_cirrus_properties; } -static TypeInfo cirrus_vga_info = { +static const TypeInfo cirrus_vga_info = { .name = "cirrus-vga", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCICirrusVGAState), diff --git a/hw/cs4231.c b/hw/cs4231.c index 23570d5b41..ae384b90fd 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -166,7 +166,7 @@ static void cs4231_class_init(ObjectClass *klass, void *data) dc->props = cs4231_properties; } -static TypeInfo cs4231_info = { +static const TypeInfo cs4231_info = { .name = "SUNW,CS4231", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CSState), diff --git a/hw/cs4231a.c b/hw/cs4231a.c index 9d528c43b0..73f08594bf 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -682,7 +682,7 @@ static void cs4231a_class_initfn (ObjectClass *klass, void *data) dc->props = cs4231a_properties; } -static TypeInfo cs4231a_info = { +static const TypeInfo cs4231a_info = { .name = "cs4231a", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof (CSState), diff --git a/hw/debugcon.c b/hw/debugcon.c index e8a855e33a..81b2bb00fd 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -119,7 +119,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) dc->props = debugcon_isa_properties; } -static TypeInfo debugcon_isa_info = { +static const TypeInfo debugcon_isa_info = { .name = TYPE_ISA_DEBUGCON_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISADebugconState), diff --git a/hw/debugexit.c b/hw/debugexit.c index 90642eb37f..c1b489ddcb 100644 --- a/hw/debugexit.c +++ b/hw/debugexit.c @@ -60,7 +60,7 @@ static void debug_exit_class_initfn(ObjectClass *klass, void *data) dc->props = debug_exit_properties; } -static TypeInfo debug_exit_info = { +static const TypeInfo debug_exit_info = { .name = TYPE_ISA_DEBUG_EXIT_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISADebugExitState), diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 4b3f69bc67..a6219a7908 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -150,7 +150,7 @@ static void nvram_sysbus_class_init(ObjectClass *klass, void *data) dc->props = nvram_sysbus_properties; } -static TypeInfo nvram_sysbus_info = { +static const TypeInfo nvram_sysbus_info = { .name = "ds1225y", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusNvRamState), diff --git a/hw/ds1338.c b/hw/ds1338.c index 1aefa3ba04..379220638e 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -221,7 +221,7 @@ static void ds1338_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ds1338; } -static TypeInfo ds1338_info = { +static const TypeInfo ds1338_info = { .name = "ds1338", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(DS1338State), diff --git a/hw/e1000.c b/hw/e1000.c index 0f177ff844..ef06ca1894 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1327,7 +1327,7 @@ static void e1000_class_init(ObjectClass *klass, void *data) dc->props = e1000_properties; } -static TypeInfo e1000_info = { +static const TypeInfo e1000_info = { .name = "e1000", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(E1000State), diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index 000bd08dee..dbac2c2bbc 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -324,7 +324,7 @@ static void ecc_class_init(ObjectClass *klass, void *data) dc->props = ecc_properties; } -static TypeInfo ecc_info = { +static const TypeInfo ecc_info = { .name = "eccmemctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ECCState), diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 23978eb149..3cb6ccb27d 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -83,7 +83,7 @@ static void empty_slot_class_init(ObjectClass *klass, void *data) k->init = empty_slot_init1; } -static TypeInfo empty_slot_info = { +static const TypeInfo empty_slot_info = { .name = "empty_slot", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(EmptySlot), diff --git a/hw/es1370.c b/hw/es1370.c index 59c3f2329e..977d2e3767 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -1073,7 +1073,7 @@ static void es1370_class_init (ObjectClass *klass, void *data) dc->vmsd = &vmstate_es1370; } -static TypeInfo es1370_info = { +static const TypeInfo es1370_info = { .name = "ES1370", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (ES1370State), diff --git a/hw/escc.c b/hw/escc.c index f09904aae4..c81088b22f 100644 --- a/hw/escc.c +++ b/hw/escc.c @@ -923,7 +923,7 @@ static void escc_class_init(ObjectClass *klass, void *data) dc->props = escc_properties; } -static TypeInfo escc_info = { +static const TypeInfo escc_info = { .name = "escc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SerialState), diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 289a810edc..ec23fa6edf 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -630,7 +630,7 @@ static void etraxfs_eth_class_init(ObjectClass *klass, void *data) dc->props = etraxfs_eth_properties; } -static TypeInfo etraxfs_eth_info = { +static const TypeInfo etraxfs_eth_info = { .name = "etraxfs-eth", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct fs_eth), diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index 62a62a36af..64af31c46e 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -165,7 +165,7 @@ static void etraxfs_pic_class_init(ObjectClass *klass, void *data) dc->props = etraxfs_pic_properties; } -static TypeInfo etraxfs_pic_info = { +static const TypeInfo etraxfs_pic_info = { .name = "etraxfs,pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct etrax_pic), diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 7bde8004d0..72c8868639 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -233,7 +233,7 @@ static void etraxfs_ser_class_init(ObjectClass *klass, void *data) dc->reset = etraxfs_ser_reset; } -static TypeInfo etraxfs_ser_info = { +static const TypeInfo etraxfs_ser_info = { .name = "etraxfs,serial", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct etrax_serial), diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index e9273cd95d..d3dac52315 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -336,7 +336,7 @@ static void etraxfs_timer_class_init(ObjectClass *klass, void *data) sdc->init = etraxfs_timer_init; } -static TypeInfo etraxfs_timer_info = { +static const TypeInfo etraxfs_timer_info = { .name = "etraxfs,timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof (struct etrax_timer), diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index 84d36ed11f..ba644b43c2 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -440,7 +440,7 @@ static void exynos4210_combiner_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_combiner; } -static TypeInfo exynos4210_combiner_info = { +static const TypeInfo exynos4210_combiner_info = { .name = "exynos4210.combiner", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210CombinerState), diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c index 5c29b5d01d..3d498b77f8 100644 --- a/hw/exynos4210_fimd.c +++ b/hw/exynos4210_fimd.c @@ -1913,7 +1913,7 @@ static void exynos4210_fimd_class_init(ObjectClass *klass, void *data) k->init = exynos4210_fimd_init; } -static TypeInfo exynos4210_fimd_info = { +static const TypeInfo exynos4210_fimd_info = { .name = "exynos4210.fimd", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210fimdState), diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 959de5679d..f67906e42f 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -346,7 +346,7 @@ static void exynos4210_gic_class_init(ObjectClass *klass, void *data) dc->props = exynos4210_gic_properties; } -static TypeInfo exynos4210_gic_info = { +static const TypeInfo exynos4210_gic_info = { .name = "exynos4210.gic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210GicState), @@ -447,7 +447,7 @@ static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) dc->props = exynos4210_irq_gate_properties; } -static TypeInfo exynos4210_irq_gate_info = { +static const TypeInfo exynos4210_irq_gate_info = { .name = "exynos4210.irq_gate", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210IRQGateState), diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c index 41cd142227..d7d5904cc0 100644 --- a/hw/exynos4210_mct.c +++ b/hw/exynos4210_mct.c @@ -1467,7 +1467,7 @@ static void exynos4210_mct_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_mct_state; } -static TypeInfo exynos4210_mct_info = { +static const TypeInfo exynos4210_mct_info = { .name = "exynos4210.mct", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210MCTState), diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c index a22b8f181a..7c81a1b628 100644 --- a/hw/exynos4210_pmu.c +++ b/hw/exynos4210_pmu.c @@ -484,7 +484,7 @@ static void exynos4210_pmu_class_init(ObjectClass *klass, void *data) dc->vmsd = &exynos4210_pmu_vmstate; } -static TypeInfo exynos4210_pmu_info = { +static const TypeInfo exynos4210_pmu_info = { .name = "exynos4210.pmu", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PmuState), diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c index 3a3eb8c27a..c8656248a8 100644 --- a/hw/exynos4210_pwm.c +++ b/hw/exynos4210_pwm.c @@ -407,7 +407,7 @@ static void exynos4210_pwm_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_pwm_state; } -static TypeInfo exynos4210_pwm_info = { +static const TypeInfo exynos4210_pwm_info = { .name = "exynos4210.pwm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PWMState), diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index 4f23079095..adaab242fe 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -661,7 +661,7 @@ static void exynos4210_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_exynos4210_uart; } -static TypeInfo exynos4210_uart_info = { +static const TypeInfo exynos4210_uart_info = { .name = "exynos4210.uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210UartState), diff --git a/hw/fdc.c b/hw/fdc.c index ddc0cc3819..976a587c42 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -2210,7 +2210,7 @@ static void isabus_fdc_class_init1(ObjectClass *klass, void *data) dc->props = isa_fdc_properties; } -static TypeInfo isa_fdc_info = { +static const TypeInfo isa_fdc_info = { .name = "isa-fdc", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(FDCtrlISABus), @@ -2244,7 +2244,7 @@ static void sysbus_fdc_class_init(ObjectClass *klass, void *data) dc->props = sysbus_fdc_properties; } -static TypeInfo sysbus_fdc_info = { +static const TypeInfo sysbus_fdc_info = { .name = "sysbus-fdc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FDCtrlSysBus), @@ -2267,7 +2267,7 @@ static void sun4m_fdc_class_init(ObjectClass *klass, void *data) dc->props = sun4m_fdc_properties; } -static TypeInfo sun4m_fdc_info = { +static const TypeInfo sun4m_fdc_info = { .name = "SUNW,fdtwo", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FDCtrlSysBus), diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 26f7125fe2..7c9480c4d7 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -575,7 +575,7 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data) dc->props = fw_cfg_properties; } -static TypeInfo fw_cfg_info = { +static const TypeInfo fw_cfg_info = { .name = "fw_cfg", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(FWCfgState), diff --git a/hw/g364fb.c b/hw/g364fb.c index b46a044607..0c0c8ba302 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -597,7 +597,7 @@ static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) dc->props = g364fb_sysbus_properties; } -static TypeInfo g364fb_sysbus_info = { +static const TypeInfo g364fb_sysbus_info = { .name = "sysbus-g364", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(G364SysBusState), diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index 88c46780d1..760bed0b72 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -256,7 +256,7 @@ static void grlib_gptimer_class_init(ObjectClass *klass, void *data) dc->props = grlib_gptimer_properties; } -static TypeInfo grlib_gptimer_info = { +static const TypeInfo grlib_gptimer_info = { .name = "grlib,apbuart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(UART), diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 252ba893e3..7962b74f2c 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -389,7 +389,7 @@ static void grlib_gptimer_class_init(ObjectClass *klass, void *data) dc->props = grlib_gptimer_properties; } -static TypeInfo grlib_gptimer_info = { +static const TypeInfo grlib_gptimer_info = { .name = "grlib,gptimer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GPTimerUnit), diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index 23a6a02bc5..b5427c8039 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -370,7 +370,7 @@ static void grlib_irqmp_class_init(ObjectClass *klass, void *data) dc->props = grlib_irqmp_properties; } -static TypeInfo grlib_irqmp_info = { +static const TypeInfo grlib_irqmp_info = { .name = "grlib,irqmp", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IRQMP), diff --git a/hw/gus.c b/hw/gus.c index 840d098d6a..aa13fccf0d 100644 --- a/hw/gus.c +++ b/hw/gus.c @@ -317,7 +317,7 @@ static void gus_class_initfn (ObjectClass *klass, void *data) dc->props = gus_properties; } -static TypeInfo gus_info = { +static const TypeInfo gus_info = { .name = "gus", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof (GUSState), diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 92a91b5ab1..3190bd1cf8 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -1039,7 +1039,7 @@ static void hda_audio_output_class_init(ObjectClass *klass, void *data) dc->props = hda_audio_properties; } -static TypeInfo hda_audio_output_info = { +static const TypeInfo hda_audio_output_info = { .name = "hda-output", .parent = TYPE_HDA_CODEC_DEVICE, .instance_size = sizeof(HDAAudioState), @@ -1060,7 +1060,7 @@ static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) dc->props = hda_audio_properties; } -static TypeInfo hda_audio_duplex_info = { +static const TypeInfo hda_audio_duplex_info = { .name = "hda-duplex", .parent = TYPE_HDA_CODEC_DEVICE, .instance_size = sizeof(HDAAudioState), @@ -1081,7 +1081,7 @@ static void hda_audio_micro_class_init(ObjectClass *klass, void *data) dc->props = hda_audio_properties; } -static TypeInfo hda_audio_micro_info = { +static const TypeInfo hda_audio_micro_info = { .name = "hda-micro", .parent = TYPE_HDA_CODEC_DEVICE, .instance_size = sizeof(HDAAudioState), diff --git a/hw/highbank.c b/hw/highbank.c index 6005622f3a..98deca8bce 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -168,7 +168,7 @@ static void highbank_regs_class_init(ObjectClass *klass, void *data) dc->reset = highbank_regs_reset; } -static TypeInfo highbank_regs_info = { +static const TypeInfo highbank_regs_info = { .name = "highbank-regs", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(HighbankRegsState), diff --git a/hw/hpet.c b/hw/hpet.c index 78c0662dfc..6efae55eee 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -745,7 +745,7 @@ static void hpet_device_class_init(ObjectClass *klass, void *data) dc->props = hpet_device_properties; } -static TypeInfo hpet_device_info = { +static const TypeInfo hpet_device_info = { .name = "hpet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(HPETState), diff --git a/hw/i2c.c b/hw/i2c.c index 296bece119..119e96bc0e 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -228,7 +228,7 @@ static void i2c_slave_class_init(ObjectClass *klass, void *data) k->props = i2c_props; } -static TypeInfo i2c_slave_type_info = { +static const TypeInfo i2c_slave_type_info = { .name = TYPE_I2C_SLAVE, .parent = TYPE_DEVICE, .instance_size = sizeof(I2CSlave), diff --git a/hw/i82374.c b/hw/i82374.c index 4a922c3f4e..6a62ba2ab8 100644 --- a/hw/i82374.c +++ b/hw/i82374.c @@ -153,7 +153,7 @@ static void i82374_class_init(ObjectClass *klass, void *data) dc->props = i82374_properties; } -static TypeInfo i82374_isa_info = { +static const TypeInfo i82374_isa_info = { .name = "i82374", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAi82374State), diff --git a/hw/i82378.c b/hw/i82378.c index c6b0b5ec55..0914d7bbfb 100644 --- a/hw/i82378.c +++ b/hw/i82378.c @@ -262,7 +262,7 @@ static void pci_i82378_class_init(ObjectClass *klass, void *data) dc->props = i82378_properties; } -static TypeInfo pci_i82378_info = { +static const TypeInfo pci_i82378_info = { .name = "i82378", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIi82378State), diff --git a/hw/i8254.c b/hw/i8254.c index 7c2aa6238d..394b2e81d7 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -347,7 +347,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data) dc->props = pit_properties; } -static TypeInfo pit_info = { +static const TypeInfo pit_info = { .name = "isa-pit", .parent = TYPE_PIT_COMMON, .instance_size = sizeof(PITCommonState), diff --git a/hw/i8254_common.c b/hw/i8254_common.c index 08ab8d14bd..8c2e45a92e 100644 --- a/hw/i8254_common.c +++ b/hw/i8254_common.c @@ -294,7 +294,7 @@ static void pit_common_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo pit_common_type = { +static const TypeInfo pit_common_type = { .name = TYPE_PIT_COMMON, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PITCommonState), diff --git a/hw/i8259.c b/hw/i8259.c index 8fc6339250..264879e097 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -481,7 +481,7 @@ static void i8259_class_init(ObjectClass *klass, void *data) dc->reset = pic_reset; } -static TypeInfo i8259_info = { +static const TypeInfo i8259_info = { .name = "isa-i8259", .instance_size = sizeof(PICCommonState), .parent = TYPE_PIC_COMMON, diff --git a/hw/i8259_common.c b/hw/i8259_common.c index ab3d98b2a1..fc91056afb 100644 --- a/hw/i8259_common.c +++ b/hw/i8259_common.c @@ -144,7 +144,7 @@ static void pic_common_class_init(ObjectClass *klass, void *data) ic->init = pic_init_common; } -static TypeInfo pic_common_type = { +static const TypeInfo pic_common_type = { .name = TYPE_PIC_COMMON, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PICCommonState), diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index d0724499c7..21f50ea5be 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1247,7 +1247,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data) dc->reset = sysbus_ahci_reset; } -static TypeInfo sysbus_ahci_info = { +static const TypeInfo sysbus_ahci_info = { .name = "sysbus-ahci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysbusAHCIState), diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index ee855b670f..745ef94deb 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -342,7 +342,7 @@ static void cmd646_ide_class_init(ObjectClass *klass, void *data) dc->props = cmd646_ide_properties; } -static TypeInfo cmd646_ide_info = { +static const TypeInfo cmd646_ide_info = { .name = "cmd646-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), diff --git a/hw/ide/ich.c b/hw/ide/ich.c index de39b3067a..1fb803d340 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -156,7 +156,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data) dc->reset = pci_ich9_reset; } -static TypeInfo ich_ahci_info = { +static const TypeInfo ich_ahci_info = { .name = "ich9-ahci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(AHCIPCIState), diff --git a/hw/ide/isa.c b/hw/ide/isa.c index aa0e7fa22d..fb7bb8201d 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -111,7 +111,7 @@ static void isa_ide_class_initfn(ObjectClass *klass, void *data) dc->props = isa_ide_properties; } -static TypeInfo isa_ide_info = { +static const TypeInfo isa_ide_info = { .name = "isa-ide", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAIDEState), diff --git a/hw/ide/piix.c b/hw/ide/piix.c index df95aec195..4d3e82266c 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -251,7 +251,7 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo piix3_ide_info = { +static const TypeInfo piix3_ide_info = { .name = "piix3-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), @@ -271,7 +271,7 @@ static void piix3_ide_xen_class_init(ObjectClass *klass, void *data) dc->unplug = pci_piix3_xen_ide_unplug; } -static TypeInfo piix3_ide_xen_info = { +static const TypeInfo piix3_ide_xen_info = { .name = "piix3-ide-xen", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), @@ -292,7 +292,7 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo piix4_ide_info = { +static const TypeInfo piix4_ide_info = { .name = "piix4-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index d2fe77398f..c436b38bcb 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -216,7 +216,7 @@ static void ide_hd_class_init(ObjectClass *klass, void *data) dc->props = ide_hd_properties; } -static TypeInfo ide_hd_info = { +static const TypeInfo ide_hd_info = { .name = "ide-hd", .parent = TYPE_IDE_DEVICE, .instance_size = sizeof(IDEDrive), @@ -238,7 +238,7 @@ static void ide_cd_class_init(ObjectClass *klass, void *data) dc->props = ide_cd_properties; } -static TypeInfo ide_cd_info = { +static const TypeInfo ide_cd_info = { .name = "ide-cd", .parent = TYPE_IDE_DEVICE, .instance_size = sizeof(IDEDrive), @@ -260,7 +260,7 @@ static void ide_drive_class_init(ObjectClass *klass, void *data) dc->props = ide_drive_properties; } -static TypeInfo ide_drive_info = { +static const TypeInfo ide_drive_info = { .name = "ide-drive", .parent = TYPE_IDE_DEVICE, .instance_size = sizeof(IDEDrive), @@ -275,7 +275,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data) k->props = ide_props; } -static TypeInfo ide_device_type_info = { +static const TypeInfo ide_device_type_info = { .name = TYPE_IDE_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(IDEDevice), diff --git a/hw/ide/via.c b/hw/ide/via.c index 14acb3ac04..f40c1adc8c 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -226,7 +226,7 @@ static void via_ide_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo via_ide_info = { +static const TypeInfo via_ide_info = { .name = "via-ide", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIIDEState), diff --git a/hw/imx_ccm.c b/hw/imx_ccm.c index 46962e4df9..477903a546 100644 --- a/hw/imx_ccm.c +++ b/hw/imx_ccm.c @@ -306,7 +306,7 @@ static void imx_ccm_class_init(ObjectClass *klass, void *data) dc->desc = "i.MX Clock Control Module"; } -static TypeInfo imx_ccm_info = { +static const TypeInfo imx_ccm_info = { .name = "imx_ccm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXCCMState), diff --git a/hw/imx_serial.c b/hw/imx_serial.c index 124dbb2860..77ed693a0c 100644 --- a/hw/imx_serial.c +++ b/hw/imx_serial.c @@ -452,7 +452,7 @@ static void imx_serial_class_init(ObjectClass *klass, void *data) dc->props = imx32_serial_properties; } -static TypeInfo imx_serial_info = { +static const TypeInfo imx_serial_info = { .name = "imx-serial", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXSerialState), diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 47fc9cb944..6c824dc36e 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -535,7 +535,7 @@ static void core_class_init(ObjectClass *klass, void *data) dc->props = core_properties; } -static TypeInfo core_info = { +static const TypeInfo core_info = { .name = "integrator_core", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(integratorcm_state), @@ -549,7 +549,7 @@ static void icp_pic_class_init(ObjectClass *klass, void *data) sdc->init = icp_pic_init; } -static TypeInfo icp_pic_info = { +static const TypeInfo icp_pic_info = { .name = "integrator_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pic_state), diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 98ff93679d..0a533dfa54 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -1249,7 +1249,7 @@ static void intel_hda_class_init(ObjectClass *klass, void *data) dc->props = intel_hda_properties; } -static TypeInfo intel_hda_info = { +static const TypeInfo intel_hda_info = { .name = "intel-hda", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IntelHDAState), @@ -1265,7 +1265,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data) k->props = hda_props; } -static TypeInfo hda_codec_device_type_info = { +static const TypeInfo hda_codec_device_type_info = { .name = TYPE_HDA_CODEC_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(HDACodecDevice), diff --git a/hw/ioapic.c b/hw/ioapic.c index 72730951a6..f06c2dcf2e 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -244,7 +244,7 @@ static void ioapic_class_init(ObjectClass *klass, void *data) dc->reset = ioapic_reset_common; } -static TypeInfo ioapic_info = { +static const TypeInfo ioapic_info = { .name = "ioapic", .parent = TYPE_IOAPIC_COMMON, .instance_size = sizeof(IOAPICCommonState), diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c index 653eef2ce1..7dc552f033 100644 --- a/hw/ioapic_common.c +++ b/hw/ioapic_common.c @@ -103,7 +103,7 @@ static void ioapic_common_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo ioapic_common_type = { +static const TypeInfo ioapic_common_type = { .name = TYPE_IOAPIC_COMMON, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IOAPICCommonState), diff --git a/hw/ioh3420.c b/hw/ioh3420.c index d706e195df..95bceb5347 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -226,7 +226,7 @@ static void ioh3420_class_init(ObjectClass *klass, void *data) dc->props = ioh3420_properties; } -static TypeInfo ioh3420_info = { +static const TypeInfo ioh3420_info = { .name = "ioh3420", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIESlot), diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 86b0bbd3d1..fce311bc2a 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -215,7 +215,7 @@ static void isabus_bridge_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo isabus_bridge_info = { +static const TypeInfo isabus_bridge_info = { .name = "isabus-bridge", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), @@ -229,7 +229,7 @@ static void isa_device_class_init(ObjectClass *klass, void *data) k->bus_type = TYPE_ISA_BUS; } -static TypeInfo isa_device_type_info = { +static const TypeInfo isa_device_type_info = { .name = TYPE_ISA_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(ISADevice), diff --git a/hw/ivshmem.c b/hw/ivshmem.c index fcf5d05bae..3adcc98a34 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -807,7 +807,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data) dc->props = ivshmem_properties; } -static TypeInfo ivshmem_info = { +static const TypeInfo ivshmem_info = { .name = "ivshmem", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IVShmemState), diff --git a/hw/jazz_led.c b/hw/jazz_led.c index f4a040631e..4822c485f2 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -277,7 +277,7 @@ static void jazz_led_class_init(ObjectClass *klass, void *data) dc->reset = jazz_led_reset; } -static TypeInfo jazz_led_info = { +static const TypeInfo jazz_led_info = { .name = "jazz-led", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LedState), diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c index a4e834744b..d994ea7c97 100644 --- a/hw/kvm/apic.c +++ b/hw/kvm/apic.c @@ -194,7 +194,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data) k->external_nmi = kvm_apic_external_nmi; } -static TypeInfo kvm_apic_info = { +static const TypeInfo kvm_apic_info = { .name = "kvm-apic", .parent = TYPE_APIC_COMMON, .instance_size = sizeof(APICCommonState), diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c index be24973df9..fa40e283f7 100644 --- a/hw/kvm/clock.c +++ b/hw/kvm/clock.c @@ -118,7 +118,7 @@ static void kvmclock_class_init(ObjectClass *klass, void *data) dc->vmsd = &kvmclock_vmsd; } -static TypeInfo kvmclock_info = { +static const TypeInfo kvmclock_info = { .name = "kvmclock", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(KVMClockState), diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c index 57faf64ab2..04ad649b0e 100644 --- a/hw/kvm/i8254.c +++ b/hw/kvm/i8254.c @@ -302,7 +302,7 @@ static void kvm_pit_class_init(ObjectClass *klass, void *data) dc->props = kvm_pit_properties; } -static TypeInfo kvm_pit_info = { +static const TypeInfo kvm_pit_info = { .name = "kvm-pit", .parent = TYPE_PIT_COMMON, .instance_size = sizeof(KVMPITState), diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c index 70e1d185de..5ae8b6819b 100644 --- a/hw/kvm/i8259.c +++ b/hw/kvm/i8259.c @@ -123,7 +123,7 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data) k->post_load = kvm_pic_put; } -static TypeInfo kvm_i8259_info = { +static const TypeInfo kvm_i8259_info = { .name = "kvm-i8259", .parent = TYPE_PIC_COMMON, .instance_size = sizeof(PICCommonState), diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c index 30db6230b4..23877d4259 100644 --- a/hw/kvm/ioapic.c +++ b/hw/kvm/ioapic.c @@ -150,7 +150,7 @@ static void kvm_ioapic_class_init(ObjectClass *klass, void *data) dc->props = kvm_ioapic_properties; } -static TypeInfo kvm_ioapic_info = { +static const TypeInfo kvm_ioapic_info = { .name = "kvm-ioapic", .parent = TYPE_IOAPIC_COMMON, .instance_size = sizeof(KVMIOAPICState), diff --git a/hw/kvmvapic.c b/hw/kvmvapic.c index 81f4bcfdf6..1b5f416a78 100644 --- a/hw/kvmvapic.c +++ b/hw/kvmvapic.c @@ -804,7 +804,7 @@ static void vapic_class_init(ObjectClass *klass, void *data) sc->init = vapic_init; } -static TypeInfo vapic_type = { +static const TypeInfo vapic_type = { .name = "kvmvapic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(VAPICROMState), diff --git a/hw/lan9118.c b/hw/lan9118.c index 5adf91199b..969b634d47 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -1368,7 +1368,7 @@ static void lan9118_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lan9118; } -static TypeInfo lan9118_info = { +static const TypeInfo lan9118_info = { .name = "lan9118", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(lan9118_state), diff --git a/hw/lance.c b/hw/lance.c index b7265c0fed..a5997fd64e 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -155,7 +155,7 @@ static void lance_class_init(ObjectClass *klass, void *data) dc->props = lance_properties; } -static TypeInfo lance_info = { +static const TypeInfo lance_info = { .name = "lance", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusPCNetState), diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c index 7c2d202d6a..8c82c85f6d 100644 --- a/hw/lm32_juart.c +++ b/hw/lm32_juart.c @@ -144,7 +144,7 @@ static void lm32_juart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm32_juart; } -static TypeInfo lm32_juart_info = { +static const TypeInfo lm32_juart_info = { .name = "lm32-juart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32JuartState), diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c index 42d5602cf0..8f13355821 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -184,7 +184,7 @@ static void lm32_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm32_pic; } -static TypeInfo lm32_pic_info = { +static const TypeInfo lm32_pic_info = { .name = "lm32-pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32PicState), diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c index e3a9db9748..187ef6d0d6 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -157,7 +157,7 @@ static void lm32_sys_class_init(ObjectClass *klass, void *data) dc->props = lm32_sys_properties; } -static TypeInfo lm32_sys_info = { +static const TypeInfo lm32_sys_info = { .name = "lm32-sys", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32SysState), diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c index bd4c346386..db527e9dc6 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -215,7 +215,7 @@ static void lm32_timer_class_init(ObjectClass *klass, void *data) dc->props = lm32_timer_properties; } -static TypeInfo lm32_timer_info = { +static const TypeInfo lm32_timer_info = { .name = "lm32-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32TimerState), diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c index 89605b8e77..9c89cca49b 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -281,7 +281,7 @@ static void lm32_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm32_uart; } -static TypeInfo lm32_uart_info = { +static const TypeInfo lm32_uart_info = { .name = "lm32-uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32UartState), diff --git a/hw/lm832x.c b/hw/lm832x.c index 3649e3d249..af49dd68bf 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -506,7 +506,7 @@ static void lm8323_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lm_kbd; } -static TypeInfo lm8323_info = { +static const TypeInfo lm8323_info = { .name = "lm8323", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(LM823KbdState), diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 0aafb00b58..89c657fb00 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -2126,7 +2126,7 @@ static void lsi_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_lsi_scsi; } -static TypeInfo lsi_info = { +static const TypeInfo lsi_info = { .name = "lsi53c895a", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(LSIState), diff --git a/hw/m48t59.c b/hw/m48t59.c index 393c5c049a..8f1ca3cccd 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -738,7 +738,7 @@ static void m48t59_init_class_isa1(ObjectClass *klass, void *data) dc->props = m48t59_isa_properties; } -static TypeInfo m48t59_isa_info = { +static const TypeInfo m48t59_isa_info = { .name = "m48t59_isa", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(M48t59ISAState), @@ -762,7 +762,7 @@ static void m48t59_class_init(ObjectClass *klass, void *data) dc->props = m48t59_properties; } -static TypeInfo m48t59_info = { +static const TypeInfo m48t59_info = { .name = "m48t59", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(M48t59SysBusState), diff --git a/hw/macio.c b/hw/macio.c index 362afdc7ec..675a71c051 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -90,7 +90,7 @@ static void macio_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_OTHERS << 8; } -static TypeInfo macio_info = { +static const TypeInfo macio_info = { .name = "macio", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MacIOState), diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index de16cfa090..511004b94e 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -288,7 +288,7 @@ static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) dc->props = mv88w8618_audio_properties; } -static TypeInfo mv88w8618_audio_info = { +static const TypeInfo mv88w8618_audio_info = { .name = "mv88w8618_audio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_audio_state), diff --git a/hw/max111x.c b/hw/max111x.c index 67640f109a..de1be4ddd6 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -162,7 +162,7 @@ static void max1110_class_init(ObjectClass *klass, void *data) k->transfer = max111x_transfer; } -static TypeInfo max1110_info = { +static const TypeInfo max1110_info = { .name = "max1110", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(MAX111xState), @@ -177,7 +177,7 @@ static void max1111_class_init(ObjectClass *klass, void *data) k->transfer = max111x_transfer; } -static TypeInfo max1111_info = { +static const TypeInfo max1111_info = { .name = "max1111", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(MAX111xState), diff --git a/hw/max7310.c b/hw/max7310.c index 1ed18ba876..de2221ba01 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -198,7 +198,7 @@ static void max7310_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_max7310; } -static TypeInfo max7310_info = { +static const TypeInfo max7310_info = { .name = "max7310", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(MAX7310State), diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 2ddd7de09e..2fb11f69a3 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -898,7 +898,7 @@ static void rtc_class_initfn(ObjectClass *klass, void *data) dc->props = mc146818rtc_properties; } -static TypeInfo mc146818rtc_info = { +static const TypeInfo mc146818rtc_info = { .name = "mc146818rtc", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(RTCState), diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c index f46af1c509..d51d1ac993 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -329,7 +329,7 @@ static void milkymist_ac97_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_ac97; } -static TypeInfo milkymist_ac97_info = { +static const TypeInfo milkymist_ac97_info = { .name = "milkymist-ac97", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistAC97State), diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c index fd54d3129a..ea4d210685 100644 --- a/hw/milkymist-hpdmc.c +++ b/hw/milkymist-hpdmc.c @@ -155,7 +155,7 @@ static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_hpdmc; } -static TypeInfo milkymist_hpdmc_info = { +static const TypeInfo milkymist_hpdmc_info = { .name = "milkymist-hpdmc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistHpdmcState), diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c index f80befc53a..9d15309ab7 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -288,7 +288,7 @@ static void milkymist_memcard_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_memcard; } -static TypeInfo milkymist_memcard_info = { +static const TypeInfo milkymist_memcard_info = { .name = "milkymist-memcard", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistMemcardState), diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 4e92ac3dcb..43d6c195eb 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -535,7 +535,7 @@ static void milkymist_minimac2_class_init(ObjectClass *klass, void *data) dc->props = milkymist_minimac2_properties; } -static TypeInfo milkymist_minimac2_info = { +static const TypeInfo milkymist_minimac2_info = { .name = "milkymist-minimac2", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistMinimac2State), diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index 0521829202..c347680ad7 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -529,7 +529,7 @@ static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_pfpu; } -static TypeInfo milkymist_pfpu_info = { +static const TypeInfo milkymist_pfpu_info = { .name = "milkymist-pfpu", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistPFPUState), diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index b7beb4bedb..01660bebf0 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -316,7 +316,7 @@ static void milkymist_softusb_class_init(ObjectClass *klass, void *data) dc->props = milkymist_softusb_properties; } -static TypeInfo milkymist_softusb_info = { +static const TypeInfo milkymist_softusb_info = { .name = "milkymist-softusb", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistSoftUsbState), diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index 796e795f04..e69ac6f047 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -323,7 +323,7 @@ static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) dc->props = milkymist_sysctl_properties; } -static TypeInfo milkymist_sysctl_info = { +static const TypeInfo milkymist_sysctl_info = { .name = "milkymist-sysctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistSysctlState), diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c index a11772aebe..42de10aafd 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -475,7 +475,7 @@ static void milkymist_tmu2_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_tmu2; } -static TypeInfo milkymist_tmu2_info = { +static const TypeInfo milkymist_tmu2_info = { .name = "milkymist-tmu2", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistTMU2State), diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c index 19e9dbdc75..e73eb8476c 100644 --- a/hw/milkymist-uart.c +++ b/hw/milkymist-uart.c @@ -228,7 +228,7 @@ static void milkymist_uart_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_milkymist_uart; } -static TypeInfo milkymist_uart_info = { +static const TypeInfo milkymist_uart_info = { .name = "milkymist-uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistUartState), diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 561285154f..4d0a5dfb78 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -319,7 +319,7 @@ static void milkymist_vgafb_class_init(ObjectClass *klass, void *data) dc->props = milkymist_vgafb_properties; } -static TypeInfo milkymist_vgafb_info = { +static const TypeInfo milkymist_vgafb_info = { .name = "milkymist-vgafb", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistVgafbState), diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 635143d20c..2250e675a5 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -1004,7 +1004,7 @@ static void mips_malta_class_init(ObjectClass *klass, void *data) k->init = mips_malta_sysbus_device_init; } -static TypeInfo mips_malta_device = { +static const TypeInfo mips_malta_device = { .name = "mips-malta", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MaltaState), diff --git a/hw/mipsnet.c b/hw/mipsnet.c index bb752d3950..feac8159ee 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -269,7 +269,7 @@ static void mipsnet_class_init(ObjectClass *klass, void *data) dc->props = mipsnet_properties; } -static TypeInfo mipsnet_info = { +static const TypeInfo mipsnet_info = { .name = "mipsnet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MIPSnetState), diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c index 84522e9722..9c57d7665f 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -128,7 +128,7 @@ static void mpc8544_guts_class_init(ObjectClass *klass, void *data) k->init = mpc8544_guts_initfn; } -static TypeInfo mpc8544_guts_info = { +static const TypeInfo mpc8544_guts_info = { .name = "mpc8544-guts", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GutsState), diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index fb4b739c7c..7ae05e389f 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -248,7 +248,7 @@ static void mst_fpga_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_mst_fpga_regs; } -static TypeInfo mst_fpga_info = { +static const TypeInfo mst_fpga_info = { .name = "mainstone-fpga", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mst_irq_state), diff --git a/hw/musicpal.c b/hw/musicpal.c index 77a585eee6..24a1722703 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -428,7 +428,7 @@ static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) dc->props = mv88w8618_eth_properties; } -static TypeInfo mv88w8618_eth_info = { +static const TypeInfo mv88w8618_eth_info = { .name = "mv88w8618_eth", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_eth_state), @@ -643,7 +643,7 @@ static void musicpal_lcd_class_init(ObjectClass *klass, void *data) dc->vmsd = &musicpal_lcd_vmsd; } -static TypeInfo musicpal_lcd_info = { +static const TypeInfo musicpal_lcd_info = { .name = "musicpal_lcd", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_lcd_state), @@ -762,7 +762,7 @@ static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &mv88w8618_pic_vmsd; } -static TypeInfo mv88w8618_pic_info = { +static const TypeInfo mv88w8618_pic_info = { .name = "mv88w8618_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_pic_state), @@ -939,7 +939,7 @@ static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) dc->vmsd = &mv88w8618_pit_vmsd; } -static TypeInfo mv88w8618_pit_info = { +static const TypeInfo mv88w8618_pit_info = { .name = "mv88w8618_pit", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_pit_state), @@ -1019,7 +1019,7 @@ static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) dc->vmsd = &mv88w8618_flashcfg_vmsd; } -static TypeInfo mv88w8618_flashcfg_info = { +static const TypeInfo mv88w8618_flashcfg_info = { .name = "mv88w8618_flashcfg", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mv88w8618_flashcfg_state), @@ -1341,7 +1341,7 @@ static void musicpal_gpio_class_init(ObjectClass *klass, void *data) dc->vmsd = &musicpal_gpio_vmsd; } -static TypeInfo musicpal_gpio_info = { +static const TypeInfo musicpal_gpio_info = { .name = "musicpal_gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_gpio_state), @@ -1495,7 +1495,7 @@ static void musicpal_key_class_init(ObjectClass *klass, void *data) dc->vmsd = &musicpal_key_vmsd; } -static TypeInfo musicpal_key_info = { +static const TypeInfo musicpal_key_info = { .name = "musicpal_key", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(musicpal_key_state), @@ -1674,7 +1674,7 @@ static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) sdc->init = mv88w8618_wlan_init; } -static TypeInfo mv88w8618_wlan_info = { +static const TypeInfo mv88w8618_wlan_info = { .name = "mv88w8618_wlan", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), diff --git a/hw/nand.c b/hw/nand.c index 16950c5ec4..6054f46581 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -435,7 +435,7 @@ static void nand_class_init(ObjectClass *klass, void *data) dc->props = nand_properties; } -static TypeInfo nand_info = { +static const TypeInfo nand_info = { .name = "nand", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(NANDFlashState), diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index c2c00c215f..7c11229f1a 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -97,7 +97,7 @@ static void isa_ne2000_class_initfn(ObjectClass *klass, void *data) dc->props = ne2000_isa_properties; } -static TypeInfo ne2000_isa_info = { +static const TypeInfo ne2000_isa_info = { .name = "ne2k_isa", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISANE2000State), diff --git a/hw/ne2000.c b/hw/ne2000.c index 00efa74a0f..872115c454 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -773,7 +773,7 @@ static void ne2000_class_init(ObjectClass *klass, void *data) dc->props = ne2000_properties; } -static TypeInfo ne2000_info = { +static const TypeInfo ne2000_info = { .name = "ne2k_pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCINE2000State), diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index 25655325d0..15bdd629bf 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -747,7 +747,7 @@ static void omap_gpio_class_init(ObjectClass *klass, void *data) dc->props = omap_gpio_properties; } -static TypeInfo omap_gpio_info = { +static const TypeInfo omap_gpio_info = { .name = "omap-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_gpif_s), @@ -776,7 +776,7 @@ static void omap2_gpio_class_init(ObjectClass *klass, void *data) dc->props = omap2_gpio_properties; } -static TypeInfo omap2_gpio_info = { +static const TypeInfo omap2_gpio_info = { .name = "omap2-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap2_gpif_s), diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index ba08e6400c..e0a5087f37 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -471,7 +471,7 @@ static void omap_i2c_class_init(ObjectClass *klass, void *data) dc->reset = omap_i2c_reset; } -static TypeInfo omap_i2c_info = { +static const TypeInfo omap_i2c_info = { .name = "omap_i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OMAPI2CState), diff --git a/hw/omap_intc.c b/hw/omap_intc.c index 61e0dafbdd..113725ef98 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -389,7 +389,7 @@ static void omap_intc_class_init(ObjectClass *klass, void *data) dc->props = omap_intc_properties; } -static TypeInfo omap_intc_info = { +static const TypeInfo omap_intc_info = { .name = "omap-intc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_intr_handler_s), @@ -633,7 +633,7 @@ static void omap2_intc_class_init(ObjectClass *klass, void *data) dc->props = omap2_intc_properties; } -static TypeInfo omap2_intc_info = { +static const TypeInfo omap2_intc_info = { .name = "omap2-intc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_intr_handler_s), diff --git a/hw/onenand.c b/hw/onenand.c index 26bf991d6d..b82bf7d333 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -821,7 +821,7 @@ static void onenand_class_init(ObjectClass *klass, void *data) dc->props = onenand_properties; } -static TypeInfo onenand_info = { +static const TypeInfo onenand_info = { .name = "onenand", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OneNANDState), diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index a0dfdce1f9..746a959f6b 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -718,7 +718,7 @@ static void open_eth_class_init(ObjectClass *klass, void *data) dc->props = open_eth_properties; } -static TypeInfo open_eth_info = { +static const TypeInfo open_eth_info = { .name = "open_eth", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OpenEthState), diff --git a/hw/openpic.c b/hw/openpic.c index 9c956b9dcc..a8c5959e30 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -1270,7 +1270,7 @@ static void openpic_class_init(ObjectClass *klass, void *data) dc->reset = openpic_reset; } -static TypeInfo openpic_info = { +static const TypeInfo openpic_info = { .name = "openpic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OpenPICState), diff --git a/hw/parallel.c b/hw/parallel.c index 64a46c6055..3a4e06bab0 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -599,7 +599,7 @@ static void parallel_isa_class_initfn(ObjectClass *klass, void *data) dc->props = parallel_isa_properties; } -static TypeInfo parallel_isa_info = { +static const TypeInfo parallel_isa_info = { .name = "isa-parallel", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAParallelState), diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c index 192848998c..ec0bc4bb95 100644 --- a/hw/pc-testdev.c +++ b/hw/pc-testdev.c @@ -172,7 +172,7 @@ static void testdev_class_init(ObjectClass *klass, void *data) k->init = init_test_device; } -static TypeInfo testdev_info = { +static const TypeInfo testdev_info = { .name = TYPE_TESTDEV, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(struct PCTestdev), diff --git a/hw/pc.c b/hw/pc.c index df0c48e41b..68984e4161 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -501,7 +501,7 @@ static void port92_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_port92_isa; } -static TypeInfo port92_info = { +static const TypeInfo port92_info = { .name = "port92", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(Port92State), diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index 7567593a63..7f6c12c8a8 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -256,7 +256,7 @@ static void pcsysfw_class_init (ObjectClass *klass, void *data) dc->props = pcsysfw_properties; } -static TypeInfo pcsysfw_info = { +static const TypeInfo pcsysfw_info = { .name = "pc-sysfw", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof (PcSysFwDevice), diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 94840c4af7..5fd1bcf08e 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2150,7 +2150,7 @@ void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque) bus->dma_context_opaque = opaque; } -static TypeInfo pci_device_type_info = { +static const TypeInfo pci_device_type_info = { .name = TYPE_PCI_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(PCIDevice), diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 7818dcc350..1a7b2cd897 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -156,7 +156,7 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) dc->vmsd = &pci_bridge_dev_vmstate; } -static TypeInfo pci_bridge_dev_info = { +static const TypeInfo pci_bridge_dev_info = { .name = "pci-bridge", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBridgeDev), diff --git a/hw/pckbd.c b/hw/pckbd.c index 6db7bbcc06..3bad09baf2 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -512,7 +512,7 @@ static void i8042_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_kbd_isa; } -static TypeInfo i8042_info = { +static const TypeInfo i8042_info = { .name = "i8042", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAKBDState), diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 40a0e6eda4..a94f642136 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -361,7 +361,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) dc->props = pcnet_properties; } -static TypeInfo pcnet_info = { +static const TypeInfo pcnet_info = { .name = "pcnet", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIPCNetState), diff --git a/hw/pcspk.c b/hw/pcspk.c index 6d55ebe82f..dfab9559ae 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -187,7 +187,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data) dc->props = pcspk_properties; } -static TypeInfo pcspk_info = { +static const TypeInfo pcspk_info = { .name = "isa-pcspk", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PCSpkState), diff --git a/hw/piix4.c b/hw/piix4.c index 799ed1729c..c1cb94d39f 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -117,7 +117,7 @@ static void piix4_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_piix4; } -static TypeInfo piix4_info = { +static const TypeInfo piix4_info = { .name = "PIIX4", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX4State), diff --git a/hw/pl011.c b/hw/pl011.c index 35835f36c0..002a50e16a 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -300,7 +300,7 @@ static void pl011_arm_class_init(ObjectClass *klass, void *data) sdc->init = pl011_arm_init; } -static TypeInfo pl011_arm_info = { +static const TypeInfo pl011_arm_info = { .name = "pl011", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl011_state), @@ -314,7 +314,7 @@ static void pl011_luminary_class_init(ObjectClass *klass, void *data) sdc->init = pl011_luminary_init; } -static TypeInfo pl011_luminary_info = { +static const TypeInfo pl011_luminary_info = { .name = "pl011_luminary", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl011_state), diff --git a/hw/pl022.c b/hw/pl022.c index fbd7ded0cf..c160e9061c 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -293,7 +293,7 @@ static void pl022_class_init(ObjectClass *klass, void *data) sdc->init = pl022_init; } -static TypeInfo pl022_info = { +static const TypeInfo pl022_info = { .name = "pl022", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl022_state), diff --git a/hw/pl031.c b/hw/pl031.c index 3a23ecde48..757867ff79 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -250,7 +250,7 @@ static void pl031_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl031; } -static TypeInfo pl031_info = { +static const TypeInfo pl031_info = { .name = "pl031", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl031_state), diff --git a/hw/pl041.c b/hw/pl041.c index 4436d97c50..0b71c45748 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -632,7 +632,7 @@ static void pl041_device_class_init(ObjectClass *klass, void *data) dc->props = pl041_device_properties; } -static TypeInfo pl041_device_info = { +static const TypeInfo pl041_device_info = { .name = "pl041", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl041_state), diff --git a/hw/pl050.c b/hw/pl050.c index 47032f1260..5d06bc9a3f 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -168,7 +168,7 @@ static void pl050_kbd_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl050; } -static TypeInfo pl050_kbd_info = { +static const TypeInfo pl050_kbd_info = { .name = "pl050_keyboard", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl050_state), @@ -184,7 +184,7 @@ static void pl050_mouse_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl050; } -static TypeInfo pl050_mouse_info = { +static const TypeInfo pl050_mouse_info = { .name = "pl050_mouse", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl050_state), diff --git a/hw/pl061.c b/hw/pl061.c index f1ed5ced1d..a78e819d96 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -304,7 +304,7 @@ static void pl061_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl061; } -static TypeInfo pl061_info = { +static const TypeInfo pl061_info = { .name = "pl061", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl061_state), @@ -320,7 +320,7 @@ static void pl061_luminary_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl061; } -static TypeInfo pl061_luminary_info = { +static const TypeInfo pl061_luminary_info = { .name = "pl061_luminary", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl061_state), diff --git a/hw/pl080.c b/hw/pl080.c index 26150af757..f6bbf98a7e 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -386,7 +386,7 @@ static void pl080_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl080; } -static TypeInfo pl080_info = { +static const TypeInfo pl080_info = { .name = "pl080", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl080_state), @@ -403,7 +403,7 @@ static void pl081_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl080; } -static TypeInfo pl081_info = { +static const TypeInfo pl081_info = { .name = "pl081", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl080_state), diff --git a/hw/pl110.c b/hw/pl110.c index 098e335aea..3d0ac00ade 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -480,7 +480,7 @@ static void pl110_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl110; } -static TypeInfo pl110_info = { +static const TypeInfo pl110_info = { .name = "pl110", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl110_state), @@ -497,7 +497,7 @@ static void pl110_versatile_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl110; } -static TypeInfo pl110_versatile_info = { +static const TypeInfo pl110_versatile_info = { .name = "pl110_versatile", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl110_state), @@ -514,7 +514,7 @@ static void pl111_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl110; } -static TypeInfo pl111_info = { +static const TypeInfo pl111_info = { .name = "pl111", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl110_state), diff --git a/hw/pl181.c b/hw/pl181.c index cbddb741ce..98529f7821 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -500,7 +500,7 @@ static void pl181_class_init(ObjectClass *klass, void *data) k->no_user = 1; } -static TypeInfo pl181_info = { +static const TypeInfo pl181_info = { .name = "pl181", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl181_state), diff --git a/hw/pl190.c b/hw/pl190.c index 40199302a9..76ac159374 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -274,7 +274,7 @@ static void pl190_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pl190; } -static TypeInfo pl190_info = { +static const TypeInfo pl190_info = { .name = "pl190", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(pl190_state), diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 177aa2d122..1b2c34f92c 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -212,7 +212,7 @@ static void ppce500_spin_class_init(ObjectClass *klass, void *data) k->init = ppce500_spin_initfn; } -static TypeInfo ppce500_spin_info = { +static const TypeInfo ppce500_spin_info = { .name = "e500-spin", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SpinState), diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 3c51bc82aa..f3dffef5ab 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1194,7 +1194,7 @@ static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pxa2xx_rtc_regs; } -static TypeInfo pxa2xx_rtc_sysbus_info = { +static const TypeInfo pxa2xx_rtc_sysbus_info = { .name = "pxa2xx_rtc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxRTCState), @@ -1442,7 +1442,7 @@ static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) k->send = pxa2xx_i2c_tx; } -static TypeInfo pxa2xx_i2c_slave_info = { +static const TypeInfo pxa2xx_i2c_slave_info = { .name = "pxa2xx-i2c-slave", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(PXA2xxI2CSlaveState), @@ -1510,7 +1510,7 @@ static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) dc->props = pxa2xx_i2c_properties; } -static TypeInfo pxa2xx_i2c_info = { +static const TypeInfo pxa2xx_i2c_info = { .name = "pxa2xx_i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxI2CState), @@ -2273,7 +2273,7 @@ static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) sdc->init = pxa2xx_ssp_init; } -static TypeInfo pxa2xx_ssp_info = { +static const TypeInfo pxa2xx_ssp_info = { .name = "pxa2xx-ssp", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxSSPState), diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index dbea1d2098..693b1c23d9 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -559,7 +559,7 @@ static void pxa2xx_dma_class_init(ObjectClass *klass, void *data) dc->props = pxa2xx_dma_properties; } -static TypeInfo pxa2xx_dma_info = { +static const TypeInfo pxa2xx_dma_info = { .name = "pxa2xx-dma", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxDMAState), diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 7aaf4092df..016833dfa1 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -334,7 +334,7 @@ static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data) dc->props = pxa2xx_gpio_properties; } -static TypeInfo pxa2xx_gpio_info = { +static const TypeInfo pxa2xx_gpio_info = { .name = "pxa2xx-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxGPIOInfo), diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index 70b2b79d07..138245b0f9 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -319,7 +319,7 @@ static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_pxa2xx_pic_regs; } -static TypeInfo pxa2xx_pic_info = { +static const TypeInfo pxa2xx_pic_info = { .name = "pxa2xx_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxPICState), diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index e4ffb15bb2..32c1872680 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -495,7 +495,7 @@ static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) dc->props = pxa25x_timer_dev_properties; } -static TypeInfo pxa25x_timer_dev_info = { +static const TypeInfo pxa25x_timer_dev_info = { .name = "pxa25x-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxTimerInfo), @@ -520,7 +520,7 @@ static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) dc->props = pxa27x_timer_dev_properties; } -static TypeInfo pxa27x_timer_dev_info = { +static const TypeInfo pxa27x_timer_dev_info = { .name = "pxa27x-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxTimerInfo), diff --git a/hw/qdev.c b/hw/qdev.c index e2a5c5735b..b027ead598 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -732,7 +732,7 @@ Object *qdev_get_machine(void) return dev; } -static TypeInfo device_type_info = { +static const TypeInfo device_type_info = { .name = TYPE_DEVICE, .parent = TYPE_OBJECT, .instance_size = sizeof(DeviceState), diff --git a/hw/qxl.c b/hw/qxl.c index d08b9bd3c1..00e517aaa3 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -2310,7 +2310,7 @@ static void qxl_primary_class_init(ObjectClass *klass, void *data) dc->props = qxl_properties; } -static TypeInfo qxl_primary_info = { +static const TypeInfo qxl_primary_info = { .name = "qxl-vga", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIQXLDevice), @@ -2332,7 +2332,7 @@ static void qxl_secondary_class_init(ObjectClass *klass, void *data) dc->props = qxl_properties; } -static TypeInfo qxl_secondary_info = { +static const TypeInfo qxl_secondary_info = { .name = "qxl", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIQXLDevice), diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 5bc37a7120..b1b74d8e9c 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -59,7 +59,7 @@ static void realview_gic_class_init(ObjectClass *klass, void *data) sdc->init = realview_gic_init; } -static TypeInfo realview_gic_info = { +static const TypeInfo realview_gic_info = { .name = "realview_gic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RealViewGICState), diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 3e080621f6..cfbf3f47c1 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3540,7 +3540,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) dc->props = rtl8139_properties; } -static TypeInfo rtl8139_info = { +static const TypeInfo rtl8139_info = { .name = "rtl8139", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(RTL8139State), diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 7e991755b4..bcb09f202e 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -419,7 +419,7 @@ static void s390_virtio_net_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_net_properties; } -static TypeInfo s390_virtio_net = { +static const TypeInfo s390_virtio_net = { .name = "virtio-net-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -445,7 +445,7 @@ static void s390_virtio_blk_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_blk_properties; } -static TypeInfo s390_virtio_blk = { +static const TypeInfo s390_virtio_blk = { .name = "virtio-blk-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -467,7 +467,7 @@ static void s390_virtio_serial_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_serial_properties; } -static TypeInfo s390_virtio_serial = { +static const TypeInfo s390_virtio_serial = { .name = "virtio-serial-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -489,7 +489,7 @@ static void s390_virtio_rng_class_init(ObjectClass *klass, void *data) k->init = s390_virtio_rng_init; } -static TypeInfo s390_virtio_rng = { +static const TypeInfo s390_virtio_rng = { .name = "virtio-rng-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -514,7 +514,7 @@ static void virtio_s390_device_class_init(ObjectClass *klass, void *data) dc->unplug = qdev_simple_unplug_cb; } -static TypeInfo virtio_s390_device_info = { +static const TypeInfo virtio_s390_device_info = { .name = TYPE_VIRTIO_S390_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -537,7 +537,7 @@ static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data) dc->props = s390_virtio_scsi_properties; } -static TypeInfo s390_virtio_scsi = { +static const TypeInfo s390_virtio_scsi = { .name = "virtio-scsi-s390", .parent = TYPE_VIRTIO_S390_DEVICE, .instance_size = sizeof(VirtIOS390Device), @@ -562,7 +562,7 @@ static void s390_virtio_bridge_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo s390_virtio_bridge_info = { +static const TypeInfo s390_virtio_bridge_info = { .name = "s390-virtio-bridge", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 89b1b66bd2..6b56995189 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -345,7 +345,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data) k->init = init_event_facility; } -static TypeInfo s390_sclp_event_facility_info = { +static const TypeInfo s390_sclp_event_facility_info = { .name = "s390-sclp-event-facility", .parent = TYPE_DEVICE_S390_SCLP, .instance_size = sizeof(S390SCLPDevice), @@ -380,7 +380,7 @@ static void event_class_init(ObjectClass *klass, void *data) dc->exit = event_qdev_exit; } -static TypeInfo s390_sclp_event_type_info = { +static const TypeInfo s390_sclp_event_type_info = { .name = TYPE_SCLP_EVENT, .parent = TYPE_DEVICE, .instance_size = sizeof(SCLPEvent), diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 7ad791d5e3..a9d3a6a91d 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -146,7 +146,7 @@ static void s390_sclp_device_class_init(ObjectClass *klass, void *data) dc->init = s390_sclp_dev_init; } -static TypeInfo s390_sclp_device_info = { +static const TypeInfo s390_sclp_device_info = { .name = TYPE_DEVICE_S390_SCLP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(S390SCLPDevice), diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index aa70e16665..adc0ee83f4 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -291,7 +291,7 @@ static void console_class_init(ObjectClass *klass, void *data) ec->write_event_data = write_event_data; } -static TypeInfo sclp_console_info = { +static const TypeInfo sclp_console_info = { .name = "sclpconsole", .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPConsole), diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 6e6f5624df..2538498959 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -107,7 +107,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data) k->write_event_data = NULL; } -static TypeInfo sclp_quiesce_info = { +static const TypeInfo sclp_quiesce_info = { .name = "sclpquiesce", .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPEvent), diff --git a/hw/sb16.c b/hw/sb16.c index bb460ccb60..52dfedf5f1 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -1409,7 +1409,7 @@ static void sb16_class_initfn (ObjectClass *klass, void *data) dc->props = sb16_properties; } -static TypeInfo sb16_info = { +static const TypeInfo sb16_info = { .name = "sb16", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof (SB16State), diff --git a/hw/sbi.c b/hw/sbi.c index ca78a384c7..d58184a6aa 100644 --- a/hw/sbi.c +++ b/hw/sbi.c @@ -141,7 +141,7 @@ static void sbi_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sbi; } -static TypeInfo sbi_info = { +static const TypeInfo sbi_info = { .name = "sbi", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SBIState), diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 970c1fc01b..267a942f76 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1863,7 +1863,7 @@ static void scsi_device_class_init(ObjectClass *klass, void *data) k->props = scsi_props; } -static TypeInfo scsi_device_type_info = { +static const TypeInfo scsi_device_type_info = { .name = TYPE_SCSI_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(SCSIDevice), diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a69735b0a6..f8d7ef3374 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -2389,7 +2389,7 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_hd_info = { +static const TypeInfo scsi_hd_info = { .name = "scsi-hd", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), @@ -2418,7 +2418,7 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_cd_info = { +static const TypeInfo scsi_cd_info = { .name = "scsi-cd", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), @@ -2447,7 +2447,7 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_block_info = { +static const TypeInfo scsi_block_info = { .name = "scsi-block", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), @@ -2481,7 +2481,7 @@ static void scsi_disk_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_disk_state; } -static TypeInfo scsi_disk_info = { +static const TypeInfo scsi_disk_info = { .name = "scsi-disk", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDiskState), diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 4c702be19f..8175474a67 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -499,7 +499,7 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_scsi_device; } -static TypeInfo scsi_generic_info = { +static const TypeInfo scsi_generic_info = { .name = "scsi-generic", .parent = TYPE_SCSI_DEVICE, .instance_size = sizeof(SCSIDevice), diff --git a/hw/serial-isa.c b/hw/serial-isa.c index 96c78f7f8d..5a6f51f856 100644 --- a/hw/serial-isa.c +++ b/hw/serial-isa.c @@ -99,7 +99,7 @@ static void serial_isa_class_initfn(ObjectClass *klass, void *data) dc->props = serial_isa_properties; } -static TypeInfo serial_isa_info = { +static const TypeInfo serial_isa_info = { .name = "isa-serial", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISASerialState), diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 6a2548a515..c62cc9e375 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -221,21 +221,21 @@ static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) dc->props = multi_4x_serial_pci_properties; } -static TypeInfo serial_pci_info = { +static const TypeInfo serial_pci_info = { .name = "pci-serial", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCISerialState), .class_init = serial_pci_class_initfn, }; -static TypeInfo multi_2x_serial_pci_info = { +static const TypeInfo multi_2x_serial_pci_info = { .name = "pci-serial-2x", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIMultiSerialState), .class_init = multi_2x_serial_pci_class_initfn, }; -static TypeInfo multi_4x_serial_pci_info = { +static const TypeInfo multi_4x_serial_pci_info = { .name = "pci-serial-4x", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIMultiSerialState), diff --git a/hw/sga.c b/hw/sga.c index d5c91ed98e..29bc3e0246 100644 --- a/hw/sga.c +++ b/hw/sga.c @@ -48,7 +48,7 @@ static void sga_class_initfn(ObjectClass *klass, void *data) dc->desc = "Serial Graphics Adapter"; } -static TypeInfo sga_info = { +static const TypeInfo sga_info = { .name = "sga", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISASGAState), diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 018b1c198b..077d957003 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -156,7 +156,7 @@ static void sh_pci_host_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R; } -static TypeInfo sh_pci_host_info = { +static const TypeInfo sh_pci_host_info = { .name = "sh_pci_host", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -170,7 +170,7 @@ static void sh_pci_device_class_init(ObjectClass *klass, void *data) sdc->init = sh_pci_device_init; } -static TypeInfo sh_pci_device_info = { +static const TypeInfo sh_pci_device_info = { .name = "sh_pci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SHPCIState), diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index a44ce95c1f..d67c8ccc9f 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -456,7 +456,7 @@ static void slavio_intctl_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_intctl; } -static TypeInfo slavio_intctl_info = { +static const TypeInfo slavio_intctl_info = { .name = "slavio_intctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLAVIO_INTCTLState), diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 704f2b173b..af24cc1ae8 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -478,7 +478,7 @@ static void slavio_misc_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_misc; } -static TypeInfo slavio_misc_info = { +static const TypeInfo slavio_misc_info = { .name = "slavio_misc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MiscState), @@ -492,7 +492,7 @@ static void apc_class_init(ObjectClass *klass, void *data) k->init = apc_init1; } -static TypeInfo apc_info = { +static const TypeInfo apc_info = { .name = "apc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MiscState), diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 584629f1a5..68a4c0cca4 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -420,7 +420,7 @@ static void slavio_timer_class_init(ObjectClass *klass, void *data) dc->props = slavio_timer_properties; } -static TypeInfo slavio_timer_info = { +static const TypeInfo slavio_timer_info = { .name = "slavio_timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLAVIO_TIMERState), diff --git a/hw/smbus.c b/hw/smbus.c index e3cf6a2cc8..a908591590 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -318,7 +318,7 @@ static void smbus_device_class_init(ObjectClass *klass, void *data) sc->send = smbus_i2c_send; } -static TypeInfo smbus_device_type_info = { +static const TypeInfo smbus_device_type_info = { .name = TYPE_SMBUS_DEVICE, .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(SMBusDevice), diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 11adab01b8..d36dc7bbe3 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -123,7 +123,7 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data) dc->props = smbus_eeprom_properties; } -static TypeInfo smbus_eeprom_info = { +static const TypeInfo smbus_eeprom_info = { .name = "smbus-eeprom", .parent = TYPE_SMBUS_DEVICE, .instance_size = sizeof(SMBusEEPROMDevice), diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 2161b4af7a..a34698f9e3 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -774,7 +774,7 @@ static void smc91c111_class_init(ObjectClass *klass, void *data) dc->props = smc91c111_properties; } -static TypeInfo smc91c111_info = { +static const TypeInfo smc91c111_info = { .name = "smc91c111", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(smc91c111_state), diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 8077eb94bc..db34b485aa 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -502,7 +502,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) k->rtce_window_size = 0x10000000; } -static TypeInfo spapr_vlan_info = { +static const TypeInfo spapr_vlan_info = { .name = "spapr-vlan", .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VIOsPAPRVLANDevice), diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index a58621d17e..3a1a4864e6 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -536,7 +536,7 @@ static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo spapr_vio_bridge_info = { +static const TypeInfo spapr_vio_bridge_info = { .name = "spapr-vio-bridge", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SysBusDevice), @@ -552,7 +552,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data) k->props = spapr_vio_props; } -static TypeInfo spapr_vio_type_info = { +static const TypeInfo spapr_vio_type_info = { .name = TYPE_VIO_SPAPR_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(VIOsPAPRDevice), diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 2d811320ca..7fc0e13f9f 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -967,7 +967,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) k->rtce_window_size = 0x10000000; } -static TypeInfo spapr_vscsi_info = { +static const TypeInfo spapr_vscsi_info = { .name = "spapr-vscsi", .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VSCSIState), diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index ec81a7e6e8..5c63eaafa9 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -150,7 +150,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data) dc->props = spapr_vty_properties; } -static TypeInfo spapr_vty_info = { +static const TypeInfo spapr_vty_info = { .name = "spapr-vty", .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(VIOsPAPRVTYDevice), diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index d11a302f20..6d0df51749 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -300,7 +300,7 @@ static void sparc32_dma_class_init(ObjectClass *klass, void *data) dc->props = sparc32_dma_properties; } -static TypeInfo sparc32_dma_info = { +static const TypeInfo sparc32_dma_info = { .name = "sparc32_dma", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(DMAState), diff --git a/hw/spitz.c b/hw/spitz.c index 8e1be7fb21..f1659c4502 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -1022,7 +1022,7 @@ static void sl_nand_class_init(ObjectClass *klass, void *data) dc->props = sl_nand_properties; } -static TypeInfo sl_nand_info = { +static const TypeInfo sl_nand_info = { .name = "sl-nand", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLNANDState), @@ -1057,7 +1057,7 @@ static void spitz_keyboard_class_init(ObjectClass *klass, void *data) dc->props = spitz_keyboard_properties; } -static TypeInfo spitz_keyboard_info = { +static const TypeInfo spitz_keyboard_info = { .name = "spitz-keyboard", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SpitzKeyboardState), @@ -1086,7 +1086,7 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_corgi_ssp_regs; } -static TypeInfo corgi_ssp_info = { +static const TypeInfo corgi_ssp_info = { .name = "corgi-ssp", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(CorgiSSPState), @@ -1116,7 +1116,7 @@ static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_spitz_lcdtg_regs; } -static TypeInfo spitz_lcdtg_info = { +static const TypeInfo spitz_lcdtg_info = { .name = "spitz-lcdtg", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(SpitzLCDTG), diff --git a/hw/ssd0303.c b/hw/ssd0303.c index cbdf49af57..8777b1681a 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -306,7 +306,7 @@ static void ssd0303_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ssd0303; } -static TypeInfo ssd0303_info = { +static const TypeInfo ssd0303_info = { .name = "ssd0303", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(ssd0303_state), diff --git a/hw/ssd0323.c b/hw/ssd0323.c index fe6f801ae7..84c86a5244 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -357,7 +357,7 @@ static void ssd0323_class_init(ObjectClass *klass, void *data) k->cs_polarity = SSI_CS_HIGH; } -static TypeInfo ssd0323_info = { +static const TypeInfo ssd0323_info = { .name = "ssd0323", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ssd0323_state), diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index d61c3328d9..dca8906e7d 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -259,7 +259,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->cs_polarity = SSI_CS_LOW; } -static TypeInfo ssi_sd_info = { +static const TypeInfo ssi_sd_info = { .name = "ssi-sd", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ssi_sd_state), diff --git a/hw/ssi.c b/hw/ssi.c index 2b56357153..0b18176f7a 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -78,7 +78,7 @@ static void ssi_slave_class_init(ObjectClass *klass, void *data) } } -static TypeInfo ssi_slave_info = { +static const TypeInfo ssi_slave_info = { .name = TYPE_SSI_SLAVE, .parent = TYPE_DEVICE, .class_init = ssi_slave_class_init, diff --git a/hw/stellaris.c b/hw/stellaris.c index 26da3c7f60..12e4568534 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1354,7 +1354,7 @@ static void stellaris_i2c_class_init(ObjectClass *klass, void *data) sdc->init = stellaris_i2c_init; } -static TypeInfo stellaris_i2c_info = { +static const TypeInfo stellaris_i2c_info = { .name = "stellaris-i2c", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_i2c_state), @@ -1368,7 +1368,7 @@ static void stellaris_gptm_class_init(ObjectClass *klass, void *data) sdc->init = stellaris_gptm_init; } -static TypeInfo stellaris_gptm_info = { +static const TypeInfo stellaris_gptm_info = { .name = "stellaris-gptm", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(gptm_state), @@ -1382,7 +1382,7 @@ static void stellaris_adc_class_init(ObjectClass *klass, void *data) sdc->init = stellaris_adc_init; } -static TypeInfo stellaris_adc_info = { +static const TypeInfo stellaris_adc_info = { .name = "stellaris-adc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_adc_state), diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index d7e1e21ff9..5e9053fa26 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -434,7 +434,7 @@ static void stellaris_enet_class_init(ObjectClass *klass, void *data) dc->props = stellaris_enet_properties; } -static TypeInfo stellaris_enet_info = { +static const TypeInfo stellaris_enet_info = { .name = "stellaris_enet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_enet_state), diff --git a/hw/stream.c b/hw/stream.c index be57e8b247..d4cf84d4c0 100644 --- a/hw/stream.c +++ b/hw/stream.c @@ -8,7 +8,7 @@ stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app) k->push(sink, buf, len, app); } -static TypeInfo stream_slave_info = { +static const TypeInfo stream_slave_info = { .name = TYPE_STREAM_SLAVE, .parent = TYPE_INTERFACE, .class_size = sizeof(StreamSlaveClass), diff --git a/hw/strongarm.c b/hw/strongarm.c index 804c1a37a6..af688ac4ca 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -212,7 +212,7 @@ static void strongarm_pic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_strongarm_pic_regs; } -static TypeInfo strongarm_pic_info = { +static const TypeInfo strongarm_pic_info = { .name = "strongarm_pic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPICState), @@ -433,7 +433,7 @@ static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_strongarm_rtc_regs; } -static TypeInfo strongarm_rtc_sysbus_info = { +static const TypeInfo strongarm_rtc_sysbus_info = { .name = "strongarm-rtc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMRTCState), @@ -674,7 +674,7 @@ static void strongarm_gpio_class_init(ObjectClass *klass, void *data) dc->desc = "StrongARM GPIO controller"; } -static TypeInfo strongarm_gpio_info = { +static const TypeInfo strongarm_gpio_info = { .name = "strongarm-gpio", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMGPIOInfo), @@ -840,7 +840,7 @@ static void strongarm_ppc_class_init(ObjectClass *klass, void *data) dc->desc = "StrongARM PPC controller"; } -static TypeInfo strongarm_ppc_info = { +static const TypeInfo strongarm_ppc_info = { .name = "strongarm-ppc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPPCInfo), @@ -1299,7 +1299,7 @@ static void strongarm_uart_class_init(ObjectClass *klass, void *data) dc->props = strongarm_uart_properties; } -static TypeInfo strongarm_uart_info = { +static const TypeInfo strongarm_uart_info = { .name = "strongarm-uart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMUARTState), @@ -1538,7 +1538,7 @@ static void strongarm_ssp_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_strongarm_ssp_regs; } -static TypeInfo strongarm_ssp_info = { +static const TypeInfo strongarm_ssp_info = { .name = "strongarm-ssp", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMSSPState), diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c index b78d54f232..f8f4d023a3 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -193,7 +193,7 @@ static void sun4c_intctl_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sun4c_intctl; } -static TypeInfo sun4c_intctl_info = { +static const TypeInfo sun4c_intctl_info = { .name = "sun4c_intctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Sun4c_INTCTLState), diff --git a/hw/sun4m.c b/hw/sun4m.c index 0d84b373b1..5925d292c3 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -633,7 +633,7 @@ static void idreg_class_init(ObjectClass *klass, void *data) k->init = idreg_init1; } -static TypeInfo idreg_info = { +static const TypeInfo idreg_info = { .name = "macio_idreg", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IDRegState), @@ -675,7 +675,7 @@ static void afx_class_init(ObjectClass *klass, void *data) k->init = afx_init1; } -static TypeInfo afx_info = { +static const TypeInfo afx_info = { .name = "tcx_afx", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(AFXState), @@ -752,7 +752,7 @@ static void prom_class_init(ObjectClass *klass, void *data) dc->props = prom_properties; } -static TypeInfo prom_info = { +static const TypeInfo prom_info = { .name = "openprom", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PROMState), @@ -816,7 +816,7 @@ static void ram_class_init(ObjectClass *klass, void *data) dc->props = ram_properties; } -static TypeInfo ram_info = { +static const TypeInfo ram_info = { .name = "memory", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RamDevice), diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index ce6819e10b..8f9635f343 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -373,7 +373,7 @@ static void iommu_class_init(ObjectClass *klass, void *data) dc->props = iommu_properties; } -static TypeInfo iommu_info = { +static const TypeInfo iommu_info = { .name = "iommu", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IOMMUState), diff --git a/hw/sun4u.c b/hw/sun4u.c index cbfd217587..3a06d70795 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -618,7 +618,7 @@ static void ebus_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_OTHER; } -static TypeInfo ebus_info = { +static const TypeInfo ebus_info = { .name = "ebus", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(EbusState), @@ -695,7 +695,7 @@ static void prom_class_init(ObjectClass *klass, void *data) dc->props = prom_properties; } -static TypeInfo prom_info = { +static const TypeInfo prom_info = { .name = "openprom", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PROMState), @@ -752,7 +752,7 @@ static void ram_class_init(ObjectClass *klass, void *data) dc->props = ram_properties; } -static TypeInfo ram_info = { +static const TypeInfo ram_info = { .name = "memory", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(RamDevice), diff --git a/hw/sysbus.c b/hw/sysbus.c index 49a41775f8..f0ab8a859a 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -255,7 +255,7 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data) k->bus_type = TYPE_SYSTEM_BUS; } -static TypeInfo sysbus_device_type_info = { +static const TypeInfo sysbus_device_type_info = { .name = TYPE_SYS_BUS_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(SysBusDevice), diff --git a/hw/tcx.c b/hw/tcx.c index 185588b49c..0ce2952f73 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -716,7 +716,7 @@ static void tcx_class_init(ObjectClass *klass, void *data) dc->props = tcx_properties; } -static TypeInfo tcx_info = { +static const TypeInfo tcx_info = { .name = "SUNW,tcx", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(TCXState), diff --git a/hw/tmp105.c b/hw/tmp105.c index 9c67e644dd..0ade4eb6bd 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -239,7 +239,7 @@ static void tmp105_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_tmp105; } -static TypeInfo tmp105_info = { +static const TypeInfo tmp105_info = { .name = "tmp105", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(TMP105State), diff --git a/hw/tosa.c b/hw/tosa.c index 6ee4693840..7048b797d3 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -270,7 +270,7 @@ static void tosa_dac_class_init(ObjectClass *klass, void *data) k->send = tosa_dac_send; } -static TypeInfo tosa_dac_info = { +static const TypeInfo tosa_dac_info = { .name = "tosa_dac", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(TosaDACState), @@ -285,7 +285,7 @@ static void tosa_ssp_class_init(ObjectClass *klass, void *data) k->transfer = tosa_ssp_tansfer; } -static TypeInfo tosa_ssp_info = { +static const TypeInfo tosa_ssp_info = { .name = "tosa-ssp", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(SSISlave), diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 990d50619d..7d05b31024 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -798,7 +798,7 @@ static void tusb6010_class_init(ObjectClass *klass, void *data) dc->reset = tusb6010_reset; } -static TypeInfo tusb6010_info = { +static const TypeInfo tusb6010_info = { .name = "tusb6010", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(TUSBState), diff --git a/hw/twl92230.c b/hw/twl92230.c index c71e4a2af0..70d9b03e55 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -867,7 +867,7 @@ static void twl92230_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_menelaus; } -static TypeInfo twl92230_info = { +static const TypeInfo twl92230_info = { .name = "twl92230", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(MenelausState), diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 180d1d739b..2dc76756a0 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -628,7 +628,7 @@ static void usb_device_class_init(ObjectClass *klass, void *data) k->props = usb_props; } -static TypeInfo usb_device_type_info = { +static const TypeInfo usb_device_type_info = { .name = TYPE_USB_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(USBDevice), diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index b669601c92..b8c79b85e9 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -684,7 +684,7 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) k->set_interface = usb_audio_set_interface; } -static TypeInfo usb_audio_info = { +static const TypeInfo usb_audio_info = { .name = "usb-audio", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBAudioState), diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index a0d7a88d91..adbf9d4697 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -555,7 +555,7 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_bt; } -static TypeInfo bt_info = { +static const TypeInfo bt_info = { .name = "usb-bt-dongle", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(struct USBBtState), diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index b4ace04eef..29b64819ab 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -657,7 +657,7 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) dc->props = usb_tablet_properties; } -static TypeInfo usb_tablet_info = { +static const TypeInfo usb_tablet_info = { .name = "usb-tablet", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHIDState), @@ -676,7 +676,7 @@ static void usb_mouse_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_ptr; } -static TypeInfo usb_mouse_info = { +static const TypeInfo usb_mouse_info = { .name = "usb-mouse", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHIDState), @@ -695,7 +695,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_kbd; } -static TypeInfo usb_keyboard_info = { +static const TypeInfo usb_keyboard_info = { .name = "usb-kbd", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHIDState), diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 470fbbb86c..79f2f46d55 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -568,7 +568,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_hub; } -static TypeInfo hub_info = { +static const TypeInfo hub_info = { .name = "usb-hub", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHubState), diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 1c54863452..9dede4c68d 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1433,7 +1433,7 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data) dc->props = net_properties; } -static TypeInfo net_info = { +static const TypeInfo net_info = { .name = "usb-net", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBNetState), diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 20cf5337b7..47ac8c9b69 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -600,7 +600,7 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data) dc->props = serial_properties; } -static TypeInfo serial_info = { +static const TypeInfo serial_info = { .name = "usb-serial", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBSerialState), @@ -628,7 +628,7 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data) dc->props = braille_properties; } -static TypeInfo braille_info = { +static const TypeInfo braille_info = { .name = "usb-braille", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBSerialState), diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index f26bb341f7..979a473b37 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1322,7 +1322,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data) dc->props = ccid_properties; } -static TypeInfo ccid_info = { +static const TypeInfo ccid_info = { .name = CCID_DEV_NAME, .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBCCIDState), @@ -1338,7 +1338,7 @@ static void ccid_card_class_init(ObjectClass *klass, void *data) k->props = ccid_props; } -static TypeInfo ccid_card_type_info = { +static const TypeInfo ccid_card_type_info = { .name = TYPE_CCID_CARD, .parent = TYPE_DEVICE, .instance_size = sizeof(CCIDCardState), diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 5025597673..1b87352db0 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -716,7 +716,7 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data) dc->props = msd_properties; } -static TypeInfo msd_info = { +static const TypeInfo msd_info = { .name = "usb-storage", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(MSDState), diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 9a0088928f..d904d1a40b 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -757,7 +757,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_uas; } -static TypeInfo uas_info = { +static const TypeInfo uas_info = { .name = "usb-uas", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(UASDevice), diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 9ab368a6c5..ab9fa2ef48 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -366,7 +366,7 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_wacom; } -static TypeInfo wacom_info = { +static const TypeInfo wacom_info = { .name = "usb-wacom-tablet", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBWacomState), diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 29bafa6da9..6a2f5f8c5d 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1909,7 +1909,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) dc->props = ohci_pci_properties; } -static TypeInfo ohci_pci_info = { +static const TypeInfo ohci_pci_info = { .name = "pci-ohci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(OHCIPCIState), @@ -1932,7 +1932,7 @@ static void ohci_sysbus_class_init(ObjectClass *klass, void *data) dc->props = ohci_sysbus_properties; } -static TypeInfo ohci_sysbus_info = { +static const TypeInfo ohci_sysbus_info = { .name = "sysbus-ohci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OHCISysBusState), diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 9132920932..92f2eee3bc 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3182,7 +3182,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) k->no_hotplug = 1; } -static TypeInfo xhci_info = { +static const TypeInfo xhci_info = { .name = "nec-usb-xhci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(XHCIState), diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index 340c21aeb4..172aecbffd 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -407,7 +407,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->handle_destroy = usb_host_handle_destroy; } -static TypeInfo usb_host_dev_info = { +static const TypeInfo usb_host_dev_info = { .name = "usb-host", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHostDevice), diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index 669fbd245c..e8e6a42fb9 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1534,7 +1534,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) dc->props = usb_host_dev_properties; } -static TypeInfo usb_host_dev_info = { +static const TypeInfo usb_host_dev_info = { .name = "usb-host", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBHostDevice), diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index f1bf84c987..8c0ead07c5 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2341,7 +2341,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) dc->props = usbredir_properties; } -static TypeInfo usbredir_dev_info = { +static const TypeInfo usbredir_dev_info = { .name = "usb-redir", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBRedirDevice), diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 1f4d66934c..9d991599cf 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -119,7 +119,7 @@ static void versatile_pci_host_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_PROCESSOR_CO; } -static TypeInfo versatile_pci_host_info = { +static const TypeInfo versatile_pci_host_info = { .name = "versatile_pci_host", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), @@ -133,7 +133,7 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data) sdc->init = pci_vpb_init; } -static TypeInfo pci_vpb_info = { +static const TypeInfo pci_vpb_info = { .name = "versatile_pci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PCIVPBState), @@ -147,7 +147,7 @@ static void pci_realview_class_init(ObjectClass *klass, void *data) sdc->init = pci_realview_init; } -static TypeInfo pci_realview_info = { +static const TypeInfo pci_realview_info = { .name = "realview_pci", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PCIVPBState), diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 5e89e747a2..bf72ebb305 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -386,7 +386,7 @@ static void vpb_sic_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_vpb_sic; } -static TypeInfo vpb_sic_info = { +static const TypeInfo vpb_sic_info = { .name = "versatilepb_sic", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(vpb_sic_state), diff --git a/hw/vga-isa.c b/hw/vga-isa.c index cbe7b05a7e..762e45aaeb 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -86,7 +86,7 @@ static void vga_class_initfn(ObjectClass *klass, void *data) dc->props = vga_isa_properties; } -static TypeInfo vga_info = { +static const TypeInfo vga_info = { .name = "isa-vga", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAVGAState), diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 87c7c0648d..c491af20e4 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -200,7 +200,7 @@ static void vga_class_init(ObjectClass *klass, void *data) dc->props = vga_pci_properties; } -static TypeInfo vga_info = { +static const TypeInfo vga_info = { .name = "VGA", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIVGAState), diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 002b028b99..46072a086f 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -142,7 +142,7 @@ static void virtconsole_class_init(ObjectClass *klass, void *data) dc->props = virtconsole_properties; } -static TypeInfo virtconsole_info = { +static const TypeInfo virtconsole_info = { .name = "virtconsole", .parent = TYPE_VIRTIO_SERIAL_PORT, .instance_size = sizeof(VirtConsole), @@ -166,7 +166,7 @@ static void virtserialport_class_init(ObjectClass *klass, void *data) dc->props = virtserialport_properties; } -static TypeInfo virtserialport_info = { +static const TypeInfo virtserialport_info = { .name = "virtserialport", .parent = TYPE_VIRTIO_SERIAL_PORT, .instance_size = sizeof(VirtConsole), diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index c7f0c4d4ed..08d2d1ba82 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -961,7 +961,7 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data) dc->props = virtio_blk_properties; } -static TypeInfo virtio_blk_info = { +static const TypeInfo virtio_blk_info = { .name = "virtio-blk-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -995,7 +995,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) dc->props = virtio_net_properties; } -static TypeInfo virtio_net_info = { +static const TypeInfo virtio_net_info = { .name = "virtio-net-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1026,7 +1026,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) dc->props = virtio_serial_properties; } -static TypeInfo virtio_serial_info = { +static const TypeInfo virtio_serial_info = { .name = "virtio-serial-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1054,7 +1054,7 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data) dc->props = virtio_balloon_properties; } -static TypeInfo virtio_balloon_info = { +static const TypeInfo virtio_balloon_info = { .name = "virtio-balloon-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1097,7 +1097,7 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) dc->props = virtio_rng_properties; } -static TypeInfo virtio_rng_info = { +static const TypeInfo virtio_rng_info = { .name = "virtio-rng-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), @@ -1155,7 +1155,7 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) dc->props = virtio_scsi_properties; } -static TypeInfo virtio_scsi_info = { +static const TypeInfo virtio_scsi_info = { .name = "virtio-scsi-pci", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VirtIOPCIProxy), diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 7272bfd5fe..aa7d0d7fc7 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -1058,7 +1058,7 @@ static void virtio_serial_port_class_init(ObjectClass *klass, void *data) k->props = virtser_props; } -static TypeInfo virtio_serial_port_type_info = { +static const TypeInfo virtio_serial_port_type_info = { .name = TYPE_VIRTIO_SERIAL_PORT, .parent = TYPE_DEVICE, .instance_size = sizeof(VirtIOSerialPort), diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 004d09851c..b9afc2c4e8 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -286,7 +286,7 @@ static void vmmouse_class_initfn(ObjectClass *klass, void *data) dc->props = vmmouse_properties; } -static TypeInfo vmmouse_info = { +static const TypeInfo vmmouse_info = { .name = "vmmouse", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(VMMouseState), diff --git a/hw/vmport.c b/hw/vmport.c index 7d425237ac..faead3a955 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -155,7 +155,7 @@ static void vmport_class_initfn(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo vmport_info = { +static const TypeInfo vmport_info = { .name = "vmport", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(VMPortState), diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index b0e772f863..62771bb7b5 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1244,7 +1244,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data) dc->props = vga_vmware_properties; } -static TypeInfo vmsvga_info = { +static const TypeInfo vmsvga_info = { .name = "vmware-svga", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(struct pci_vmsvga_state_s), diff --git a/hw/vt82c686.c b/hw/vt82c686.c index d3469d49f1..2d8e3988db 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -284,7 +284,7 @@ static void via_ac97_class_init(ObjectClass *klass, void *data) dc->desc = "AC97"; } -static TypeInfo via_ac97_info = { +static const TypeInfo via_ac97_info = { .name = "VT82C686B_AC97", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686AC97State), @@ -325,7 +325,7 @@ static void via_mc97_class_init(ObjectClass *klass, void *data) dc->desc = "MC97"; } -static TypeInfo via_mc97_info = { +static const TypeInfo via_mc97_info = { .name = "VT82C686B_MC97", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686MC97State), @@ -404,7 +404,7 @@ static void via_pm_class_init(ObjectClass *klass, void *data) dc->props = via_pm_properties; } -static TypeInfo via_pm_info = { +static const TypeInfo via_pm_info = { .name = "VT82C686B_PM", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT686PMState), @@ -471,7 +471,7 @@ static void via_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_via; } -static TypeInfo via_info = { +static const TypeInfo via_info = { .name = "VT82C686B", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VT82C686BState), diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 54f0665135..37ce362811 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -439,7 +439,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_i6300esb; } -static TypeInfo i6300esb_info = { +static const TypeInfo i6300esb_info = { .name = "i6300esb", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(I6300State), diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index 4475f7b862..599a86f5f6 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -129,7 +129,7 @@ static void wdt_ib700_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_ib700; } -static TypeInfo wdt_ib700_info = { +static const TypeInfo wdt_ib700_info = { .name = "ib700", .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(IB700State), diff --git a/hw/wm8750.c b/hw/wm8750.c index 44f138fd51..bb85064c9b 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -701,7 +701,7 @@ static void wm8750_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_wm8750; } -static TypeInfo wm8750_info = { +static const TypeInfo wm8750_info = { .name = "wm8750", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(WM8750State), diff --git a/hw/xen_apic.c b/hw/xen_apic.c index a6632fe798..1d1d15c289 100644 --- a/hw/xen_apic.c +++ b/hw/xen_apic.c @@ -80,7 +80,7 @@ static void xen_apic_class_init(ObjectClass *klass, void *data) k->external_nmi = xen_apic_external_nmi; } -static TypeInfo xen_apic_info = { +static const TypeInfo xen_apic_info = { .name = "xen-apic", .parent = TYPE_APIC_COMMON, .instance_size = sizeof(APICCommonState), diff --git a/hw/xen_platform.c b/hw/xen_platform.c index e7611bb353..ca66047d82 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -420,7 +420,7 @@ static void xen_platform_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xen_platform; } -static TypeInfo xen_platform_info = { +static const TypeInfo xen_platform_info = { .name = "xen-platform", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIXenPlatformState), diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 6fd8433a2d..9db5f6e964 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -829,7 +829,7 @@ static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data) dc->props = xen_pci_passthrough_properties; }; -static TypeInfo xen_pci_passthrough_info = { +static const TypeInfo xen_pci_passthrough_info = { .name = "xen-pci-passthrough", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(XenPCIPassthroughState), diff --git a/hw/xgmac.c b/hw/xgmac.c index 9639b6141b..00dae7789c 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -418,7 +418,7 @@ static void xgmac_enet_class_init(ObjectClass *klass, void *data) dc->props = xgmac_properties; } -static TypeInfo xgmac_enet_info = { +static const TypeInfo xgmac_enet_info = { .name = "xgmac", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XgmacState), diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index ce02764b3f..d0ee566a28 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -503,7 +503,7 @@ static void axidma_class_init(ObjectClass *klass, void *data) ssc->push = axidma_push; } -static TypeInfo axidma_info = { +static const TypeInfo axidma_info = { .name = "xlnx.axi-dma", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XilinxAXIDMA), diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 09e49b0aee..51c2896e44 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -893,7 +893,7 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data) ssc->push = axienet_stream_push; } -static TypeInfo xilinx_enet_info = { +static const TypeInfo xilinx_enet_info = { .name = "xlnx.axi-ethernet", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct XilinxAXIEnet), diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 4de4a53a0b..2254851f0a 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -243,7 +243,7 @@ static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) dc->props = xilinx_ethlite_properties; } -static TypeInfo xilinx_ethlite_info = { +static const TypeInfo xilinx_ethlite_info = { .name = "xlnx.xps-ethernetlite", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_ethlite), diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index 7765079802..0c34149c27 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -175,7 +175,7 @@ static void xilinx_intc_class_init(ObjectClass *klass, void *data) dc->props = xilinx_intc_properties; } -static TypeInfo xilinx_intc_info = { +static const TypeInfo xilinx_intc_info = { .name = "xlnx.xps-intc", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct xlx_pic), diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c index 77f9178008..be581c2ac5 100644 --- a/hw/xilinx_spi.c +++ b/hw/xilinx_spi.c @@ -370,7 +370,7 @@ static void xilinx_spi_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xilinx_spi; } -static TypeInfo xilinx_spi_info = { +static const TypeInfo xilinx_spi_info = { .name = "xlnx.xps-spi", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(XilinxSPI), diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index 69294bb83c..aa162efaad 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -240,7 +240,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) dc->props = xilinx_timer_properties; } -static TypeInfo xilinx_timer_info = { +static const TypeInfo xilinx_timer_info = { .name = "xlnx.xps-timer", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct timerblock), diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index abd256ae00..9963982ef6 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -216,7 +216,7 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) sdc->init = xilinx_uartlite_init; } -static TypeInfo xilinx_uartlite_info = { +static const TypeInfo xilinx_uartlite_info = { .name = "xlnx.xps-uartlite", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof (struct xlx_uartlite), diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 2dcd46bff1..7f00bc8256 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -193,7 +193,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) dc->props = xio3130_downstream_properties; } -static TypeInfo xio3130_downstream_info = { +static const TypeInfo xio3130_downstream_info = { .name = "xio3130-downstream", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIESlot), diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 713caf2dda..70b15d37c8 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -167,7 +167,7 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data) dc->props = xio3130_upstream_properties; } -static TypeInfo xio3130_upstream_info = { +static const TypeInfo xio3130_upstream_info = { .name = "x3130-upstream", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIEPort), diff --git a/hw/z2.c b/hw/z2.c index 09b03687d1..496e47df6c 100644 --- a/hw/z2.c +++ b/hw/z2.c @@ -185,7 +185,7 @@ static void zipit_lcd_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_zipit_lcd_state; } -static TypeInfo zipit_lcd_info = { +static const TypeInfo zipit_lcd_info = { .name = "zipit-lcd", .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ZipitLCD), @@ -288,7 +288,7 @@ static void aer915_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_aer915_state; } -static TypeInfo aer915_info = { +static const TypeInfo aer915_info = { .name = "aer915", .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(AER915State), diff --git a/hw/zaurus.c b/hw/zaurus.c index d77b34ecce..2defe3b48d 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -236,7 +236,7 @@ static void scoop_sysbus_class_init(ObjectClass *klass, void *data) dc->props = scoop_sysbus_properties; } -static TypeInfo scoop_sysbus_info = { +static const TypeInfo scoop_sysbus_info = { .name = "scoop", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ScoopInfo), diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 143a7cf436..4d6f8d9001 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -521,7 +521,7 @@ static void zynq_slcr_class_init(ObjectClass *klass, void *data) dc->reset = zynq_slcr_reset; } -static TypeInfo zynq_slcr_info = { +static const TypeInfo zynq_slcr_info = { .class_init = zynq_slcr_class_init, .name = "xilinx,zynq_slcr", .parent = TYPE_SYS_BUS_DEVICE, diff --git a/include/qom/object.h b/include/qom/object.h index abe9691cb7..d43b289a40 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -65,7 +65,7 @@ typedef struct InterfaceInfo InterfaceInfo; * int reg0, reg1, reg2; * } MyDevice; * - * static TypeInfo my_device_info = { + * static const TypeInfo my_device_info = { * .name = TYPE_MY_DEVICE, * .parent = TYPE_DEVICE, * .instance_size = sizeof(MyDevice), @@ -138,7 +138,7 @@ typedef struct InterfaceInfo InterfaceInfo; * dc->reset = my_device_reset; * } * - * static TypeInfo my_device_info = { + * static const TypeInfo my_device_info = { * .name = TYPE_MY_DEVICE, * .parent = TYPE_DEVICE, * .instance_size = sizeof(MyDevice), @@ -163,7 +163,7 @@ typedef struct InterfaceInfo InterfaceInfo; * void (*frobnicate) (MyDevice *obj); * } MyDeviceClass; * - * static TypeInfo my_device_info = { + * static const TypeInfo my_device_info = { * .name = TYPE_MY_DEVICE, * .parent = TYPE_DEVICE, * .instance_size = sizeof(MyDevice), diff --git a/qom/container.c b/qom/container.c index 5270a5ee9c..62b1648add 100644 --- a/qom/container.c +++ b/qom/container.c @@ -14,7 +14,7 @@ #include "qemu/module.h" #include -static TypeInfo container_info = { +static const TypeInfo container_info = { .name = "container", .instance_size = sizeof(Object), .parent = TYPE_OBJECT, From d0508c3664290baad379f6513c92cae6e5aac95b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Jan 2013 15:49:07 +0100 Subject: [PATCH 0369/1634] qdev: add qbus_reset_all Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev-core.h | 12 ++++++++++++ hw/qdev.c | 7 ++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/hw/qdev-core.h b/hw/qdev-core.h index fdf14ec4a6..853bd08a1f 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -182,6 +182,18 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, qbus_walkerfn *busfn, void *opaque); void qdev_reset_all(DeviceState *dev); + +/** + * @qbus_reset_all: + * @bus: Bus to be reset. + * + * Reset @bus and perform a bus-level ("hard") reset of all devices connected + * to it, including recursive processing of all buses below @bus itself. A + * hard reset means that qbus_reset_all will reset all state of the device. + * For PCI devices, for example, this will include the base address registers + * or configuration space. + */ +void qbus_reset_all(BusState *bus); void qbus_reset_all_fn(void *opaque); void qbus_free(BusState *bus); diff --git a/hw/qdev.c b/hw/qdev.c index b027ead598..1b68d0234a 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -228,10 +228,15 @@ void qdev_reset_all(DeviceState *dev) qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL); } +void qbus_reset_all(BusState *bus) +{ + qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL); +} + void qbus_reset_all_fn(void *opaque) { BusState *bus = opaque; - qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL); + qbus_reset_all(bus); } /* can be used as ->unplug() callback for the simple cases */ From 47a150a4bbb06e45ef439a8222e9f46a7c4cca3f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Jan 2013 15:49:08 +0100 Subject: [PATCH 0370/1634] virtio-scsi: abort in-flight I/O when the device is reset When the device is reset, the SCSI bus should also be reset so that in-flight I/O is cancelled. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/virtio-scsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index bfe1860505..0715865489 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -565,6 +565,10 @@ static void virtio_scsi_reset(VirtIODevice *vdev) { VirtIOSCSI *s = (VirtIOSCSI *)vdev; + s->resetting++; + qbus_reset_all(&s->bus.qbus); + s->resetting--; + s->sense_size = VIRTIO_SCSI_SENSE_SIZE; s->cdb_size = VIRTIO_SCSI_CDB_SIZE; s->events_dropped = false; From 8b07eaa110df41b027ee62cbf3549cc3e48ec147 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 8 Jan 2013 09:25:16 +0100 Subject: [PATCH 0371/1634] q35: add ich9 intel hda controller Signed-off-by: Gerd Hoffmann --- hw/intel-hda.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 98ff93679d..eed1d384fc 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -1232,7 +1232,7 @@ static Property intel_hda_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void intel_hda_class_init(ObjectClass *klass, void *data) +static void intel_hda_class_init_common(ObjectClass *klass) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1240,20 +1240,46 @@ static void intel_hda_class_init(ObjectClass *klass, void *data) k->init = intel_hda_init; k->exit = intel_hda_exit; k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = 0x2668; - k->revision = 1; k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO; - dc->desc = "Intel HD Audio Controller"; dc->reset = intel_hda_reset; dc->vmsd = &vmstate_intel_hda; dc->props = intel_hda_properties; } -static TypeInfo intel_hda_info = { +static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + intel_hda_class_init_common(klass); + k->device_id = 0x2668; + k->revision = 1; + dc->desc = "Intel HD Audio Controller (ich6)"; +} + +static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + intel_hda_class_init_common(klass); + k->device_id = 0x293e; + k->revision = 3; + dc->desc = "Intel HD Audio Controller (ich9)"; +} + +static TypeInfo intel_hda_info_ich6 = { .name = "intel-hda", .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IntelHDAState), - .class_init = intel_hda_class_init, + .class_init = intel_hda_class_init_ich6, +}; + +static TypeInfo intel_hda_info_ich9 = { + .name = "ich9-intel-hda", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(IntelHDAState), + .class_init = intel_hda_class_init_ich9, }; static void hda_codec_device_class_init(ObjectClass *klass, void *data) @@ -1277,7 +1303,8 @@ static TypeInfo hda_codec_device_type_info = { static void intel_hda_register_types(void) { type_register_static(&hda_codec_bus_info); - type_register_static(&intel_hda_info); + type_register_static(&intel_hda_info_ich6); + type_register_static(&intel_hda_info_ich9); type_register_static(&hda_codec_device_type_info); } From 7d9f7b51cc62ec23ac72e3338165a2f3007631a2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 8 Jan 2013 09:38:19 +0100 Subject: [PATCH 0372/1634] q35: document chipset devices Signed-off-by: Gerd Hoffmann --- docs/q35-chipset.cfg | 129 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 docs/q35-chipset.cfg diff --git a/docs/q35-chipset.cfg b/docs/q35-chipset.cfg new file mode 100644 index 0000000000..1b6efc0f2c --- /dev/null +++ b/docs/q35-chipset.cfg @@ -0,0 +1,129 @@ +################################################################ +# +# qemu -M q35 creates a bare machine with just the very essential +# chipset devices being present: +# +# 00.0 - Host bridge +# 1f.0 - ISA bridge / LPC +# 1f.2 - SATA (AHCI) controller +# 1f.3 - SMBus controller +# +# This config file documents the other devices and how they are +# created. You can simply use "-readconfig $thisfile" to create +# them all. Here is a overview: +# +# 19.0 - Ethernet controller (not created, our e1000 emulation +# doesn't emulate the ich9 device). +# 1a.* - USB Controller #2 (ehci + uhci companions) +# 1b.0 - HD Audio Controller +# 1c.* - PCI Express Ports +# 1d.* - USB Controller #1 (ehci + uhci companions, +# "qemu -M q35 -usb" creates these too) +# 1e.0 - PCI Bridge +# + +[device "ich9-ehci-2"] + driver = "ich9-usb-ehci2" + multifunction = "on" + bus = "pcie.0" + addr = "1a.7" + +[device "ich9-uhci-4"] + driver = "ich9-usb-uhci4" + multifunction = "on" + bus = "pcie.0" + addr = "1a.0" + masterbus = "ich9-ehci-2.0" + firstport = "0" + +[device "ich9-uhci-5"] + driver = "ich9-usb-uhci5" + multifunction = "on" + bus = "pcie.0" + addr = "1a.1" + masterbus = "ich9-ehci-2.0" + firstport = "2" + +[device "ich9-uhci-6"] + driver = "ich9-usb-uhci6" + multifunction = "on" + bus = "pcie.0" + addr = "1a.2" + masterbus = "ich9-ehci-2.0" + firstport = "4" + + +[device "ich9-hda-audio"] + driver = "ich9-intel-hda" + bus = "pcie.0" + addr = "1b.0" + + +[device "ich9-pcie-port-1"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.0" + port = "1" + chassis = "1" + +[device "ich9-pcie-port-2"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.1" + port = "2" + chassis = "2" + +[device "ich9-pcie-port-3"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.2" + port = "3" + chassis = "3" + +[device "ich9-pcie-port-4"] + driver = "ioh3420" + multifunction = "on" + bus = "pcie.0" + addr = "1c.3" + port = "4" + chassis = "4" + + +[device "ich9-ehci-1"] + driver = "ich9-usb-ehci1" + multifunction = "on" + bus = "pcie.0" + addr = "1d.7" + +[device "ich9-uhci-1"] + driver = "ich9-usb-uhci1" + multifunction = "on" + bus = "pcie.0" + addr = "1d.0" + masterbus = "ich9-ehci-1.0" + firstport = "0" + +[device "ich9-uhci-2"] + driver = "ich9-usb-uhci2" + multifunction = "on" + bus = "pcie.0" + addr = "1d.1" + masterbus = "ich9-ehci-1.0" + firstport = "2" + +[device "ich9-uhci-3"] + driver = "ich9-usb-uhci3" + multifunction = "on" + bus = "pcie.0" + addr = "1d.2" + masterbus = "ich9-ehci-1.0" + firstport = "4" + + +[device "ich9-pci-bridge"] + driver = "i82801b11-bridge" + bus = "pcie.0" + addr = "1e.0" From 94dec5948aeb240c7e324ce9ecffeb3e066c1b69 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 8 Jan 2013 08:53:13 +0100 Subject: [PATCH 0373/1634] pc: rename machine types Starting with release 1.4 we have a fully functional q35 machine type, i.e. "qemu -M q35" JustWorks[tm]. Update machine type names to reflect that: * pc-1.4 becomes pc-i440fx-1.4 * q35-next becomes pc-q35-1.4 The pc-1.3 (+older) names are maintained for compatibility reasons. For the same reason the "pc" and "q35" aliases are kept. pc-piix-1.4 continues to be the default machine type, again for compatibility reasons. Also updated the description (shown by "qemu -M ?") with host bridge name, south bridge name and chipset release year. Signed-off-by: Gerd Hoffmann --- hw/pc_piix.c | 8 ++++---- hw/pc_q35.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 2b3d58b852..e630aeab9d 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -282,10 +282,10 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) } #endif -static QEMUMachine pc_machine_v1_4 = { - .name = "pc-1.4", +static QEMUMachine pc_i440fx_machine_v1_4 = { + .name = "pc-i440fx-1.4", .alias = "pc", - .desc = "Standard PC", + .desc = "Standard PC (i440FX + PIIX, 1996)", .init = pc_init_pci_1_3, .max_cpus = 255, .is_default = 1, @@ -646,7 +646,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { - qemu_register_machine(&pc_machine_v1_4); + qemu_register_machine(&pc_i440fx_machine_v1_4); qemu_register_machine(&pc_machine_v1_3); qemu_register_machine(&pc_machine_v1_2); qemu_register_machine(&pc_machine_v1_1); diff --git a/hw/pc_q35.c b/hw/pc_q35.c index ef540b6a71..52d997613f 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -209,9 +209,9 @@ static void pc_q35_init(QEMUMachineInitArgs *args) } static QEMUMachine pc_q35_machine = { - .name = "q35-next", + .name = "pc-q35-1.4", .alias = "q35", - .desc = "Q35 chipset PC", + .desc = "Standard PC (Q35 + ICH9, 2009)", .init = pc_q35_init, .max_cpus = 255, }; From 7e973bb2e17f929f47376a3872f7ccdff25a51ab Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Tue, 8 Jan 2013 19:52:20 +0100 Subject: [PATCH 0374/1634] Makefile: install the "acpi-dsdt.aml" and "q35-acpi-dsdt.aml" blobs too The WARNING message from commit f7e4dd6c made me notice. Signed-off-by: Laszlo Ersek Signed-off-by: Gerd Hoffmann --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index ee06448e28..0200bf345c 100644 --- a/Makefile +++ b/Makefile @@ -280,6 +280,7 @@ bepo ifdef INSTALL_BLOBS BLOBS=bios.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \ vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \ +acpi-dsdt.aml q35-acpi-dsdt.aml \ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \ From 75f13596452692fb7375ee558e9fb37cd649e603 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 5 Jan 2013 12:17:38 +0100 Subject: [PATCH 0375/1634] configure: Fix comment (copy+paste bug) Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index fe18ed2b25..148d5aa052 100755 --- a/configure +++ b/configure @@ -2705,7 +2705,7 @@ if compile_prog "" "" ; then byteswap_h=yes fi -# Search for bswap_32 function +# Search for bswap32 function bswap_h=no cat > $TMPC << EOF #include From 1d57db193f2eb619ccc9a60e76120379b757d9f2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 7 Jan 2013 17:29:55 +0000 Subject: [PATCH 0376/1634] qga/channel-posix.c: Explicitly include string.h Explicitly include string.h to avoid warnings under MacOS X/clang about implicit declarations of strerror() and strlen(). Signed-off-by: Peter Maydell Reviewed-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- qga/channel-posix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qga/channel-posix.c b/qga/channel-posix.c index d4fd628907..ca9e4aaaf9 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "qemu/osdep.h" #include "qemu/sockets.h" #include "qga/channel.h" From 68b891ec3937aa2e18eed5a403b1d9fd9b875084 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 7 Jan 2013 22:20:27 +0100 Subject: [PATCH 0377/1634] savevm: Remove MinGW specific code which is no longer needed QEMU provides a portable function qemu_gettimeofday instead of gettimeofday and also an implementation of localtime_r for MinGW. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- savevm.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/savevm.c b/savevm.c index 529d60ec1f..4e970ca0db 100644 --- a/savevm.c +++ b/savevm.c @@ -23,15 +23,6 @@ */ #include "config-host.h" - -#ifndef _WIN32 -#include -#endif - -#ifdef _WIN32 -#include -#endif - #include "qemu-common.h" #include "hw/hw.h" #include "hw/qdev.h" @@ -2093,13 +2084,8 @@ void do_savevm(Monitor *mon, const QDict *qdict) QEMUFile *f; int saved_vm_running; uint64_t vm_state_size; -#ifdef _WIN32 - struct _timeb tb; - struct tm *ptm; -#else - struct timeval tv; + qemu_timeval tv; struct tm tm; -#endif const char *name = qdict_get_try_str(qdict, "name"); /* Verify if there is a device that doesn't support snapshots and is writable */ @@ -2129,15 +2115,9 @@ void do_savevm(Monitor *mon, const QDict *qdict) memset(sn, 0, sizeof(*sn)); /* fill auxiliary fields */ -#ifdef _WIN32 - _ftime(&tb); - sn->date_sec = tb.time; - sn->date_nsec = tb.millitm * 1000000; -#else - gettimeofday(&tv, NULL); + qemu_gettimeofday(&tv); sn->date_sec = tv.tv_sec; sn->date_nsec = tv.tv_usec * 1000; -#endif sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); if (name) { @@ -2149,15 +2129,9 @@ void do_savevm(Monitor *mon, const QDict *qdict) pstrcpy(sn->name, sizeof(sn->name), name); } } else { -#ifdef _WIN32 - time_t t = tb.time; - ptm = localtime(&t); - strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm); -#else /* cast below needed for OpenBSD where tv_sec is still 'long' */ localtime_r((const time_t *)&tv.tv_sec, &tm); strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm); -#endif } /* Delete old snapshots of the same name */ From eb7ff6fb0bddb33991fa44586ac8e2e02019dc97 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 7 Jan 2013 23:08:13 +0100 Subject: [PATCH 0378/1634] Replace remaining gmtime, localtime by gmtime_r, localtime_r MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows removing of MinGW specific code and improves reentrancy for POSIX hosts. [Removed unused ret variable in qemu_get_timedate() to fix warning: vl.c: In function ‘qemu_get_timedate’: vl.c:451:16: error: variable ‘ret’ set but not used [-Werror=unused-but-set-variable] -- Stefan Hajnoczi] Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- block.c | 10 ---------- block/vvfat.c | 4 ---- hw/omap1.c | 2 +- vl.c | 9 +++------ 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/block.c b/block.c index 4e28c55bc7..60873eafea 100644 --- a/block.c +++ b/block.c @@ -3338,11 +3338,7 @@ char *get_human_readable_size(char *buf, int buf_size, int64_t size) char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) { char buf1[128], date_buf[128], clock_buf[128]; -#ifdef _WIN32 - struct tm *ptm; -#else struct tm tm; -#endif time_t ti; int64_t secs; @@ -3352,15 +3348,9 @@ char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn) "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); } else { ti = sn->date_sec; -#ifdef _WIN32 - ptm = localtime(&ti); - strftime(date_buf, sizeof(date_buf), - "%Y-%m-%d %H:%M:%S", ptm); -#else localtime_r(&ti, &tm); strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm); -#endif secs = sn->vm_clock_nsec / 1000000000; snprintf(clock_buf, sizeof(clock_buf), "%02d:%02d:%02d.%03d", diff --git a/block/vvfat.c b/block/vvfat.c index 83706ce556..06e6654824 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -529,13 +529,9 @@ static inline uint8_t fat_chksum(const direntry_t* entry) /* if return_time==0, this returns the fat_date, else the fat_time */ static uint16_t fat_datetime(time_t time,int return_time) { struct tm* t; -#ifdef _WIN32 - t=localtime(&time); /* this is not thread safe */ -#else struct tm t1; t = &t1; localtime_r(&time,t); -#endif if(return_time) return cpu_to_le16((t->tm_sec/2)|(t->tm_min<<5)|(t->tm_hour<<11)); return cpu_to_le16((t->tm_mday)|((t->tm_mon+1)<<5)|((t->tm_year-80)<<9)); diff --git a/hw/omap1.c b/hw/omap1.c index 8536e96687..e85f2e2423 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -2830,7 +2830,7 @@ static void omap_rtc_tick(void *opaque) s->round = 0; } - memcpy(&s->current_tm, localtime(&s->ti), sizeof(s->current_tm)); + localtime_r(&s->ti, &s->current_tm); if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) { s->status |= 0x40; diff --git a/vl.c b/vl.c index f056c95807..aed4182ae8 100644 --- a/vl.c +++ b/vl.c @@ -448,21 +448,18 @@ StatusInfo *qmp_query_status(Error **errp) void qemu_get_timedate(struct tm *tm, int offset) { time_t ti; - struct tm *ret; time(&ti); ti += offset; if (rtc_date_offset == -1) { if (rtc_utc) - ret = gmtime(&ti); + gmtime_r(&ti, tm); else - ret = localtime(&ti); + localtime_r(&ti, tm); } else { ti -= rtc_date_offset; - ret = gmtime(&ti); + gmtime_r(&ti, tm); } - - memcpy(tm, ret, sizeof(struct tm)); } int qemu_timedate_diff(struct tm *tm) From c02e1eac887b1b0aee7361b1fcf889e7d47fed9d Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Wed, 9 Jan 2013 18:10:22 +0000 Subject: [PATCH 0379/1634] hw/pc.c: Fix converting of ioport_register* to MemoryRegion The commit 258711 introduced MemoryRegion to replace ioport_region* for ioport 80h and F0h. A MemoryRegion needs to have both read and write callback otherwise a segfault will occur when an access is made. The previous behaviour of this both ioport is to return 0xffffffffffffffff. So keep this behaviour. Reported-by: Adam Lackorzynski Signed-off-by: Julien Grall Tested-by: Adam Lackorzynski Signed-off-by: Stefan Hajnoczi --- hw/pc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/pc.c b/hw/pc.c index df0c48e41b..90b1bf76d6 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -103,6 +103,11 @@ static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, { } +static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0xffffffffffffffff; +} + /* MSDOS compatibility mode FPU exception support */ static qemu_irq ferr_irq; @@ -123,6 +128,11 @@ static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, qemu_irq_lower(ferr_irq); } +static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0xffffffffffffffff; +} + /* TSC handling */ uint64_t cpu_get_tsc(CPUX86State *env) { @@ -960,6 +970,7 @@ static void cpu_request_exit(void *opaque, int irq, int level) static const MemoryRegionOps ioport80_io_ops = { .write = ioport80_write, + .read = ioport80_read, .endianness = DEVICE_NATIVE_ENDIAN, .impl = { .min_access_size = 1, @@ -969,6 +980,7 @@ static const MemoryRegionOps ioport80_io_ops = { static const MemoryRegionOps ioportF0_io_ops = { .write = ioportF0_write, + .read = ioportF0_read, .endianness = DEVICE_NATIVE_ENDIAN, .impl = { .min_access_size = 1, From 918fd0839eeafc83bd4984364321a947d29041fe Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 11 Jan 2013 15:21:22 +0000 Subject: [PATCH 0380/1634] target-arm: use type_register() instead of type_register_static() The type_register_static() interface is documented as: type_register_static: @info: The #TypeInfo of the new type. @info and all of the strings it points to should exist for the life time that the type is registered. But cpu_register() uses a stack variable for the 'info' argument, so it has to use type_register() instead of type_register_static(). Signed-off-by: Eduardo Habkost Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 17875ed0f0..94536bb0cc 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -778,7 +778,7 @@ static void cpu_register(const ARMCPUInfo *info) .class_size = sizeof(ARMCPUClass), }; - type_register_static(&type_info); + type_register(&type_info); } static const TypeInfo arm_cpu_type_info = { From 314e2296dc945e286b605563d7b6e6b269d29816 Mon Sep 17 00:00:00 2001 From: "Alex_Rozenman@mentor.com" Date: Fri, 11 Jan 2013 15:21:22 +0000 Subject: [PATCH 0381/1634] target-arm: Fix SWI (SVC) instruction in M profile. When do_interrupt_v7m is called with EXCP_SWI, the PC already points to the next instruction. Don't modify it here. Signed-off-by: Alex Rozenman Signed-off-by: Peter Maydell --- target-arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 0525aec87a..66ab78e3f1 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1736,7 +1736,7 @@ static void do_interrupt_v7m(CPUARMState *env) armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE); return; case EXCP_SWI: - env->regs[15] += 2; + /* The PC already points to the next instruction. */ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC); return; case EXCP_PREFETCH_ABORT: From fedb88bd32d331131d77a9b567d12e682fd102ac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:26 -0800 Subject: [PATCH 0382/1634] fdt: Use bswapN instead of bswap_N Fixes the libfdt enabled build for hosts that have . The code at the beginning of qemu/bswap.h is attempting to standardize on bswapN. In the case of CONFIG_MACHINE_BSWAP_H, this is all we get. In the case of CONFIG_BYTESWAP_H, we get bswap_N from the system header and then wrap these with inline functions to get bswapN. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- include/libfdt_env.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/libfdt_env.h b/include/libfdt_env.h index 7938d73fae..3667d4cb3a 100644 --- a/include/libfdt_env.h +++ b/include/libfdt_env.h @@ -22,15 +22,15 @@ #include "qemu/bswap.h" #ifdef HOST_WORDS_BIGENDIAN -#define fdt32_to_cpu(x) (x) -#define cpu_to_fdt32(x) (x) -#define fdt64_to_cpu(x) (x) -#define cpu_to_fdt64(x) (x) +#define fdt32_to_cpu(x) (x) +#define cpu_to_fdt32(x) (x) +#define fdt64_to_cpu(x) (x) +#define cpu_to_fdt64(x) (x) #else -#define fdt32_to_cpu(x) (bswap_32((x))) -#define cpu_to_fdt32(x) (bswap_32((x))) -#define fdt64_to_cpu(x) (bswap_64((x))) -#define cpu_to_fdt64(x) (bswap_64((x))) +#define fdt32_to_cpu(x) bswap32(x) +#define cpu_to_fdt32(x) bswap32(x) +#define fdt64_to_cpu(x) bswap64(x) +#define cpu_to_fdt64(x) bswap64(x) #endif #endif /* _LIBFDT_ENV_H */ From cdfe2851c6c33c133bd90c2643cb0486c0f5b325 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:27 -0800 Subject: [PATCH 0383/1634] bswap: Tidy base definitions of bswapN Move the bswap_N -> bswapN wrappers inside CONFIG_BYTESWAP_H. Change the ultimate fallback defintions from macros to inline functions. The proper types recieved by the function arguments means we can remove unnecessary casts, making the code more readable. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- include/qemu/bswap.h | 72 ++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 2006fcd621..b2a8f94bb4 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -7,48 +7,11 @@ #include "fpu/softfloat.h" #ifdef CONFIG_MACHINE_BSWAP_H -#include -#include -#include -#else - -#ifdef CONFIG_BYTESWAP_H -#include -#else - -#define bswap_16(x) \ -({ \ - uint16_t __x = (x); \ - ((uint16_t)( \ - (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ - (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ -}) - -#define bswap_32(x) \ -({ \ - uint32_t __x = (x); \ - ((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ -}) - -#define bswap_64(x) \ -({ \ - uint64_t __x = (x); \ - ((uint64_t)( \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ - (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ -}) - -#endif /* !CONFIG_BYTESWAP_H */ +# include +# include +# include +#elif defined(CONFIG_BYTESWAP_H) +# include static inline uint16_t bswap16(uint16_t x) { @@ -64,7 +27,32 @@ static inline uint64_t bswap64(uint64_t x) { return bswap_64(x); } +# else +static inline uint16_t bswap16(uint16_t x) +{ + return (((x & 0x00ff) << 8) | + ((x & 0xff00) >> 8)); +} +static inline uint32_t bswap32(uint32_t x) +{ + return (((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24)); +} + +static inline uint64_t bswap64(uint64_t x) +{ + return (((x & 0x00000000000000ffULL) << 56) | + ((x & 0x000000000000ff00ULL) << 40) | + ((x & 0x0000000000ff0000ULL) << 24) | + ((x & 0x00000000ff000000ULL) << 8) | + ((x & 0x000000ff00000000ULL) >> 8) | + ((x & 0x0000ff0000000000ULL) >> 24) | + ((x & 0x00ff000000000000ULL) >> 40) | + ((x & 0xff00000000000000ULL) >> 56)); +} #endif /* ! CONFIG_MACHINE_BSWAP_H */ static inline void bswap16s(uint16_t *s) From 7db2145a6826b14efceb8dd64bfe6ad8647072eb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:28 -0800 Subject: [PATCH 0384/1634] bswap: Add host endian unaligned access functions Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- include/qemu/bswap.h | 51 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index b2a8f94bb4..381554b5b1 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -226,6 +226,8 @@ static inline uint32_t qemu_bswap_len(uint32_t value, int len) return bswap32(value) >> (32 - 8 * len); } +/* Unions for reinterpreting between floats and integers. */ + typedef union { float32 f; uint32_t l; @@ -309,7 +311,7 @@ typedef union { * q: 64 bits * * endian is: - * (empty): 8 bit access + * (empty): host endian * be : big endian * le : little endian */ @@ -328,6 +330,53 @@ static inline void stb_p(void *ptr, int v) *(uint8_t *)ptr = v; } +/* Any compiler worth its salt will turn these memcpy into native unaligned + operations. Thus we don't need to play games with packed attributes, or + inline byte-by-byte stores. */ + +static inline int lduw_p(const void *ptr) +{ + uint16_t r; + memcpy(&r, ptr, sizeof(r)); + return r; +} + +static inline int ldsw_p(const void *ptr) +{ + int16_t r; + memcpy(&r, ptr, sizeof(r)); + return r; +} + +static inline void stw_p(void *ptr, uint16_t v) +{ + memcpy(ptr, &v, sizeof(v)); +} + +static inline int ldl_p(const void *ptr) +{ + int32_t r; + memcpy(&r, ptr, sizeof(r)); + return r; +} + +static inline void stl_p(void *ptr, uint32_t v) +{ + memcpy(ptr, &v, sizeof(v)); +} + +static inline uint64_t ldq_p(const void *ptr) +{ + uint64_t r; + memcpy(&r, ptr, sizeof(r)); + return r; +} + +static inline void stq_p(void *ptr, uint64_t v) +{ + memcpy(ptr, &v, sizeof(v)); +} + /* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the kernel handles unaligned load/stores may give better results, but it is a system wide setting : bad */ From 612d590ebc6cef179cf5f7823522237e622ab430 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:29 -0800 Subject: [PATCH 0385/1634] bswap: Rewrite all ld__p functions Use the new host endian unaligned access functions instead of open coding byte-by-byte references. Remove assembly special cases for i386 and ppc -- we've now exposed the operation to the compiler sufficiently for these to be optimized automatically. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- include/qemu/bswap.h | 300 +++++-------------------------------------- 1 file changed, 30 insertions(+), 270 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 381554b5b1..68cda6ab44 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -215,11 +215,6 @@ static inline void cpu_to_be64wu(uint64_t *p, uint64_t v) #define leul_to_cpu(v) (v) #endif -#undef le_bswap -#undef be_bswap -#undef le_bswaps -#undef be_bswaps - /* len must be one of 1, 2, 4 */ static inline uint32_t qemu_bswap_len(uint32_t value, int len) { @@ -377,115 +372,61 @@ static inline void stq_p(void *ptr, uint64_t v) memcpy(ptr, &v, sizeof(v)); } -/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the - kernel handles unaligned load/stores may give better results, but - it is a system wide setting : bad */ -#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) - -/* conservative code for little endian unaligned accesses */ static inline int lduw_le_p(const void *ptr) { -#ifdef _ARCH_PPC - int val; - __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return val; -#else - const uint8_t *p = ptr; - return p[0] | (p[1] << 8); -#endif + return (uint16_t)le_bswap(lduw_p(ptr), 16); } static inline int ldsw_le_p(const void *ptr) { -#ifdef _ARCH_PPC - int val; - __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return (int16_t)val; -#else - const uint8_t *p = ptr; - return (int16_t)(p[0] | (p[1] << 8)); -#endif + return (int16_t)le_bswap(lduw_p(ptr), 16); } static inline int ldl_le_p(const void *ptr) { -#ifdef _ARCH_PPC - int val; - __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); - return val; -#else - const uint8_t *p = ptr; - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -#endif + return le_bswap(ldl_p(ptr), 32); } static inline uint64_t ldq_le_p(const void *ptr) { - const uint8_t *p = ptr; - uint32_t v1, v2; - v1 = ldl_le_p(p); - v2 = ldl_le_p(p + 4); - return v1 | ((uint64_t)v2 << 32); + return le_bswap(ldq_p(ptr), 64); } static inline void stw_le_p(void *ptr, int v) { -#ifdef _ARCH_PPC - __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); -#else - uint8_t *p = ptr; - p[0] = v; - p[1] = v >> 8; -#endif + stw_p(ptr, le_bswap(v, 16)); } static inline void stl_le_p(void *ptr, int v) { -#ifdef _ARCH_PPC - __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); -#else - uint8_t *p = ptr; - p[0] = v; - p[1] = v >> 8; - p[2] = v >> 16; - p[3] = v >> 24; -#endif + stl_p(ptr, le_bswap(v, 32)); } static inline void stq_le_p(void *ptr, uint64_t v) { - uint8_t *p = ptr; - stl_le_p(p, (uint32_t)v); - stl_le_p(p + 4, v >> 32); + stq_p(ptr, le_bswap(v, 64)); } /* float access */ static inline float32 ldfl_le_p(const void *ptr) { - union { - float32 f; - uint32_t i; - } u; - u.i = ldl_le_p(ptr); + CPU_FloatU u; + u.l = ldl_le_p(ptr); return u.f; } static inline void stfl_le_p(void *ptr, float32 v) { - union { - float32 f; - uint32_t i; - } u; + CPU_FloatU u; u.f = v; - stl_le_p(ptr, u.i); + stl_le_p(ptr, u.l); } static inline float64 ldfq_le_p(const void *ptr) { CPU_DoubleU u; - u.l.lower = ldl_le_p(ptr); - u.l.upper = ldl_le_p(ptr + 4); + u.ll = ldq_le_p(ptr); return u.d; } @@ -493,188 +434,64 @@ static inline void stfq_le_p(void *ptr, float64 v) { CPU_DoubleU u; u.d = v; - stl_le_p(ptr, u.l.lower); - stl_le_p(ptr + 4, u.l.upper); + stq_le_p(ptr, u.ll); } -#else - -static inline int lduw_le_p(const void *ptr) -{ - return *(uint16_t *)ptr; -} - -static inline int ldsw_le_p(const void *ptr) -{ - return *(int16_t *)ptr; -} - -static inline int ldl_le_p(const void *ptr) -{ - return *(uint32_t *)ptr; -} - -static inline uint64_t ldq_le_p(const void *ptr) -{ - return *(uint64_t *)ptr; -} - -static inline void stw_le_p(void *ptr, int v) -{ - *(uint16_t *)ptr = v; -} - -static inline void stl_le_p(void *ptr, int v) -{ - *(uint32_t *)ptr = v; -} - -static inline void stq_le_p(void *ptr, uint64_t v) -{ - *(uint64_t *)ptr = v; -} - -/* float access */ - -static inline float32 ldfl_le_p(const void *ptr) -{ - return *(float32 *)ptr; -} - -static inline float64 ldfq_le_p(const void *ptr) -{ - return *(float64 *)ptr; -} - -static inline void stfl_le_p(void *ptr, float32 v) -{ - *(float32 *)ptr = v; -} - -static inline void stfq_le_p(void *ptr, float64 v) -{ - *(float64 *)ptr = v; -} -#endif - -#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) - static inline int lduw_be_p(const void *ptr) { -#if defined(__i386__) - int val; - asm volatile ("movzwl %1, %0\n" - "xchgb %b0, %h0\n" - : "=q" (val) - : "m" (*(uint16_t *)ptr)); - return val; -#else - const uint8_t *b = ptr; - return ((b[0] << 8) | b[1]); -#endif + return (uint16_t)be_bswap(lduw_p(ptr), 16); } static inline int ldsw_be_p(const void *ptr) { -#if defined(__i386__) - int val; - asm volatile ("movzwl %1, %0\n" - "xchgb %b0, %h0\n" - : "=q" (val) - : "m" (*(uint16_t *)ptr)); - return (int16_t)val; -#else - const uint8_t *b = ptr; - return (int16_t)((b[0] << 8) | b[1]); -#endif + return (int16_t)be_bswap(lduw_p(ptr), 16); } static inline int ldl_be_p(const void *ptr) { -#if defined(__i386__) || defined(__x86_64__) - int val; - asm volatile ("movl %1, %0\n" - "bswap %0\n" - : "=r" (val) - : "m" (*(uint32_t *)ptr)); - return val; -#else - const uint8_t *b = ptr; - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; -#endif + return be_bswap(ldl_p(ptr), 32); } static inline uint64_t ldq_be_p(const void *ptr) { - uint32_t a,b; - a = ldl_be_p(ptr); - b = ldl_be_p((uint8_t *)ptr + 4); - return (((uint64_t)a<<32)|b); + return be_bswap(ldq_p(ptr), 64); } static inline void stw_be_p(void *ptr, int v) { -#if defined(__i386__) - asm volatile ("xchgb %b0, %h0\n" - "movw %w0, %1\n" - : "=q" (v) - : "m" (*(uint16_t *)ptr), "0" (v)); -#else - uint8_t *d = (uint8_t *) ptr; - d[0] = v >> 8; - d[1] = v; -#endif + stw_p(ptr, be_bswap(v, 16)); } static inline void stl_be_p(void *ptr, int v) { -#if defined(__i386__) || defined(__x86_64__) - asm volatile ("bswap %0\n" - "movl %0, %1\n" - : "=r" (v) - : "m" (*(uint32_t *)ptr), "0" (v)); -#else - uint8_t *d = (uint8_t *) ptr; - d[0] = v >> 24; - d[1] = v >> 16; - d[2] = v >> 8; - d[3] = v; -#endif + stl_p(ptr, be_bswap(v, 32)); } static inline void stq_be_p(void *ptr, uint64_t v) { - stl_be_p(ptr, v >> 32); - stl_be_p((uint8_t *)ptr + 4, v); + stq_p(ptr, be_bswap(v, 64)); } /* float access */ static inline float32 ldfl_be_p(const void *ptr) { - union { - float32 f; - uint32_t i; - } u; - u.i = ldl_be_p(ptr); + CPU_FloatU u; + u.l = ldl_be_p(ptr); return u.f; } static inline void stfl_be_p(void *ptr, float32 v) { - union { - float32 f; - uint32_t i; - } u; + CPU_FloatU u; u.f = v; - stl_be_p(ptr, u.i); + stl_be_p(ptr, u.l); } static inline float64 ldfq_be_p(const void *ptr) { CPU_DoubleU u; - u.l.upper = ldl_be_p(ptr); - u.l.lower = ldl_be_p((uint8_t *)ptr + 4); + u.ll = ldq_be_p(ptr); return u.d; } @@ -682,69 +499,12 @@ static inline void stfq_be_p(void *ptr, float64 v) { CPU_DoubleU u; u.d = v; - stl_be_p(ptr, u.l.upper); - stl_be_p((uint8_t *)ptr + 4, u.l.lower); + stq_be_p(ptr, u.ll); } -#else - -static inline int lduw_be_p(const void *ptr) -{ - return *(uint16_t *)ptr; -} - -static inline int ldsw_be_p(const void *ptr) -{ - return *(int16_t *)ptr; -} - -static inline int ldl_be_p(const void *ptr) -{ - return *(uint32_t *)ptr; -} - -static inline uint64_t ldq_be_p(const void *ptr) -{ - return *(uint64_t *)ptr; -} - -static inline void stw_be_p(void *ptr, int v) -{ - *(uint16_t *)ptr = v; -} - -static inline void stl_be_p(void *ptr, int v) -{ - *(uint32_t *)ptr = v; -} - -static inline void stq_be_p(void *ptr, uint64_t v) -{ - *(uint64_t *)ptr = v; -} - -/* float access */ - -static inline float32 ldfl_be_p(const void *ptr) -{ - return *(float32 *)ptr; -} - -static inline float64 ldfq_be_p(const void *ptr) -{ - return *(float64 *)ptr; -} - -static inline void stfl_be_p(void *ptr, float32 v) -{ - *(float32 *)ptr = v; -} - -static inline void stfq_be_p(void *ptr, float64 v) -{ - *(float64 *)ptr = v; -} - -#endif +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps #endif /* BSWAP_H */ From c732a52d3e3b7ed42d7daa94ba40a83408cd6f22 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:30 -0800 Subject: [PATCH 0386/1634] bswap: Rewrite cpu_to_u with {ld,st}__p We've now optimized the ld/st versions; reuse that for the "legacy" versions. Always use inlines so that we get the type checking that we expect. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- include/qemu/bswap.h | 147 ++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 94 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 68cda6ab44..be9b035353 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -121,100 +121,6 @@ CPU_CONVERT(le, 16, uint16_t) CPU_CONVERT(le, 32, uint32_t) CPU_CONVERT(le, 64, uint64_t) -/* unaligned versions (optimized for frequent unaligned accesses)*/ - -#if defined(__i386__) || defined(_ARCH_PPC) - -#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) -#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) -#define le16_to_cpupu(p) le16_to_cpup(p) -#define le32_to_cpupu(p) le32_to_cpup(p) -#define be32_to_cpupu(p) be32_to_cpup(p) - -#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) -#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) -#define cpu_to_be64wu(p, v) cpu_to_be64w(p, v) - -#else - -static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v & 0xff; - p1[1] = v >> 8; -} - -static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v & 0xff; - p1[1] = v >> 8; - p1[2] = v >> 16; - p1[3] = v >> 24; -} - -static inline uint16_t le16_to_cpupu(const uint16_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[0] | (p1[1] << 8); -} - -static inline uint32_t le32_to_cpupu(const uint32_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); -} - -static inline uint32_t be32_to_cpupu(const uint32_t *p) -{ - const uint8_t *p1 = (const uint8_t *)p; - return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24); -} - -static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 8; - p1[1] = v & 0xff; -} - -static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 24; - p1[1] = v >> 16; - p1[2] = v >> 8; - p1[3] = v & 0xff; -} - -static inline void cpu_to_be64wu(uint64_t *p, uint64_t v) -{ - uint8_t *p1 = (uint8_t *)p; - - p1[0] = v >> 56; - p1[1] = v >> 48; - p1[2] = v >> 40; - p1[3] = v >> 32; - p1[4] = v >> 24; - p1[5] = v >> 16; - p1[6] = v >> 8; - p1[7] = v & 0xff; -} - -#endif - -#ifdef HOST_WORDS_BIGENDIAN -#define cpu_to_32wu cpu_to_be32wu -#define leul_to_cpu(v) glue(glue(le,HOST_LONG_BITS),_to_cpu)(v) -#else -#define cpu_to_32wu cpu_to_le32wu -#define leul_to_cpu(v) (v) -#endif - /* len must be one of 1, 2, 4 */ static inline uint32_t qemu_bswap_len(uint32_t value, int len) { @@ -310,6 +216,7 @@ typedef union { * be : big endian * le : little endian */ + static inline int ldub_p(const void *ptr) { return *(uint8_t *)ptr; @@ -502,6 +409,58 @@ static inline void stfq_be_p(void *ptr, float64 v) stq_be_p(ptr, u.ll); } +/* Legacy unaligned versions. Note that we never had a complete set. */ + +static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) +{ + stw_le_p(p, v); +} + +static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) +{ + stl_le_p(p, v); +} + +static inline uint16_t le16_to_cpupu(const uint16_t *p) +{ + return lduw_le_p(p); +} + +static inline uint32_t le32_to_cpupu(const uint32_t *p) +{ + return ldl_le_p(p); +} + +static inline uint32_t be32_to_cpupu(const uint32_t *p) +{ + return ldl_be_p(p); +} + +static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) +{ + stw_be_p(p, v); +} + +static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) +{ + stl_be_p(p, v); +} + +static inline void cpu_to_be64wu(uint64_t *p, uint64_t v) +{ + stq_be_p(p, v); +} + +static inline void cpu_to_32wu(uint32_t *p, uint32_t v) +{ + stl_p(p, v); +} + +static inline unsigned long leul_to_cpu(unsigned long v) +{ + return le_bswap(v, HOST_LONG_BITS); +} + #undef le_bswap #undef be_bswap #undef le_bswaps From 658f2dc970996d547a641b5685e384ebe6f2648e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:31 -0800 Subject: [PATCH 0387/1634] linux-user: Rewrite __get_user/__put_user with __builtin_choose_expr The previous formuation with multiple assignments to __typeof(*hptr) falls down when hptr is qualified const. E.g. with const struct S *p, p->f is also qualified const. With this formulation, there's no assignment to any local variable. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- linux-user/qemu.h | 61 +++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 8a3538c631..31a220af81 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -287,36 +287,39 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) (type == VERIFY_READ) ? PAGE_READ : (PAGE_READ | PAGE_WRITE)) == 0; } -/* NOTE __get_user and __put_user use host pointers and don't check access. */ -/* These are usually used to access struct data members once the - * struct has been locked - usually with lock_user_struct(). - */ -#define __put_user(x, hptr)\ -({ __typeof(*hptr) pu_ = (x);\ - switch(sizeof(*hptr)) {\ - case 1: break;\ - case 2: pu_ = tswap16(pu_); break; \ - case 4: pu_ = tswap32(pu_); break; \ - case 8: pu_ = tswap64(pu_); break; \ - default: abort();\ - }\ - memcpy(hptr, &pu_, sizeof(pu_)); \ - 0;\ -}) +/* NOTE __get_user and __put_user use host pointers and don't check access. + These are usually used to access struct data members once the struct has + been locked - usually with lock_user_struct. */ -#define __get_user(x, hptr) \ -({ __typeof(*hptr) gu_; \ - memcpy(&gu_, hptr, sizeof(gu_)); \ - switch(sizeof(*hptr)) {\ - case 1: break; \ - case 2: gu_ = tswap16(gu_); break; \ - case 4: gu_ = tswap32(gu_); break; \ - case 8: gu_ = tswap64(gu_); break; \ - default: abort();\ - }\ - (x) = gu_; \ - 0;\ -}) +/* Tricky points: + - Use __builtin_choose_expr to avoid type promotion from ?:, + - Invalid sizes result in a compile time error stemming from + the fact that abort has no parameters. + - It's easier to use the endian-specific unaligned load/store + functions than host-endian unaligned load/store plus tswapN. */ + +#define __put_user_e(x, hptr, e) \ + (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort)))) \ + ((hptr), (x)), 0) + +#define __get_user_e(x, hptr, e) \ + ((x) = \ + __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p, \ + __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort)))) \ + (hptr), 0) + +#ifdef TARGET_WORDS_BIGENDIAN +# define __put_user(x, hptr) __put_user_e(x, hptr, be) +# define __get_user(x, hptr) __get_user_e(x, hptr, be) +#else +# define __put_user(x, hptr) __put_user_e(x, hptr, le) +# define __get_user(x, hptr) __get_user_e(x, hptr, le) +#endif /* put_user()/get_user() take a guest address and check access */ /* These are usually used to access an atomic data type, such as an int, From d2565875ec5a483ddcdf3cec821830bd1f082cf6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:32 -0800 Subject: [PATCH 0388/1634] alpha-linux-user: Fix sigaction Unconditional bswap replaced by __get_user/__put_user. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- linux-user/signal.c | 22 ++++++++-------------- linux-user/syscall_defs.h | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 95e2ffa007..407619ac4e 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -607,28 +607,22 @@ int do_sigaction(int sig, const struct target_sigaction *act, sig, act, oact); #endif if (oact) { - oact->_sa_handler = tswapal(k->_sa_handler); -#if defined(TARGET_MIPS) || defined (TARGET_ALPHA) - oact->sa_flags = bswap32(k->sa_flags); -#else - oact->sa_flags = tswapal(k->sa_flags); -#endif + __put_user(k->_sa_handler, &oact->_sa_handler); + __put_user(k->sa_flags, &oact->sa_flags); #if !defined(TARGET_MIPS) - oact->sa_restorer = tswapal(k->sa_restorer); + __put_user(k->sa_restorer, &oact->sa_restorer); #endif + /* Not swapped. */ oact->sa_mask = k->sa_mask; } if (act) { /* FIXME: This is not threadsafe. */ - k->_sa_handler = tswapal(act->_sa_handler); -#if defined(TARGET_MIPS) || defined (TARGET_ALPHA) - k->sa_flags = bswap32(act->sa_flags); -#else - k->sa_flags = tswapal(act->sa_flags); -#endif + __get_user(k->_sa_handler, &act->_sa_handler); + __get_user(k->sa_flags, &act->sa_flags); #if !defined(TARGET_MIPS) - k->sa_restorer = tswapal(act->sa_restorer); + __get_user(k->sa_restorer, &act->sa_restorer); #endif + /* To be swapped in target_to_host_sigset. */ k->sa_mask = act->sa_mask; /* we update the host linux signal state */ diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index d4589e7906..f8f553915d 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -544,7 +544,7 @@ int do_sigaction(int sig, const struct target_sigaction *act, struct target_old_sigaction { abi_ulong _sa_handler; abi_ulong sa_mask; - abi_ulong sa_flags; + int32_t sa_flags; }; struct target_rt_sigaction { From 338d80dd353c50b6397723ffecf7e5bc3ba1651d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Jan 2013 16:39:33 -0800 Subject: [PATCH 0389/1634] user: Consider symbolic links as possible directories Commit 2296f194dfde4c0a54f249d3fdb8c8ca21dc611b reduced the number of syscalls performed during user emulation startup, but failed to consider the use of symbolic links in creating directory structures. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- path.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/path.c b/path.c index ef3f277f17..4c5b0f6296 100644 --- a/path.c +++ b/path.c @@ -58,9 +58,10 @@ static struct pathelem *new_entry(const char *root, #define streq(a,b) (strcmp((a), (b)) == 0) /* Not all systems provide this feature */ -#if defined(DT_DIR) && defined(DT_UNKNOWN) +#if defined(DT_DIR) && defined(DT_UNKNOWN) && defined(DT_LNK) # define dirent_type(dirent) ((dirent)->d_type) -# define is_dir_maybe(type) ((type) == DT_DIR || (type) == DT_UNKNOWN) +# define is_dir_maybe(type) \ + ((type) == DT_DIR || (type) == DT_UNKNOWN || (type) == DT_LNK) #else # define dirent_type(dirent) (1) # define is_dir_maybe(type) (type) From b6d9439c0d221b477c479a41a46797eee228bf88 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 5 Jan 2013 14:48:22 +0000 Subject: [PATCH 0390/1634] slirp: remove unused field tt Signed-off-by: Blue Swirl --- slirp/slirp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/slirp/slirp.h b/slirp/slirp.h index dfc3e3a2b8..fe0e65d0ee 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -215,7 +215,6 @@ struct Slirp { char client_hostname[33]; int restricted; - struct timeval tt; struct ex_list *exec_list; /* mbuf states */ From 3dd46c78525a30e98c68a44e1c3797d9fcfb0462 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 5 Jan 2013 10:10:27 +0000 Subject: [PATCH 0391/1634] optionrom: build with discrete CPP and AS steps Build option ROM .S files with separate preprocessor and assembler steps because the C compiler could be unsuitable. Signed-off-by: Blue Swirl --- configure | 7 ++++++- rules.mak | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/configure b/configure index b5bc9b9ce5..ec8238e1e8 100755 --- a/configure +++ b/configure @@ -264,6 +264,8 @@ else fi ar="${AR-${cross_prefix}ar}" +as="${AS-${cross_prefix}as}" +cpp="${CPP-$cc -E}" objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" libtool="${LIBTOOL-${cross_prefix}libtool}" @@ -3726,6 +3728,8 @@ echo "CC_I386=$cc_i386" >> $config_host_mak echo "HOST_CC=$host_cc" >> $config_host_mak echo "OBJCC=$objcc" >> $config_host_mak echo "AR=$ar" >> $config_host_mak +echo "AS=$as" >> $config_host_mak +echo "CPP=$cpp" >> $config_host_mak echo "OBJCOPY=$objcopy" >> $config_host_mak echo "LD=$ld" >> $config_host_mak echo "WINDRES=$windres" >> $config_host_mak @@ -4277,9 +4281,10 @@ for rom in seabios vgabios ; do config_mak=roms/$rom/config.mak echo "# Automatically generated by configure - do not modify" > $config_mak echo "SRC_PATH=$source_path/roms/$rom" >> $config_mak + echo "AS=$as" >> $config_mak echo "CC=$cc" >> $config_mak echo "BCC=bcc" >> $config_mak - echo "CPP=${cross_prefix}cpp" >> $config_mak + echo "CPP=$cpp" >> $config_mak echo "OBJCOPY=objcopy" >> $config_mak echo "IASL=iasl" >> $config_mak echo "LD=$ld" >> $config_mak diff --git a/rules.mak b/rules.mak index 8448b94cdf..fe0c881a3a 100644 --- a/rules.mak +++ b/rules.mak @@ -28,8 +28,11 @@ else $(call quiet-command,$(LIBTOOL) --mode=compile --quiet --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@") endif -%.o: %.S - $(call quiet-command,$(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," AS $(TARGET_DIR)$@") +%.asm: %.S + $(call quiet-command,$(CPP) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -o $@ $<," CPP $(TARGET_DIR)$@") + +%.o: %.asm + $(call quiet-command,$(AS) $(ASFLAGS) -o $@ $<," AS $(TARGET_DIR)$@") %.o: %.m $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@") From cc6e3ca93c1b40fba579e8724dd06ca9f0507b31 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 9 Jan 2013 10:17:07 +0100 Subject: [PATCH 0392/1634] gcc: rename CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET to CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE Signed-off-by: Gerd Hoffmann Signed-off-by: Blue Swirl --- configure | 6 +++--- coroutine-ucontext.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configure b/configure index ec8238e1e8..ea42fe2457 100755 --- a/configure +++ b/configure @@ -3078,7 +3078,7 @@ int main(void) { } EOF if compile_prog "-Werror" "" ; then - pragma_disable_unused_but_set=yes + pragma_diagnostic_available=yes fi ######################################## @@ -3648,8 +3648,8 @@ if test "$linux_magic_h" = "yes" ; then echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak fi -if test "$pragma_disable_unused_but_set" = "yes" ; then - echo "CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET=y" >> $config_host_mak +if test "$pragma_diagnostic_available" = "yes" ; then + echo "CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE=y" >> $config_host_mak fi if test "$valgrind_h" = "yes" ; then diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index 2ed703a3ed..a9c30e9df4 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -200,7 +200,7 @@ Coroutine *qemu_coroutine_new(void) } #ifdef CONFIG_VALGRIND_H -#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE /* Work around an unused variable in the valgrind.h macro... */ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif @@ -208,7 +208,7 @@ static inline void valgrind_stack_deregister(CoroutineUContext *co) { VALGRIND_STACK_DEREGISTER(co->valgrind_stack_id); } -#ifdef CONFIG_PRAGMA_DISABLE_UNUSED_BUT_SET +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE #pragma GCC diagnostic error "-Wunused-but-set-variable" #endif #endif From 092bb3068801bd6bfc90fcced2661e77bb811764 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 9 Jan 2013 10:17:08 +0100 Subject: [PATCH 0393/1634] pixman: fix warning Cc: afaerber@suse.de Cc: agraf@suse.de Signed-off-by: Gerd Hoffmann Signed-off-by: Blue Swirl --- include/ui/qemu-pixman.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 3c05c83a7c..016fd87726 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -6,7 +6,14 @@ #ifndef QEMU_PIXMAN_H #define QEMU_PIXMAN_H +/* pixman-0.16.0 headers have a redundant declaration */ +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif #include +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#pragma GCC diagnostic error "-Wredundant-decls" +#endif #include "console.h" From 163fa4b09db3e36c612e178fd11b3af4247cbd56 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Jan 2013 15:05:06 -0800 Subject: [PATCH 0394/1634] tcg-i386: use LEA for 3-operand 64-bit addition Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/i386/tcg-target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index e0838748a9..7aec3043e3 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -2099,7 +2099,7 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_st32_i64, { "ri", "r" } }, { INDEX_op_st_i64, { "re", "r" } }, - { INDEX_op_add_i64, { "r", "0", "re" } }, + { INDEX_op_add_i64, { "r", "r", "re" } }, { INDEX_op_mul_i64, { "r", "0", "re" } }, { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } }, { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } }, From a6fc23e5dc76660792c8363d058adf22caa82945 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 11 Jan 2013 16:41:43 +0000 Subject: [PATCH 0395/1634] hw/pc.c: add ULL suffix in ioport80_read and ioportF0_read return value The commit c02e1eac887b1b0aee7361b1fcf889e7d47fed9d broke the compilation for i386. ULL need to be specify for uint64_t value. Signed-off-by: Julien Grall Signed-off-by: Blue Swirl --- hw/pc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index dfa3144aea..ba1f19d7e8 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -105,7 +105,7 @@ static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size) { - return 0xffffffffffffffff; + return 0xffffffffffffffffULL; } /* MSDOS compatibility mode FPU exception support */ @@ -130,7 +130,7 @@ static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size) { - return 0xffffffffffffffff; + return 0xffffffffffffffffULL; } /* TSC handling */ From 4d4545743f55b37d37535f7b32456b82c97efeb8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 26 Nov 2012 16:03:42 +0100 Subject: [PATCH 0396/1634] qemu-option: move standard option definitions out of qemu-config.c Signed-off-by: Paolo Bonzini --- block/iscsi.c | 27 ++ blockdev.c | 118 +++++++ fsdev/Makefile.objs | 1 + fsdev/qemu-fsdev-dummy.c | 7 - fsdev/qemu-fsdev-opts.c | 85 +++++ fsdev/qemu-fsdev.c | 8 - hw/qdev-monitor.c | 51 +++ include/qemu/config-file.h | 5 - include/sysemu/sysemu.h | 8 + monitor.c | 22 ++ net/net.c | 26 ++ qemu-char.c | 72 ++++ qemu-config.c | 681 +------------------------------------ ui/spice-core.c | 84 +++++ vl.c | 205 +++++++++++ 15 files changed, 700 insertions(+), 700 deletions(-) create mode 100644 fsdev/qemu-fsdev-opts.c diff --git a/block/iscsi.c b/block/iscsi.c index 041ee07de3..f08cf9663b 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -980,9 +980,36 @@ static BlockDriver bdrv_iscsi = { #endif }; +static QemuOptsList qemu_iscsi_opts = { + .name = "iscsi", + .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), + .desc = { + { + .name = "user", + .type = QEMU_OPT_STRING, + .help = "username for CHAP authentication to target", + },{ + .name = "password", + .type = QEMU_OPT_STRING, + .help = "password for CHAP authentication to target", + },{ + .name = "header-digest", + .type = QEMU_OPT_STRING, + .help = "HeaderDigest setting. " + "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", + },{ + .name = "initiator-name", + .type = QEMU_OPT_STRING, + .help = "Initiator iqn name to use when connecting", + }, + { /* end of list */ } + }, +}; + static void iscsi_block_init(void) { bdrv_register(&bdrv_iscsi); + qemu_add_opts(&qemu_iscsi_opts); } block_init(iscsi_block_init); diff --git a/blockdev.c b/blockdev.c index d724e2dc5b..9126587c45 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1427,3 +1427,121 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) bdrv_iterate(do_qmp_query_block_jobs_one, &prev); return dummy.next; } + +QemuOptsList qemu_drive_opts = { + .name = "drive", + .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), + .desc = { + { + .name = "bus", + .type = QEMU_OPT_NUMBER, + .help = "bus number", + },{ + .name = "unit", + .type = QEMU_OPT_NUMBER, + .help = "unit number (i.e. lun for scsi)", + },{ + .name = "if", + .type = QEMU_OPT_STRING, + .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)", + },{ + .name = "index", + .type = QEMU_OPT_NUMBER, + .help = "index number", + },{ + .name = "cyls", + .type = QEMU_OPT_NUMBER, + .help = "number of cylinders (ide disk geometry)", + },{ + .name = "heads", + .type = QEMU_OPT_NUMBER, + .help = "number of heads (ide disk geometry)", + },{ + .name = "secs", + .type = QEMU_OPT_NUMBER, + .help = "number of sectors (ide disk geometry)", + },{ + .name = "trans", + .type = QEMU_OPT_STRING, + .help = "chs translation (auto, lba. none)", + },{ + .name = "media", + .type = QEMU_OPT_STRING, + .help = "media type (disk, cdrom)", + },{ + .name = "snapshot", + .type = QEMU_OPT_BOOL, + .help = "enable/disable snapshot mode", + },{ + .name = "file", + .type = QEMU_OPT_STRING, + .help = "disk image", + },{ + .name = "cache", + .type = QEMU_OPT_STRING, + .help = "host cache usage (none, writeback, writethrough, " + "directsync, unsafe)", + },{ + .name = "aio", + .type = QEMU_OPT_STRING, + .help = "host AIO implementation (threads, native)", + },{ + .name = "format", + .type = QEMU_OPT_STRING, + .help = "disk format (raw, qcow2, ...)", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "disk serial number", + },{ + .name = "rerror", + .type = QEMU_OPT_STRING, + .help = "read error action", + },{ + .name = "werror", + .type = QEMU_OPT_STRING, + .help = "write error action", + },{ + .name = "addr", + .type = QEMU_OPT_STRING, + .help = "pci address (virtio only)", + },{ + .name = "readonly", + .type = QEMU_OPT_BOOL, + .help = "open drive file as read-only", + },{ + .name = "iops", + .type = QEMU_OPT_NUMBER, + .help = "limit total I/O operations per second", + },{ + .name = "iops_rd", + .type = QEMU_OPT_NUMBER, + .help = "limit read operations per second", + },{ + .name = "iops_wr", + .type = QEMU_OPT_NUMBER, + .help = "limit write operations per second", + },{ + .name = "bps", + .type = QEMU_OPT_NUMBER, + .help = "limit total bytes per second", + },{ + .name = "bps_rd", + .type = QEMU_OPT_NUMBER, + .help = "limit read bytes per second", + },{ + .name = "bps_wr", + .type = QEMU_OPT_NUMBER, + .help = "limit write bytes per second", + },{ + .name = "copy-on-read", + .type = QEMU_OPT_BOOL, + .help = "copy read data from backing file into image file", + },{ + .name = "boot", + .type = QEMU_OPT_BOOL, + .help = "(deprecated, ignored)", + }, + { /* end of list */ } + }, +}; diff --git a/fsdev/Makefile.objs b/fsdev/Makefile.objs index cb1e2500b9..ee16ca600c 100644 --- a/fsdev/Makefile.objs +++ b/fsdev/Makefile.objs @@ -7,3 +7,4 @@ extra-obj-y = qemu-fsdev-dummy.o else common-obj-y = qemu-fsdev-dummy.o endif +common-obj-y += qemu-fsdev-opts.o diff --git a/fsdev/qemu-fsdev-dummy.c b/fsdev/qemu-fsdev-dummy.c index 4bcf38fe4b..7dc2630a78 100644 --- a/fsdev/qemu-fsdev-dummy.c +++ b/fsdev/qemu-fsdev-dummy.c @@ -20,10 +20,3 @@ int qemu_fsdev_add(QemuOpts *opts) { return 0; } - -static void fsdev_register_config(void) -{ - qemu_add_opts(&qemu_fsdev_opts); - qemu_add_opts(&qemu_virtfs_opts); -} -machine_init(fsdev_register_config); diff --git a/fsdev/qemu-fsdev-opts.c b/fsdev/qemu-fsdev-opts.c new file mode 100644 index 0000000000..6311c7a7e5 --- /dev/null +++ b/fsdev/qemu-fsdev-opts.c @@ -0,0 +1,85 @@ +/* + * Virtio 9p + * + * 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/config-file.h" +#include "qemu/option.h" +#include "qemu/module.h" + +static QemuOptsList qemu_fsdev_opts = { + .name = "fsdev", + .implied_opt_name = "fsdriver", + .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head), + .desc = { + { + .name = "fsdriver", + .type = QEMU_OPT_STRING, + }, { + .name = "path", + .type = QEMU_OPT_STRING, + }, { + .name = "security_model", + .type = QEMU_OPT_STRING, + }, { + .name = "writeout", + .type = QEMU_OPT_STRING, + }, { + .name = "readonly", + .type = QEMU_OPT_BOOL, + + }, { + .name = "socket", + .type = QEMU_OPT_STRING, + }, { + .name = "sock_fd", + .type = QEMU_OPT_NUMBER, + }, + + { /*End of list */ } + }, +}; + +static QemuOptsList qemu_virtfs_opts = { + .name = "virtfs", + .implied_opt_name = "fsdriver", + .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head), + .desc = { + { + .name = "fsdriver", + .type = QEMU_OPT_STRING, + }, { + .name = "path", + .type = QEMU_OPT_STRING, + }, { + .name = "mount_tag", + .type = QEMU_OPT_STRING, + }, { + .name = "security_model", + .type = QEMU_OPT_STRING, + }, { + .name = "writeout", + .type = QEMU_OPT_STRING, + }, { + .name = "readonly", + .type = QEMU_OPT_BOOL, + }, { + .name = "socket", + .type = QEMU_OPT_STRING, + }, { + .name = "sock_fd", + .type = QEMU_OPT_NUMBER, + }, + + { /*End of list */ } + }, +}; + +static void fsdev_register_config(void) +{ + qemu_add_opts(&qemu_fsdev_opts); + qemu_add_opts(&qemu_virtfs_opts); +} +machine_init(fsdev_register_config); diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index 4cc04d4fde..6eaf36dbfa 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -97,11 +97,3 @@ FsDriverEntry *get_fsdev_fsentry(char *id) } return NULL; } - -static void fsdev_register_config(void) -{ - qemu_add_opts(&qemu_fsdev_opts); - qemu_add_opts(&qemu_virtfs_opts); -} -machine_init(fsdev_register_config); - diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index b73986759b..93283ee57a 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -615,3 +615,54 @@ void qdev_machine_init(void) qdev_get_peripheral_anon(); qdev_get_peripheral(); } + +QemuOptsList qemu_device_opts = { + .name = "device", + .implied_opt_name = "driver", + .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head), + .desc = { + /* + * no elements => accept any + * sanity checking will happen later + * when setting device properties + */ + { /* end of list */ } + }, +}; + +QemuOptsList qemu_global_opts = { + .name = "global", + .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), + .desc = { + { + .name = "driver", + .type = QEMU_OPT_STRING, + },{ + .name = "property", + .type = QEMU_OPT_STRING, + },{ + .name = "value", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +int qemu_global_option(const char *str) +{ + char driver[64], property[64]; + QemuOpts *opts; + int rc, offset; + + rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); + if (rc < 2 || str[offset] != '=') { + error_report("can't parse: \"%s\"", str); + return -1; + } + + opts = qemu_opts_create_nofail(&qemu_global_opts); + qemu_opt_set(opts, "driver", driver); + qemu_opt_set(opts, "property", property); + qemu_opt_set(opts, "value", str+offset+1); + return 0; +} diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h index 486c77cad4..ccfccae2b4 100644 --- a/include/qemu/config-file.h +++ b/include/qemu/config-file.h @@ -6,11 +6,6 @@ #include "qapi/error.h" #include "qemu/option.h" -extern QemuOptsList qemu_fsdev_opts; -extern QemuOptsList qemu_virtfs_opts; -extern QemuOptsList qemu_spice_opts; -extern QemuOptsList qemu_sandbox_opts; - QemuOptsList *qemu_find_opts(const char *group); QemuOptsList *qemu_find_opts_err(const char *group, Error **errp); void qemu_add_opts(QemuOptsList *list); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 28a783e2be..c07d4ee458 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -183,4 +183,12 @@ char *get_boot_devices_list(uint32_t *size); bool usb_enabled(bool default_usb); +extern QemuOptsList qemu_drive_opts; +extern QemuOptsList qemu_chardev_opts; +extern QemuOptsList qemu_device_opts; +extern QemuOptsList qemu_netdev_opts; +extern QemuOptsList qemu_net_opts; +extern QemuOptsList qemu_global_opts; +extern QemuOptsList qemu_mon_opts; + #endif diff --git a/monitor.c b/monitor.c index 9cf419bb1d..7b7221999c 100644 --- a/monitor.c +++ b/monitor.c @@ -4790,3 +4790,25 @@ int monitor_read_block_device_key(Monitor *mon, const char *device, return monitor_read_bdrv_key_start(mon, bs, completion_cb, opaque); } + +QemuOptsList qemu_mon_opts = { + .name = "mon", + .implied_opt_name = "chardev", + .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), + .desc = { + { + .name = "mode", + .type = QEMU_OPT_STRING, + },{ + .name = "chardev", + .type = QEMU_OPT_STRING, + },{ + .name = "default", + .type = QEMU_OPT_BOOL, + },{ + .name = "pretty", + .type = QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +}; diff --git a/net/net.c b/net/net.c index dbf3e1b003..02b5458a1b 100644 --- a/net/net.c +++ b/net/net.c @@ -1054,3 +1054,29 @@ unsigned compute_mcast_idx(const uint8_t *ep) } return crc >> 26; } + +QemuOptsList qemu_netdev_opts = { + .name = "netdev", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + }, +}; + +QemuOptsList qemu_net_opts = { + .name = "net", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + }, +}; diff --git a/qemu-char.c b/qemu-char.c index f41788c9ef..3be4970423 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2924,3 +2924,75 @@ CharDriverState *qemu_char_get_next_serial(void) return serial_hds[next_serial++]; } +QemuOptsList qemu_chardev_opts = { + .name = "chardev", + .implied_opt_name = "backend", + .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head), + .desc = { + { + .name = "backend", + .type = QEMU_OPT_STRING, + },{ + .name = "path", + .type = QEMU_OPT_STRING, + },{ + .name = "host", + .type = QEMU_OPT_STRING, + },{ + .name = "port", + .type = QEMU_OPT_STRING, + },{ + .name = "localaddr", + .type = QEMU_OPT_STRING, + },{ + .name = "localport", + .type = QEMU_OPT_STRING, + },{ + .name = "to", + .type = QEMU_OPT_NUMBER, + },{ + .name = "ipv4", + .type = QEMU_OPT_BOOL, + },{ + .name = "ipv6", + .type = QEMU_OPT_BOOL, + },{ + .name = "wait", + .type = QEMU_OPT_BOOL, + },{ + .name = "server", + .type = QEMU_OPT_BOOL, + },{ + .name = "delay", + .type = QEMU_OPT_BOOL, + },{ + .name = "telnet", + .type = QEMU_OPT_BOOL, + },{ + .name = "width", + .type = QEMU_OPT_NUMBER, + },{ + .name = "height", + .type = QEMU_OPT_NUMBER, + },{ + .name = "cols", + .type = QEMU_OPT_NUMBER, + },{ + .name = "rows", + .type = QEMU_OPT_NUMBER, + },{ + .name = "mux", + .type = QEMU_OPT_BOOL, + },{ + .name = "signal", + .type = QEMU_OPT_BOOL, + },{ + .name = "name", + .type = QEMU_OPT_STRING, + },{ + .name = "debug", + .type = QEMU_OPT_NUMBER, + }, + { /* end of list */ } + }, +}; diff --git a/qemu-config.c b/qemu-config.c index 2188c3e5ec..47c81f72d3 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -5,667 +5,7 @@ #include "hw/qdev.h" #include "qapi/error.h" -static QemuOptsList qemu_drive_opts = { - .name = "drive", - .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), - .desc = { - { - .name = "bus", - .type = QEMU_OPT_NUMBER, - .help = "bus number", - },{ - .name = "unit", - .type = QEMU_OPT_NUMBER, - .help = "unit number (i.e. lun for scsi)", - },{ - .name = "if", - .type = QEMU_OPT_STRING, - .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)", - },{ - .name = "index", - .type = QEMU_OPT_NUMBER, - .help = "index number", - },{ - .name = "cyls", - .type = QEMU_OPT_NUMBER, - .help = "number of cylinders (ide disk geometry)", - },{ - .name = "heads", - .type = QEMU_OPT_NUMBER, - .help = "number of heads (ide disk geometry)", - },{ - .name = "secs", - .type = QEMU_OPT_NUMBER, - .help = "number of sectors (ide disk geometry)", - },{ - .name = "trans", - .type = QEMU_OPT_STRING, - .help = "chs translation (auto, lba. none)", - },{ - .name = "media", - .type = QEMU_OPT_STRING, - .help = "media type (disk, cdrom)", - },{ - .name = "snapshot", - .type = QEMU_OPT_BOOL, - .help = "enable/disable snapshot mode", - },{ - .name = "file", - .type = QEMU_OPT_STRING, - .help = "disk image", - },{ - .name = "cache", - .type = QEMU_OPT_STRING, - .help = "host cache usage (none, writeback, writethrough, " - "directsync, unsafe)", - },{ - .name = "aio", - .type = QEMU_OPT_STRING, - .help = "host AIO implementation (threads, native)", - },{ - .name = "format", - .type = QEMU_OPT_STRING, - .help = "disk format (raw, qcow2, ...)", - },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "disk serial number", - },{ - .name = "rerror", - .type = QEMU_OPT_STRING, - .help = "read error action", - },{ - .name = "werror", - .type = QEMU_OPT_STRING, - .help = "write error action", - },{ - .name = "addr", - .type = QEMU_OPT_STRING, - .help = "pci address (virtio only)", - },{ - .name = "readonly", - .type = QEMU_OPT_BOOL, - .help = "open drive file as read-only", - },{ - .name = "iops", - .type = QEMU_OPT_NUMBER, - .help = "limit total I/O operations per second", - },{ - .name = "iops_rd", - .type = QEMU_OPT_NUMBER, - .help = "limit read operations per second", - },{ - .name = "iops_wr", - .type = QEMU_OPT_NUMBER, - .help = "limit write operations per second", - },{ - .name = "bps", - .type = QEMU_OPT_NUMBER, - .help = "limit total bytes per second", - },{ - .name = "bps_rd", - .type = QEMU_OPT_NUMBER, - .help = "limit read bytes per second", - },{ - .name = "bps_wr", - .type = QEMU_OPT_NUMBER, - .help = "limit write bytes per second", - },{ - .name = "copy-on-read", - .type = QEMU_OPT_BOOL, - .help = "copy read data from backing file into image file", - },{ - .name = "boot", - .type = QEMU_OPT_BOOL, - .help = "(deprecated, ignored)", - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_iscsi_opts = { - .name = "iscsi", - .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), - .desc = { - { - .name = "user", - .type = QEMU_OPT_STRING, - .help = "username for CHAP authentication to target", - },{ - .name = "password", - .type = QEMU_OPT_STRING, - .help = "password for CHAP authentication to target", - },{ - .name = "header-digest", - .type = QEMU_OPT_STRING, - .help = "HeaderDigest setting. " - "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", - },{ - .name = "initiator-name", - .type = QEMU_OPT_STRING, - .help = "Initiator iqn name to use when connecting", - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_chardev_opts = { - .name = "chardev", - .implied_opt_name = "backend", - .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head), - .desc = { - { - .name = "backend", - .type = QEMU_OPT_STRING, - },{ - .name = "path", - .type = QEMU_OPT_STRING, - },{ - .name = "host", - .type = QEMU_OPT_STRING, - },{ - .name = "port", - .type = QEMU_OPT_STRING, - },{ - .name = "localaddr", - .type = QEMU_OPT_STRING, - },{ - .name = "localport", - .type = QEMU_OPT_STRING, - },{ - .name = "to", - .type = QEMU_OPT_NUMBER, - },{ - .name = "ipv4", - .type = QEMU_OPT_BOOL, - },{ - .name = "ipv6", - .type = QEMU_OPT_BOOL, - },{ - .name = "wait", - .type = QEMU_OPT_BOOL, - },{ - .name = "server", - .type = QEMU_OPT_BOOL, - },{ - .name = "delay", - .type = QEMU_OPT_BOOL, - },{ - .name = "telnet", - .type = QEMU_OPT_BOOL, - },{ - .name = "width", - .type = QEMU_OPT_NUMBER, - },{ - .name = "height", - .type = QEMU_OPT_NUMBER, - },{ - .name = "cols", - .type = QEMU_OPT_NUMBER, - },{ - .name = "rows", - .type = QEMU_OPT_NUMBER, - },{ - .name = "mux", - .type = QEMU_OPT_BOOL, - },{ - .name = "signal", - .type = QEMU_OPT_BOOL, - },{ - .name = "name", - .type = QEMU_OPT_STRING, - },{ - .name = "debug", - .type = QEMU_OPT_NUMBER, - }, - { /* end of list */ } - }, -}; - -QemuOptsList qemu_fsdev_opts = { - .name = "fsdev", - .implied_opt_name = "fsdriver", - .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head), - .desc = { - { - .name = "fsdriver", - .type = QEMU_OPT_STRING, - }, { - .name = "path", - .type = QEMU_OPT_STRING, - }, { - .name = "security_model", - .type = QEMU_OPT_STRING, - }, { - .name = "writeout", - .type = QEMU_OPT_STRING, - }, { - .name = "readonly", - .type = QEMU_OPT_BOOL, - - }, { - .name = "socket", - .type = QEMU_OPT_STRING, - }, { - .name = "sock_fd", - .type = QEMU_OPT_NUMBER, - }, - - { /*End of list */ } - }, -}; - -QemuOptsList qemu_virtfs_opts = { - .name = "virtfs", - .implied_opt_name = "fsdriver", - .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head), - .desc = { - { - .name = "fsdriver", - .type = QEMU_OPT_STRING, - }, { - .name = "path", - .type = QEMU_OPT_STRING, - }, { - .name = "mount_tag", - .type = QEMU_OPT_STRING, - }, { - .name = "security_model", - .type = QEMU_OPT_STRING, - }, { - .name = "writeout", - .type = QEMU_OPT_STRING, - }, { - .name = "readonly", - .type = QEMU_OPT_BOOL, - }, { - .name = "socket", - .type = QEMU_OPT_STRING, - }, { - .name = "sock_fd", - .type = QEMU_OPT_NUMBER, - }, - - { /*End of list */ } - }, -}; - -static QemuOptsList qemu_device_opts = { - .name = "device", - .implied_opt_name = "driver", - .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head), - .desc = { - /* - * no elements => accept any - * sanity checking will happen later - * when setting device properties - */ - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_netdev_opts = { - .name = "netdev", - .implied_opt_name = "type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), - .desc = { - /* - * no elements => accept any params - * validation will happen later - */ - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_net_opts = { - .name = "net", - .implied_opt_name = "type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), - .desc = { - /* - * no elements => accept any params - * validation will happen later - */ - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_rtc_opts = { - .name = "rtc", - .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), - .desc = { - { - .name = "base", - .type = QEMU_OPT_STRING, - },{ - .name = "clock", - .type = QEMU_OPT_STRING, - },{ - .name = "driftfix", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_global_opts = { - .name = "global", - .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head), - .desc = { - { - .name = "driver", - .type = QEMU_OPT_STRING, - },{ - .name = "property", - .type = QEMU_OPT_STRING, - },{ - .name = "value", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -QemuOptsList qemu_sandbox_opts = { - .name = "sandbox", - .implied_opt_name = "enable", - .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head), - .desc = { - { - .name = "enable", - .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_mon_opts = { - .name = "mon", - .implied_opt_name = "chardev", - .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head), - .desc = { - { - .name = "mode", - .type = QEMU_OPT_STRING, - },{ - .name = "chardev", - .type = QEMU_OPT_STRING, - },{ - .name = "default", - .type = QEMU_OPT_BOOL, - },{ - .name = "pretty", - .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_trace_opts = { - .name = "trace", - .implied_opt_name = "trace", - .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), - .desc = { - { - .name = "events", - .type = QEMU_OPT_STRING, - },{ - .name = "file", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -QemuOptsList qemu_spice_opts = { - .name = "spice", - .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), - .desc = { - { - .name = "port", - .type = QEMU_OPT_NUMBER, - },{ - .name = "tls-port", - .type = QEMU_OPT_NUMBER, - },{ - .name = "addr", - .type = QEMU_OPT_STRING, - },{ - .name = "ipv4", - .type = QEMU_OPT_BOOL, - },{ - .name = "ipv6", - .type = QEMU_OPT_BOOL, - },{ - .name = "password", - .type = QEMU_OPT_STRING, - },{ - .name = "disable-ticketing", - .type = QEMU_OPT_BOOL, - },{ - .name = "disable-copy-paste", - .type = QEMU_OPT_BOOL, - },{ - .name = "sasl", - .type = QEMU_OPT_BOOL, - },{ - .name = "x509-dir", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-key-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-key-password", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-cert-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-cacert-file", - .type = QEMU_OPT_STRING, - },{ - .name = "x509-dh-key-file", - .type = QEMU_OPT_STRING, - },{ - .name = "tls-ciphers", - .type = QEMU_OPT_STRING, - },{ - .name = "tls-channel", - .type = QEMU_OPT_STRING, - },{ - .name = "plaintext-channel", - .type = QEMU_OPT_STRING, - },{ - .name = "image-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "jpeg-wan-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "zlib-glz-wan-compression", - .type = QEMU_OPT_STRING, - },{ - .name = "streaming-video", - .type = QEMU_OPT_STRING, - },{ - .name = "agent-mouse", - .type = QEMU_OPT_BOOL, - },{ - .name = "playback-compression", - .type = QEMU_OPT_BOOL, - }, { - .name = "seamless-migration", - .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -}; - -QemuOptsList qemu_option_rom_opts = { - .name = "option-rom", - .implied_opt_name = "romfile", - .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head), - .desc = { - { - .name = "bootindex", - .type = QEMU_OPT_NUMBER, - }, { - .name = "romfile", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_machine_opts = { - .name = "machine", - .implied_opt_name = "type", - .merge_lists = true, - .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head), - .desc = { - { - .name = "type", - .type = QEMU_OPT_STRING, - .help = "emulated machine" - }, { - .name = "accel", - .type = QEMU_OPT_STRING, - .help = "accelerator list", - }, { - .name = "kernel_irqchip", - .type = QEMU_OPT_BOOL, - .help = "use KVM in-kernel irqchip", - }, { - .name = "kvm_shadow_mem", - .type = QEMU_OPT_SIZE, - .help = "KVM shadow MMU size", - }, { - .name = "kernel", - .type = QEMU_OPT_STRING, - .help = "Linux kernel image file", - }, { - .name = "initrd", - .type = QEMU_OPT_STRING, - .help = "Linux initial ramdisk file", - }, { - .name = "append", - .type = QEMU_OPT_STRING, - .help = "Linux kernel command line", - }, { - .name = "dtb", - .type = QEMU_OPT_STRING, - .help = "Linux kernel device tree file", - }, { - .name = "dumpdtb", - .type = QEMU_OPT_STRING, - .help = "Dump current dtb to a file and quit", - }, { - .name = "phandle_start", - .type = QEMU_OPT_STRING, - .help = "The first phandle ID we may generate dynamically", - }, { - .name = "dt_compatible", - .type = QEMU_OPT_STRING, - .help = "Overrides the \"compatible\" property of the dt root node", - }, { - .name = "dump-guest-core", - .type = QEMU_OPT_BOOL, - .help = "Include guest memory in a core dump", - }, { - .name = "mem-merge", - .type = QEMU_OPT_BOOL, - .help = "enable/disable memory merge support", - },{ - .name = "usb", - .type = QEMU_OPT_BOOL, - .help = "Set on/off to enable/disable usb", - }, { - .name = "nvram", - .type = QEMU_OPT_STRING, - .help = "Drive backing persistent NVRAM", - }, - { /* End of list */ } - }, -}; - -QemuOptsList qemu_boot_opts = { - .name = "boot-opts", - .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head), - .desc = { - /* the three names below are not used now */ - { - .name = "order", - .type = QEMU_OPT_STRING, - }, { - .name = "once", - .type = QEMU_OPT_STRING, - }, { - .name = "menu", - .type = QEMU_OPT_STRING, - /* following are really used */ - }, { - .name = "splash", - .type = QEMU_OPT_STRING, - }, { - .name = "splash-time", - .type = QEMU_OPT_STRING, - }, { - .name = "reboot-timeout", - .type = QEMU_OPT_STRING, - }, - { /*End of list */ } - }, -}; - -static QemuOptsList qemu_add_fd_opts = { - .name = "add-fd", - .head = QTAILQ_HEAD_INITIALIZER(qemu_add_fd_opts.head), - .desc = { - { - .name = "fd", - .type = QEMU_OPT_NUMBER, - .help = "file descriptor of which a duplicate is added to fd set", - },{ - .name = "set", - .type = QEMU_OPT_NUMBER, - .help = "ID of the fd set to add fd to", - },{ - .name = "opaque", - .type = QEMU_OPT_STRING, - .help = "free-form string used to describe fd", - }, - { /* end of list */ } - }, -}; - -static QemuOptsList qemu_object_opts = { - .name = "object", - .implied_opt_name = "qom-type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), - .desc = { - { } - }, -}; - -static QemuOptsList *vm_config_groups[32] = { - &qemu_drive_opts, - &qemu_chardev_opts, - &qemu_device_opts, - &qemu_netdev_opts, - &qemu_net_opts, - &qemu_rtc_opts, - &qemu_global_opts, - &qemu_mon_opts, - &qemu_trace_opts, - &qemu_option_rom_opts, - &qemu_machine_opts, - &qemu_boot_opts, - &qemu_iscsi_opts, - &qemu_sandbox_opts, - &qemu_add_fd_opts, - &qemu_object_opts, - NULL, -}; +static QemuOptsList *vm_config_groups[32]; static QemuOptsList *find_list(QemuOptsList **lists, const char *group, Error **errp) @@ -748,25 +88,6 @@ int qemu_set_option(const char *str) return 0; } -int qemu_global_option(const char *str) -{ - char driver[64], property[64]; - QemuOpts *opts; - int rc, offset; - - rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset); - if (rc < 2 || str[offset] != '=') { - error_report("can't parse: \"%s\"", str); - return -1; - } - - opts = qemu_opts_create_nofail(&qemu_global_opts); - qemu_opt_set(opts, "driver", driver); - qemu_opt_set(opts, "property", property); - qemu_opt_set(opts, "value", str+offset+1); - return 0; -} - struct ConfigWriteData { QemuOptsList *list; FILE *fp; diff --git a/ui/spice-core.c b/ui/spice-core.c index d83de2a46e..3f2c5650cd 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -417,6 +417,90 @@ static SpiceChannelList *qmp_query_spice_channels(void) return head; } +static QemuOptsList qemu_spice_opts = { + .name = "spice", + .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), + .desc = { + { + .name = "port", + .type = QEMU_OPT_NUMBER, + },{ + .name = "tls-port", + .type = QEMU_OPT_NUMBER, + },{ + .name = "addr", + .type = QEMU_OPT_STRING, + },{ + .name = "ipv4", + .type = QEMU_OPT_BOOL, + },{ + .name = "ipv6", + .type = QEMU_OPT_BOOL, + },{ + .name = "password", + .type = QEMU_OPT_STRING, + },{ + .name = "disable-ticketing", + .type = QEMU_OPT_BOOL, + },{ + .name = "disable-copy-paste", + .type = QEMU_OPT_BOOL, + },{ + .name = "sasl", + .type = QEMU_OPT_BOOL, + },{ + .name = "x509-dir", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-key-file", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-key-password", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-cert-file", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-cacert-file", + .type = QEMU_OPT_STRING, + },{ + .name = "x509-dh-key-file", + .type = QEMU_OPT_STRING, + },{ + .name = "tls-ciphers", + .type = QEMU_OPT_STRING, + },{ + .name = "tls-channel", + .type = QEMU_OPT_STRING, + },{ + .name = "plaintext-channel", + .type = QEMU_OPT_STRING, + },{ + .name = "image-compression", + .type = QEMU_OPT_STRING, + },{ + .name = "jpeg-wan-compression", + .type = QEMU_OPT_STRING, + },{ + .name = "zlib-glz-wan-compression", + .type = QEMU_OPT_STRING, + },{ + .name = "streaming-video", + .type = QEMU_OPT_STRING, + },{ + .name = "agent-mouse", + .type = QEMU_OPT_BOOL, + },{ + .name = "playback-compression", + .type = QEMU_OPT_BOOL, + }, { + .name = "seamless-migration", + .type = QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +}; + SpiceInfo *qmp_query_spice(Error **errp) { QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); diff --git a/vl.c b/vl.c index e5da31cf4a..59ce063601 100644 --- a/vl.c +++ b/vl.c @@ -299,6 +299,195 @@ static struct { { .driver = "qxl-vga", .flag = &default_vga }, }; +static QemuOptsList qemu_rtc_opts = { + .name = "rtc", + .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head), + .desc = { + { + .name = "base", + .type = QEMU_OPT_STRING, + },{ + .name = "clock", + .type = QEMU_OPT_STRING, + },{ + .name = "driftfix", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_sandbox_opts = { + .name = "sandbox", + .implied_opt_name = "enable", + .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head), + .desc = { + { + .name = "enable", + .type = QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_trace_opts = { + .name = "trace", + .implied_opt_name = "trace", + .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), + .desc = { + { + .name = "events", + .type = QEMU_OPT_STRING, + },{ + .name = "file", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_option_rom_opts = { + .name = "option-rom", + .implied_opt_name = "romfile", + .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head), + .desc = { + { + .name = "bootindex", + .type = QEMU_OPT_NUMBER, + }, { + .name = "romfile", + .type = QEMU_OPT_STRING, + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_machine_opts = { + .name = "machine", + .implied_opt_name = "type", + .merge_lists = true, + .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head), + .desc = { + { + .name = "type", + .type = QEMU_OPT_STRING, + .help = "emulated machine" + }, { + .name = "accel", + .type = QEMU_OPT_STRING, + .help = "accelerator list", + }, { + .name = "kernel_irqchip", + .type = QEMU_OPT_BOOL, + .help = "use KVM in-kernel irqchip", + }, { + .name = "kvm_shadow_mem", + .type = QEMU_OPT_SIZE, + .help = "KVM shadow MMU size", + }, { + .name = "kernel", + .type = QEMU_OPT_STRING, + .help = "Linux kernel image file", + }, { + .name = "initrd", + .type = QEMU_OPT_STRING, + .help = "Linux initial ramdisk file", + }, { + .name = "append", + .type = QEMU_OPT_STRING, + .help = "Linux kernel command line", + }, { + .name = "dtb", + .type = QEMU_OPT_STRING, + .help = "Linux kernel device tree file", + }, { + .name = "dumpdtb", + .type = QEMU_OPT_STRING, + .help = "Dump current dtb to a file and quit", + }, { + .name = "phandle_start", + .type = QEMU_OPT_STRING, + .help = "The first phandle ID we may generate dynamically", + }, { + .name = "dt_compatible", + .type = QEMU_OPT_STRING, + .help = "Overrides the \"compatible\" property of the dt root node", + }, { + .name = "dump-guest-core", + .type = QEMU_OPT_BOOL, + .help = "Include guest memory in a core dump", + }, { + .name = "mem-merge", + .type = QEMU_OPT_BOOL, + .help = "enable/disable memory merge support", + },{ + .name = "usb", + .type = QEMU_OPT_BOOL, + .help = "Set on/off to enable/disable usb", + }, + { /* End of list */ } + }, +}; + +static QemuOptsList qemu_boot_opts = { + .name = "boot-opts", + .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head), + .desc = { + /* the three names below are not used now */ + { + .name = "order", + .type = QEMU_OPT_STRING, + }, { + .name = "once", + .type = QEMU_OPT_STRING, + }, { + .name = "menu", + .type = QEMU_OPT_STRING, + /* following are really used */ + }, { + .name = "splash", + .type = QEMU_OPT_STRING, + }, { + .name = "splash-time", + .type = QEMU_OPT_STRING, + }, { + .name = "reboot-timeout", + .type = QEMU_OPT_STRING, + }, + { /*End of list */ } + }, +}; + +static QemuOptsList qemu_add_fd_opts = { + .name = "add-fd", + .head = QTAILQ_HEAD_INITIALIZER(qemu_add_fd_opts.head), + .desc = { + { + .name = "fd", + .type = QEMU_OPT_NUMBER, + .help = "file descriptor of which a duplicate is added to fd set", + },{ + .name = "set", + .type = QEMU_OPT_NUMBER, + .help = "ID of the fd set to add fd to", + },{ + .name = "opaque", + .type = QEMU_OPT_STRING, + .help = "free-form string used to describe fd", + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_object_opts = { + .name = "object", + .implied_opt_name = "qom-type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head), + .desc = { + { } + }, +}; + const char *qemu_get_vm_name(void) { return qemu_name; @@ -2566,6 +2755,22 @@ int main(int argc, char **argv, char **envp) module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_drive_opts); + qemu_add_opts(&qemu_chardev_opts); + qemu_add_opts(&qemu_device_opts); + qemu_add_opts(&qemu_netdev_opts); + qemu_add_opts(&qemu_net_opts); + qemu_add_opts(&qemu_rtc_opts); + qemu_add_opts(&qemu_global_opts); + qemu_add_opts(&qemu_mon_opts); + qemu_add_opts(&qemu_trace_opts); + qemu_add_opts(&qemu_option_rom_opts); + qemu_add_opts(&qemu_machine_opts); + qemu_add_opts(&qemu_boot_opts); + qemu_add_opts(&qemu_sandbox_opts); + qemu_add_opts(&qemu_add_fd_opts); + qemu_add_opts(&qemu_object_opts); + runstate_init(); init_clocks(); From 5708fc665524c5218076388504d078441fb3940c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 26 Nov 2012 15:36:40 +0100 Subject: [PATCH 0397/1634] stubs: fully replace qemu-tool.c and qemu-user.c Signed-off-by: Paolo Bonzini --- Makefile | 2 +- Makefile.objs | 3 +- exec.c | 2 +- qemu-tool.c | 115 ------------------------------------- qemu-user.c | 37 ------------ stubs/Makefile.objs | 17 +++++- stubs/clock-warp.c | 7 +++ stubs/cpu-get-clock.c | 7 +++ stubs/cpu-get-icount.c | 9 +++ stubs/get-vm-name.c | 7 +++ stubs/iothread-lock.c | 10 ++++ stubs/migr-blocker.c | 10 ++++ stubs/mon-is-qmp.c | 7 +++ stubs/mon-print-filename.c | 6 ++ stubs/mon-printf.c | 10 ++++ stubs/mon-protocol-event.c | 6 ++ stubs/mon-set-error.c | 8 +++ stubs/slirp.c | 17 ++++++ stubs/vm-stop.c | 7 +++ tests/Makefile | 18 +++--- 20 files changed, 138 insertions(+), 167 deletions(-) delete mode 100644 qemu-tool.c delete mode 100644 qemu-user.c create mode 100644 stubs/clock-warp.c create mode 100644 stubs/cpu-get-clock.c create mode 100644 stubs/cpu-get-icount.c create mode 100644 stubs/get-vm-name.c create mode 100644 stubs/iothread-lock.c create mode 100644 stubs/migr-blocker.c create mode 100644 stubs/mon-is-qmp.c create mode 100644 stubs/mon-print-filename.c create mode 100644 stubs/mon-printf.c create mode 100644 stubs/mon-protocol-event.c create mode 100644 stubs/mon-set-error.c create mode 100644 stubs/slirp.c create mode 100644 stubs/vm-stop.c diff --git a/Makefile b/Makefile index 0200bf345c..3c960a166f 100644 --- a/Makefile +++ b/Makefile @@ -171,7 +171,7 @@ install-libcacard: libcacard.la qemu-img.o: qemu-img-cmds.h -tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ +tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-timer.o \ main-loop.o iohandler.o error.o tools-obj-$(CONFIG_POSIX) += compatfd.o diff --git a/Makefile.objs b/Makefile.objs index 12a314e3fb..c64c0c69da 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -130,7 +130,6 @@ user-obj-y += envlist.o path.o user-obj-y += tcg-runtime.o host-utils.o user-obj-y += cache-utils.o user-obj-y += module.o -user-obj-y += qemu-user.o user-obj-y += qom/ ###################################################################### @@ -171,7 +170,7 @@ universal-obj-y += $(qapi-obj-y) ###################################################################### # guest agent -qga-obj-y = qga/ module.o qemu-tool.o +qga-obj-y = qga/ module.o qga-obj-$(CONFIG_POSIX) += qemu-sockets.o qemu-option.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/exec.c b/exec.c index a6923addd4..34353f7527 100644 --- a/exec.c +++ b/exec.c @@ -78,7 +78,7 @@ DEFINE_TLS(CPUArchState *,cpu_single_env); /* 0 = Do not count executed instructions. 1 = Precise instruction counting. 2 = Adaptive rate instruction counting. */ -int use_icount = 0; +int use_icount; #if !defined(CONFIG_USER_ONLY) diff --git a/qemu-tool.c b/qemu-tool.c deleted file mode 100644 index 1a474c45bc..0000000000 --- a/qemu-tool.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Compatibility for qemu-img/qemu-nbd - * - * Copyright IBM, Corp. 2008 - * - * Authors: - * Anthony Liguori - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu-common.h" -#include "monitor/monitor.h" -#include "qemu/timer.h" -#include "qemu/log.h" -#include "migration/migration.h" -#include "qemu/main-loop.h" -#include "sysemu/sysemu.h" -#include "qemu/sockets.h" -#include "slirp/libslirp.h" - -#include - -struct QEMUBH -{ - QEMUBHFunc *cb; - void *opaque; -}; - -const char *qemu_get_vm_name(void) -{ - return NULL; -} - -Monitor *cur_mon; - -void vm_stop(RunState state) -{ - abort(); -} - -int monitor_cur_is_qmp(void) -{ - return 0; -} - -void monitor_set_error(Monitor *mon, QError *qerror) -{ -} - -void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) -{ -} - -void monitor_printf(Monitor *mon, const char *fmt, ...) -{ -} - -void monitor_print_filename(Monitor *mon, const char *filename) -{ -} - -void monitor_protocol_event(MonitorEvent event, QObject *data) -{ -} - -int64_t cpu_get_clock(void) -{ - return get_clock_realtime(); -} - -int64_t cpu_get_icount(void) -{ - abort(); -} - -void qemu_mutex_lock_iothread(void) -{ -} - -void qemu_mutex_unlock_iothread(void) -{ -} - -int use_icount; - -void qemu_clock_warp(QEMUClock *clock) -{ -} - -void slirp_update_timeout(uint32_t *timeout) -{ -} - -void slirp_select_fill(int *pnfds, fd_set *readfds, - fd_set *writefds, fd_set *xfds) -{ -} - -void slirp_select_poll(fd_set *readfds, fd_set *writefds, - fd_set *xfds, int select_error) -{ -} - -void migrate_add_blocker(Error *reason) -{ -} - -void migrate_del_blocker(Error *reason) -{ -} diff --git a/qemu-user.c b/qemu-user.c deleted file mode 100644 index f8b450c03d..0000000000 --- a/qemu-user.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Stubs for QEMU user emulation - * - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see - * - */ - -#include "qemu-common.h" -#include "monitor/monitor.h" - -Monitor *cur_mon; - -int monitor_cur_is_qmp(void) -{ - return 0; -} - -void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) -{ -} - -void monitor_set_error(Monitor *mon, QError *qerror) -{ -} diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 7672c69a29..a2603947db 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -1,11 +1,24 @@ stub-obj-y += arch-query-cpu-def.o +stub-obj-y += clock-warp.o +stub-obj-y += cpu-get-clock.o +stub-obj-y += cpu-get-icount.o stub-obj-y += fdset-add-fd.o stub-obj-y += fdset-find-fd.o stub-obj-y += fdset-get-fd.o stub-obj-y += fdset-remove-fd.o stub-obj-y += get-fd.o -stub-obj-y += set-fd-handler.o +stub-obj-y += get-vm-name.o +stub-obj-y += iothread-lock.o +stub-obj-y += migr-blocker.o +stub-obj-y += mon-is-qmp.o +stub-obj-y += mon-printf.o +stub-obj-y += mon-print-filename.o +stub-obj-y += mon-protocol-event.o +stub-obj-y += mon-set-error.o stub-obj-y += reset.o -stub-obj-y += vmstate.o +stub-obj-y += set-fd-handler.o +stub-obj-y += slirp.o stub-obj-y += sysbus.o +stub-obj-y += vm-stop.o +stub-obj-y += vmstate.o stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/clock-warp.c b/stubs/clock-warp.c new file mode 100644 index 0000000000..b64c462e73 --- /dev/null +++ b/stubs/clock-warp.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "qemu/timer.h" + +void qemu_clock_warp(QEMUClock *clock) +{ +} + diff --git a/stubs/cpu-get-clock.c b/stubs/cpu-get-clock.c new file mode 100644 index 0000000000..5b34c976d9 --- /dev/null +++ b/stubs/cpu-get-clock.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "qemu/timer.h" + +int64_t cpu_get_clock(void) +{ + return get_clock_realtime(); +} diff --git a/stubs/cpu-get-icount.c b/stubs/cpu-get-icount.c new file mode 100644 index 0000000000..d68585965f --- /dev/null +++ b/stubs/cpu-get-icount.c @@ -0,0 +1,9 @@ +#include "qemu-common.h" +#include "qemu/timer.h" + +int use_icount; + +int64_t cpu_get_icount(void) +{ + abort(); +} diff --git a/stubs/get-vm-name.c b/stubs/get-vm-name.c new file mode 100644 index 0000000000..e5f619ffab --- /dev/null +++ b/stubs/get-vm-name.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" + +const char *qemu_get_vm_name(void) +{ + return NULL; +} + diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c new file mode 100644 index 0000000000..5d8aca1b37 --- /dev/null +++ b/stubs/iothread-lock.c @@ -0,0 +1,10 @@ +#include "qemu-common.h" +#include "qemu/main-loop.h" + +void qemu_mutex_lock_iothread(void) +{ +} + +void qemu_mutex_unlock_iothread(void) +{ +} diff --git a/stubs/migr-blocker.c b/stubs/migr-blocker.c new file mode 100644 index 0000000000..300df6e205 --- /dev/null +++ b/stubs/migr-blocker.c @@ -0,0 +1,10 @@ +#include "qemu-common.h" +#include "migration/migration.h" + +void migrate_add_blocker(Error *reason) +{ +} + +void migrate_del_blocker(Error *reason) +{ +} diff --git a/stubs/mon-is-qmp.c b/stubs/mon-is-qmp.c new file mode 100644 index 0000000000..1f0a8fd98a --- /dev/null +++ b/stubs/mon-is-qmp.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +int monitor_cur_is_qmp(void) +{ + return 0; +} diff --git a/stubs/mon-print-filename.c b/stubs/mon-print-filename.c new file mode 100644 index 0000000000..9c939641ff --- /dev/null +++ b/stubs/mon-print-filename.c @@ -0,0 +1,6 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +void monitor_print_filename(Monitor *mon, const char *filename) +{ +} diff --git a/stubs/mon-printf.c b/stubs/mon-printf.c new file mode 100644 index 0000000000..0ce2ca6925 --- /dev/null +++ b/stubs/mon-printf.c @@ -0,0 +1,10 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +void monitor_printf(Monitor *mon, const char *fmt, ...) +{ +} + +void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) +{ +} diff --git a/stubs/mon-protocol-event.c b/stubs/mon-protocol-event.c new file mode 100644 index 0000000000..0946e94724 --- /dev/null +++ b/stubs/mon-protocol-event.c @@ -0,0 +1,6 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +void monitor_protocol_event(MonitorEvent event, QObject *data) +{ +} diff --git a/stubs/mon-set-error.c b/stubs/mon-set-error.c new file mode 100644 index 0000000000..d0411f97fa --- /dev/null +++ b/stubs/mon-set-error.c @@ -0,0 +1,8 @@ +#include "qemu-common.h" +#include "monitor/monitor.h" + +Monitor *cur_mon; + +void monitor_set_error(Monitor *mon, QError *qerror) +{ +} diff --git a/stubs/slirp.c b/stubs/slirp.c new file mode 100644 index 0000000000..9a3309a2b9 --- /dev/null +++ b/stubs/slirp.c @@ -0,0 +1,17 @@ +#include "qemu-common.h" +#include "slirp/slirp.h" + +void slirp_update_timeout(uint32_t *timeout) +{ +} + +void slirp_select_fill(int *pnfds, fd_set *readfds, + fd_set *writefds, fd_set *xfds) +{ +} + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, + fd_set *xfds, int select_error) +{ +} + diff --git a/stubs/vm-stop.c b/stubs/vm-stop.c new file mode 100644 index 0000000000..45689354f6 --- /dev/null +++ b/stubs/vm-stop.c @@ -0,0 +1,7 @@ +#include "qemu-common.h" +#include "sysemu/sysemu.h" + +void vm_stop(RunState state) +{ + abort(); +} diff --git a/tests/Makefile b/tests/Makefile index b09a3437cd..cfd2d6aebd 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -70,7 +70,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o -test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) qemu-tool.o +test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o test-qapi-obj-y += module.o @@ -81,7 +81,7 @@ tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o -tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) qemu-tool.o +tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) libqemustub.a tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) iov.o libqemustub.a tests/test-aio$(EXESUF): tests/test-aio.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a @@ -98,13 +98,13 @@ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") -tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) -tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) -tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) -tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) -tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) -tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) -tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) +tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemustub.a +tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemustub.a +tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemustub.a +tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemustub.a +tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemustub.a +tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) libqemustub.a +tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemustub.a tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) From f141ccfa15096a7610b9973ae5ebae6562625a8d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 18:32:53 +0100 Subject: [PATCH 0398/1634] build: make libtool verbose when making with V=1 Signed-off-by: Paolo Bonzini --- libcacard/Makefile | 2 +- rules.mak | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libcacard/Makefile b/libcacard/Makefile index c26aac65c3..9fa109f8ae 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -36,7 +36,7 @@ install-libcacard: @echo "libtool is missing, please install and rerun configure"; exit 1 else libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB) - $(call quiet-command,$(LIBTOOL) --mode=link --quiet --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs)," lt LINK $@") + $(call quiet-command,$(LIBTOOL) --mode=link --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs)," lt LINK $@") libcacard_srcpath=$(SRC_PATH)/libcacard libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in diff --git a/rules.mak b/rules.mak index fe0c881a3a..927301251e 100644 --- a/rules.mak +++ b/rules.mak @@ -24,8 +24,9 @@ ifeq ($(LIBTOOL),) %.lo: %.c @echo "missing libtool. please install and rerun configure"; exit 1 else +LIBTOOL += $(if $(V),,--quiet) %.lo: %.c - $(call quiet-command,$(LIBTOOL) --mode=compile --quiet --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@") + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=CC $(CC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," lt CC $@") endif %.asm: %.S From 2165588274332e9f08891d5b22d56f4c0b7dc437 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 18:57:45 +0100 Subject: [PATCH 0399/1634] build: support linking with libtool objects/libraries This patch moves the complication of using libtool to the generic rules.mak file. Signed-off-by: Paolo Bonzini --- configure | 8 +++++++- libcacard/Makefile | 11 +++++++---- rules.mak | 10 ++++++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/configure b/configure index ea42fe2457..5ae203df08 100755 --- a/configure +++ b/configure @@ -3721,7 +3721,13 @@ echo "MAKE=$make" >> $config_host_mak echo "INSTALL=$install" >> $config_host_mak echo "INSTALL_DIR=$install -d -m 0755" >> $config_host_mak echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak -echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak +if test -n "$libtool"; then + echo "INSTALL_PROG=\$(LIBTOOL) --mode=install $install -c -m 0755" >> $config_host_mak + echo "INSTALL_LIB=\$(LIBTOOL) --mode=install $install -c -m 0644" >> $config_host_mak +else + echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak + echo "INSTALL_LIB=$install -c -m 0644" >> $config_host_mak +fi echo "PYTHON=$python" >> $config_host_mak echo "CC=$cc" >> $config_host_mak echo "CC_I386=$cc_i386" >> $config_host_mak diff --git a/libcacard/Makefile b/libcacard/Makefile index 9fa109f8ae..34d503b8cc 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -10,6 +10,9 @@ $(call set-vpath, $(SRC_PATH)) QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) $(stub-obj-y) QEMU_OBJS_LIB=$(patsubst %.o,%.lo,$(QEMU_OBJS)) +# libtool will build the .o files, too +$(libcacard-obj-y): | $(libcacard-lobj-y) + QEMU_CFLAGS+=-I../ libcacard.lib-y=$(patsubst %.o,%.lo,$(libcacard-y)) @@ -54,10 +57,10 @@ install-libcacard: libcacard.pc libcacard.la vscclient $(INSTALL_DIR) "$(DESTDIR)$(libdir)/pkgconfig" $(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)" $(INSTALL_DIR) "$(DESTDIR)$(bindir)" - $(LIBTOOL) --mode=install $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)" - $(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.la "$(DESTDIR)$(libdir)" - $(LIBTOOL) --mode=install $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig" + $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)" + $(INSTALL_LIB) libcacard.la "$(DESTDIR)$(libdir)" + $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig" for inc in *.h; do \ - $(LIBTOOL) --mode=install $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \ + $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \ done endif diff --git a/rules.mak b/rules.mak index 927301251e..4673aada07 100644 --- a/rules.mak +++ b/rules.mak @@ -23,10 +23,18 @@ QEMU_CFLAGS += -I$( Date: Fri, 21 Dec 2012 09:23:18 +0100 Subject: [PATCH 0400/1634] build: move dtrace rules to rules.mak Signed-off-by: Paolo Bonzini --- rules.mak | 9 +++++++++ trace/Makefile.objs | 12 ------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/rules.mak b/rules.mak index 4673aada07..5865e9ba93 100644 --- a/rules.mak +++ b/rules.mak @@ -23,6 +23,9 @@ QEMU_CFLAGS += -I$( Date: Thu, 20 Dec 2012 20:39:36 +0100 Subject: [PATCH 0401/1634] build: remove CONFIG_SMARTCARD The passthru smartcard does not have the shared library dependency, build it unconditionally. Signed-off-by: Paolo Bonzini --- configure | 69 +++++++++++++++++--------------------------- hw/Makefile.objs | 2 +- hw/usb/Makefile.objs | 2 +- 3 files changed, 28 insertions(+), 45 deletions(-) diff --git a/configure b/configure index 5ae203df08..35762f5b5d 100755 --- a/configure +++ b/configure @@ -214,7 +214,6 @@ trace_backend="nop" trace_file="trace" spice="" rbd="" -smartcard="" smartcard_nss="" usb_redir="" opengl="" @@ -861,10 +860,6 @@ for opt do ;; --enable-xfsctl) xfs="yes" ;; - --disable-smartcard) smartcard="no" - ;; - --enable-smartcard) smartcard="yes" - ;; --disable-smartcard-nss) smartcard_nss="no" ;; --enable-smartcard-nss) smartcard_nss="yes" @@ -1128,8 +1123,6 @@ echo " --enable-spice enable spice" echo " --enable-rbd enable building the rados block device (rbd)" echo " --disable-libiscsi disable iscsi support" echo " --enable-libiscsi enable iscsi support" -echo " --disable-smartcard disable smartcard support" -echo " --enable-smartcard enable smartcard support" echo " --disable-smartcard-nss disable smartcard nss support" echo " --enable-smartcard-nss enable smartcard nss support" echo " --disable-usb-redir disable usb network redirection support" @@ -2813,42 +2806,36 @@ EOF fi # check for libcacard for smartcard support -if test "$smartcard" != "no" ; then - smartcard="yes" - smartcard_cflags="" - # TODO - what's the minimal nss version we support? - if test "$smartcard_nss" != "no"; then - cat > $TMPC << EOF +smartcard_cflags="" +# TODO - what's the minimal nss version we support? +if test "$smartcard_nss" != "no"; then + cat > $TMPC << EOF #include int main(void) { PK11_FreeSlot(0); return 0; } EOF - smartcard_includes="-I\$(SRC_PATH)/libcacard" - libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" - libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" - test_cflags="$libcacard_cflags" - # The header files in nss < 3.13.3 have a bug which causes them to - # emit a warning. If we're going to compile QEMU with -Werror, then - # test that the headers don't have this bug. Otherwise we would pass - # the configure test but fail to compile QEMU later. - if test "$werror" = "yes"; then - test_cflags="-Werror $test_cflags" - fi - if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \ - compile_prog "$test_cflags" "$libcacard_libs"; then - smartcard_nss="yes" - QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags" - QEMU_INCLUDES="$QEMU_INCLUDES $smartcard_includes" - libs_softmmu="$libcacard_libs $libs_softmmu" - else - if test "$smartcard_nss" = "yes"; then - feature_not_found "nss" - fi - smartcard_nss="no" - fi + smartcard_includes="-I\$(SRC_PATH)/libcacard" + libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" + libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" + test_cflags="$libcacard_cflags" + # The header files in nss < 3.13.3 have a bug which causes them to + # emit a warning. If we're going to compile QEMU with -Werror, then + # test that the headers don't have this bug. Otherwise we would pass + # the configure test but fail to compile QEMU later. + if test "$werror" = "yes"; then + test_cflags="-Werror $test_cflags" + fi + if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \ + compile_prog "$test_cflags" "$libcacard_libs"; then + smartcard_nss="yes" + QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags" + QEMU_INCLUDES="$QEMU_INCLUDES $smartcard_includes" + libs_softmmu="$libcacard_libs $libs_softmmu" + else + if test "$smartcard_nss" = "yes"; then + feature_not_found "nss" + fi + smartcard_nss="no" fi -fi -if test "$smartcard" = "no" ; then - smartcard_nss="no" fi # check for usbredirparser for usb network redirection support @@ -3594,10 +3581,6 @@ if test "$spice" = "yes" ; then echo "CONFIG_SPICE=y" >> $config_host_mak fi -if test "$smartcard" = "yes" ; then - echo "CONFIG_SMARTCARD=y" >> $config_host_mak -fi - if test "$smartcard_nss" = "yes" ; then echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak echo "libcacard_libs=$libcacard_libs" >> $config_host_mak diff --git a/hw/Makefile.objs b/hw/Makefile.objs index d8671847fe..6fdd25e4b0 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -37,7 +37,7 @@ common-obj-$(CONFIG_DMA) += dma.o common-obj-$(CONFIG_I82374) += i82374.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_APPLESMC) += applesmc.o -common-obj-$(CONFIG_SMARTCARD) += ccid-card-passthru.o +common-obj-y += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-y += fifo.o diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index dad4cb9f3c..d1bbbc06e7 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -4,11 +4,11 @@ common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o common-obj-y += libhw.o -common-obj-$(CONFIG_SMARTCARD) += dev-smartcard-reader.o common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o common-obj-y += host-$(HOST_USB).o dev-bluetooth.o common-obj-y += dev-hid.o dev-storage.o dev-wacom.o common-obj-y += dev-serial.o dev-network.o dev-audio.o +common-obj-y += dev-smartcard-reader.o common-obj-y += dev-uas.o From e832341bde5448a6a1392ea903a553497a13763b Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Wed, 28 Nov 2012 11:16:26 +0200 Subject: [PATCH 0402/1634] libcacard: fix missing symbol in libcacard.so Before patch: $ make libcacard.la $ nm ./libcacard/.libs/libcacard.so.0.0.0 | grep " U " | \ egrep -v "(g_)|(GLIBC)|(SECMOD)|(PK11)|(CERT)|(NSS)|(PORT)|(PR)" U error_set Signed-off-by: Alon Levy Signed-off-by: Paolo Bonzini --- libcacard/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcacard/Makefile b/libcacard/Makefile index 34d503b8cc..08a47e0207 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -7,7 +7,7 @@ libcacard_includedir=$(includedir)/cacard $(call set-vpath, $(SRC_PATH)) # objects linked into a shared library, built with libtool with -fPIC if required -QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) $(stub-obj-y) +QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o error.o $(trace-obj-y) $(stub-obj-y) QEMU_OBJS_LIB=$(patsubst %.o,%.lo,$(QEMU_OBJS)) # libtool will build the .o files, too From b6fc675b25d32f018870e202eb4b2a6eb509f88b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 20:40:35 +0100 Subject: [PATCH 0403/1634] libcacard: require libtool to build it Do not fail at build time, instead just disable the library if libtool is not present. Signed-off-by: Paolo Bonzini --- Makefile | 2 ++ configure | 3 ++- libcacard/Makefile | 8 -------- rules.mak | 6 +----- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 3c960a166f..f035a61ce3 100644 --- a/Makefile +++ b/Makefile @@ -160,12 +160,14 @@ libqemustub.a: $(stub-obj-y) ###################################################################### # Support building shared library libcacard +ifeq ($(CONFIG_SMARTCARD_NSS),y) .PHONY: libcacard.la install-libcacard libcacard.la: $(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,) install-libcacard: libcacard.la $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,) +endif ###################################################################### diff --git a/configure b/configure index 35762f5b5d..39358add77 100755 --- a/configure +++ b/configure @@ -2824,7 +2824,8 @@ EOF if test "$werror" = "yes"; then test_cflags="-Werror $test_cflags" fi - if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \ + if test -n "$libtool" && + $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \ compile_prog "$test_cflags" "$libcacard_libs"; then smartcard_nss="yes" QEMU_CFLAGS="$QEMU_CFLAGS $libcacard_cflags" diff --git a/libcacard/Makefile b/libcacard/Makefile index 08a47e0207..a526eaeabd 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -31,13 +31,6 @@ all: libcacard.la libcacard.pc ######################################################################### # Rules for building libcacard standalone library -ifeq ($(LIBTOOL),) -libcacard.la: - @echo "libtool is missing, please install and rerun configure"; exit 1 - -install-libcacard: - @echo "libtool is missing, please install and rerun configure"; exit 1 -else libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB) $(call quiet-command,$(LIBTOOL) --mode=link --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs)," lt LINK $@") @@ -63,4 +56,3 @@ install-libcacard: libcacard.pc libcacard.la vscclient for inc in *.h; do \ $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \ done -endif diff --git a/rules.mak b/rules.mak index 5865e9ba93..4297345474 100644 --- a/rules.mak +++ b/rules.mak @@ -21,11 +21,7 @@ QEMU_CFLAGS += -I$( Date: Fri, 21 Dec 2012 09:16:33 +0100 Subject: [PATCH 0404/1634] libcacard: prepare to use -y trick in the Makefile Rename variables to follow the conventions of the rest of the build systems. Signed-off-by: Paolo Bonzini --- libcacard/Makefile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libcacard/Makefile b/libcacard/Makefile index a526eaeabd..ddab5d8297 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -7,17 +7,15 @@ libcacard_includedir=$(includedir)/cacard $(call set-vpath, $(SRC_PATH)) # objects linked into a shared library, built with libtool with -fPIC if required -QEMU_OBJS=$(oslib-obj-y) qemu-timer-common.o error.o $(trace-obj-y) $(stub-obj-y) -QEMU_OBJS_LIB=$(patsubst %.o,%.lo,$(QEMU_OBJS)) +libcacard-obj-y=$(oslib-obj-y) error.o $(trace-obj-y) $(stub-obj-y) $(libcacard-y) +libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y)) # libtool will build the .o files, too $(libcacard-obj-y): | $(libcacard-lobj-y) QEMU_CFLAGS+=-I../ -libcacard.lib-y=$(patsubst %.o,%.lo,$(libcacard-y)) - -vscclient: $(libcacard-y) $(QEMU_OBJS) vscclient.o cutils.o +vscclient: vscclient.o $(libcacard-obj-y) $(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@") clean: @@ -31,7 +29,7 @@ all: libcacard.la libcacard.pc ######################################################################### # Rules for building libcacard standalone library -libcacard.la: $(libcacard.lib-y) $(QEMU_OBJS_LIB) +libcacard.la: $(libcacard-lobj-y) $(call quiet-command,$(LIBTOOL) --mode=link --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs)," lt LINK $@") libcacard_srcpath=$(SRC_PATH)/libcacard From af0c8e9f3c75a23905b97be6f6e530acaa7bedc3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 21 Dec 2012 09:13:10 +0100 Subject: [PATCH 0405/1634] libcacard: use per-target variable definitions This lets the libcacard Makefile use more rules.mak magic. Signed-off-by: Paolo Bonzini --- libcacard/Makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libcacard/Makefile b/libcacard/Makefile index ddab5d8297..7fc6a06b8d 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -15,8 +15,9 @@ $(libcacard-obj-y): | $(libcacard-lobj-y) QEMU_CFLAGS+=-I../ +vscclient: LIBS += $(libcacard_libs) vscclient: vscclient.o $(libcacard-obj-y) - $(call quiet-command,$(CC) -o $@ $^ $(libcacard_libs) $(LIBS)," LINK $@") + $(call LINK,$^) clean: rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo */*.lo .libs/* */.libs/* *.la */*.la *.pc @@ -29,8 +30,10 @@ all: libcacard.la libcacard.pc ######################################################################### # Rules for building libcacard standalone library +libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined +libcacard.la: LIBS += $(libcacard_libs) libcacard.la: $(libcacard-lobj-y) - $(call quiet-command,$(LIBTOOL) --mode=link --tag=CC $(CC) -rpath $(libdir) -o $@ $^ $(libcacard_libs)," lt LINK $@") + $(call LINK,$^) libcacard_srcpath=$(SRC_PATH)/libcacard libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in From 5018f1cc9f9e2b68c12671e83cd1e3c6a12ec2b5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 18:19:51 +0100 Subject: [PATCH 0406/1634] libcacard: add list of exported symbols Do not export internal QEMU symbols. Signed-off-by: Paolo Bonzini --- libcacard/Makefile | 3 +- libcacard/libcacard.syms | 77 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 libcacard/libcacard.syms diff --git a/libcacard/Makefile b/libcacard/Makefile index 7fc6a06b8d..73fc817759 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -30,7 +30,8 @@ all: libcacard.la libcacard.pc ######################################################################### # Rules for building libcacard standalone library -libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined +libcacard.la: LDFLAGS += -rpath $(libdir) -no-undefined \ + -export-syms $(SRC_PATH)/libcacard/libcacard.syms libcacard.la: LIBS += $(libcacard_libs) libcacard.la: $(libcacard-lobj-y) $(call LINK,$^) diff --git a/libcacard/libcacard.syms b/libcacard/libcacard.syms new file mode 100644 index 0000000000..1697515a7f --- /dev/null +++ b/libcacard/libcacard.syms @@ -0,0 +1,77 @@ +cac_card_init +cac_is_cac_card +vcard_add_applet +vcard_apdu_delete +vcard_apdu_new +vcard_applet_get_aid +vcard_buffer_response_delete +vcard_buffer_response_new +vcard_delete_applet +vcard_emul_delete_key +vcard_emul_force_card_insert +vcard_emul_force_card_remove +vcard_emul_get_atr +vcard_emul_get_login_count +vcard_emul_init +vcard_emul_login +vcard_emul_options +vcard_emul_replay_insertion_events +vcard_emul_reset +vcard_emul_rsa_op +vcard_emul_type_from_string +vcard_emul_type_select +vcard_emul_usage +vcard_find_applet +vcard_free +vcard_get_atr +vcard_get_buffer_response +vcard_get_current_applet_private +vcard_get_private +vcard_get_type +vcard_init +vcard_make_response +vcard_new +vcard_new_applet +vcard_process_apdu +vcard_process_applet_apdu +vcard_reference +vcard_reset +vcard_response_delete +vcard_response_new +vcard_response_new_bytes +vcard_response_new_data +vcard_response_new_status_bytes +vcard_select_applet +vcard_set_applet_private +vcard_set_atr_func +vcard_set_buffer_response +vcard_set_type +vevent_delete +vevent_get_next_vevent +vevent_new +vevent_queue_init +vevent_queue_vevent +vevent_wait_next_vevent +vreader_add_reader +vreader_card_is_present +vreader_free +vreader_get_id +vreader_get_name +vreader_get_private +vreader_get_reader_by_id +vreader_get_reader_by_name +vreader_get_reader_list +vreader_init +vreader_insert_card +vreader_list_delete +vreader_list_get_first +vreader_list_get_next +vreader_list_get_reader +vreader_new +vreader_power_off +vreader_power_on +vreader_queue_card_event +vreader_reference +vreader_remove_reader +vreader_set_id +vreader_xfr_bytes From 992aeb8eb53e5846a957cf333f2e1ec8cb6e0c04 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 21 Dec 2012 08:34:49 +0100 Subject: [PATCH 0407/1634] libcacard: rewrite Makefile in non-recursive style Signed-off-by: Paolo Bonzini --- Makefile | 35 +++++++++-------------------------- configure | 9 +-------- libcacard/Makefile | 37 +++++++++++-------------------------- 3 files changed, 21 insertions(+), 60 deletions(-) diff --git a/Makefile b/Makefile index f035a61ce3..039d07011b 100644 --- a/Makefile +++ b/Makefile @@ -104,6 +104,14 @@ defconfig: -include config-all-devices.mak -include config-all-disas.mak +ifneq ($(wildcard config-host.mak),) +include $(SRC_PATH)/Makefile.objs +include $(SRC_PATH)/tests/Makefile +endif +ifeq ($(CONFIG_SMARTCARD_NSS),y) +include $(SRC_PATH)/libcacard/Makefile +endif + all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all config-host.h: config-host.h-timestamp @@ -116,12 +124,6 @@ SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) subdir-%: $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) -ifneq ($(wildcard config-host.mak),) -include $(SRC_PATH)/Makefile.objs -endif - -subdir-libcacard: $(oslib-obj-y) $(trace-obj-y) qemu-timer-common.o - subdir-pixman: pixman/Makefile $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,) @@ -157,18 +159,6 @@ version-obj-$(CONFIG_WIN32) += version.o libqemustub.a: $(stub-obj-y) -###################################################################### -# Support building shared library libcacard - -ifeq ($(CONFIG_SMARTCARD_NSS),y) -.PHONY: libcacard.la install-libcacard -libcacard.la: $(oslib-obj-y) qemu-timer-common.o $(trace-obj-y) - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" libcacard.la,) - -install-libcacard: libcacard.la - $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libcacard V="$(V)" TARGET_DIR="$*/" install-libcacard,) -endif - ###################################################################### qemu-img.o: qemu-img-cmds.h @@ -183,10 +173,6 @@ qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o -vscclient$(EXESUF): LIBS += $(libcacard_libs) -vscclient$(EXESUF): $(libcacard-y) $(oslib-obj-y) $(trace-obj-y) libcacard/vscclient.o libqemustub.a - $(call LINK, $^) - fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y) fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap @@ -198,10 +184,6 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated gen-out-type = $(subst .,-,$(suffix $@)) -ifneq ($(wildcard config-host.mak),) -include $(SRC_PATH)/tests/Makefile -endif - qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\ @@ -236,6 +218,7 @@ clean: rm -f qemu-options.def find . -name '*.[od]' -type f -exec rm -f {} + rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ + rm -f *.la rm -Rf .libs rm -f qemu-img-cmds.h @# May not be present in GENERATED_HEADERS diff --git a/configure b/configure index 39358add77..27ef38c6a3 100755 --- a/configure +++ b/configure @@ -3191,9 +3191,6 @@ if test "$softmmu" = yes ; then tools="qemu-ga\$(EXESUF) $tools" fi fi - if test "$smartcard_nss" = "yes" ; then - tools="vscclient\$(EXESUF) $tools" - fi fi # Mac OS X ships with a broken assembler @@ -4039,9 +4036,6 @@ fi if test "$target_softmmu" = "yes" ; then echo "CONFIG_SOFTMMU=y" >> $config_target_mak echo "LIBS+=$libs_softmmu $target_libs_softmmu" >> $config_target_mak - if test "$smartcard_nss" = "yes" ; then - echo "subdir-$target: subdir-libcacard" >> $config_host_mak - fi case "$target_arch2" in i386|x86_64) echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak @@ -4242,10 +4236,9 @@ DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32" DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas" DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS qapi-generated" -DIRS="$DIRS libcacard libcacard/libcacard libcacard/trace" FILES="Makefile tests/tcg/Makefile qdict-test-data.txt" FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" -FILES="$FILES tests/tcg/lm32/Makefile libcacard/Makefile" +FILES="$FILES tests/tcg/lm32/Makefile" FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" diff --git a/libcacard/Makefile b/libcacard/Makefile index 73fc817759..734065eff8 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -1,10 +1,6 @@ --include ../config-host.mak --include $(SRC_PATH)/rules.mak --include $(SRC_PATH)/Makefile.objs - libcacard_includedir=$(includedir)/cacard -$(call set-vpath, $(SRC_PATH)) +TOOLS += vscclient$(EXESUF) # objects linked into a shared library, built with libtool with -fPIC if required libcacard-obj-y=$(oslib-obj-y) error.o $(trace-obj-y) $(stub-obj-y) $(libcacard-y) @@ -13,19 +9,11 @@ libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y)) # libtool will build the .o files, too $(libcacard-obj-y): | $(libcacard-lobj-y) -QEMU_CFLAGS+=-I../ - -vscclient: LIBS += $(libcacard_libs) -vscclient: vscclient.o $(libcacard-obj-y) - $(call LINK,$^) - -clean: - rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ vscclient *.lo */*.lo .libs/* */.libs/* *.la */*.la *.pc - rm -Rf .libs */.libs - all: libcacard.la libcacard.pc -# Dummy command so that make thinks it has done something - @true + +vscclient$(EXESUF): LIBS += $(libcacard_libs) +vscclient$(EXESUF): libcacard/vscclient.o $(libcacard-obj-y) + $(call LINK,$^) ######################################################################### # Rules for building libcacard standalone library @@ -36,25 +24,22 @@ libcacard.la: LIBS += $(libcacard_libs) libcacard.la: $(libcacard-lobj-y) $(call LINK,$^) -libcacard_srcpath=$(SRC_PATH)/libcacard -libcacard.pc: $(libcacard_srcpath)/libcacard.pc.in +libcacard.pc: $(SRC_PATH)/libcacard/libcacard.pc.in $(call quiet-command,sed -e 's|@LIBDIR@|$(libdir)|' \ -e 's|@INCLUDEDIR@|$(libcacard_includedir)|' \ -e 's|@VERSION@|$(shell cat $(SRC_PATH)/VERSION)|' \ - -e 's|@PREFIX@|$(prefix)|' \ - < $(libcacard_srcpath)/libcacard.pc.in > libcacard.pc,\ + -e 's|@PREFIX@|$(prefix)|' $< > libcacard.pc,\ " GEN $@") .PHONY: install-libcacard -install-libcacard: libcacard.pc libcacard.la vscclient +install: install-libcacard +install-libcacard: libcacard.pc libcacard.la $(INSTALL_DIR) "$(DESTDIR)$(libdir)" $(INSTALL_DIR) "$(DESTDIR)$(libdir)/pkgconfig" $(INSTALL_DIR) "$(DESTDIR)$(libcacard_includedir)" - $(INSTALL_DIR) "$(DESTDIR)$(bindir)" - $(INSTALL_PROG) vscclient "$(DESTDIR)$(bindir)" $(INSTALL_LIB) libcacard.la "$(DESTDIR)$(libdir)" $(INSTALL_DATA) libcacard.pc "$(DESTDIR)$(libdir)/pkgconfig" - for inc in *.h; do \ - $(INSTALL_DATA) $(libcacard_srcpath)/$$inc "$(DESTDIR)$(libcacard_includedir)"; \ + for inc in $(SRC_PATH)/libcacard/*.h; do \ + $(INSTALL_DATA) $$inc "$(DESTDIR)$(libcacard_includedir)"; \ done From 26ca8c06d2e4fb43903c9d5e8ebe27792ffc461b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 21 Dec 2012 08:42:03 +0100 Subject: [PATCH 0408/1634] libcacard: link vscclient to dynamic library There is no reason for vscclient to duplicate the code. rules.mak takes care of invoking libtool to do the link. Signed-off-by: Paolo Bonzini --- libcacard/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcacard/Makefile b/libcacard/Makefile index 734065eff8..259ecf257d 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -11,8 +11,7 @@ $(libcacard-obj-y): | $(libcacard-lobj-y) all: libcacard.la libcacard.pc -vscclient$(EXESUF): LIBS += $(libcacard_libs) -vscclient$(EXESUF): libcacard/vscclient.o $(libcacard-obj-y) +vscclient$(EXESUF): libcacard/vscclient.o libcacard.la $(call LINK,$^) ######################################################################### From d9dc91ace82d1c4ca6f2c6f10a9cfcacf988662e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 18:24:27 +0100 Subject: [PATCH 0409/1634] libcacard: list oslib-obj-y file explicitly We will grow the list of files in the next patches, but libcacard should remain slim. Signed-off-by: Paolo Bonzini --- libcacard/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libcacard/Makefile b/libcacard/Makefile index 259ecf257d..63295f5ae6 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -3,7 +3,11 @@ libcacard_includedir=$(includedir)/cacard TOOLS += vscclient$(EXESUF) # objects linked into a shared library, built with libtool with -fPIC if required -libcacard-obj-y=$(oslib-obj-y) error.o $(trace-obj-y) $(stub-obj-y) $(libcacard-y) +libcacard-obj-y = $(trace-obj-y) $(stub-obj-y) $(libcacard-y) +libcacard-obj-y += osdep.o cutils.o qemu-timer-common.o error.o +libcacard-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o +libcacard-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o + libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y)) # libtool will build the .o files, too From e4b42e6ebc2442f5ae9885d62171599cc682b4f5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 14:34:31 +0100 Subject: [PATCH 0410/1634] build: rename oslib-obj-y to util-obj-y This prepares the creation of libqemuutil.a in the next patch. Signed-off-by: Paolo Bonzini --- Makefile | 4 ++-- Makefile.objs | 10 +++++----- Makefile.target | 4 ++-- tests/Makefile | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 039d07011b..965ffebce2 100644 --- a/Makefile +++ b/Makefile @@ -163,7 +163,7 @@ libqemustub.a: $(stub-obj-y) qemu-img.o: qemu-img-cmds.h -tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-timer.o \ +tools-obj-y = $(util-obj-y) $(trace-obj-y) qemu-timer.o \ main-loop.o iohandler.o error.o tools-obj-$(CONFIG_POSIX) += compatfd.o @@ -209,7 +209,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): $(qga-obj-y) $(oslib-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a +qemu-ga$(EXESUF): $(qga-obj-y) $(util-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a $(call LINK, $^) clean: diff --git a/Makefile.objs b/Makefile.objs index c64c0c69da..56d95e5d8e 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -29,10 +29,10 @@ hw-core-obj-y += qemu-option.o universal-obj-y += $(hw-core-obj-y) ####################################################################### -# oslib-obj-y is code depending on the OS (win32 vs posix) -oslib-obj-y = osdep.o cutils.o qemu-timer-common.o -oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o -oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o +# util-obj-y is code depending on the OS (win32 vs posix) +util-obj-y = osdep.o cutils.o qemu-timer-common.o +util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o +util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o ####################################################################### # coroutines @@ -78,7 +78,7 @@ common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ common-obj-y += qom/ common-obj-y += readline.o -common-obj-y += $(oslib-obj-y) +common-obj-y += $(util-obj-y) common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o diff --git a/Makefile.target b/Makefile.target index 5bfa496080..2534e77a11 100644 --- a/Makefile.target +++ b/Makefile.target @@ -83,7 +83,7 @@ ifdef CONFIG_LINUX_USER QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user obj-y += linux-user/ -obj-y += gdbstub.o thunk.o user-exec.o $(oslib-obj-y) +obj-y += gdbstub.o thunk.o user-exec.o $(util-obj-y) endif #CONFIG_LINUX_USER @@ -95,7 +95,7 @@ ifdef CONFIG_BSD_USER QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) obj-y += bsd-user/ -obj-y += gdbstub.o user-exec.o $(oslib-obj-y) +obj-y += gdbstub.o user-exec.o $(util-obj-y) endif #CONFIG_BSD_USER diff --git a/tests/Makefile b/tests/Makefile index cfd2d6aebd..693d137760 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -117,7 +117,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS))) QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),)) check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y)) -qtest-obj-y = tests/libqtest.o $(oslib-obj-y) libqemustub.a +qtest-obj-y = tests/libqtest.o $(util-obj-y) libqemustub.a $(check-qtest-y): $(qtest-obj-y) .PHONY: check-help From 8a090705b4485eaed602632963cc53acaf3ba12e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 15:40:20 +0100 Subject: [PATCH 0411/1634] build: move util-obj-y to libqemuutil.a Use a static library to eliminate repetition in the linking rules. Signed-off-by: Paolo Bonzini --- Makefile | 17 +++++++++-------- Makefile.objs | 1 - Makefile.target | 8 ++++---- tests/Makefile | 17 ++++++++--------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 965ffebce2..0b470ecac7 100644 --- a/Makefile +++ b/Makefile @@ -133,7 +133,7 @@ pixman/Makefile: $(SRC_PATH)/pixman/configure $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) -$(SUBDIR_RULES): libqemustub.a +$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) @@ -155,25 +155,26 @@ version.o: $(SRC_PATH)/version.rc config-host.h version-obj-$(CONFIG_WIN32) += version.o ###################################################################### -# Build library with stubs +# Build libraries libqemustub.a: $(stub-obj-y) +libqemuutil.a: $(util-obj-y) ###################################################################### qemu-img.o: qemu-img-cmds.h -tools-obj-y = $(util-obj-y) $(trace-obj-y) qemu-timer.o \ +tools-obj-y = $(trace-obj-y) qemu-timer.o \ main-loop.o iohandler.o error.o tools-obj-$(CONFIG_POSIX) += compatfd.o -qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemustub.a -qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemustub.a -qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a +qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a +qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a +qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o -fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y) +fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o $(trace-obj-y) libqemuutil.a libqemustub.a fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx @@ -209,7 +210,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): $(qga-obj-y) $(util-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemustub.a +qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) clean: diff --git a/Makefile.objs b/Makefile.objs index 56d95e5d8e..a5bfc7da8e 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -78,7 +78,6 @@ common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ common-obj-y += qom/ common-obj-y += readline.o -common-obj-y += $(util-obj-y) common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o diff --git a/Makefile.target b/Makefile.target index 2534e77a11..0a12873ff0 100644 --- a/Makefile.target +++ b/Makefile.target @@ -83,7 +83,7 @@ ifdef CONFIG_LINUX_USER QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user obj-y += linux-user/ -obj-y += gdbstub.o thunk.o user-exec.o $(util-obj-y) +obj-y += gdbstub.o thunk.o user-exec.o endif #CONFIG_LINUX_USER @@ -95,7 +95,7 @@ ifdef CONFIG_BSD_USER QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) obj-y += bsd-user/ -obj-y += gdbstub.o user-exec.o $(util-obj-y) +obj-y += gdbstub.o user-exec.o endif #CONFIG_BSD_USER @@ -155,12 +155,12 @@ endif #CONFIG_LINUX_USER ifdef QEMU_PROGW # The linker builds a windows executable. Make also a console executable. -$(QEMU_PROGW): $(all-obj-y) ../libqemustub.a +$(QEMU_PROGW): $(all-obj-y) ../libqemuutil.a ../libqemustub.a $(call LINK,$^) $(QEMU_PROG): $(QEMU_PROGW) $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)") else -$(QEMU_PROG): $(all-obj-y) ../libqemustub.a +$(QEMU_PROG): $(all-obj-y) ../libqemuutil.a ../libqemustub.a $(call LINK,$^) endif diff --git a/tests/Makefile b/tests/Makefile index 693d137760..329c912a0d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -72,7 +72,6 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o -test-qapi-obj-y += module.o $(test-obj-y): QEMU_INCLUDES += -Itests @@ -98,13 +97,13 @@ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") -tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemustub.a -tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemustub.a -tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemustub.a -tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemustub.a -tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemustub.a -tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) libqemustub.a -tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemustub.a +tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) @@ -117,7 +116,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS))) QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),)) check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y)) -qtest-obj-y = tests/libqtest.o $(util-obj-y) libqemustub.a +qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a $(check-qtest-y): $(qtest-obj-y) .PHONY: check-help From f157ebba2de4a6225679e13cc1ce01ff5d147c76 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 16:09:36 +0100 Subject: [PATCH 0412/1634] build: move files away from tools-obj-y, common-obj-y, user-obj-y Split them between libqemuutil.a and, for those used by qemu-img/io/nbd, block-obj-y. Static libraries ensure that binaries such as qemu-ga do not include unused modules. Signed-off-by: Paolo Bonzini --- Makefile | 10 +++------- Makefile.objs | 41 +++++++++++++++++++---------------------- tests/Makefile | 10 +++++----- 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 0b470ecac7..989cb1f6a5 100644 --- a/Makefile +++ b/Makefile @@ -164,13 +164,9 @@ libqemuutil.a: $(util-obj-y) qemu-img.o: qemu-img-cmds.h -tools-obj-y = $(trace-obj-y) qemu-timer.o \ - main-loop.o iohandler.o error.o -tools-obj-$(CONFIG_POSIX) += compatfd.o - -qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a -qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a -qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a +qemu-img$(EXESUF): qemu-img.o $(trace-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a +qemu-nbd$(EXESUF): qemu-nbd.o $(trace-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a +qemu-io$(EXESUF): qemu-io.o cmd.o $(trace-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o diff --git a/Makefile.objs b/Makefile.objs index a5bfc7da8e..1c88fc1451 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -11,7 +11,7 @@ universal-obj-y += qemu-log.o # QObject qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o -qobject-obj-y += qerror.o error.o qemu-error.o +qobject-obj-y += qerror.o universal-obj-y += $(qobject-obj-y) @@ -24,15 +24,21 @@ universal-obj-y += $(qom-obj-y) ####################################################################### # Core hw code (qdev core) hw-core-obj-y += hw/ -hw-core-obj-y += qemu-option.o universal-obj-y += $(hw-core-obj-y) ####################################################################### # util-obj-y is code depending on the OS (win32 vs posix) util-obj-y = osdep.o cutils.o qemu-timer-common.o -util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o -util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o +util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win32.o +util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o +util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o +util-obj-y += bitmap.o bitops.o +util-obj-y += acl.o +util-obj-y += error.o qemu-error.o +util-obj-$(CONFIG_POSIX) += compatfd.o +util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o +util-obj-y += qemu-option.o qemu-progress.o ####################################################################### # coroutines @@ -54,12 +60,12 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o ####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img -block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o -block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o -block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o +block-obj-y = async.o thread-pool.o +block-obj-y += nbd.o block.o blockjob.o block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y) -block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o -block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o +block-obj-y += main-loop.o iohandler.o qemu-timer.o +block-obj-$(CONFIG_POSIX) += aio-posix.o +block-obj-$(CONFIG_WIN32) += aio-win32.o block-obj-y += block/ block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o @@ -84,12 +90,10 @@ common-obj-$(CONFIG_POSIX) += os-posix.o common-obj-$(CONFIG_LINUX) += fsdev/ extra-obj-$(CONFIG_LINUX) += fsdev/ -common-obj-y += tcg-runtime.o host-utils.o main-loop.o -common-obj-y += migration.o migration-tcp.o +common-obj-y += tcg-runtime.o common-obj-y += migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o -common-obj-y += block-migration.o iohandler.o -common-obj-y += bitmap.o bitops.o +common-obj-y += block-migration.o common-obj-y += page_cache.o common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o @@ -105,9 +109,6 @@ common-obj-y += ui/ common-obj-y += bt-host.o bt-vhci.o common-obj-y += dma-helpers.o -common-obj-y += acl.o -common-obj-$(CONFIG_POSIX) += compatfd.o -common-obj-y += qemu-timer.o qemu-timer-common.o common-obj-y += qtest.o common-obj-y += vl.o @@ -125,10 +126,7 @@ endif # libuser user-obj-y = -user-obj-y += envlist.o path.o -user-obj-y += tcg-runtime.o host-utils.o -user-obj-y += cache-utils.o -user-obj-y += module.o +user-obj-y += tcg-runtime.o user-obj-y += qom/ ###################################################################### @@ -169,8 +167,7 @@ universal-obj-y += $(qapi-obj-y) ###################################################################### # guest agent -qga-obj-y = qga/ module.o -qga-obj-$(CONFIG_POSIX) += qemu-sockets.o qemu-option.o +qga-obj-y = qga/ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/tests/Makefile b/tests/Makefile index 329c912a0d..a398b4afb9 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -80,11 +80,11 @@ tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o -tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) libqemustub.a -tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) iov.o libqemustub.a -tests/test-aio$(EXESUF): tests/test-aio.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a -tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a -tests/test-iov$(EXESUF): tests/test-iov.o iov.o +tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) libqemuutil.a libqemustub.a +tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py From baacf04799ace72a9c735dd9306a1ceaf305e7cf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 15:58:44 +0100 Subject: [PATCH 0413/1634] build: move libqemuutil.a components to util/ Signed-off-by: Paolo Bonzini --- Makefile.objs | 12 ++---------- libcacard/Makefile | 6 +++--- util/Makefile.objs | 10 ++++++++++ acl.c => util/acl.c | 0 aes.c => util/aes.c | 0 bitmap.c => util/bitmap.c | 0 bitops.c => util/bitops.c | 0 cache-utils.c => util/cache-utils.c | 0 compatfd.c => util/compatfd.c | 0 cutils.c => util/cutils.c | 0 envlist.c => util/envlist.c | 0 error.c => util/error.c | 0 .../event_notifier-posix.c | 0 .../event_notifier-win32.c | 0 host-utils.c => util/host-utils.c | 0 iov.c => util/iov.c | 0 module.c => util/module.c | 0 notify.c => util/notify.c | 0 osdep.c => util/osdep.c | 0 oslib-posix.c => util/oslib-posix.c | 0 oslib-win32.c => util/oslib-win32.c | 0 path.c => util/path.c | 0 qemu-config.c => util/qemu-config.c | 0 qemu-error.c => util/qemu-error.c | 0 qemu-option.c => util/qemu-option.c | 0 qemu-progress.c => util/qemu-progress.c | 0 qemu-sockets.c => util/qemu-sockets.c | 0 qemu-thread-posix.c => util/qemu-thread-posix.c | 0 qemu-thread-win32.c => util/qemu-thread-win32.c | 0 qemu-timer-common.c => util/qemu-timer-common.c | 0 uri.c => util/uri.c | 0 31 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 util/Makefile.objs rename acl.c => util/acl.c (100%) rename aes.c => util/aes.c (100%) rename bitmap.c => util/bitmap.c (100%) rename bitops.c => util/bitops.c (100%) rename cache-utils.c => util/cache-utils.c (100%) rename compatfd.c => util/compatfd.c (100%) rename cutils.c => util/cutils.c (100%) rename envlist.c => util/envlist.c (100%) rename error.c => util/error.c (100%) rename event_notifier-posix.c => util/event_notifier-posix.c (100%) rename event_notifier-win32.c => util/event_notifier-win32.c (100%) rename host-utils.c => util/host-utils.c (100%) rename iov.c => util/iov.c (100%) rename module.c => util/module.c (100%) rename notify.c => util/notify.c (100%) rename osdep.c => util/osdep.c (100%) rename oslib-posix.c => util/oslib-posix.c (100%) rename oslib-win32.c => util/oslib-win32.c (100%) rename path.c => util/path.c (100%) rename qemu-config.c => util/qemu-config.c (100%) rename qemu-error.c => util/qemu-error.c (100%) rename qemu-option.c => util/qemu-option.c (100%) rename qemu-progress.c => util/qemu-progress.c (100%) rename qemu-sockets.c => util/qemu-sockets.c (100%) rename qemu-thread-posix.c => util/qemu-thread-posix.c (100%) rename qemu-thread-win32.c => util/qemu-thread-win32.c (100%) rename qemu-timer-common.c => util/qemu-timer-common.c (100%) rename uri.c => util/uri.c (100%) diff --git a/Makefile.objs b/Makefile.objs index 1c88fc1451..3b777c822e 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -29,16 +29,7 @@ universal-obj-y += $(hw-core-obj-y) ####################################################################### # util-obj-y is code depending on the OS (win32 vs posix) -util-obj-y = osdep.o cutils.o qemu-timer-common.o -util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win32.o -util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o -util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o -util-obj-y += bitmap.o bitops.o -util-obj-y += acl.o -util-obj-y += error.o qemu-error.o -util-obj-$(CONFIG_POSIX) += compatfd.o -util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o -util-obj-y += qemu-option.o qemu-progress.o +util-obj-y += util/ ####################################################################### # coroutines @@ -177,6 +168,7 @@ QEMU_CFLAGS+=$(GLIB_CFLAGS) nested-vars += \ stub-obj-y \ + util-obj-y \ qga-obj-y \ qom-obj-y \ qapi-obj-y \ diff --git a/libcacard/Makefile b/libcacard/Makefile index 63295f5ae6..c658d3a9b7 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -4,9 +4,9 @@ TOOLS += vscclient$(EXESUF) # objects linked into a shared library, built with libtool with -fPIC if required libcacard-obj-y = $(trace-obj-y) $(stub-obj-y) $(libcacard-y) -libcacard-obj-y += osdep.o cutils.o qemu-timer-common.o error.o -libcacard-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o -libcacard-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o +libcacard-obj-y += util/osdep.o util/cutils.o util/qemu-timer-common.o util/error.o +libcacard-obj-$(CONFIG_WIN32) += util/oslib-win32.o util/qemu-thread-win32.o +libcacard-obj-$(CONFIG_POSIX) += util/oslib-posix.o util/qemu-thread-posix.o libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y)) diff --git a/util/Makefile.objs b/util/Makefile.objs new file mode 100644 index 0000000000..5baeb53af6 --- /dev/null +++ b/util/Makefile.objs @@ -0,0 +1,10 @@ +util-obj-y = osdep.o cutils.o qemu-timer-common.o +util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win32.o +util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o +util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o +util-obj-y += bitmap.o bitops.o +util-obj-y += acl.o +util-obj-y += error.o qemu-error.o +util-obj-$(CONFIG_POSIX) += compatfd.o +util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o +util-obj-y += qemu-option.o qemu-progress.o diff --git a/acl.c b/util/acl.c similarity index 100% rename from acl.c rename to util/acl.c diff --git a/aes.c b/util/aes.c similarity index 100% rename from aes.c rename to util/aes.c diff --git a/bitmap.c b/util/bitmap.c similarity index 100% rename from bitmap.c rename to util/bitmap.c diff --git a/bitops.c b/util/bitops.c similarity index 100% rename from bitops.c rename to util/bitops.c diff --git a/cache-utils.c b/util/cache-utils.c similarity index 100% rename from cache-utils.c rename to util/cache-utils.c diff --git a/compatfd.c b/util/compatfd.c similarity index 100% rename from compatfd.c rename to util/compatfd.c diff --git a/cutils.c b/util/cutils.c similarity index 100% rename from cutils.c rename to util/cutils.c diff --git a/envlist.c b/util/envlist.c similarity index 100% rename from envlist.c rename to util/envlist.c diff --git a/error.c b/util/error.c similarity index 100% rename from error.c rename to util/error.c diff --git a/event_notifier-posix.c b/util/event_notifier-posix.c similarity index 100% rename from event_notifier-posix.c rename to util/event_notifier-posix.c diff --git a/event_notifier-win32.c b/util/event_notifier-win32.c similarity index 100% rename from event_notifier-win32.c rename to util/event_notifier-win32.c diff --git a/host-utils.c b/util/host-utils.c similarity index 100% rename from host-utils.c rename to util/host-utils.c diff --git a/iov.c b/util/iov.c similarity index 100% rename from iov.c rename to util/iov.c diff --git a/module.c b/util/module.c similarity index 100% rename from module.c rename to util/module.c diff --git a/notify.c b/util/notify.c similarity index 100% rename from notify.c rename to util/notify.c diff --git a/osdep.c b/util/osdep.c similarity index 100% rename from osdep.c rename to util/osdep.c diff --git a/oslib-posix.c b/util/oslib-posix.c similarity index 100% rename from oslib-posix.c rename to util/oslib-posix.c diff --git a/oslib-win32.c b/util/oslib-win32.c similarity index 100% rename from oslib-win32.c rename to util/oslib-win32.c diff --git a/path.c b/util/path.c similarity index 100% rename from path.c rename to util/path.c diff --git a/qemu-config.c b/util/qemu-config.c similarity index 100% rename from qemu-config.c rename to util/qemu-config.c diff --git a/qemu-error.c b/util/qemu-error.c similarity index 100% rename from qemu-error.c rename to util/qemu-error.c diff --git a/qemu-option.c b/util/qemu-option.c similarity index 100% rename from qemu-option.c rename to util/qemu-option.c diff --git a/qemu-progress.c b/util/qemu-progress.c similarity index 100% rename from qemu-progress.c rename to util/qemu-progress.c diff --git a/qemu-sockets.c b/util/qemu-sockets.c similarity index 100% rename from qemu-sockets.c rename to util/qemu-sockets.c diff --git a/qemu-thread-posix.c b/util/qemu-thread-posix.c similarity index 100% rename from qemu-thread-posix.c rename to util/qemu-thread-posix.c diff --git a/qemu-thread-win32.c b/util/qemu-thread-win32.c similarity index 100% rename from qemu-thread-win32.c rename to util/qemu-thread-win32.c diff --git a/qemu-timer-common.c b/util/qemu-timer-common.c similarity index 100% rename from qemu-timer-common.c rename to util/qemu-timer-common.c diff --git a/uri.c b/util/uri.c similarity index 100% rename from uri.c rename to util/uri.c From a372823a14461c454feaa86373bd672fd518847a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 16:10:26 +0100 Subject: [PATCH 0414/1634] build: move qobject files to qobject/ and libqemuutil.a Signed-off-by: Paolo Bonzini --- Makefile | 2 +- Makefile.objs | 17 +++-------------- qobject/Makefile.objs | 3 +++ json-lexer.c => qobject/json-lexer.c | 0 json-parser.c => qobject/json-parser.c | 0 json-streamer.c => qobject/json-streamer.c | 0 qbool.c => qobject/qbool.c | 0 qdict.c => qobject/qdict.c | 0 qerror.c => qobject/qerror.c | 0 qfloat.c => qobject/qfloat.c | 0 qint.c => qobject/qint.c | 0 qjson.c => qobject/qjson.c | 0 qlist.c => qobject/qlist.c | 0 qstring.c => qobject/qstring.c | 0 tests/Makefile | 14 +++++++------- 15 files changed, 14 insertions(+), 22 deletions(-) create mode 100644 qobject/Makefile.objs rename json-lexer.c => qobject/json-lexer.c (100%) rename json-parser.c => qobject/json-parser.c (100%) rename json-streamer.c => qobject/json-streamer.c (100%) rename qbool.c => qobject/qbool.c (100%) rename qdict.c => qobject/qdict.c (100%) rename qerror.c => qobject/qerror.c (100%) rename qfloat.c => qobject/qfloat.c (100%) rename qint.c => qobject/qint.c (100%) rename qjson.c => qobject/qjson.c (100%) rename qlist.c => qobject/qlist.c (100%) rename qstring.c => qobject/qstring.c (100%) diff --git a/Makefile b/Makefile index 989cb1f6a5..ee39b364fb 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) $(qapi-obj-y) $(qobject-obj-y) $(version-obj-y) libqemuutil.a libqemustub.a +qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) $(qapi-obj-y) $(version-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) clean: diff --git a/Makefile.objs b/Makefile.objs index 3b777c822e..d412d8c6a8 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,20 +1,13 @@ ####################################################################### -# Stub library, linked in tools +# Common libraries for tools and emulators stub-obj-y = stubs/ +util-obj-y = util/ qobject/ ####################################################################### # Target-independent parts used in system and user emulation universal-obj-y = universal-obj-y += qemu-log.o -####################################################################### -# QObject -qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o -qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o -qobject-obj-y += qerror.o - -universal-obj-y += $(qobject-obj-y) - ####################################################################### # QOM qom-obj-y = qom/ @@ -27,10 +20,6 @@ hw-core-obj-y += hw/ universal-obj-y += $(hw-core-obj-y) -####################################################################### -# util-obj-y is code depending on the OS (win32 vs posix) -util-obj-y += util/ - ####################################################################### # coroutines coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o @@ -53,7 +42,7 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o block-obj-y = async.o thread-pool.o block-obj-y += nbd.o block.o blockjob.o -block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y) +block-obj-y += $(coroutine-obj-y) $(version-obj-y) block-obj-y += main-loop.o iohandler.o qemu-timer.o block-obj-$(CONFIG_POSIX) += aio-posix.o block-obj-$(CONFIG_WIN32) += aio-win32.o diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs new file mode 100644 index 0000000000..c9ff59c6cc --- /dev/null +++ b/qobject/Makefile.objs @@ -0,0 +1,3 @@ +util-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o +util-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o +util-obj-y += qerror.o diff --git a/json-lexer.c b/qobject/json-lexer.c similarity index 100% rename from json-lexer.c rename to qobject/json-lexer.c diff --git a/json-parser.c b/qobject/json-parser.c similarity index 100% rename from json-parser.c rename to qobject/json-parser.c diff --git a/json-streamer.c b/qobject/json-streamer.c similarity index 100% rename from json-streamer.c rename to qobject/json-streamer.c diff --git a/qbool.c b/qobject/qbool.c similarity index 100% rename from qbool.c rename to qobject/qbool.c diff --git a/qdict.c b/qobject/qdict.c similarity index 100% rename from qdict.c rename to qobject/qdict.c diff --git a/qerror.c b/qobject/qerror.c similarity index 100% rename from qerror.c rename to qobject/qerror.c diff --git a/qfloat.c b/qobject/qfloat.c similarity index 100% rename from qfloat.c rename to qobject/qfloat.c diff --git a/qint.c b/qobject/qint.c similarity index 100% rename from qint.c rename to qobject/qint.c diff --git a/qjson.c b/qobject/qjson.c similarity index 100% rename from qjson.c rename to qobject/qjson.c diff --git a/qlist.c b/qobject/qlist.c similarity index 100% rename from qlist.c rename to qobject/qlist.c diff --git a/qstring.c b/qobject/qstring.c similarity index 100% rename from qstring.c rename to qobject/qstring.c diff --git a/tests/Makefile b/tests/Makefile index a398b4afb9..837f769433 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -70,17 +70,17 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o -test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) +test-qapi-obj-y = $(qapi-obj-y) test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o $(test-obj-y): QEMU_INCLUDES += -Itests -tests/check-qint$(EXESUF): tests/check-qint.o qint.o -tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o -tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o -tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o -tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o -tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) libqemuutil.a libqemustub.a +tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a +tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a +tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a +tests/check-qlist$(EXESUF): tests/check-qlist.o libqemuutil.a +tests/check-qfloat$(EXESUF): tests/check-qfloat.o libqemuutil.a +tests/check-qjson$(EXESUF): tests/check-qjson.o libqemuutil.a libqemustub.a tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a From 9444e9e640d56039253d885ba88c3fa818a00149 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 15:24:49 +0100 Subject: [PATCH 0415/1634] build: consolidate multiple variables into universal-obj-y The directory descent mechanism, and a less-flat tree both helped in making some *-obj-y definitions very short. Many of these often end up in universal-obj-y, and used to be separate only because of libuser (which is now part of history...). Consolidate these variables in a single one. Signed-off-by: Paolo Bonzini --- Makefile.objs | 46 +++++++++------------------------------------- Makefile.target | 7 +------ hw/Makefile.objs | 5 ++--- qom/Makefile.objs | 6 ++---- 4 files changed, 14 insertions(+), 50 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index d412d8c6a8..f2f43b2385 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -3,23 +3,6 @@ stub-obj-y = stubs/ util-obj-y = util/ qobject/ -####################################################################### -# Target-independent parts used in system and user emulation -universal-obj-y = -universal-obj-y += qemu-log.o - -####################################################################### -# QOM -qom-obj-y = qom/ - -universal-obj-y += $(qom-obj-y) - -####################################################################### -# Core hw code (qdev core) -hw-core-obj-y += hw/ - -universal-obj-y += $(hw-core-obj-y) - ####################################################################### # coroutines coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o @@ -62,7 +45,6 @@ endif common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ -common-obj-y += qom/ common-obj-y += readline.o common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o @@ -70,7 +52,6 @@ common-obj-$(CONFIG_POSIX) += os-posix.o common-obj-$(CONFIG_LINUX) += fsdev/ extra-obj-$(CONFIG_LINUX) += fsdev/ -common-obj-y += tcg-runtime.o common-obj-y += migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o common-obj-y += block-migration.o @@ -102,26 +83,11 @@ ifeq ($(CONFIG_SECCOMP),y) common-obj-y += qemu-seccomp.o endif -###################################################################### -# libuser - -user-obj-y = -user-obj-y += tcg-runtime.o -user-obj-y += qom/ - -###################################################################### -# disassemblers -# NOTE: the disassembler code is only needed for debugging - -universal-obj-y += disas/ - ###################################################################### # trace trace-obj-y += trace/ -universal-obj-y += $(trace-obj-y) - ###################################################################### # smartcard @@ -142,6 +108,15 @@ qapi-obj-y += qapi-types.o qapi-visit.o common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o common-obj-y += qmp.o hmp.o +####################################################################### +# Target-independent parts used in system and user emulation +universal-obj-y = +universal-obj-y += qemu-log.o +universal-obj-y += tcg-runtime.o +universal-obj-y += hw/ +universal-obj-y += qom/ +universal-obj-y += disas/ +universal-obj-y += $(trace-obj-y) universal-obj-y += $(qapi-obj-y) ###################################################################### @@ -159,13 +134,10 @@ nested-vars += \ stub-obj-y \ util-obj-y \ qga-obj-y \ - qom-obj-y \ qapi-obj-y \ block-obj-y \ - user-obj-y \ common-obj-y \ universal-obj-y \ - hw-core-obj-y \ extra-obj-y \ trace-obj-y dummy := $(call unnest-vars) diff --git a/Makefile.target b/Makefile.target index 0a12873ff0..d55134c12f 100644 --- a/Makefile.target +++ b/Makefile.target @@ -146,12 +146,7 @@ include $(SRC_PATH)/Makefile.objs all-obj-y = $(obj-y) all-obj-y += $(addprefix ../, $(universal-obj-y)) - -ifdef CONFIG_SOFTMMU -all-obj-y += $(addprefix ../, $(common-obj-y)) -else -all-obj-y += $(addprefix ../, $(user-obj-y)) -endif #CONFIG_LINUX_USER +all-obj-$(CONFIG_SOFTMMU) += $(addprefix ../, $(common-obj-y)) ifdef QEMU_PROGW # The linker builds a windows executable. Make also a console executable. diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 6fdd25e4b0..aa55ce9873 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,8 +1,7 @@ # core qdev-related obj files, also used by *-user: -hw-core-obj-y += qdev.o qdev-properties.o +universal-obj-y += qdev.o qdev-properties.o # irq.o needed for qdev GPIO handling: -hw-core-obj-y += irq.o - +universal-obj-y += irq.o common-obj-y = usb/ ide/ pci/ common-obj-y += loader.o diff --git a/qom/Makefile.objs b/qom/Makefile.objs index 5ef060a401..1899a4ce42 100644 --- a/qom/Makefile.objs +++ b/qom/Makefile.objs @@ -1,4 +1,2 @@ -qom-obj-y = object.o container.o qom-qobject.o -qom-obj-twice-y = cpu.o -common-obj-y = $(qom-obj-twice-y) -user-obj-y = $(qom-obj-twice-y) +universal-obj-y = object.o container.o qom-qobject.o +universal-obj-y += cpu.o From 59cacde8cdf2e85de9b1aff63e456e89a8a5c59d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 15:03:18 +0100 Subject: [PATCH 0416/1634] build: move QAPI definitions for QEMU out of qapi-obj-y There is no reason why for example qemu-ga should include all the definitions for the QEMU monitor. However, there are a few that are needed (qapi_free_SocketAddress, qapi_free_InetSocketAddress, ErrorClass_lookup). These should be moved to a separate "core" .json schema that goes into libqemuutil.a. For now, make this clearer by moving the qapi-*.o definitions out of libqemuutil.a. Once the above refactoring is done, qga-obj-y should not include anymore qapi-types.o and qapi-visit.o. Signed-off-by: Paolo Bonzini --- Makefile.objs | 6 ++++-- tests/Makefile | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index f2f43b2385..48a7173e68 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -103,7 +103,6 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) # qapi qapi-obj-y = qapi/ -qapi-obj-y += qapi-types.o qapi-visit.o common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o common-obj-y += qmp.o hmp.o @@ -118,11 +117,14 @@ universal-obj-y += qom/ universal-obj-y += disas/ universal-obj-y += $(trace-obj-y) universal-obj-y += $(qapi-obj-y) +universal-obj-y += qapi-types.o qapi-visit.o ###################################################################### # guest agent -qga-obj-y = qga/ +# FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed +# by libqemuutil.a. These should be moved to a separate .json schema. +qga-obj-y = qga/ qapi-types.o qapi-visit.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) diff --git a/tests/Makefile b/tests/Makefile index 837f769433..9017fead15 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -102,7 +102,7 @@ tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(te tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) qapi-types.o qapi-visit.o libqemuutil.a libqemustub.a tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) From 576d55068d210c7316297af4194a10f729efe742 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 15:27:51 +0100 Subject: [PATCH 0417/1634] build: move base QAPI files to libqemuutil.a Signed-off-by: Paolo Bonzini --- Makefile | 2 +- Makefile.objs | 9 ++------- qapi/Makefile.objs | 8 ++++---- tests/Makefile | 3 +-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index ee39b364fb..8c3b13e4be 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) $(qapi-obj-y) $(version-obj-y) libqemuutil.a libqemustub.a +qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) $(version-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) clean: diff --git a/Makefile.objs b/Makefile.objs index 48a7173e68..eed27df106 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,7 +1,7 @@ ####################################################################### # Common libraries for tools and emulators stub-obj-y = stubs/ -util-obj-y = util/ qobject/ +util-obj-y = util/ qobject/ qapi/ ####################################################################### # coroutines @@ -30,7 +30,7 @@ block-obj-y += main-loop.o iohandler.o qemu-timer.o block-obj-$(CONFIG_POSIX) += aio-posix.o block-obj-$(CONFIG_WIN32) += aio-win32.o block-obj-y += block/ -block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o +block-obj-y += qapi-types.o qapi-visit.o ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. @@ -102,8 +102,6 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) ###################################################################### # qapi -qapi-obj-y = qapi/ - common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o common-obj-y += qmp.o hmp.o @@ -116,8 +114,6 @@ universal-obj-y += hw/ universal-obj-y += qom/ universal-obj-y += disas/ universal-obj-y += $(trace-obj-y) -universal-obj-y += $(qapi-obj-y) -universal-obj-y += qapi-types.o qapi-visit.o ###################################################################### # guest agent @@ -136,7 +132,6 @@ nested-vars += \ stub-obj-y \ util-obj-y \ qga-obj-y \ - qapi-obj-y \ block-obj-y \ common-obj-y \ universal-obj-y \ diff --git a/qapi/Makefile.objs b/qapi/Makefile.objs index f9bd3b9910..1f9c97342c 100644 --- a/qapi/Makefile.objs +++ b/qapi/Makefile.objs @@ -1,5 +1,5 @@ -qapi-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o -qapi-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o -qapi-obj-y += string-input-visitor.o string-output-visitor.o +util-obj-y = qapi-visit-core.o qapi-dealloc-visitor.o qmp-input-visitor.o +util-obj-y += qmp-output-visitor.o qmp-registry.o qmp-dispatch.o +util-obj-y += string-input-visitor.o string-output-visitor.o -common-obj-y += opts-visitor.o +util-obj-y += opts-visitor.o diff --git a/tests/Makefile b/tests/Makefile index 9017fead15..f224eb2390 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -70,8 +70,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o -test-qapi-obj-y = $(qapi-obj-y) -test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o +test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o $(test-obj-y): QEMU_INCLUDES += -Itests From bf0842b71f581e0c60f4bbfbebf37ff999a22b88 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 17:36:35 +0100 Subject: [PATCH 0418/1634] build: move version-obj-y to the generic LINK rule There is no reason for it to be in block-obj-y, in particular. Signed-off-by: Paolo Bonzini --- Makefile | 2 +- Makefile.objs | 3 +-- rules.mak | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 8c3b13e4be..ad85e5ba8d 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) $(version-obj-y) libqemuutil.a libqemustub.a +qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) clean: diff --git a/Makefile.objs b/Makefile.objs index eed27df106..aae2696b79 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -25,7 +25,7 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o block-obj-y = async.o thread-pool.o block-obj-y += nbd.o block.o blockjob.o -block-obj-y += $(coroutine-obj-y) $(version-obj-y) +block-obj-y += $(coroutine-obj-y) block-obj-y += main-loop.o iohandler.o qemu-timer.o block-obj-$(CONFIG_POSIX) += aio-posix.o block-obj-$(CONFIG_WIN32) += aio-win32.o @@ -58,7 +58,6 @@ common-obj-y += block-migration.o common-obj-y += page_cache.o common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o -common-obj-$(CONFIG_WIN32) += version.o common-obj-$(CONFIG_SPICE) += spice-qemu-char.o diff --git a/rules.mak b/rules.mak index 4297345474..6d82c0d5a0 100644 --- a/rules.mak +++ b/rules.mak @@ -23,7 +23,7 @@ QEMU_CFLAGS += -I$( Date: Thu, 20 Dec 2012 17:38:14 +0100 Subject: [PATCH 0419/1634] build: remove coroutine-obj-y Just fold it into block-obj-y. Signed-off-by: Paolo Bonzini --- Makefile.objs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index aae2696b79..bc56c61af6 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -3,35 +3,30 @@ stub-obj-y = stubs/ util-obj-y = util/ qobject/ qapi/ -####################################################################### -# coroutines -coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o -coroutine-obj-y += qemu-coroutine-sleep.o - -# If you change this logic, please also check tests/Makefile -ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) -coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o -else -ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y) -coroutine-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o -else -coroutine-obj-$(CONFIG_POSIX) += coroutine-gthread.o -endif -endif -coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o - ####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img block-obj-y = async.o thread-pool.o block-obj-y += nbd.o block.o blockjob.o -block-obj-y += $(coroutine-obj-y) block-obj-y += main-loop.o iohandler.o qemu-timer.o block-obj-$(CONFIG_POSIX) += aio-posix.o block-obj-$(CONFIG_WIN32) += aio-win32.o block-obj-y += block/ block-obj-y += qapi-types.o qapi-visit.o +block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o +block-obj-y += qemu-coroutine-sleep.o +ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) +block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o +else +ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y) +block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o +else +block-obj-$(CONFIG_POSIX) += coroutine-gthread.o +endif +endif +block-obj-$(CONFIG_WIN32) += coroutine-win32.o + ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. # only pull in the actual virtio-9p device if we also enabled virtio. From 0e848f482bce75f4d9cbac9f495fa45e51d08c9a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 24 Dec 2012 14:06:27 +0100 Subject: [PATCH 0420/1634] build: some simplifications for "trace/Makefile.objs" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lluís Vilanova Signed-off-by: Paolo Bonzini --- trace.h => include/trace.h | 0 trace/Makefile.objs | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) rename trace.h => include/trace.h (100%) diff --git a/trace.h b/include/trace.h similarity index 100% rename from trace.h rename to include/trace.h diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 40febce5a1..ed2e30b001 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -1,12 +1,9 @@ # -*- mode: makefile -*- ###################################################################### -# Auto-generated tracing routines +# Auto-generated header for tracing routines -ifeq ($(TRACE_BACKEND),dtrace) -TRACE_H_EXTRA_DEPS=$(obj)/generated-tracers-dtrace.h -endif -$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(TRACE_H_EXTRA_DEPS) +$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=h \ @@ -14,6 +11,10 @@ $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) +###################################################################### +# Auto-generated tracing routines (non-DTrace) + +ifneq ($(TRACE_BACKEND),dtrace) $(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ @@ -23,9 +24,6 @@ $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h - -ifneq ($(TRACE_BACKEND),dtrace) -trace-obj-y += generated-tracers.o endif @@ -35,19 +33,20 @@ endif # Normal practice is to name DTrace probe file with a '.d' extension # but that gets picked up by QEMU's Makefile as an external dependency # rule file. So we use '.dtrace' instead -$(obj)/generated-tracers-dtrace.dtrace: $(obj)/generated-tracers-dtrace.dtrace-timestamp -$(obj)/generated-tracers-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak +ifeq ($(TRACE_BACKEND),dtrace) +$(obj)/generated-tracers.dtrace: $(obj)/generated-tracers.dtrace-timestamp +$(obj)/generated-tracers.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=d \ --backend=$(TRACE_BACKEND) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) -$(obj)/generated-tracers-dtrace.h: trace/generated-tracers-dtrace.dtrace +$(obj)/generated-tracers-dtrace.h: $(obj)/generated-tracers.dtrace $(call quiet-command,dtrace -o $@ -h -s $<, " GEN $@") -trace-obj-$(CONFIG_TRACE_DTRACE) += generated-tracers-dtrace.o - +$(obj)/generated-tracers.o: $(obj)/generated-tracers.dtrace +endif ###################################################################### # Backend code @@ -56,3 +55,4 @@ trace-obj-$(CONFIG_TRACE_DEFAULT) += default.o trace-obj-$(CONFIG_TRACE_SIMPLE) += simple.o trace-obj-$(CONFIG_TRACE_STDERR) += stderr.o trace-obj-y += control.o +trace-obj-y += generated-tracers.o From ff667e2e9b86fdc36e3b143483526f4c4fe80049 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 21 Dec 2012 09:45:20 +0100 Subject: [PATCH 0421/1634] build: fold trace-obj-y into libqemuutil.a Signed-off-by: Paolo Bonzini --- Makefile | 14 +++++++------- Makefile.objs | 11 ++--------- libcacard/Makefile | 3 ++- tests/Makefile | 8 ++++---- trace/Makefile.objs | 10 +++++----- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index ad85e5ba8d..2b737d57b7 100644 --- a/Makefile +++ b/Makefile @@ -135,9 +135,9 @@ $(SRC_PATH)/pixman/configure: $(SUBDIR_RULES): libqemuutil.a libqemustub.a -$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(common-obj-y) $(extra-obj-y) +$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(common-obj-y) $(extra-obj-y) -$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(trace-obj-y) $(user-obj-y) +$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(user-obj-y) ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) romsubdir-%: @@ -164,13 +164,13 @@ libqemuutil.a: $(util-obj-y) qemu-img.o: qemu-img-cmds.h -qemu-img$(EXESUF): qemu-img.o $(trace-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a -qemu-nbd$(EXESUF): qemu-nbd.o $(trace-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a -qemu-io$(EXESUF): qemu-io.o cmd.o $(trace-obj-y) $(block-obj-y) libqemuutil.a libqemustub.a +qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a +qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a +qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o -fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o $(trace-obj-y) libqemuutil.a libqemustub.a +fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o libqemuutil.a libqemustub.a fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx @@ -206,7 +206,7 @@ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h) $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) -qemu-ga$(EXESUF): $(qga-obj-y) $(trace-obj-y) libqemuutil.a libqemustub.a +qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) clean: diff --git a/Makefile.objs b/Makefile.objs index bc56c61af6..d465a72030 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -1,7 +1,7 @@ ####################################################################### # Common libraries for tools and emulators stub-obj-y = stubs/ -util-obj-y = util/ qobject/ qapi/ +util-obj-y = util/ qobject/ qapi/ trace/ ####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img @@ -77,11 +77,6 @@ ifeq ($(CONFIG_SECCOMP),y) common-obj-y += qemu-seccomp.o endif -###################################################################### -# trace - -trace-obj-y += trace/ - ###################################################################### # smartcard @@ -107,7 +102,6 @@ universal-obj-y += tcg-runtime.o universal-obj-y += hw/ universal-obj-y += qom/ universal-obj-y += disas/ -universal-obj-y += $(trace-obj-y) ###################################################################### # guest agent @@ -129,6 +123,5 @@ nested-vars += \ block-obj-y \ common-obj-y \ universal-obj-y \ - extra-obj-y \ - trace-obj-y + extra-obj-y dummy := $(call unnest-vars) diff --git a/libcacard/Makefile b/libcacard/Makefile index c658d3a9b7..47827a0eb8 100644 --- a/libcacard/Makefile +++ b/libcacard/Makefile @@ -3,10 +3,11 @@ libcacard_includedir=$(includedir)/cacard TOOLS += vscclient$(EXESUF) # objects linked into a shared library, built with libtool with -fPIC if required -libcacard-obj-y = $(trace-obj-y) $(stub-obj-y) $(libcacard-y) +libcacard-obj-y = $(stub-obj-y) $(libcacard-y) libcacard-obj-y += util/osdep.o util/cutils.o util/qemu-timer-common.o util/error.o libcacard-obj-$(CONFIG_WIN32) += util/oslib-win32.o util/qemu-thread-win32.o libcacard-obj-$(CONFIG_POSIX) += util/oslib-posix.o util/qemu-thread-posix.o +libcacard-obj-y += $(filter trace/%, $(util-obj-y)) libcacard-lobj-y=$(patsubst %.o,%.lo,$(libcacard-obj-y)) diff --git a/tests/Makefile b/tests/Makefile index f224eb2390..d97a571c8b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -104,10 +104,10 @@ tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi- tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) qapi-types.o qapi-visit.o libqemuutil.a libqemustub.a tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) -tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) -tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y) -tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o $(trace-obj-y) +tests/rtc-test$(EXESUF): tests/rtc-test.o +tests/m48t59-test$(EXESUF): tests/m48t59-test.o +tests/fdc-test$(EXESUF): tests/fdc-test.o +tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o # QTest rules diff --git a/trace/Makefile.objs b/trace/Makefile.objs index ed2e30b001..27fe26b5c2 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -51,8 +51,8 @@ endif ###################################################################### # Backend code -trace-obj-$(CONFIG_TRACE_DEFAULT) += default.o -trace-obj-$(CONFIG_TRACE_SIMPLE) += simple.o -trace-obj-$(CONFIG_TRACE_STDERR) += stderr.o -trace-obj-y += control.o -trace-obj-y += generated-tracers.o +util-obj-$(CONFIG_TRACE_DEFAULT) += default.o +util-obj-$(CONFIG_TRACE_SIMPLE) += simple.o +util-obj-$(CONFIG_TRACE_STDERR) += stderr.o +util-obj-y += control.o +util-obj-y += generated-tracers.o From aaf821fde35f2ac5cf509ebd83a7d40704ea8d48 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 21 Dec 2012 10:45:20 +0100 Subject: [PATCH 0422/1634] build: improve quiet output for .stp rules Mention the directory in which the .stp file is being generated. Signed-off-by: Paolo Bonzini --- Makefile.target | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.target b/Makefile.target index d55134c12f..eb84b1f8e3 100644 --- a/Makefile.target +++ b/Makefile.target @@ -54,7 +54,7 @@ $(QEMU_PROG).stp: $(SRC_PATH)/trace-events --binary=$(bindir)/$(QEMU_PROG) \ --target-arch=$(TARGET_ARCH) \ --target-type=$(TARGET_TYPE) \ - < $< > $@," GEN $(QEMU_PROG).stp") + < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp") else stap: endif From bc5f92e5db6f303e73387278e32f8669f0abf0e5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Jan 2013 14:24:49 +0100 Subject: [PATCH 0423/1634] qxl: Fix SPICE_RING_PROD_ITEM(), SPICE_RING_CONS_ITEM() sanity check The pointer arithmetic there is safe, but ugly. Coverity grouses about it. However, the actual comparison is off by one: <= end instead of < end. Fix by rewriting the check in a cleaner way. Signed-off-by: Markus Armbruster Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index 00e517aaa3..e8f380bd55 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -37,33 +37,25 @@ */ #undef SPICE_RING_PROD_ITEM #define SPICE_RING_PROD_ITEM(qxl, r, ret) { \ - typeof(r) start = r; \ - typeof(r) end = r + 1; \ uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \ - typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ - if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + if (prod >= ARRAY_SIZE((r)->items)) { \ qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \ - "! %p <= %p < %p", (uint8_t *)start, \ - (uint8_t *)m_item, (uint8_t *)end); \ + "%u >= %zu", prod, ARRAY_SIZE((r)->items)); \ ret = NULL; \ } else { \ - ret = &m_item->el; \ + ret = &(r)->items[prod].el; \ } \ } #undef SPICE_RING_CONS_ITEM #define SPICE_RING_CONS_ITEM(qxl, r, ret) { \ - typeof(r) start = r; \ - typeof(r) end = r + 1; \ uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \ - typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \ - if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ + if (cons >= ARRAY_SIZE((r)->items)) { \ qxl_set_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \ - "! %p <= %p < %p", (uint8_t *)start, \ - (uint8_t *)m_item, (uint8_t *)end); \ + "%u >= %zu", cons, ARRAY_SIZE((r)->items)); \ ret = NULL; \ } else { \ - ret = &m_item->el; \ + ret = &(r)->items[cons].el; \ } \ } From 08688af04dc1137ac2f420b35c235183926b4a23 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Jan 2013 14:24:50 +0100 Subject: [PATCH 0424/1634] qxl: Don't drop client capability bits interface_set_client_capabilities() copies only the first few bits, because it falls into a Classic C trap: you can declare a parameter uint8_t caps[58], but the resulting parameter type is uint8_t *, not uint8_t[58]. In particular, sizeof(caps) is sizeof(uint8_t *), not the intended sizeof(uint8_t[58]). Harmless, because the bits aren't used, yet. Broken in commit c10018d6. Spotted by Coverity. Signed-off-by: Markus Armbruster Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index e8f380bd55..9dc44b9b88 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -951,9 +951,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, } qxl->shadow_rom.client_present = client_present; - memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); + memcpy(qxl->shadow_rom.client_capabilities, caps, + sizeof(qxl->shadow_rom.client_capabilities)); qxl->rom->client_present = client_present; - memcpy(qxl->rom->client_capabilities, caps, sizeof(caps)); + memcpy(qxl->rom->client_capabilities, caps, + sizeof(qxl->rom->client_capabilities)); qxl_rom_set_dirty(qxl); qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); From 00e4d0dbad9f2d449f021394addec9dfae5678bf Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 7 Jan 2013 12:59:43 +0100 Subject: [PATCH 0425/1634] pc-testdev: use typedefs Signed-off-by: Gerd Hoffmann --- hw/pc-testdev.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c index ec0bc4bb95..cf64a1f203 100644 --- a/hw/pc-testdev.c +++ b/hw/pc-testdev.c @@ -58,13 +58,13 @@ typedef struct PCTestdev { #define TYPE_TESTDEV "pc-testdev" #define TESTDEV(obj) \ - OBJECT_CHECK(struct PCTestdev, (obj), TYPE_TESTDEV) + OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV) static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, unsigned len) { - struct PCTestdev *dev = opaque; - struct ISADevice *isa = ISA_DEVICE(dev); + PCTestdev *dev = opaque; + ISADevice *isa = ISA_DEVICE(dev); qemu_set_irq(isa_get_irq(isa, addr), !!data); } @@ -79,13 +79,13 @@ static const MemoryRegionOps test_irq_ops = { static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data, unsigned len) { - struct PCTestdev *dev = opaque; + PCTestdev *dev = opaque; dev->ioport_data = data; } static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len) { - struct PCTestdev *dev = opaque; + PCTestdev *dev = opaque; return dev->ioport_data; } @@ -119,7 +119,7 @@ static const MemoryRegionOps test_flush_ops = { static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) { - struct PCTestdev *dev = opaque; + PCTestdev *dev = opaque; uint64_t ret = 0; memcpy(&ret, &dev->iomem_buf[addr], len); ret = le64_to_cpu(ret); @@ -130,7 +130,7 @@ static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { - struct PCTestdev *dev = opaque; + PCTestdev *dev = opaque; val = cpu_to_le64(val); memcpy(&dev->iomem_buf[addr], &val, len); dev->iomem_buf[addr] = val; @@ -144,7 +144,7 @@ static const MemoryRegionOps test_iomem_ops = { static int init_test_device(ISADevice *isa) { - struct PCTestdev *dev = TESTDEV(isa); + PCTestdev *dev = TESTDEV(isa); MemoryRegion *mem = isa_address_space(isa); MemoryRegion *io = isa_address_space_io(isa); @@ -175,7 +175,7 @@ static void testdev_class_init(ObjectClass *klass, void *data) static const TypeInfo testdev_info = { .name = TYPE_TESTDEV, .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(struct PCTestdev), + .instance_size = sizeof(PCTestdev), .class_init = testdev_class_init, }; From 8125184178de05d762e39ee07f44ada6006e87bd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 8 Jan 2013 13:06:16 +0100 Subject: [PATCH 0426/1634] xhci: create xhci_detach_slot helper function Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 92f2eee3bc..3ff8bc1f8a 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -2198,6 +2198,23 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr return slotid; } +/* cleanup slot state on usb device detach */ +static void xhci_detach_slot(XHCIState *xhci, USBPort *uport) +{ + int slot; + + for (slot = 0; slot < xhci->numslots; slot++) { + if (xhci->slots[slot].uport == uport) { + break; + } + } + if (slot == xhci->numslots) { + return; + } + + xhci->slots[slot].uport = NULL; +} + static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) { dma_addr_t ctx; @@ -2971,13 +2988,8 @@ static void xhci_child_detach(USBPort *uport, USBDevice *child) { USBBus *bus = usb_bus_from_device(child); XHCIState *xhci = container_of(bus, XHCIState, bus); - int i; - for (i = 0; i < xhci->numslots; i++) { - if (xhci->slots[i].uport == uport) { - xhci->slots[i].uport = NULL; - } - } + xhci_detach_slot(xhci, uport); } static USBPortOps xhci_uport_ops = { From f3dcf6384cc94b6a688f3a366c20642f36247b68 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 8 Jan 2013 13:06:57 +0100 Subject: [PATCH 0427/1634] xhci: call xhci_detach_slot on root port detach too Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 3ff8bc1f8a..5b2e7f89e4 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -2957,6 +2957,7 @@ static void xhci_detach(USBPort *usbport) XHCIState *xhci = usbport->opaque; XHCIPort *port = xhci_lookup_port(xhci, usbport); + xhci_detach_slot(xhci, usbport); xhci_port_update(port, 1); } From 0cb41e2c5ebc1f8fa180a1726981416fee9abad1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 8 Jan 2013 14:06:51 +0100 Subject: [PATCH 0428/1634] xhci: nuke transfe5rs on detach Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 5b2e7f89e4..5fb0c488e8 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1197,6 +1197,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, ep = epctx->transfers[xferi].packet.ep; } killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi]); + epctx->transfers[xferi].packet.ep = NULL; xferi = (xferi + 1) % TD_QUEUE; } if (ep) { @@ -2201,7 +2202,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr /* cleanup slot state on usb device detach */ static void xhci_detach_slot(XHCIState *xhci, USBPort *uport) { - int slot; + int slot, ep; for (slot = 0; slot < xhci->numslots; slot++) { if (xhci->slots[slot].uport == uport) { @@ -2212,6 +2213,11 @@ static void xhci_detach_slot(XHCIState *xhci, USBPort *uport) return; } + for (ep = 0; ep < 31; ep++) { + if (xhci->slots[slot].eps[ep]) { + xhci_ep_nuke_xfers(xhci, slot+1, ep+1); + } + } xhci->slots[slot].uport = NULL; } From 8e895599a1beb250ebca00e83b5fae6a828d2171 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Jan 2013 15:39:27 +0100 Subject: [PATCH 0429/1634] block: do not probe zero-sized disks A blank CD or DVD is visible as a zero-sized disks. Probing such disks will lead to an EIO and a failure to start the VM. Treating them as raw is a better solution. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block.c b/block.c index 60873eafea..14f82020ed 100644 --- a/block.c +++ b/block.c @@ -527,7 +527,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename, int ret = 0; /* Return the raw BlockDriver * to scsi-generic devices or empty drives */ - if (bs->sg || !bdrv_is_inserted(bs)) { + if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) { drv = bdrv_find_format("raw"); if (!drv) { ret = -ENOENT; From 0e7106d8b5f7ef4f9df10baf1dfb3db482bcd046 Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Thu, 10 Jan 2013 16:03:47 +0800 Subject: [PATCH 0430/1634] sheepdog: implement direct write semantics Sheepdog supports both writeback/writethrough write but has not yet supported DIRECTIO semantics which bypass the cache completely even if Sheepdog daemon is set up with cache enabled. Suppose cache is enabled on Sheepdog daemon size, the new cache control is cache=writeback # enable the writeback semantics for write cache=writethrough # enable the emulated writethrough semantics for write cache=directsync # disable cache competely Guest WCE toggling on the run time to toggle writeback/writethrough is also supported. Cc: MORITA Kazutaka Cc: Kevin Wolf Cc: Stefan Hajnoczi Signed-off-by: Liu Yuan Reviewed-by: Stefan Hajnoczi Reviewed-by: MORITA Kazutaka Signed-off-by: Kevin Wolf --- block/sheepdog.c | 70 +++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index e821746116..462c4b2d5d 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -36,7 +36,8 @@ #define SD_FLAG_CMD_WRITE 0x01 #define SD_FLAG_CMD_COW 0x02 -#define SD_FLAG_CMD_CACHE 0x04 +#define SD_FLAG_CMD_CACHE 0x04 /* Writeback mode for cache */ +#define SD_FLAG_CMD_DIRECT 0x08 /* Don't use cache */ #define SD_RES_SUCCESS 0x00 /* Success */ #define SD_RES_UNKNOWN 0x01 /* Unknown error */ @@ -293,7 +294,7 @@ typedef struct BDRVSheepdogState { char name[SD_MAX_VDI_LEN]; bool is_snapshot; - bool cache_enabled; + uint32_t cache_flags; char *addr; char *port; @@ -977,8 +978,8 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, hdr.flags = SD_FLAG_CMD_WRITE | flags; } - if (s->cache_enabled) { - hdr.flags |= SD_FLAG_CMD_CACHE; + if (s->cache_flags) { + hdr.flags |= s->cache_flags; } hdr.oid = oid; @@ -1023,7 +1024,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, static int read_write_object(int fd, char *buf, uint64_t oid, int copies, unsigned int datalen, uint64_t offset, - bool write, bool create, bool cache) + bool write, bool create, uint32_t cache_flags) { SheepdogObjReq hdr; SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr; @@ -1047,9 +1048,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies, hdr.opcode = SD_OP_READ_OBJ; } - if (cache) { - hdr.flags |= SD_FLAG_CMD_CACHE; - } + hdr.flags |= cache_flags; hdr.oid = oid; hdr.data_length = datalen; @@ -1072,18 +1071,19 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies, } static int read_object(int fd, char *buf, uint64_t oid, int copies, - unsigned int datalen, uint64_t offset, bool cache) + unsigned int datalen, uint64_t offset, + uint32_t cache_flags) { return read_write_object(fd, buf, oid, copies, datalen, offset, false, - false, cache); + false, cache_flags); } static int write_object(int fd, char *buf, uint64_t oid, int copies, unsigned int datalen, uint64_t offset, bool create, - bool cache) + uint32_t cache_flags) { return read_write_object(fd, buf, oid, copies, datalen, offset, true, - create, cache); + create, cache_flags); } static int sd_open(BlockDriverState *bs, const char *filename, int flags) @@ -1118,12 +1118,22 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) goto out; } - s->cache_enabled = true; - s->flush_fd = connect_to_sdog(s->addr, s->port); - if (s->flush_fd < 0) { - error_report("failed to connect"); - ret = s->flush_fd; - goto out; + /* + * QEMU block layer emulates writethrough cache as 'writeback + flush', so + * we always set SD_FLAG_CMD_CACHE (writeback cache) as default. + */ + s->cache_flags = SD_FLAG_CMD_CACHE; + if (flags & BDRV_O_NOCACHE) { + s->cache_flags = SD_FLAG_CMD_DIRECT; + } + + if (s->cache_flags == SD_FLAG_CMD_CACHE) { + s->flush_fd = connect_to_sdog(s->addr, s->port); + if (s->flush_fd < 0) { + error_report("failed to connect"); + ret = s->flush_fd; + goto out; + } } if (snapid || tag[0] != '\0') { @@ -1140,7 +1150,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) buf = g_malloc(SD_INODE_SIZE); ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0, - s->cache_enabled); + s->cache_flags); closesocket(fd); @@ -1387,7 +1397,7 @@ static void sd_close(BlockDriverState *bs) qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); - if (s->cache_enabled) { + if (s->cache_flags) { closesocket(s->flush_fd); } g_free(s->addr); @@ -1423,7 +1433,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id); s->inode.vdi_size = offset; ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id), - s->inode.nr_copies, datalen, 0, false, s->cache_enabled); + s->inode.nr_copies, datalen, 0, false, s->cache_flags); close(fd); if (ret < 0) { @@ -1506,7 +1516,7 @@ static int sd_create_branch(BDRVSheepdogState *s) } ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies, - SD_INODE_SIZE, 0, s->cache_enabled); + SD_INODE_SIZE, 0, s->cache_flags); closesocket(fd); @@ -1707,7 +1717,7 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) int ret; unsigned int wlen = 0, rlen = 0; - if (!s->cache_enabled) { + if (s->cache_flags != SD_FLAG_CMD_CACHE) { return 0; } @@ -1723,7 +1733,7 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) if (rsp->result == SD_RES_INVALID_PARMS) { dprintf("disable write cache since the server doesn't support it\n"); - s->cache_enabled = false; + s->cache_flags = SD_FLAG_CMD_DIRECT; closesocket(s->flush_fd); return 0; } @@ -1774,7 +1784,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) } ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id), - s->inode.nr_copies, datalen, 0, false, s->cache_enabled); + s->inode.nr_copies, datalen, 0, false, s->cache_flags); if (ret < 0) { error_report("failed to write snapshot's inode."); goto cleanup; @@ -1791,7 +1801,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) inode = (SheepdogInode *)g_malloc(datalen); ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid), - s->inode.nr_copies, datalen, 0, s->cache_enabled); + s->inode.nr_copies, datalen, 0, s->cache_flags); if (ret < 0) { error_report("failed to read new inode info. %s", strerror(errno)); @@ -1845,7 +1855,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) buf = g_malloc(SD_INODE_SIZE); ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies, - SD_INODE_SIZE, 0, s->cache_enabled); + SD_INODE_SIZE, 0, s->cache_flags); closesocket(fd); @@ -1942,7 +1952,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) /* we don't need to read entire object */ ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0, - s->cache_enabled); + s->cache_flags); if (ret) { continue; @@ -2003,11 +2013,11 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, if (load) { ret = read_object(fd, (char *)data, vmstate_oid, s->inode.nr_copies, data_len, offset, - s->cache_enabled); + s->cache_flags); } else { ret = write_object(fd, (char *)data, vmstate_oid, s->inode.nr_copies, data_len, offset, create, - s->cache_enabled); + s->cache_flags); } if (ret < 0) { From b608c8dc02c78ee95455a0989bdf1b41c768b2ef Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Jan 2013 15:28:35 +0100 Subject: [PATCH 0431/1634] raw-posix: fix bdrv_aio_ioctl When the raw-posix aio=thread code was moved from posix-aio-compat.c to block/raw-posix.c, there was an unintended change to the ioctl code. The code used to return the ioctl command, which posix_aio_read() would later morph into a zero. This hack is not necessary anymore, and in fact breaks scsi-generic (which expects a zero return code). Remove it. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/raw-posix.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 87d888ed01..0e705ba07d 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -455,15 +455,7 @@ static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb) return -errno; } - /* - * This looks weird, but the aio code only considers a request - * successful if it has written the full number of bytes. - * - * Now we overload aio_nbytes as aio_ioctl_cmd for the ioctl command, - * so in fact we return the ioctl command here to make posix_aio_read() - * happy.. - */ - return aiocb->aio_nbytes; + return 0; } static ssize_t handle_aiocb_flush(RawPosixAIOData *aiocb) From c53b1c5114bdf7fc945cbf11436da61789ca2267 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 11 Jan 2013 16:41:27 +0100 Subject: [PATCH 0432/1634] block: make qiov_is_aligned() public The qiov_is_aligned() function checks whether a QEMUIOVector meets a BlockDriverState's alignment requirements. This is needed by virtio-blk-data-plane so: 1. Move the function from block/raw-posix.c to block/block.c. 2. Make it public in block/block.h. 3. Rename to bdrv_qiov_is_aligned(). 4. Change return type from int to bool. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block.c | 16 ++++++++++++++++ block/raw-posix.c | 18 +----------------- include/block/block.h | 1 + 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/block.c b/block.c index 14f82020ed..b5e64ecf11 100644 --- a/block.c +++ b/block.c @@ -4313,6 +4313,22 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size) return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size); } +/* + * Check if all memory in this vector is sector aligned. + */ +bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) +{ + int i; + + for (i = 0; i < qiov->niov; i++) { + if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) { + return false; + } + } + + return true; +} + void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) { int64_t bitmap_size; diff --git a/block/raw-posix.c b/block/raw-posix.c index 0e705ba07d..c3d7fda7b7 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -430,22 +430,6 @@ static void raw_reopen_abort(BDRVReopenState *state) #endif */ -/* - * Check if all memory in this vector is sector aligned. - */ -static int qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) -{ - int i; - - for (i = 0; i < qiov->niov; i++) { - if ((uintptr_t) qiov->iov[i].iov_base % bs->buffer_alignment) { - return 0; - } - } - - return 1; -} - static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb) { int ret; @@ -714,7 +698,7 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs, * driver that it needs to copy the buffer. */ if ((bs->open_flags & BDRV_O_NOCACHE)) { - if (!qiov_is_aligned(bs, qiov)) { + if (!bdrv_qiov_is_aligned(bs, qiov)) { type |= QEMU_AIO_MISALIGNED; #ifdef CONFIG_LINUX_AIO } else if (s->use_aio) { diff --git a/include/block/block.h b/include/block/block.h index 0719339231..ffd193637d 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -349,6 +349,7 @@ void bdrv_img_create(const char *filename, const char *fmt, void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); void *qemu_blockalign(BlockDriverState *bs, size_t size); +bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048 From b5ef1aab945c1b04740574064b13eb93f1572587 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 11 Jan 2013 16:41:28 +0100 Subject: [PATCH 0433/1634] dataplane: extract virtio-blk read/write processing into do_rdwr_cmd() Extract code for read/write command processing into do_rdwr_cmd(). This brings together pieces that are spread across process_request(). The real motivation is to set the stage for handling misaligned requests, which the next patch tackles. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- hw/dataplane/virtio-blk.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 4c4ad8422a..a6696b89e1 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -130,6 +130,22 @@ static void do_get_id_cmd(VirtIOBlockDataPlane *s, complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK); } +static int do_rdwr_cmd(VirtIOBlockDataPlane *s, bool read, + struct iovec *iov, unsigned int iov_cnt, + long long offset, unsigned int head, + QEMUIOVector *inhdr) +{ + struct iocb *iocb; + + iocb = ioq_rdwr(&s->ioqueue, read, iov, iov_cnt, offset); + + /* Fill in virtio block metadata needed for completion */ + VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); + req->head = head; + req->inhdr = inhdr; + return 0; +} + static int process_request(IOQueue *ioq, struct iovec iov[], unsigned int out_num, unsigned int in_num, unsigned int head) @@ -139,7 +155,6 @@ static int process_request(IOQueue *ioq, struct iovec iov[], struct virtio_blk_outhdr outhdr; QEMUIOVector *inhdr; size_t in_size; - struct iocb *iocb; /* Copy in outhdr */ if (unlikely(iov_to_buf(iov, out_num, 0, &outhdr, @@ -167,12 +182,12 @@ static int process_request(IOQueue *ioq, struct iovec iov[], switch (outhdr.type) { case VIRTIO_BLK_T_IN: - iocb = ioq_rdwr(ioq, true, in_iov, in_num, outhdr.sector * 512); - break; + do_rdwr_cmd(s, true, in_iov, in_num, outhdr.sector * 512, head, inhdr); + return 0; case VIRTIO_BLK_T_OUT: - iocb = ioq_rdwr(ioq, false, iov, out_num, outhdr.sector * 512); - break; + do_rdwr_cmd(s, false, iov, out_num, outhdr.sector * 512, head, inhdr); + return 0; case VIRTIO_BLK_T_SCSI_CMD: /* TODO support SCSI commands */ @@ -198,12 +213,6 @@ static int process_request(IOQueue *ioq, struct iovec iov[], g_slice_free(QEMUIOVector, inhdr); return -EFAULT; } - - /* Fill in virtio block metadata needed for completion */ - VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); - req->head = head; - req->inhdr = inhdr; - return 0; } static void handle_notify(EventHandler *handler) From de0161c0d553f2aaf6118ca87f978a5e6b4a9732 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 11 Jan 2013 16:41:29 +0100 Subject: [PATCH 0434/1634] dataplane: handle misaligned virtio-blk requests O_DIRECT on Linux has alignment requirements on I/O buffers and misaligned requests result in -EINVAL. The Linux virtio_blk guest driver usually submits aligned requests so I forgot to handle misaligned requests. It turns out that virtio-win guest drivers submit misaligned requests. Handle them using a bounce buffer that meets alignment requirements. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- hw/dataplane/virtio-blk.c | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index a6696b89e1..1f7346ea19 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -34,6 +34,8 @@ typedef struct { struct iocb iocb; /* Linux AIO control block */ QEMUIOVector *inhdr; /* iovecs for virtio_blk_inhdr */ unsigned int head; /* vring descriptor index */ + struct iovec *bounce_iov; /* used if guest buffers are unaligned */ + QEMUIOVector *read_qiov; /* for read completion /w bounce buffer */ } VirtIOBlockRequest; struct VirtIOBlockDataPlane { @@ -89,6 +91,18 @@ static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque) trace_virtio_blk_data_plane_complete_request(s, req->head, ret); + if (req->read_qiov) { + assert(req->bounce_iov); + qemu_iovec_from_buf(req->read_qiov, 0, req->bounce_iov->iov_base, len); + qemu_iovec_destroy(req->read_qiov); + g_slice_free(QEMUIOVector, req->read_qiov); + } + + if (req->bounce_iov) { + qemu_vfree(req->bounce_iov->iov_base); + g_slice_free(struct iovec, req->bounce_iov); + } + qemu_iovec_from_buf(req->inhdr, 0, &hdr, sizeof(hdr)); qemu_iovec_destroy(req->inhdr); g_slice_free(QEMUIOVector, req->inhdr); @@ -136,6 +150,30 @@ static int do_rdwr_cmd(VirtIOBlockDataPlane *s, bool read, QEMUIOVector *inhdr) { struct iocb *iocb; + QEMUIOVector qiov; + struct iovec *bounce_iov = NULL; + QEMUIOVector *read_qiov = NULL; + + qemu_iovec_init_external(&qiov, iov, iov_cnt); + if (!bdrv_qiov_is_aligned(s->blk->conf.bs, &qiov)) { + void *bounce_buffer = qemu_blockalign(s->blk->conf.bs, qiov.size); + + if (read) { + /* Need to copy back from bounce buffer on completion */ + read_qiov = g_slice_new(QEMUIOVector); + qemu_iovec_init(read_qiov, iov_cnt); + qemu_iovec_concat_iov(read_qiov, iov, iov_cnt, 0, qiov.size); + } else { + qemu_iovec_to_buf(&qiov, 0, bounce_buffer, qiov.size); + } + + /* Redirect I/O to aligned bounce buffer */ + bounce_iov = g_slice_new(struct iovec); + bounce_iov->iov_base = bounce_buffer; + bounce_iov->iov_len = qiov.size; + iov = bounce_iov; + iov_cnt = 1; + } iocb = ioq_rdwr(&s->ioqueue, read, iov, iov_cnt, offset); @@ -143,6 +181,8 @@ static int do_rdwr_cmd(VirtIOBlockDataPlane *s, bool read, VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb); req->head = head; req->inhdr = inhdr; + req->bounce_iov = bounce_iov; + req->read_qiov = read_qiov; return 0; } From cc8d2b65c7e5f44172bf3ec300407522162e9a7f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Jan 2013 14:33:23 +0100 Subject: [PATCH 0435/1634] ehci: Assert state machine is sane w.r.t. EHCIQueue Coverity worries the EHCIQueue pointer could be null when we pass it to functions that reference it. The state machine ensures it can't be null then. Assert that, to hush the checker. Signed-off-by: Markus Armbruster Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 320b7e7239..70406592ef 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2092,18 +2092,22 @@ static void ehci_advance_state(EHCIState *ehci, int async) break; case EST_ADVANCEQUEUE: + assert(q != NULL); again = ehci_state_advqueue(q); break; case EST_FETCHQTD: + assert(q != NULL); again = ehci_state_fetchqtd(q); break; case EST_HORIZONTALQH: + assert(q != NULL); again = ehci_state_horizqh(q); break; case EST_EXECUTE: + assert(q != NULL); again = ehci_state_execute(q); if (async) { ehci->async_stepdown = 0; From 4663530898a15944706d51b523d1f1545e32e46a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Jan 2013 14:33:24 +0100 Subject: [PATCH 0436/1634] usb-host: Drop superfluous null test from usb_host_auto_scan() Coverity points out that port is later passed to usb_host_open(), which dereferences it. It actually can't be null: it always points to usb_host_scan()'s auto port[]. Drop the superfluous port == NULL test. Signed-off-by: Markus Armbruster Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index e8e6a42fb9..a498840e0a 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1760,7 +1760,7 @@ static int usb_host_auto_scan(void *opaque, int bus_num, if (f->addr > 0 && f->addr != addr) { continue; } - if (f->port != NULL && (port == NULL || strcmp(f->port, port) != 0)) { + if (f->port != NULL && strcmp(f->port, port) != 0) { continue; } From 036078475427f2562c8e505f6bb44dbf5d8cbd95 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 10 Jan 2013 14:33:25 +0100 Subject: [PATCH 0437/1634] usb-host: Initialize dev->port the obviously safe way Coverity worries the strcpy() could overrun the destination. It can't, because the source always points to usb_host_scan()'s auto port[], which has the same size. Use pstrcpy() anyway, to hush the checker. Signed-off-by: Markus Armbruster Signed-off-by: Gerd Hoffmann --- hw/usb/host-linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index a498840e0a..ad75ce0702 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1314,7 +1314,7 @@ static int usb_host_open(USBHostDevice *dev, int bus_num, dev->bus_num = bus_num; dev->addr = addr; - strcpy(dev->port, port); + pstrcpy(dev->port, sizeof(dev->port), port); dev->fd = fd; /* read the device description */ From f9943cd58f8a053172aa701d79da512ccd10d758 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 4 Jan 2013 10:15:53 +0100 Subject: [PATCH 0438/1634] pixman: pass extra cflags and ldflags Store --extra-cflags and --extra-ldflags in config-host.mak, then pass them on to the pixman configure script. Cc: Scott Wood Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- configure | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0200bf345c..2286174bcb 100644 --- a/Makefile +++ b/Makefile @@ -126,7 +126,7 @@ subdir-pixman: pixman/Makefile $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pixman V="$(V)" all,) pixman/Makefile: $(SRC_PATH)/pixman/configure - (cd pixman; CFLAGS="$(CFLAGS) -fPIC" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static) + (cd pixman; CFLAGS="$(CFLAGS) -fPIC $(extra_cflags) $(extra_ldflags)" $(SRC_PATH)/pixman/configure $(AUTOCONF_HOST) --disable-gtk --disable-shared --enable-static) $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) diff --git a/configure b/configure index ea42fe2457..a750bb5a23 100755 --- a/configure +++ b/configure @@ -240,8 +240,10 @@ for opt do --cpu=*) cpu="$optarg" ;; --extra-cflags=*) QEMU_CFLAGS="$optarg $QEMU_CFLAGS" + EXTRA_CFLAGS="$optarg" ;; --extra-ldflags=*) LDFLAGS="$optarg $LDFLAGS" + EXTRA_LDFLAGS="$optarg" ;; --enable-debug-info) debug_info="yes" ;; @@ -3349,6 +3351,8 @@ echo "qemu_datadir=$qemu_datadir" >> $config_host_mak echo "qemu_docdir=$qemu_docdir" >> $config_host_mak echo "qemu_localstatedir=$local_statedir" >> $config_host_mak echo "qemu_helperdir=$libexecdir" >> $config_host_mak +echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak +echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak if test "$debug_tcg" = "yes" ; then From 6ffacc5d3ddf2e3227aae2a8cc5c15627265f727 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 8 Jan 2013 19:26:25 -0200 Subject: [PATCH 0439/1634] qemu-ga: ga_open_pidfile(): use qemu_open() This ensures that O_CLOEXEC is passed to open(), this way the pid file fd is not leaked to executed processes. Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake Acked-by: Amos Kong Tested-by: Amos Kong Signed-off-by: Michael Roth --- qga/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/main.c b/qga/main.c index a9b968c507..4239150d4e 100644 --- a/qga/main.c +++ b/qga/main.c @@ -267,7 +267,7 @@ static bool ga_open_pidfile(const char *pidfile) int pidfd; char pidstr[32]; - pidfd = open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); + pidfd = qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); if (pidfd == -1 || lockf(pidfd, F_TLOCK, 0)) { g_critical("Cannot lock pid file, %s", strerror(errno)); if (pidfd != -1) { From 9e92f6d46233171898fc7d0487a04e5b78e44234 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 8 Jan 2013 19:26:26 -0200 Subject: [PATCH 0440/1634] qemu-ga: add ga_open_logfile() This function sets O_CLOEXEC on the log file fd so that it isn't leaked to executed processes. Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake Acked-by: Amos Kong Tested-by: Amos Kong Signed-off-by: Michael Roth --- qga/main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/qga/main.c b/qga/main.c index 4239150d4e..bd70ead126 100644 --- a/qga/main.c +++ b/qga/main.c @@ -261,6 +261,19 @@ void ga_set_response_delimited(GAState *s) s->delimit_response = true; } +static FILE *ga_open_logfile(const char *logfile) +{ + FILE *f; + + f = fopen(logfile, "a"); + if (!f) { + return NULL; + } + + qemu_set_cloexec(fileno(f)); + return f; +} + #ifndef _WIN32 static bool ga_open_pidfile(const char *pidfile) { @@ -402,7 +415,7 @@ void ga_unset_frozen(GAState *s) * in a frozen state at start up, do it now */ if (s->deferred_options.log_filepath) { - s->log_file = fopen(s->deferred_options.log_filepath, "a"); + s->log_file = ga_open_logfile(s->deferred_options.log_filepath); if (!s->log_file) { s->log_file = stderr; } @@ -884,7 +897,7 @@ int main(int argc, char **argv) become_daemon(pid_filepath); } if (log_filepath) { - FILE *log_file = fopen(log_filepath, "a"); + FILE *log_file = ga_open_logfile(log_filepath); if (!log_file) { g_critical("unable to open specified log file: %s", strerror(errno)); From f5b795787864ddde1104a4f7c061dcb0e58e45c0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 11 Jan 2013 11:24:57 +0100 Subject: [PATCH 0441/1634] qemu-ga: Document intentional fall through in channel_event_cb() For clarity, and to hush up Coverity. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Michael Roth Reviewed-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qga/main.c b/qga/main.c index bd70ead126..e8a9a9ee7e 100644 --- a/qga/main.c +++ b/qga/main.c @@ -618,6 +618,7 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data) if (!s->virtio) { return false; } + /* fall through */ case G_IO_STATUS_AGAIN: /* virtio causes us to spin here when no process is attached to * host-side chardev. sleep a bit to mitigate this From 5d27f9ce3de424207883d84352d76150e9707394 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 11 Jan 2013 11:24:58 +0100 Subject: [PATCH 0442/1634] qemu-ga: Drop pointless lseek() from ga_open_pidfile() After open(), the file offset is already zero, and neither lockf() nor ftruncate() change it. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Michael Roth Reviewed-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/main.c b/qga/main.c index e8a9a9ee7e..96d3cfa381 100644 --- a/qga/main.c +++ b/qga/main.c @@ -289,7 +289,7 @@ static bool ga_open_pidfile(const char *pidfile) return false; } - if (ftruncate(pidfd, 0) || lseek(pidfd, 0, SEEK_SET)) { + if (ftruncate(pidfd, 0)) { g_critical("Failed to truncate pid file"); goto fail; } From 03ac10f166b790cb66804e512abec6d002cd8481 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 11 Jan 2013 11:24:59 +0100 Subject: [PATCH 0443/1634] qemu-ga: Plug file descriptor leak on ga_open_pidfile() error path Spotted by Coverity. Also document why we keep it open on success. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Michael Roth Reviewed-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qga/main.c b/qga/main.c index 96d3cfa381..db281a508b 100644 --- a/qga/main.c +++ b/qga/main.c @@ -299,10 +299,12 @@ static bool ga_open_pidfile(const char *pidfile) goto fail; } + /* keep pidfile open & locked forever */ return true; fail: unlink(pidfile); + close(pidfd); return false; } #else /* _WIN32 */ From 32c16620dda8ba16f6d6bcd20efefdec8975af77 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 11 Jan 2013 11:25:00 +0100 Subject: [PATCH 0444/1634] qemu-ga: Plug fd leak on ga_channel_listen_accept() error path Spotted by Coverity. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Michael Roth Reviewed-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/channel-posix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qga/channel-posix.c b/qga/channel-posix.c index ca9e4aaaf9..9a5c05d666 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -46,6 +46,7 @@ static gboolean ga_channel_listen_accept(GIOChannel *channel, ret = ga_channel_client_add(c, client_fd); if (ret) { g_warning("error setting up connection"); + close(client_fd); goto out; } accepted = true; From d4f4a3efdf0a71621ae5351176f5f15b522d0026 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 11 Jan 2013 11:25:01 +0100 Subject: [PATCH 0445/1634] qemu-ga: Plug fd leak on ga_channel_open() error paths Spotted by Coverity. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Michael Roth Reviewed-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/channel-posix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 9a5c05d666..05e83860ca 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -154,6 +154,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod ret = ga_channel_client_add(c, fd); if (ret) { g_critical("error adding channel to main loop"); + close(fd); return false; } break; From 7868181f98ff1fbcd7f7034153eec5e03615d023 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 11 Jan 2013 11:25:02 +0100 Subject: [PATCH 0446/1634] qemu-ga: Handle errors uniformely in ga_channel_open() We detect errors in several places. One reports with g_error(), which calls abort(), the others report with g_critical(). Three of them exit(), three return false. Always report with g_critical(), and return false. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Michael Roth Reviewed-by: Luiz Capitulino *minor fix-up of commit msg Signed-off-by: Michael Roth --- qga/channel-posix.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 05e83860ca..e65dda3822 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -141,14 +141,15 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod ); if (fd == -1) { g_critical("error opening channel: %s", strerror(errno)); - exit(EXIT_FAILURE); + return false; } #ifdef CONFIG_SOLARIS ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI); if (ret == -1) { g_critical("error setting event mask for channel: %s", strerror(errno)); - exit(EXIT_FAILURE); + close(fd); + return false; } #endif ret = ga_channel_client_add(c, fd); @@ -164,7 +165,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod int fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { g_critical("error opening channel: %s", strerror(errno)); - exit(EXIT_FAILURE); + return false; } tcgetattr(fd, &tio); /* set up serial port for non-canonical, dumb byte streaming */ @@ -184,7 +185,9 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod tcsetattr(fd, TCSANOW, &tio); ret = ga_channel_client_add(c, fd); if (ret) { - g_error("error adding channel to main loop"); + g_critical("error adding channel to main loop"); + close(fd); + return false; } break; } From 282c6a2f292705f823554447ca0b7731b6f81a97 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 14 Jan 2013 18:26:53 +0000 Subject: [PATCH 0447/1634] xen_disk: fix memory leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On ioreq_release the full ioreq was memset to 0, loosing all the data and memory allocations inside the QEMUIOVector, which leads to a memory leak. Create a new function to specifically reset ioreq. Reported-by: Maik Wessler Signed-off-by: Roger Pau Monné Signed-off-by: Stefano Stabellini --- hw/xen_disk.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/hw/xen_disk.c b/hw/xen_disk.c index a6a64a2455..b7c7977870 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -112,6 +112,31 @@ struct XenBlkDev { /* ------------------------------------------------------------- */ +static void ioreq_reset(struct ioreq *ioreq) +{ + memset(&ioreq->req, 0, sizeof(ioreq->req)); + ioreq->status = 0; + ioreq->start = 0; + ioreq->presync = 0; + ioreq->postsync = 0; + ioreq->mapped = 0; + + memset(ioreq->domids, 0, sizeof(ioreq->domids)); + memset(ioreq->refs, 0, sizeof(ioreq->refs)); + ioreq->prot = 0; + memset(ioreq->page, 0, sizeof(ioreq->page)); + ioreq->pages = NULL; + + ioreq->aio_inflight = 0; + ioreq->aio_errors = 0; + + ioreq->blkdev = NULL; + memset(&ioreq->list, 0, sizeof(ioreq->list)); + memset(&ioreq->acct, 0, sizeof(ioreq->acct)); + + qemu_iovec_reset(&ioreq->v); +} + static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) { struct ioreq *ioreq = NULL; @@ -129,7 +154,6 @@ static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) /* get one from freelist */ ioreq = QLIST_FIRST(&blkdev->freelist); QLIST_REMOVE(ioreq, list); - qemu_iovec_reset(&ioreq->v); } QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list); blkdev->requests_inflight++; @@ -153,7 +177,7 @@ static void ioreq_release(struct ioreq *ioreq, bool finish) struct XenBlkDev *blkdev = ioreq->blkdev; QLIST_REMOVE(ioreq, list); - memset(ioreq, 0, sizeof(*ioreq)); + ioreq_reset(ioreq); ioreq->blkdev = blkdev; QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list); if (finish) { From 9e496d7458bb01b717afe22db10a724db57d53fd Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 14 Jan 2013 18:28:19 +0000 Subject: [PATCH 0448/1634] xen_disk: add persistent grant support to xen_disk backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This protocol extension reuses the same set of grant pages for all transactions between the front/back drivers, avoiding expensive tlb flushes, grant table lock contention and switches between userspace and kernel space. The full description of the protocol can be found in the public blkif.h header. http://xenbits.xen.org/gitweb/?p=xen.git;a=blob_plain;f=xen/include/public/io/blkif.h Speed improvement with 15 guests performing I/O is ~450%. Signed-off-by: Roger Pau Monné Signed-off-by: Stefano Stabellini --- hw/xen_disk.c | 171 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 154 insertions(+), 17 deletions(-) diff --git a/hw/xen_disk.c b/hw/xen_disk.c index b7c7977870..9ee72a0ded 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -51,6 +51,13 @@ static int max_requests = 32; #define BLOCK_SIZE 512 #define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2) +struct PersistentGrant { + void *page; + struct XenBlkDev *blkdev; +}; + +typedef struct PersistentGrant PersistentGrant; + struct ioreq { blkif_request_t req; int16_t status; @@ -68,6 +75,7 @@ struct ioreq { int prot; void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST]; void *pages; + int num_unmap; /* aio status */ int aio_inflight; @@ -104,6 +112,12 @@ struct XenBlkDev { int requests_inflight; int requests_finished; + /* Persistent grants extension */ + gboolean feature_persistent; + GTree *persistent_gnts; + unsigned int persistent_gnt_count; + unsigned int max_grants; + /* qemu block driver */ DriveInfo *dinfo; BlockDriverState *bs; @@ -137,6 +151,29 @@ static void ioreq_reset(struct ioreq *ioreq) qemu_iovec_reset(&ioreq->v); } +static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data) +{ + uint ua = GPOINTER_TO_UINT(a); + uint ub = GPOINTER_TO_UINT(b); + return (ua > ub) - (ua < ub); +} + +static void destroy_grant(gpointer pgnt) +{ + PersistentGrant *grant = pgnt; + XenGnttab gnt = grant->blkdev->xendev.gnttabdev; + + if (xc_gnttab_munmap(gnt, grant->page, 1) != 0) { + xen_be_printf(&grant->blkdev->xendev, 0, + "xc_gnttab_munmap failed: %s\n", + strerror(errno)); + } + grant->blkdev->persistent_gnt_count--; + xen_be_printf(&grant->blkdev->xendev, 3, + "unmapped grant %p\n", grant->page); + g_free(grant); +} + static struct ioreq *ioreq_start(struct XenBlkDev *blkdev) { struct ioreq *ioreq = NULL; @@ -265,21 +302,21 @@ static void ioreq_unmap(struct ioreq *ioreq) XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; int i; - if (ioreq->v.niov == 0 || ioreq->mapped == 0) { + if (ioreq->num_unmap == 0 || ioreq->mapped == 0) { return; } if (batch_maps) { if (!ioreq->pages) { return; } - if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0) { + if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->num_unmap) != 0) { xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n", strerror(errno)); } - ioreq->blkdev->cnt_map -= ioreq->v.niov; + ioreq->blkdev->cnt_map -= ioreq->num_unmap; ioreq->pages = NULL; } else { - for (i = 0; i < ioreq->v.niov; i++) { + for (i = 0; i < ioreq->num_unmap; i++) { if (!ioreq->page[i]) { continue; } @@ -297,41 +334,120 @@ static void ioreq_unmap(struct ioreq *ioreq) static int ioreq_map(struct ioreq *ioreq) { XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev; - int i; + uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + int i, j, new_maps = 0; + PersistentGrant *grant; + /* domids and refs variables will contain the information necessary + * to map the grants that are needed to fulfill this request. + * + * After mapping the needed grants, the page array will contain the + * memory address of each granted page in the order specified in ioreq + * (disregarding if it's a persistent grant or not). + */ if (ioreq->v.niov == 0 || ioreq->mapped == 1) { return 0; } - if (batch_maps) { + if (ioreq->blkdev->feature_persistent) { + for (i = 0; i < ioreq->v.niov; i++) { + grant = g_tree_lookup(ioreq->blkdev->persistent_gnts, + GUINT_TO_POINTER(ioreq->refs[i])); + + if (grant != NULL) { + page[i] = grant->page; + xen_be_printf(&ioreq->blkdev->xendev, 3, + "using persistent-grant %" PRIu32 "\n", + ioreq->refs[i]); + } else { + /* Add the grant to the list of grants that + * should be mapped + */ + domids[new_maps] = ioreq->domids[i]; + refs[new_maps] = ioreq->refs[i]; + page[i] = NULL; + new_maps++; + } + } + /* Set the protection to RW, since grants may be reused later + * with a different protection than the one needed for this request + */ + ioreq->prot = PROT_WRITE | PROT_READ; + } else { + /* All grants in the request should be mapped */ + memcpy(refs, ioreq->refs, sizeof(refs)); + memcpy(domids, ioreq->domids, sizeof(domids)); + memset(page, 0, sizeof(page)); + new_maps = ioreq->v.niov; + } + + if (batch_maps && new_maps) { ioreq->pages = xc_gnttab_map_grant_refs - (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot); + (gnt, new_maps, domids, refs, ioreq->prot); if (ioreq->pages == NULL) { xen_be_printf(&ioreq->blkdev->xendev, 0, "can't map %d grant refs (%s, %d maps)\n", - ioreq->v.niov, strerror(errno), ioreq->blkdev->cnt_map); + new_maps, strerror(errno), ioreq->blkdev->cnt_map); return -1; } - for (i = 0; i < ioreq->v.niov; i++) { - ioreq->v.iov[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE + - (uintptr_t)ioreq->v.iov[i].iov_base; + for (i = 0, j = 0; i < ioreq->v.niov; i++) { + if (page[i] == NULL) { + page[i] = ioreq->pages + (j++) * XC_PAGE_SIZE; + } } - ioreq->blkdev->cnt_map += ioreq->v.niov; - } else { - for (i = 0; i < ioreq->v.niov; i++) { + ioreq->blkdev->cnt_map += new_maps; + } else if (new_maps) { + for (i = 0; i < new_maps; i++) { ioreq->page[i] = xc_gnttab_map_grant_ref - (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot); + (gnt, domids[i], refs[i], ioreq->prot); if (ioreq->page[i] == NULL) { xen_be_printf(&ioreq->blkdev->xendev, 0, "can't map grant ref %d (%s, %d maps)\n", - ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map); + refs[i], strerror(errno), ioreq->blkdev->cnt_map); ioreq_unmap(ioreq); return -1; } - ioreq->v.iov[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->v.iov[i].iov_base; ioreq->blkdev->cnt_map++; } + for (i = 0, j = 0; i < ioreq->v.niov; i++) { + if (page[i] == NULL) { + page[i] = ioreq->page[j++]; + } + } + } + if (ioreq->blkdev->feature_persistent) { + while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants) + && new_maps) { + /* Go through the list of newly mapped grants and add as many + * as possible to the list of persistently mapped grants. + * + * Since we start at the end of ioreq->page(s), we only need + * to decrease new_maps to prevent this granted pages from + * being unmapped in ioreq_unmap. + */ + grant = g_malloc0(sizeof(*grant)); + new_maps--; + if (batch_maps) { + grant->page = ioreq->pages + (new_maps) * XC_PAGE_SIZE; + } else { + grant->page = ioreq->page[new_maps]; + } + grant->blkdev = ioreq->blkdev; + xen_be_printf(&ioreq->blkdev->xendev, 3, + "adding grant %" PRIu32 " page: %p\n", + refs[new_maps], grant->page); + g_tree_insert(ioreq->blkdev->persistent_gnts, + GUINT_TO_POINTER(refs[new_maps]), + grant); + ioreq->blkdev->persistent_gnt_count++; + } + } + for (i = 0; i < ioreq->v.niov; i++) { + ioreq->v.iov[i].iov_base += (uintptr_t)page[i]; } ioreq->mapped = 1; + ioreq->num_unmap = new_maps; return 0; } @@ -679,6 +795,7 @@ static int blk_init(struct XenDevice *xendev) /* fill info */ xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1); + xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1); xenstore_write_be_int(&blkdev->xendev, "info", info); xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk); xenstore_write_be_int(&blkdev->xendev, "sectors", @@ -702,6 +819,7 @@ out_error: static int blk_connect(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + int pers; if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) { return -1; @@ -710,6 +828,11 @@ static int blk_connect(struct XenDevice *xendev) &blkdev->xendev.remote_port) == -1) { return -1; } + if (xenstore_read_fe_int(&blkdev->xendev, "feature-persistent", &pers)) { + blkdev->feature_persistent = FALSE; + } else { + blkdev->feature_persistent = !!pers; + } blkdev->protocol = BLKIF_PROTOCOL_NATIVE; if (blkdev->xendev.protocol) { @@ -753,6 +876,15 @@ static int blk_connect(struct XenDevice *xendev) } } + if (blkdev->feature_persistent) { + /* Init persistent grants */ + blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST; + blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp, + NULL, NULL, + (GDestroyNotify)destroy_grant); + blkdev->persistent_gnt_count = 0; + } + xen_be_bind_evtchn(&blkdev->xendev); xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, " @@ -793,6 +925,11 @@ static int blk_free(struct XenDevice *xendev) blk_disconnect(xendev); } + /* Free persistent grants */ + if (blkdev->feature_persistent) { + g_tree_destroy(blkdev->persistent_gnts); + } + while (!QLIST_EMPTY(&blkdev->freelist)) { ioreq = QLIST_FIRST(&blkdev->freelist); QLIST_REMOVE(ioreq, list); From 7e7b7cba16faa7b721b822fa9ed8bebafa35700f Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 14 Jan 2013 18:30:30 +0000 Subject: [PATCH 0449/1634] xen_disk: implement BLKIF_OP_FLUSH_DISKCACHE, remove BLKIF_OP_WRITE_BARRIER Signed-off-by: Stefano Stabellini --- hw/xen_disk.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 9ee72a0ded..7fea87156d 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -243,12 +243,11 @@ static int ioreq_parse(struct ioreq *ioreq) case BLKIF_OP_READ: ioreq->prot = PROT_WRITE; /* to memory */ break; - case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: + ioreq->presync = 1; if (!ioreq->req.nr_segments) { - ioreq->presync = 1; return 0; } - ioreq->presync = ioreq->postsync = 1; /* fall through */ case BLKIF_OP_WRITE: ioreq->prot = PROT_READ; /* from memory */ @@ -509,7 +508,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) qemu_aio_complete, ioreq); break; case BLKIF_OP_WRITE: - case BLKIF_OP_WRITE_BARRIER: + case BLKIF_OP_FLUSH_DISKCACHE: if (!ioreq->req.nr_segments) { break; } @@ -794,7 +793,7 @@ static int blk_init(struct XenDevice *xendev) blkdev->file_size, blkdev->file_size >> 20); /* fill info */ - xenstore_write_be_int(&blkdev->xendev, "feature-barrier", 1); + xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1); xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1); xenstore_write_be_int(&blkdev->xendev, "info", info); xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk); From 9c16fa79bfa0f8d7a937ee58fa45f2bd0995fa53 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Fri, 11 Jan 2013 18:25:29 +0100 Subject: [PATCH 0450/1634] Add TEWS TPCI200 IndustryPack emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TPCI200 is a PCI board that supports up to 4 IndustryPack modules. A new bus type called 'IndustryPack' has been created so any compatible module can be attached to this board. Reviewed-by: Andreas Färber Signed-off-by: Alberto Garcia Signed-off-by: Anthony Liguori --- default-configs/pci.mak | 1 + hw/Makefile.objs | 3 + hw/ipack.c | 115 +++++++ hw/ipack.h | 79 +++++ hw/pci/pci_ids.h | 3 + hw/tpci200.c | 671 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 872 insertions(+) create mode 100644 hw/ipack.c create mode 100644 hw/ipack.h create mode 100644 hw/tpci200.c diff --git a/default-configs/pci.mak b/default-configs/pci.mak index ae9d1eb487..ee2d18d5f2 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -21,3 +21,4 @@ CONFIG_ESP=y CONFIG_ESP_PCI=y CONFIG_SERIAL=y CONFIG_SERIAL_PCI=y +CONFIG_IPACK=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index aa55ce9873..47d47864fb 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -106,6 +106,9 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o # PCI watchdog devices common-obj-$(CONFIG_PCI) += wdt_i6300esb.o +# IndustryPack +common-obj-$(CONFIG_IPACK) += tpci200.o ipack.o + # PCI network cards common-obj-$(CONFIG_NE2000_PCI) += ne2000.o common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o diff --git a/hw/ipack.c b/hw/ipack.c new file mode 100644 index 0000000000..e15540d5cd --- /dev/null +++ b/hw/ipack.c @@ -0,0 +1,115 @@ +/* + * QEMU IndustryPack emulation + * + * Copyright (C) 2012 Igalia, S.L. + * Author: Alberto Garcia + * + * This code is licensed under the GNU GPL v2 or (at your option) any + * later version. + */ + +#include "ipack.h" + +IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot) +{ + BusChild *kid; + + QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) { + DeviceState *qdev = kid->child; + IPackDevice *ip = IPACK_DEVICE(qdev); + if (ip->slot == slot) { + return ip; + } + } + return NULL; +} + +void ipack_bus_new_inplace(IPackBus *bus, DeviceState *parent, + const char *name, uint8_t n_slots, + qemu_irq_handler handler) +{ + qbus_create_inplace(&bus->qbus, TYPE_IPACK_BUS, parent, name); + bus->n_slots = n_slots; + bus->set_irq = handler; +} + +static int ipack_device_dev_init(DeviceState *qdev) +{ + IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(qdev)); + IPackDevice *dev = IPACK_DEVICE(qdev); + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); + + if (dev->slot < 0) { + dev->slot = bus->free_slot; + } + if (dev->slot >= bus->n_slots) { + return -1; + } + bus->free_slot = dev->slot + 1; + + dev->irq = qemu_allocate_irqs(bus->set_irq, dev, 2); + + return k->init(dev); +} + +static int ipack_device_dev_exit(DeviceState *qdev) +{ + IPackDevice *dev = IPACK_DEVICE(qdev); + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev); + + if (k->exit) { + k->exit(dev); + } + + qemu_free_irqs(dev->irq); + + return 0; +} + +static Property ipack_device_props[] = { + DEFINE_PROP_INT32("slot", IPackDevice, slot, -1), + DEFINE_PROP_END_OF_LIST() +}; + +static void ipack_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->bus_type = TYPE_IPACK_BUS; + k->init = ipack_device_dev_init; + k->exit = ipack_device_dev_exit; + k->props = ipack_device_props; +} + +const VMStateDescription vmstate_ipack_device = { + .name = "ipack_device", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32(slot, IPackDevice), + VMSTATE_END_OF_LIST() + } +}; + +static const TypeInfo ipack_device_info = { + .name = TYPE_IPACK_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(IPackDevice), + .class_size = sizeof(IPackDeviceClass), + .class_init = ipack_device_class_init, + .abstract = true, +}; + +static const TypeInfo ipack_bus_info = { + .name = TYPE_IPACK_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(IPackBus), +}; + +static void ipack_register_types(void) +{ + type_register_static(&ipack_device_info); + type_register_static(&ipack_bus_info); +} + +type_init(ipack_register_types) diff --git a/hw/ipack.h b/hw/ipack.h new file mode 100644 index 0000000000..69e26282d3 --- /dev/null +++ b/hw/ipack.h @@ -0,0 +1,79 @@ +/* + * QEMU IndustryPack emulation + * + * Copyright (C) 2012 Igalia, S.L. + * Author: Alberto Garcia + * + * This code is licensed under the GNU GPL v2 or (at your option) any + * later version. + */ + +#ifndef QEMU_IPACK_H +#define QEMU_IPACK_H + +#include "qdev.h" + +typedef struct IPackBus IPackBus; + +#define TYPE_IPACK_BUS "IndustryPack" +#define IPACK_BUS(obj) OBJECT_CHECK(IPackBus, (obj), TYPE_IPACK_BUS) + +struct IPackBus { + BusState qbus; + /* All fields are private */ + uint8_t n_slots; + uint8_t free_slot; + qemu_irq_handler set_irq; +}; + +typedef struct IPackDevice IPackDevice; +typedef struct IPackDeviceClass IPackDeviceClass; + +#define TYPE_IPACK_DEVICE "ipack-device" +#define IPACK_DEVICE(obj) \ + OBJECT_CHECK(IPackDevice, (obj), TYPE_IPACK_DEVICE) +#define IPACK_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(IPackDeviceClass, (klass), TYPE_IPACK_DEVICE) +#define IPACK_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IPackDeviceClass, (obj), TYPE_IPACK_DEVICE) + +struct IPackDeviceClass { + DeviceClass parent_class; + + int (*init)(IPackDevice *dev); + int (*exit)(IPackDevice *dev); + + uint16_t (*io_read)(IPackDevice *dev, uint8_t addr); + void (*io_write)(IPackDevice *dev, uint8_t addr, uint16_t val); + + uint16_t (*id_read)(IPackDevice *dev, uint8_t addr); + void (*id_write)(IPackDevice *dev, uint8_t addr, uint16_t val); + + uint16_t (*int_read)(IPackDevice *dev, uint8_t addr); + void (*int_write)(IPackDevice *dev, uint8_t addr, uint16_t val); + + uint16_t (*mem_read16)(IPackDevice *dev, uint32_t addr); + void (*mem_write16)(IPackDevice *dev, uint32_t addr, uint16_t val); + + uint8_t (*mem_read8)(IPackDevice *dev, uint32_t addr); + void (*mem_write8)(IPackDevice *dev, uint32_t addr, uint8_t val); +}; + +struct IPackDevice { + DeviceState qdev; + int32_t slot; + /* IRQ objects for the IndustryPack INT0# and INT1# */ + qemu_irq *irq; +}; + +extern const VMStateDescription vmstate_ipack_device; + +#define VMSTATE_IPACK_DEVICE(_field, _state) \ + VMSTATE_STRUCT(_field, _state, 1, vmstate_ipack_device, IPackDevice) + +IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot); +void ipack_bus_new_inplace(IPackBus *bus, DeviceState *parent, + const char *name, uint8_t n_slots, + qemu_irq_handler handler); + +#endif diff --git a/hw/pci/pci_ids.h b/hw/pci/pci_ids.h index 271d935bc7..d8dc2f1bf7 100644 --- a/hw/pci/pci_ids.h +++ b/hw/pci/pci_ids.h @@ -148,4 +148,7 @@ #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_UPD720200 0x0194 +#define PCI_VENDOR_ID_TEWS 0x1498 +#define PCI_DEVICE_ID_TEWS_TPCI200 0x30C8 + #endif diff --git a/hw/tpci200.c b/hw/tpci200.c new file mode 100644 index 0000000000..e082bca965 --- /dev/null +++ b/hw/tpci200.c @@ -0,0 +1,671 @@ +/* + * QEMU TEWS TPCI200 IndustryPack carrier emulation + * + * Copyright (C) 2012 Igalia, S.L. + * Author: Alberto Garcia + * + * This code is licensed under the GNU GPL v2 or (at your option) any + * later version. + */ + +#include "ipack.h" +#include "pci/pci.h" +#include "qemu/bitops.h" +#include + +/* #define DEBUG_TPCI */ + +#ifdef DEBUG_TPCI +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, "TPCI200: " fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) do { } while (0) +#endif + +#define N_MODULES 4 + +#define IP_ID_SPACE 2 +#define IP_INT_SPACE 3 +#define IP_IO_SPACE_ADDR_MASK 0x7F +#define IP_ID_SPACE_ADDR_MASK 0x3F +#define IP_INT_SPACE_ADDR_MASK 0x3F + +#define STATUS_INT(IP, INTNO) BIT((IP) * 2 + (INTNO)) +#define STATUS_TIMEOUT(IP) BIT((IP) + 12) +#define STATUS_ERR_ANY 0xF00 + +#define CTRL_CLKRATE BIT(0) +#define CTRL_RECOVER BIT(1) +#define CTRL_TIME_INT BIT(2) +#define CTRL_ERR_INT BIT(3) +#define CTRL_INT_EDGE(INTNO) BIT(4 + (INTNO)) +#define CTRL_INT(INTNO) BIT(6 + (INTNO)) + +#define REG_REV_ID 0x00 +#define REG_IP_A_CTRL 0x02 +#define REG_IP_B_CTRL 0x04 +#define REG_IP_C_CTRL 0x06 +#define REG_IP_D_CTRL 0x08 +#define REG_RESET 0x0A +#define REG_STATUS 0x0C +#define IP_N_FROM_REG(REG) ((REG) / 2 - 1) + +typedef struct { + PCIDevice dev; + IPackBus bus; + MemoryRegion mmio; + MemoryRegion io; + MemoryRegion las0; + MemoryRegion las1; + MemoryRegion las2; + MemoryRegion las3; + bool big_endian[3]; + uint8_t ctrl[N_MODULES]; + uint16_t status; + uint8_t int_set; +} TPCI200State; + +#define TYPE_TPCI200 "tpci200" + +#define TPCI200(obj) \ + OBJECT_CHECK(TPCI200State, (obj), TYPE_TPCI200) + +static const uint8_t local_config_regs[] = { + 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x60, 0x41, 0xD4, + 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x01, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x08, 0x01, 0x02, + 0x00, 0x04, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0x02, 0x41, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x52, 0x92, 0x24, 0x02 +}; + +static void adjust_addr(bool big_endian, hwaddr *addr, unsigned size) +{ + /* During 8 bit access in big endian mode, + odd and even addresses are swapped */ + if (big_endian && size == 1) { + *addr ^= 1; + } +} + +static uint64_t adjust_value(bool big_endian, uint64_t *val, unsigned size) +{ + /* Local spaces only support 8/16 bit access, + * so there's no need to care for sizes > 2 */ + if (big_endian && size == 2) { + *val = bswap16(*val); + } + return *val; +} + +static void tpci200_set_irq(void *opaque, int intno, int level) +{ + IPackDevice *ip = opaque; + IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(DEVICE(ip))); + PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent); + TPCI200State *dev = TPCI200(pcidev); + unsigned ip_n = ip->slot; + uint16_t prev_status = dev->status; + + assert(ip->slot >= 0 && ip->slot < N_MODULES); + + /* The requested interrupt must be enabled in the IP CONTROL + * register */ + if (!(dev->ctrl[ip_n] & CTRL_INT(intno))) { + return; + } + + /* Update the interrupt status in the IP STATUS register */ + if (level) { + dev->status |= STATUS_INT(ip_n, intno); + } else { + dev->status &= ~STATUS_INT(ip_n, intno); + } + + /* Return if there are no changes */ + if (dev->status == prev_status) { + return; + } + + DPRINTF("IP %u INT%u#: %u\n", ip_n, intno, level); + + /* Check if the interrupt is edge sensitive */ + if (dev->ctrl[ip_n] & CTRL_INT_EDGE(intno)) { + if (level) { + qemu_set_irq(dev->dev.irq[0], !dev->int_set); + qemu_set_irq(dev->dev.irq[0], dev->int_set); + } + } else { + unsigned i, j; + uint16_t level_status = dev->status; + + /* Check if there are any level sensitive interrupts set by + removing the ones that are edge sensitive from the status + register */ + for (i = 0; i < N_MODULES; i++) { + for (j = 0; j < 2; j++) { + if (dev->ctrl[i] & CTRL_INT_EDGE(j)) { + level_status &= ~STATUS_INT(i, j); + } + } + } + + if (level_status && !dev->int_set) { + qemu_irq_raise(dev->dev.irq[0]); + dev->int_set = 1; + } else if (!level_status && dev->int_set) { + qemu_irq_lower(dev->dev.irq[0]); + dev->int_set = 0; + } + } +} + +static uint64_t tpci200_read_cfg(void *opaque, hwaddr addr, unsigned size) +{ + TPCI200State *s = opaque; + uint8_t ret = 0; + if (addr < ARRAY_SIZE(local_config_regs)) { + ret = local_config_regs[addr]; + } + /* Endianness is stored in the first bit of these registers */ + if ((addr == 0x2b && s->big_endian[0]) || + (addr == 0x2f && s->big_endian[1]) || + (addr == 0x33 && s->big_endian[2])) { + ret |= 1; + } + DPRINTF("Read from LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) ret); + return ret; +} + +static void tpci200_write_cfg(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + TPCI200State *s = opaque; + /* Endianness is stored in the first bit of these registers */ + if (addr == 0x2b || addr == 0x2f || addr == 0x33) { + unsigned las = (addr - 0x2b) / 4; + s->big_endian[las] = val & 1; + DPRINTF("LAS%u big endian mode: %u\n", las, (unsigned) val & 1); + } else { + DPRINTF("Write to LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) val); + } +} + +static uint64_t tpci200_read_las0(void *opaque, hwaddr addr, unsigned size) +{ + TPCI200State *s = opaque; + uint64_t ret = 0; + + switch (addr) { + + case REG_REV_ID: + DPRINTF("Read REVISION ID\n"); /* Current value is 0x00 */ + break; + + case REG_IP_A_CTRL: + case REG_IP_B_CTRL: + case REG_IP_C_CTRL: + case REG_IP_D_CTRL: + { + unsigned ip_n = IP_N_FROM_REG(addr); + ret = s->ctrl[ip_n]; + DPRINTF("Read IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) ret); + } + break; + + case REG_RESET: + DPRINTF("Read RESET\n"); /* Not implemented */ + break; + + case REG_STATUS: + ret = s->status; + DPRINTF("Read STATUS: 0x%x\n", (unsigned) ret); + break; + + /* Reserved */ + default: + DPRINTF("Unsupported read from LAS0 0x%x\n", (unsigned) addr); + break; + } + + return adjust_value(s->big_endian[0], &ret, size); +} + +static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + TPCI200State *s = opaque; + + adjust_value(s->big_endian[0], &val, size); + + switch (addr) { + + case REG_REV_ID: + DPRINTF("Write Revision ID: 0x%x\n", (unsigned) val); /* No effect */ + break; + + case REG_IP_A_CTRL: + case REG_IP_B_CTRL: + case REG_IP_C_CTRL: + case REG_IP_D_CTRL: + { + unsigned ip_n = IP_N_FROM_REG(addr); + s->ctrl[ip_n] = val; + DPRINTF("Write IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) val); + } + break; + + case REG_RESET: + DPRINTF("Write RESET: 0x%x\n", (unsigned) val); /* Not implemented */ + break; + + case REG_STATUS: + { + unsigned i; + + for (i = 0; i < N_MODULES; i++) { + IPackDevice *ip = ipack_device_find(&s->bus, i); + + if (ip != NULL) { + if (val & STATUS_INT(i, 0)) { + DPRINTF("Clear IP %c INT0# status\n", 'A' + i); + qemu_irq_lower(ip->irq[0]); + } + if (val & STATUS_INT(i, 1)) { + DPRINTF("Clear IP %c INT1# status\n", 'A' + i); + qemu_irq_lower(ip->irq[1]); + } + } + + if (val & STATUS_TIMEOUT(i)) { + DPRINTF("Clear IP %c timeout\n", 'A' + i); + s->status &= ~STATUS_TIMEOUT(i); + } + } + + if (val & STATUS_ERR_ANY) { + DPRINTF("Unexpected write to STATUS register: 0x%x\n", + (unsigned) val); + } + } + break; + + /* Reserved */ + default: + DPRINTF("Unsupported write to LAS0 0x%x: 0x%x\n", + (unsigned) addr, (unsigned) val); + break; + } +} + +static uint64_t tpci200_read_las1(void *opaque, hwaddr addr, unsigned size) +{ + TPCI200State *s = opaque; + IPackDevice *ip; + uint64_t ret = 0; + unsigned ip_n, space; + uint8_t offset; + + adjust_addr(s->big_endian[1], &addr, size); + + /* + * The address is divided into the IP module number (0-4), the IP + * address space (I/O, ID, INT) and the offset within that space. + */ + ip_n = addr >> 8; + space = (addr >> 6) & 3; + ip = ipack_device_find(&s->bus, ip_n); + + if (ip == NULL) { + DPRINTF("Read LAS1: IP module %u not installed\n", ip_n); + } else { + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip); + switch (space) { + + case IP_ID_SPACE: + offset = addr & IP_ID_SPACE_ADDR_MASK; + if (k->id_read) { + ret = k->id_read(ip, offset); + } + break; + + case IP_INT_SPACE: + offset = addr & IP_INT_SPACE_ADDR_MASK; + + /* Read address 0 to ACK IP INT0# and address 2 to ACK IP INT1# */ + if (offset == 0 || offset == 2) { + unsigned intno = offset / 2; + bool int_set = s->status & STATUS_INT(ip_n, intno); + bool int_edge_sensitive = s->ctrl[ip_n] & CTRL_INT_EDGE(intno); + if (int_set && !int_edge_sensitive) { + qemu_irq_lower(ip->irq[intno]); + } + } + + if (k->int_read) { + ret = k->int_read(ip, offset); + } + break; + + default: + offset = addr & IP_IO_SPACE_ADDR_MASK; + if (k->io_read) { + ret = k->io_read(ip, offset); + } + break; + } + } + + return adjust_value(s->big_endian[1], &ret, size); +} + +static void tpci200_write_las1(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + TPCI200State *s = opaque; + IPackDevice *ip; + unsigned ip_n, space; + uint8_t offset; + + adjust_addr(s->big_endian[1], &addr, size); + adjust_value(s->big_endian[1], &val, size); + + /* + * The address is divided into the IP module number, the IP + * address space (I/O, ID, INT) and the offset within that space. + */ + ip_n = addr >> 8; + space = (addr >> 6) & 3; + ip = ipack_device_find(&s->bus, ip_n); + + if (ip == NULL) { + DPRINTF("Write LAS1: IP module %u not installed\n", ip_n); + } else { + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip); + switch (space) { + + case IP_ID_SPACE: + offset = addr & IP_ID_SPACE_ADDR_MASK; + if (k->id_write) { + k->id_write(ip, offset, val); + } + break; + + case IP_INT_SPACE: + offset = addr & IP_INT_SPACE_ADDR_MASK; + if (k->int_write) { + k->int_write(ip, offset, val); + } + break; + + default: + offset = addr & IP_IO_SPACE_ADDR_MASK; + if (k->io_write) { + k->io_write(ip, offset, val); + } + break; + } + } +} + +static uint64_t tpci200_read_las2(void *opaque, hwaddr addr, unsigned size) +{ + TPCI200State *s = opaque; + IPackDevice *ip; + uint64_t ret = 0; + unsigned ip_n; + uint32_t offset; + + adjust_addr(s->big_endian[2], &addr, size); + + /* + * The address is divided into the IP module number and the offset + * within the IP module MEM space. + */ + ip_n = addr >> 23; + offset = addr & 0x7fffff; + ip = ipack_device_find(&s->bus, ip_n); + + if (ip == NULL) { + DPRINTF("Read LAS2: IP module %u not installed\n", ip_n); + } else { + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip); + if (k->mem_read16) { + ret = k->mem_read16(ip, offset); + } + } + + return adjust_value(s->big_endian[2], &ret, size); +} + +static void tpci200_write_las2(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + TPCI200State *s = opaque; + IPackDevice *ip; + unsigned ip_n; + uint32_t offset; + + adjust_addr(s->big_endian[2], &addr, size); + adjust_value(s->big_endian[2], &val, size); + + /* + * The address is divided into the IP module number and the offset + * within the IP module MEM space. + */ + ip_n = addr >> 23; + offset = addr & 0x7fffff; + ip = ipack_device_find(&s->bus, ip_n); + + if (ip == NULL) { + DPRINTF("Write LAS2: IP module %u not installed\n", ip_n); + } else { + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip); + if (k->mem_write16) { + k->mem_write16(ip, offset, val); + } + } +} + +static uint64_t tpci200_read_las3(void *opaque, hwaddr addr, unsigned size) +{ + TPCI200State *s = opaque; + IPackDevice *ip; + uint64_t ret = 0; + /* + * The address is divided into the IP module number and the offset + * within the IP module MEM space. + */ + unsigned ip_n = addr >> 22; + uint32_t offset = addr & 0x3fffff; + + ip = ipack_device_find(&s->bus, ip_n); + + if (ip == NULL) { + DPRINTF("Read LAS3: IP module %u not installed\n", ip_n); + } else { + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip); + if (k->mem_read8) { + ret = k->mem_read8(ip, offset); + } + } + + return ret; +} + +static void tpci200_write_las3(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + TPCI200State *s = opaque; + IPackDevice *ip; + /* + * The address is divided into the IP module number and the offset + * within the IP module MEM space. + */ + unsigned ip_n = addr >> 22; + uint32_t offset = addr & 0x3fffff; + + ip = ipack_device_find(&s->bus, ip_n); + + if (ip == NULL) { + DPRINTF("Write LAS3: IP module %u not installed\n", ip_n); + } else { + IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip); + if (k->mem_write8) { + k->mem_write8(ip, offset, val); + } + } +} + +static const MemoryRegionOps tpci200_cfg_ops = { + .read = tpci200_read_cfg, + .write = tpci200_write_cfg, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4 + }, + .impl = { + .min_access_size = 1, + .max_access_size = 1 + } +}; + +static const MemoryRegionOps tpci200_las0_ops = { + .read = tpci200_read_las0, + .write = tpci200_write_las0, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 2, + .max_access_size = 2 + } +}; + +static const MemoryRegionOps tpci200_las1_ops = { + .read = tpci200_read_las1, + .write = tpci200_write_las1, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 2 + } +}; + +static const MemoryRegionOps tpci200_las2_ops = { + .read = tpci200_read_las2, + .write = tpci200_write_las2, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 2 + } +}; + +static const MemoryRegionOps tpci200_las3_ops = { + .read = tpci200_read_las3, + .write = tpci200_write_las3, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1 + } +}; + +static int tpci200_initfn(PCIDevice *pci_dev) +{ + TPCI200State *s = TPCI200(pci_dev); + uint8_t *c = s->dev.config; + + pci_set_word(c + PCI_COMMAND, 0x0003); + pci_set_word(c + PCI_STATUS, 0x0280); + + pci_set_byte(c + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */ + + pci_set_byte(c + PCI_CAPABILITY_LIST, 0x40); + pci_set_long(c + 0x40, 0x48014801); + pci_set_long(c + 0x48, 0x00024C06); + pci_set_long(c + 0x4C, 0x00000003); + + memory_region_init_io(&s->mmio, &tpci200_cfg_ops, + s, "tpci200_mmio", 128); + memory_region_init_io(&s->io, &tpci200_cfg_ops, + s, "tpci200_io", 128); + memory_region_init_io(&s->las0, &tpci200_las0_ops, + s, "tpci200_las0", 256); + memory_region_init_io(&s->las1, &tpci200_las1_ops, + s, "tpci200_las1", 1024); + memory_region_init_io(&s->las2, &tpci200_las2_ops, + s, "tpci200_las2", 1024*1024*32); + memory_region_init_io(&s->las3, &tpci200_las3_ops, + s, "tpci200_las3", 1024*1024*16); + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io); + pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las0); + pci_register_bar(&s->dev, 3, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las1); + pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las2); + pci_register_bar(&s->dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las3); + + ipack_bus_new_inplace(&s->bus, DEVICE(&s->dev), NULL, + N_MODULES, tpci200_set_irq); + + return 0; +} + +static void tpci200_exitfn(PCIDevice *pci_dev) +{ + TPCI200State *s = TPCI200(pci_dev); + + memory_region_destroy(&s->mmio); + memory_region_destroy(&s->io); + memory_region_destroy(&s->las0); + memory_region_destroy(&s->las1); + memory_region_destroy(&s->las2); + memory_region_destroy(&s->las3); +} + +static const VMStateDescription vmstate_tpci200 = { + .name = "tpci200", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, TPCI200State), + VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3), + VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES), + VMSTATE_UINT16(status, TPCI200State), + VMSTATE_UINT8(int_set, TPCI200State), + VMSTATE_END_OF_LIST() + } +}; + +static void tpci200_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = tpci200_initfn; + k->exit = tpci200_exitfn; + k->vendor_id = PCI_VENDOR_ID_TEWS; + k->device_id = PCI_DEVICE_ID_TEWS_TPCI200; + k->class_id = PCI_CLASS_BRIDGE_OTHER; + k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS; + k->subsystem_id = 0x300A; + dc->desc = "TEWS TPCI200 IndustryPack carrier"; + dc->vmsd = &vmstate_tpci200; +} + +static const TypeInfo tpci200_info = { + .name = TYPE_TPCI200, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(TPCI200State), + .class_init = tpci200_class_init, +}; + +static void tpci200_register_types(void) +{ + type_register_static(&tpci200_info); +} + +type_init(tpci200_register_types) From be657dea4bec90031cc66a111a772299bfca7fa5 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Fri, 11 Jan 2013 18:25:30 +0100 Subject: [PATCH 0451/1634] Add GE IP-Octal 232 IndustryPack emulation The GE IP-Octal 232 is an IndustryPack module that implements eight RS-232 serial ports, each one of which can be redirected to a character device in the host. Signed-off-by: Alberto Garcia Signed-off-by: Anthony Liguori --- hw/Makefile.objs | 2 +- hw/ipoctal232.c | 619 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 620 insertions(+), 1 deletion(-) create mode 100644 hw/ipoctal232.c diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 47d47864fb..74b07a7e7e 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -107,7 +107,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o common-obj-$(CONFIG_PCI) += wdt_i6300esb.o # IndustryPack -common-obj-$(CONFIG_IPACK) += tpci200.o ipack.o +common-obj-$(CONFIG_IPACK) += tpci200.o ipoctal232.o ipack.o # PCI network cards common-obj-$(CONFIG_NE2000_PCI) += ne2000.o diff --git a/hw/ipoctal232.c b/hw/ipoctal232.c new file mode 100644 index 0000000000..c1e3b197b5 --- /dev/null +++ b/hw/ipoctal232.c @@ -0,0 +1,619 @@ +/* + * QEMU GE IP-Octal 232 IndustryPack emulation + * + * Copyright (C) 2012 Igalia, S.L. + * Author: Alberto Garcia + * + * This code is licensed under the GNU GPL v2 or (at your option) any + * later version. + */ + +#include "ipack.h" +#include "qemu/bitops.h" +#include "char/char.h" + +/* #define DEBUG_IPOCTAL */ + +#ifdef DEBUG_IPOCTAL +#define DPRINTF2(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF2(fmt, ...) do { } while (0) +#endif + +#define DPRINTF(fmt, ...) DPRINTF2("IP-Octal: " fmt, ## __VA_ARGS__) + +#define RX_FIFO_SIZE 3 + +/* The IP-Octal has 8 channels (a-h) + divided into 4 blocks (A-D) */ +#define N_CHANNELS 8 +#define N_BLOCKS 4 + +#define REG_MRa 0x01 +#define REG_MRb 0x11 +#define REG_SRa 0x03 +#define REG_SRb 0x13 +#define REG_CSRa 0x03 +#define REG_CSRb 0x13 +#define REG_CRa 0x05 +#define REG_CRb 0x15 +#define REG_RHRa 0x07 +#define REG_RHRb 0x17 +#define REG_THRa 0x07 +#define REG_THRb 0x17 +#define REG_ACR 0x09 +#define REG_ISR 0x0B +#define REG_IMR 0x0B +#define REG_OPCR 0x1B + +#define CR_ENABLE_RX BIT(0) +#define CR_DISABLE_RX BIT(1) +#define CR_ENABLE_TX BIT(2) +#define CR_DISABLE_TX BIT(3) +#define CR_CMD(cr) ((cr) >> 4) +#define CR_NO_OP 0 +#define CR_RESET_MR 1 +#define CR_RESET_RX 2 +#define CR_RESET_TX 3 +#define CR_RESET_ERR 4 +#define CR_RESET_BRKINT 5 +#define CR_START_BRK 6 +#define CR_STOP_BRK 7 +#define CR_ASSERT_RTSN 8 +#define CR_NEGATE_RTSN 9 +#define CR_TIMEOUT_ON 10 +#define CR_TIMEOUT_OFF 12 + +#define SR_RXRDY BIT(0) +#define SR_FFULL BIT(1) +#define SR_TXRDY BIT(2) +#define SR_TXEMT BIT(3) +#define SR_OVERRUN BIT(4) +#define SR_PARITY BIT(5) +#define SR_FRAMING BIT(6) +#define SR_BREAK BIT(7) + +#define ISR_TXRDYA BIT(0) +#define ISR_RXRDYA BIT(1) +#define ISR_BREAKA BIT(2) +#define ISR_CNTRDY BIT(3) +#define ISR_TXRDYB BIT(4) +#define ISR_RXRDYB BIT(5) +#define ISR_BREAKB BIT(6) +#define ISR_MPICHG BIT(7) +#define ISR_TXRDY(CH) (((CH) & 1) ? BIT(4) : BIT(0)) +#define ISR_RXRDY(CH) (((CH) & 1) ? BIT(5) : BIT(1)) +#define ISR_BREAK(CH) (((CH) & 1) ? BIT(6) : BIT(2)) + +typedef struct IPOctalState IPOctalState; +typedef struct SCC2698Channel SCC2698Channel; +typedef struct SCC2698Block SCC2698Block; + +struct SCC2698Channel { + IPOctalState *ipoctal; + CharDriverState *dev; + char *devpath; + bool rx_enabled; + uint8_t mr[2]; + uint8_t mr_idx; + uint8_t sr; + uint8_t rhr[RX_FIFO_SIZE]; + uint8_t rhr_idx; + uint8_t rx_pending; +}; + +struct SCC2698Block { + uint8_t imr; + uint8_t isr; +}; + +struct IPOctalState { + IPackDevice dev; + SCC2698Channel ch[N_CHANNELS]; + SCC2698Block blk[N_BLOCKS]; + uint8_t irq_vector; +}; + +#define TYPE_IPOCTAL "ipoctal232" + +#define IPOCTAL(obj) \ + OBJECT_CHECK(IPOctalState, (obj), TYPE_IPOCTAL) + +static const VMStateDescription vmstate_scc2698_channel = { + .name = "scc2698_channel", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(rx_enabled, SCC2698Channel), + VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2), + VMSTATE_UINT8(mr_idx, SCC2698Channel), + VMSTATE_UINT8(sr, SCC2698Channel), + VMSTATE_UINT8_ARRAY(rhr, SCC2698Channel, RX_FIFO_SIZE), + VMSTATE_UINT8(rhr_idx, SCC2698Channel), + VMSTATE_UINT8(rx_pending, SCC2698Channel), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_scc2698_block = { + .name = "scc2698_block", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(imr, SCC2698Block), + VMSTATE_UINT8(isr, SCC2698Block), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_ipoctal = { + .name = "ipoctal232", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_IPACK_DEVICE(dev, IPOctalState), + VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1, + vmstate_scc2698_channel, SCC2698Channel), + VMSTATE_STRUCT_ARRAY(blk, IPOctalState, N_BLOCKS, 1, + vmstate_scc2698_block, SCC2698Block), + VMSTATE_UINT8(irq_vector, IPOctalState), + VMSTATE_END_OF_LIST() + } +}; + +/* data[10] is 0x0C, not 0x0B as the doc says */ +static const uint8_t id_prom_data[] = { + 0x49, 0x50, 0x41, 0x43, 0xF0, 0x22, + 0xA1, 0x00, 0x00, 0x00, 0x0C, 0xCC +}; + +static void update_irq(IPOctalState *dev, unsigned block) +{ + /* Blocks A and B interrupt on INT0#, C and D on INT1#. + Thus, to get the status we have to check two blocks. */ + SCC2698Block *blk0 = &dev->blk[block]; + SCC2698Block *blk1 = &dev->blk[block^1]; + unsigned intno = block / 2; + + if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) { + qemu_irq_raise(dev->dev.irq[intno]); + } else { + qemu_irq_lower(dev->dev.irq[intno]); + } +} + +static void write_cr(IPOctalState *dev, unsigned channel, uint8_t val) +{ + SCC2698Channel *ch = &dev->ch[channel]; + SCC2698Block *blk = &dev->blk[channel / 2]; + + DPRINTF("Write CR%c %u: ", channel + 'a', val); + + /* The lower 4 bits are used to enable and disable Tx and Rx */ + if (val & CR_ENABLE_RX) { + DPRINTF2("Rx on, "); + ch->rx_enabled = true; + } + if (val & CR_DISABLE_RX) { + DPRINTF2("Rx off, "); + ch->rx_enabled = false; + } + if (val & CR_ENABLE_TX) { + DPRINTF2("Tx on, "); + ch->sr |= SR_TXRDY | SR_TXEMT; + blk->isr |= ISR_TXRDY(channel); + } + if (val & CR_DISABLE_TX) { + DPRINTF2("Tx off, "); + ch->sr &= ~(SR_TXRDY | SR_TXEMT); + blk->isr &= ~ISR_TXRDY(channel); + } + + DPRINTF2("cmd: "); + + /* The rest of the bits implement different commands */ + switch (CR_CMD(val)) { + case CR_NO_OP: + DPRINTF2("none"); + break; + case CR_RESET_MR: + DPRINTF2("reset MR"); + ch->mr_idx = 0; + break; + case CR_RESET_RX: + DPRINTF2("reset Rx"); + ch->rx_enabled = false; + ch->rx_pending = 0; + ch->sr &= ~SR_RXRDY; + blk->isr &= ~ISR_RXRDY(channel); + break; + case CR_RESET_TX: + DPRINTF2("reset Tx"); + ch->sr &= ~(SR_TXRDY | SR_TXEMT); + blk->isr &= ~ISR_TXRDY(channel); + break; + case CR_RESET_ERR: + DPRINTF2("reset err"); + ch->sr &= ~(SR_OVERRUN | SR_PARITY | SR_FRAMING | SR_BREAK); + break; + case CR_RESET_BRKINT: + DPRINTF2("reset brk ch int"); + blk->isr &= ~(ISR_BREAKA | ISR_BREAKB); + break; + default: + DPRINTF2("unsupported 0x%x", CR_CMD(val)); + } + + DPRINTF2("\n"); +} + +static uint16_t io_read(IPackDevice *ip, uint8_t addr) +{ + IPOctalState *dev = IPOCTAL(ip); + uint16_t ret = 0; + /* addr[7:6]: block (A-D) + addr[7:5]: channel (a-h) + addr[5:0]: register */ + unsigned block = addr >> 5; + unsigned channel = addr >> 4; + /* Big endian, accessed using 8-bit bytes at odd locations */ + unsigned offset = (addr & 0x1F) ^ 1; + SCC2698Channel *ch = &dev->ch[channel]; + SCC2698Block *blk = &dev->blk[block]; + uint8_t old_isr = blk->isr; + + switch (offset) { + + case REG_MRa: + case REG_MRb: + ret = ch->mr[ch->mr_idx]; + DPRINTF("Read MR%u%c: 0x%x\n", ch->mr_idx + 1, channel + 'a', ret); + ch->mr_idx = 1; + break; + + case REG_SRa: + case REG_SRb: + ret = ch->sr; + DPRINTF("Read SR%c: 0x%x\n", channel + 'a', ret); + break; + + case REG_RHRa: + case REG_RHRb: + ret = ch->rhr[ch->rhr_idx]; + if (ch->rx_pending > 0) { + ch->rx_pending--; + if (ch->rx_pending == 0) { + ch->sr &= ~SR_RXRDY; + blk->isr &= ~ISR_RXRDY(channel); + if (ch->dev) { + qemu_chr_accept_input(ch->dev); + } + } else { + ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE; + } + if (ch->sr & SR_BREAK) { + ch->sr &= ~SR_BREAK; + blk->isr |= ISR_BREAK(channel); + } + } + DPRINTF("Read RHR%c (0x%x)\n", channel + 'a', ret); + break; + + case REG_ISR: + ret = blk->isr; + DPRINTF("Read ISR%c: 0x%x\n", block + 'A', ret); + break; + + default: + DPRINTF("Read unknown/unsupported register 0x%02x\n", offset); + } + + if (old_isr != blk->isr) { + update_irq(dev, block); + } + + return ret; +} + +static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val) +{ + IPOctalState *dev = IPOCTAL(ip); + unsigned reg = val & 0xFF; + /* addr[7:6]: block (A-D) + addr[7:5]: channel (a-h) + addr[5:0]: register */ + unsigned block = addr >> 5; + unsigned channel = addr >> 4; + /* Big endian, accessed using 8-bit bytes at odd locations */ + unsigned offset = (addr & 0x1F) ^ 1; + SCC2698Channel *ch = &dev->ch[channel]; + SCC2698Block *blk = &dev->blk[block]; + uint8_t old_isr = blk->isr; + uint8_t old_imr = blk->imr; + + switch (offset) { + + case REG_MRa: + case REG_MRb: + ch->mr[ch->mr_idx] = reg; + DPRINTF("Write MR%u%c 0x%x\n", ch->mr_idx + 1, channel + 'a', reg); + ch->mr_idx = 1; + break; + + /* Not implemented */ + case REG_CSRa: + case REG_CSRb: + DPRINTF("Write CSR%c: 0x%x\n", channel + 'a', reg); + break; + + case REG_CRa: + case REG_CRb: + write_cr(dev, channel, reg); + break; + + case REG_THRa: + case REG_THRb: + if (ch->sr & SR_TXRDY) { + DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg); + if (ch->dev) { + uint8_t thr = reg; + qemu_chr_fe_write(ch->dev, &thr, 1); + } + } else { + DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg); + } + break; + + /* Not implemented */ + case REG_ACR: + DPRINTF("Write ACR%c 0x%x\n", block + 'A', val); + break; + + case REG_IMR: + DPRINTF("Write IMR%c 0x%x\n", block + 'A', val); + blk->imr = reg; + break; + + /* Not implemented */ + case REG_OPCR: + DPRINTF("Write OPCR%c 0x%x\n", block + 'A', val); + break; + + default: + DPRINTF("Write unknown/unsupported register 0x%02x %u\n", offset, val); + } + + if (old_isr != blk->isr || old_imr != blk->imr) { + update_irq(dev, block); + } +} + +static uint16_t id_read(IPackDevice *ip, uint8_t addr) +{ + uint16_t ret = 0; + unsigned pos = addr / 2; /* The ID PROM data is stored every other byte */ + + if (pos < ARRAY_SIZE(id_prom_data)) { + ret = id_prom_data[pos]; + } else { + DPRINTF("Attempt to read unavailable PROM data at 0x%x\n", addr); + } + + return ret; +} + +static void id_write(IPackDevice *ip, uint8_t addr, uint16_t val) +{ + IPOctalState *dev = IPOCTAL(ip); + if (addr == 1) { + DPRINTF("Write IRQ vector: %u\n", (unsigned) val); + dev->irq_vector = val; /* Undocumented, but the hw works like that */ + } else { + DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); + } +} + +static uint16_t int_read(IPackDevice *ip, uint8_t addr) +{ + IPOctalState *dev = IPOCTAL(ip); + /* Read address 0 to ACK INT0# and address 2 to ACK INT1# */ + if (addr != 0 && addr != 2) { + DPRINTF("Attempt to read from 0x%x\n", addr); + return 0; + } else { + /* Update interrupts if necessary */ + update_irq(dev, addr); + return dev->irq_vector; + } +} + +static void int_write(IPackDevice *ip, uint8_t addr, uint16_t val) +{ + DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); +} + +static uint16_t mem_read16(IPackDevice *ip, uint32_t addr) +{ + DPRINTF("Attempt to read from 0x%x\n", addr); + return 0; +} + +static void mem_write16(IPackDevice *ip, uint32_t addr, uint16_t val) +{ + DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); +} + +static uint8_t mem_read8(IPackDevice *ip, uint32_t addr) +{ + DPRINTF("Attempt to read from 0x%x\n", addr); + return 0; +} + +static void mem_write8(IPackDevice *ip, uint32_t addr, uint8_t val) +{ + IPOctalState *dev = IPOCTAL(ip); + if (addr == 1) { + DPRINTF("Write IRQ vector: %u\n", (unsigned) val); + dev->irq_vector = val; + } else { + DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr); + } +} + +static int hostdev_can_receive(void *opaque) +{ + SCC2698Channel *ch = opaque; + int available_bytes = RX_FIFO_SIZE - ch->rx_pending; + return ch->rx_enabled ? available_bytes : 0; +} + +static void hostdev_receive(void *opaque, const uint8_t *buf, int size) +{ + SCC2698Channel *ch = opaque; + IPOctalState *dev = ch->ipoctal; + unsigned pos = ch->rhr_idx + ch->rx_pending; + int i; + + assert(size + ch->rx_pending <= RX_FIFO_SIZE); + + /* Copy data to the RxFIFO */ + for (i = 0; i < size; i++) { + pos %= RX_FIFO_SIZE; + ch->rhr[pos++] = buf[i]; + } + + ch->rx_pending += size; + + /* If the RxFIFO was empty raise an interrupt */ + if (!(ch->sr & SR_RXRDY)) { + unsigned block, channel = 0; + /* Find channel number to update the ISR register */ + while (&dev->ch[channel] != ch) { + channel++; + } + block = channel / 2; + dev->blk[block].isr |= ISR_RXRDY(channel); + ch->sr |= SR_RXRDY; + update_irq(dev, block); + } +} + +static void hostdev_event(void *opaque, int event) +{ + SCC2698Channel *ch = opaque; + switch (event) { + case CHR_EVENT_OPENED: + DPRINTF("Device %s opened\n", ch->dev->label); + break; + case CHR_EVENT_BREAK: { + uint8_t zero = 0; + DPRINTF("Device %s received break\n", ch->dev->label); + + if (!(ch->sr & SR_BREAK)) { + IPOctalState *dev = ch->ipoctal; + unsigned block, channel = 0; + + while (&dev->ch[channel] != ch) { + channel++; + } + block = channel / 2; + + ch->sr |= SR_BREAK; + dev->blk[block].isr |= ISR_BREAK(channel); + } + + /* Put a zero character in the buffer */ + hostdev_receive(ch, &zero, 1); + } + break; + default: + DPRINTF("Device %s received event %d\n", ch->dev->label, event); + } +} + +static int ipoctal_init(IPackDevice *ip) +{ + IPOctalState *s = IPOCTAL(ip); + unsigned i; + + for (i = 0; i < N_CHANNELS; i++) { + SCC2698Channel *ch = &s->ch[i]; + ch->ipoctal = s; + + /* Redirect IP-Octal channels to host character devices */ + if (ch->devpath) { + const char chr_name[] = "ipoctal"; + char label[ARRAY_SIZE(chr_name) + 2]; + static int index; + + snprintf(label, sizeof(label), "%s%d", chr_name, index); + + ch->dev = qemu_chr_new(label, ch->devpath, NULL); + + if (ch->dev) { + index++; + qemu_chr_add_handlers(ch->dev, hostdev_can_receive, + hostdev_receive, hostdev_event, ch); + DPRINTF("Redirecting channel %u to %s (%s)\n", + i, ch->devpath, label); + } else { + DPRINTF("Could not redirect channel %u to %s\n", + i, ch->devpath); + } + } + } + + return 0; +} + +static Property ipoctal_properties[] = { + DEFINE_PROP_STRING("serial0", IPOctalState, ch[0].devpath), + DEFINE_PROP_STRING("serial1", IPOctalState, ch[1].devpath), + DEFINE_PROP_STRING("serial2", IPOctalState, ch[2].devpath), + DEFINE_PROP_STRING("serial3", IPOctalState, ch[3].devpath), + DEFINE_PROP_STRING("serial4", IPOctalState, ch[4].devpath), + DEFINE_PROP_STRING("serial5", IPOctalState, ch[5].devpath), + DEFINE_PROP_STRING("serial6", IPOctalState, ch[6].devpath), + DEFINE_PROP_STRING("serial7", IPOctalState, ch[7].devpath), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ipoctal_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass); + + ic->init = ipoctal_init; + ic->io_read = io_read; + ic->io_write = io_write; + ic->id_read = id_read; + ic->id_write = id_write; + ic->int_read = int_read; + ic->int_write = int_write; + ic->mem_read16 = mem_read16; + ic->mem_write16 = mem_write16; + ic->mem_read8 = mem_read8; + ic->mem_write8 = mem_write8; + + dc->desc = "GE IP-Octal 232 8-channel RS-232 IndustryPack"; + dc->props = ipoctal_properties; + dc->vmsd = &vmstate_ipoctal; +} + +static const TypeInfo ipoctal_info = { + .name = TYPE_IPOCTAL, + .parent = TYPE_IPACK_DEVICE, + .instance_size = sizeof(IPOctalState), + .class_init = ipoctal_class_init, +}; + +static void ipoctal_register_types(void) +{ + type_register_static(&ipoctal_info); +} + +type_init(ipoctal_register_types) From 53510bfc1256711365cd2a841649f3ad5a79790f Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 14 Jan 2013 13:20:12 -0600 Subject: [PATCH 0452/1634] virtio-pci: build for uninitialized return value in vq_vector_unmask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following: /home/mdroth/w/qemu2.git/hw/virtio-pci.c: In function ‘kvm_virtio_pci_vector_unmask’: /home/mdroth/w/qemu2.git/hw/virtio-pci.c:673:12: error: ‘ret’ may be used uninitialized in this function [-Werror=uninitialized] cc1: all warnings being treated as errors make: *** [hw/virtio-pci.o] Error 1 make: *** Waiting for unfinished jobs.... Signed-off-by: Michael Roth Signed-off-by: Anthony Liguori --- hw/virtio-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 0b49739946..09342463ad 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -616,7 +616,7 @@ static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; - int ret; + int ret = 0; if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) { ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg); From b8bec49cccbf8e34558371df60e7e64419c4fde9 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 14 Jan 2013 13:20:13 -0600 Subject: [PATCH 0453/1634] dataplane: fix build breakage on set_guest_notifiers() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_pci_set_guest_notifiers() now takes an additional argument to specify the number of virtqueues to assign a guest notifier for. This causes a build breakage for CONFIG_VIRTIO_BLK_DATA_PLANE builds: /home/mdroth/w/qemu2.git/hw/dataplane/virtio-blk.c: In function ‘virtio_blk_data_plane_start’: /home/mdroth/w/qemu2.git/hw/dataplane/virtio-blk.c:451:47: error: too few arguments to function ‘s->vdev->binding->set_guest_notifiers’ /home/mdroth/w/qemu2.git/hw/dataplane/virtio-blk.c: In function ‘virtio_blk_data_plane_stop’: /home/mdroth/w/qemu2.git/hw/dataplane/virtio-blk.c:511:5: error: too few arguments to function ‘s->vdev->binding->set_guest_notifiers’ make[1]: *** [hw/dataplane/virtio-blk.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [subdir-x86_64-softmmu] Error 2 Fix this by passing 1 as the number of virtqueues to assign notifiers for. Signed-off-by: Michael Roth Signed-off-by: Anthony Liguori --- hw/dataplane/virtio-blk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 1f7346ea19..4b26faa6c2 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -447,7 +447,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) event_poll_init(&s->event_poll); /* Set up guest notifier (irq) */ - if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, + if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, true) != 0) { fprintf(stderr, "virtio-blk failed to set guest notifier, " "ensure -enable-kvm is set\n"); @@ -508,7 +508,7 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) event_poll_cleanup(&s->event_poll); /* Clean up guest notifier (irq) */ - s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, false); + s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, false); vring_teardown(&s->vring); } From 01b87f6d217ed05d5948562f74f5cf7b511a9c6c Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 2 Jan 2013 09:15:11 -0700 Subject: [PATCH 0454/1634] qga: add missing commas in json docs * qga/qapi-schema.json: Use valid JSON. Signed-off-by: Eric Blake Signed-off-by: Michael Roth --- qga/qapi-schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index ed0eb698c6..d91d903256 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -31,7 +31,7 @@ # # Since: 1.1 # ## -{ 'command': 'guest-sync-delimited' +{ 'command': 'guest-sync-delimited', 'data': { 'id': 'int' }, 'returns': 'int' } @@ -69,7 +69,7 @@ # # Since: 0.15.0 ## -{ 'command': 'guest-sync' +{ 'command': 'guest-sync', 'data': { 'id': 'int' }, 'returns': 'int' } From cf7c3f0cb5a7129f57fa9e69d410d6a05031988c Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Mon, 14 Jan 2013 22:52:02 +0100 Subject: [PATCH 0455/1634] virtio-9p: fix compilation error. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the compilation error introduced by msg new field. CC hw/9pfs/virtio-9p.o In file included from /home/konradf/Documents/safe/greensocs/virtio-project/x86-qemu/qemu/hw/9pfs/virtio-9p.c:17:0: /home/konradf/Documents/safe/greensocs/virtio-project/x86-qemu/qemu/hw/virtio-pci.h:30:16: erreur: field ‘msg’ has incomplete type make: *** [hw/9pfs/virtio-9p.o] Erreur 1 Signed-off-by: KONRAD Frederic --- hw/virtio-pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index 9ff3139fe9..917b465874 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -15,6 +15,7 @@ #ifndef QEMU_VIRTIO_PCI_H #define QEMU_VIRTIO_PCI_H +#include "hw/pci/msi.h" #include "virtio-blk.h" #include "virtio-net.h" #include "virtio-rng.h" From 328c24a97b9cde975bc8b12caa4c6c067fff83c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 11 Jan 2013 21:11:20 +0100 Subject: [PATCH 0456/1634] pc87312: Replace register_ioport_*() with MemoryRegion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare an instance_init function for the MemoryRegion init. Signed-off-by: Andreas Färber Tested-by: Hervé Poussineau --- hw/pc87312.c | 26 ++++++++++++++++++++++---- hw/pc87312.h | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/hw/pc87312.c b/hw/pc87312.c index 6a17afd45c..97fabfa9dd 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -194,7 +194,8 @@ static void pc87312_hard_reset(PC87312State *s) pc87312_soft_reset(s); } -static void pc87312_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void pc87312_io_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) { PC87312State *s = opaque; @@ -213,7 +214,7 @@ static void pc87312_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t pc87312_ioport_read(void *opaque, uint32_t addr) +static uint64_t pc87312_io_read(void *opaque, hwaddr addr, unsigned int size) { PC87312State *s = opaque; uint32_t val; @@ -241,6 +242,16 @@ static uint32_t pc87312_ioport_read(void *opaque, uint32_t addr) return val; } +static const MemoryRegionOps pc87312_io_ops = { + .read = pc87312_io_read, + .write = pc87312_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static int pc87312_post_load(void *opaque, int version_id) { PC87312State *s = opaque; @@ -270,6 +281,7 @@ static int pc87312_init(ISADevice *dev) s = PC87312(dev); bus = isa_bus_from_device(dev); pc87312_hard_reset(s); + isa_register_ioport(dev, &s->io, s->iobase); if (is_parallel_enabled(s)) { chr = parallel_hds[0]; @@ -337,11 +349,16 @@ static int pc87312_init(ISADevice *dev) trace_pc87312_info_ide(get_ide_iobase(s)); } - register_ioport_write(s->iobase, 2, 1, pc87312_ioport_write, s); - register_ioport_read(s->iobase, 2, 1, pc87312_ioport_read, s); return 0; } +static void pc87312_initfn(Object *obj) +{ + PC87312State *s = PC87312(obj); + + memory_region_init_io(&s->io, &pc87312_io_ops, s, "pc87312", 2); +} + static const VMStateDescription vmstate_pc87312 = { .name = "pc87312", .version_id = 1, @@ -376,6 +393,7 @@ static const TypeInfo pc87312_type_info = { .name = TYPE_PC87312, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PC87312State), + .instance_init = pc87312_initfn, .class_init = pc87312_class_init, }; diff --git a/hw/pc87312.h b/hw/pc87312.h index 7ca7912ba7..7b9e6f6132 100644 --- a/hw/pc87312.h +++ b/hw/pc87312.h @@ -56,6 +56,8 @@ typedef struct PC87312State { uint32_t base; } ide; + MemoryRegion io; + uint8_t read_id_step; uint8_t selected_index; From 08bb4a7c9bb9c12746bce9b3a1f031dd4192afc1 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 13 Jan 2013 08:12:45 +0000 Subject: [PATCH 0457/1634] pc87312: Avoid define conflict on mingw32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mingw32 headers define FAR, causing this warning: /src/qemu/hw/pc87312.c:38:0: warning: "FAR" redefined [enabled by default] In file included from /usr/local/lib/gcc/i686-mingw32msvc/4.7.0/../../../../i686-mingw32msvc/include/windows.h:48:0, from /src/qemu/include/sysemu/os-win32.h:29, from /src/qemu/include/qemu-common.h:46, from /src/qemu/include/exec/ioport.h:27, from /src/qemu/hw/isa.h:6, from /src/qemu/hw/pc87312.h:28, from /src/qemu/hw/pc87312.c:26: /usr/local/lib/gcc/i686-mingw32msvc/4.7.0/../../../../i686-mingw32msvc/include/windef.h:34:0: note: this is the location of the previous definition Avoid the warning by expanding the macros. Signed-off-by: Blue Swirl Acked-by: Hervé Poussineau Signed-off-by: Andreas Färber --- hw/pc87312.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/hw/pc87312.c b/hw/pc87312.c index 97fabfa9dd..38af4c1d10 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -34,10 +34,6 @@ #define REG_FAR 1 #define REG_PTR 2 -#define FER regs[REG_FER] -#define FAR regs[REG_FAR] -#define PTR regs[REG_PTR] - #define FER_PARALLEL_EN 0x01 #define FER_UART1_EN 0x02 #define FER_UART2_EN 0x04 @@ -66,14 +62,14 @@ static inline bool is_parallel_enabled(PC87312State *s) { - return s->FER & FER_PARALLEL_EN; + return s->regs[REG_FER] & FER_PARALLEL_EN; } static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 }; static inline uint32_t get_parallel_iobase(PC87312State *s) { - return parallel_base[s->FAR & FAR_PARALLEL_ADDR]; + return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR]; } static const uint32_t parallel_irq[] = { 5, 7, 5, 0 }; @@ -81,9 +77,9 @@ static const uint32_t parallel_irq[] = { 5, 7, 5, 0 }; static inline uint32_t get_parallel_irq(PC87312State *s) { int idx; - idx = (s->FAR & FAR_PARALLEL_ADDR); + idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR); if (idx == 0) { - return (s->PTR & PTR_IRQ_5_7) ? 7 : 5; + return (s->regs[REG_PTR] & PTR_IRQ_5_7) ? 7 : 5; } else { return parallel_irq[idx]; } @@ -91,7 +87,7 @@ static inline uint32_t get_parallel_irq(PC87312State *s) static inline bool is_parallel_epp(PC87312State *s) { - return s->PTR & PTR_EPP_MODE; + return s->regs[REG_PTR] & PTR_EPP_MODE; } @@ -105,26 +101,26 @@ static const uint32_t uart_base[2][4] = { static inline uint32_t get_uart_iobase(PC87312State *s, int i) { int idx; - idx = (s->FAR >> (2 * i + 2)) & 0x3; + idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; if (idx == 0) { return 0x3f8; } else if (idx == 1) { return 0x2f8; } else { - return uart_base[idx & 1][(s->FAR & FAR_UART_3_4) >> 6]; + return uart_base[idx & 1][(s->regs[REG_FAR] & FAR_UART_3_4) >> 6]; } } static inline uint32_t get_uart_irq(PC87312State *s, int i) { int idx; - idx = (s->FAR >> (2 * i + 2)) & 0x3; + idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3; return (idx & 1) ? 3 : 4; } static inline bool is_uart_enabled(PC87312State *s, int i) { - return s->FER & (FER_UART1_EN << i); + return s->regs[REG_FER] & (FER_UART1_EN << i); } @@ -132,12 +128,12 @@ static inline bool is_uart_enabled(PC87312State *s, int i) static inline bool is_fdc_enabled(PC87312State *s) { - return s->FER & FER_FDC_EN; + return s->regs[REG_FER] & FER_FDC_EN; } static inline uint32_t get_fdc_iobase(PC87312State *s) { - return (s->FER & FER_FDC_ADDR) ? 0x370 : 0x3f0; + return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0; } @@ -145,19 +141,19 @@ static inline uint32_t get_fdc_iobase(PC87312State *s) static inline bool is_ide_enabled(PC87312State *s) { - return s->FER & FER_IDE_EN; + return s->regs[REG_FER] & FER_IDE_EN; } static inline uint32_t get_ide_iobase(PC87312State *s) { - return (s->FER & FER_IDE_ADDR) ? 0x170 : 0x1f0; + return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0; } static void reconfigure_devices(PC87312State *s) { error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)", - s->FER, s->FAR, s->PTR); + s->regs[REG_FER], s->regs[REG_FAR], s->regs[REG_PTR]); } static void pc87312_soft_reset(PC87312State *s) @@ -184,9 +180,9 @@ static void pc87312_soft_reset(PC87312State *s) s->read_id_step = 0; s->selected_index = REG_FER; - s->FER = fer_init[s->config & 0x1f]; - s->FAR = far_init[s->config & 0x1f]; - s->PTR = ptr_init[s->config & 0x1f]; + s->regs[REG_FER] = fer_init[s->config & 0x1f]; + s->regs[REG_FAR] = far_init[s->config & 0x1f]; + s->regs[REG_PTR] = ptr_init[s->config & 0x1f]; } static void pc87312_hard_reset(PC87312State *s) From ce3960ebe57d0601a3628b64adac6fd23c901f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 03:27:07 +0100 Subject: [PATCH 0458/1634] cpu: Move nr_{cores,threads} fields to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To facilitate the field movements, pass MIPSCPU to malta_mips_config(); avoid that for mips_cpu_map_tc() since callers only access MIPS Thread Contexts, inside TCG helpers. Signed-off-by: Andreas Färber --- cpus.c | 4 ++-- hw/mips_malta.c | 9 ++++++--- include/exec/cpu-defs.h | 2 -- include/qom/cpu.h | 5 +++++ target-i386/cpu.c | 18 +++++++++--------- target-mips/op_helper.c | 8 +++++--- 6 files changed, 27 insertions(+), 19 deletions(-) diff --git a/cpus.c b/cpus.c index 4a7782a541..6aee15eb27 100644 --- a/cpus.c +++ b/cpus.c @@ -1041,8 +1041,8 @@ void qemu_init_vcpu(void *_env) CPUArchState *env = _env; CPUState *cpu = ENV_GET_CPU(env); - env->nr_cores = smp_cores; - env->nr_threads = smp_threads; + cpu->nr_cores = smp_cores; + cpu->nr_threads = smp_threads; cpu->stopped = true; if (kvm_enabled()) { qemu_kvm_start_vcpu(env); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2250e675a5..771d1256d7 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -743,10 +743,13 @@ static int64_t load_kernel (void) return kernel_entry; } -static void malta_mips_config(CPUMIPSState *env) +static void malta_mips_config(MIPSCPU *cpu) { + CPUMIPSState *env = &cpu->env; + CPUState *cs = CPU(cpu); + env->mvp->CP0_MVPConf0 |= ((smp_cpus - 1) << CP0MVPC0_PVPE) | - ((smp_cpus * env->nr_threads - 1) << CP0MVPC0_PTC); + ((smp_cpus * cs->nr_threads - 1) << CP0MVPC0_PTC); } static void main_cpu_reset(void *opaque) @@ -763,7 +766,7 @@ static void main_cpu_reset(void *opaque) env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL)); } - malta_mips_config(env); + malta_mips_config(cpu); } static void cpu_request_exit(void *opaque, int irq, int level) diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index b22b4c6255..c02687b610 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -196,8 +196,6 @@ typedef struct CPUWatchpoint { int cpu_index; /* CPU index (informative) */ \ uint32_t host_tid; /* host thread ID */ \ int numa_node; /* NUMA node this cpu is belonging to */ \ - int nr_cores; /* number of cores within this CPU package */ \ - int nr_threads;/* number of threads within this CPU */ \ int running; /* Nonzero if cpu is currently running(usermode). */ \ /* user data */ \ void *opaque; \ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index fbacb2756b..806b01a01d 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -57,6 +57,8 @@ struct kvm_run; /** * CPUState: + * @nr_cores: Number of cores within this CPU package. + * @nr_threads: Number of threads within this CPU. * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. @@ -69,6 +71,9 @@ struct CPUState { DeviceState parent_obj; /*< public >*/ + int nr_cores; + int nr_threads; + struct QemuThread *thread; #ifdef _WIN32 HANDLE hThread; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 78bd61e18f..9f98a41e5c 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1691,8 +1691,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */ *ecx = env->cpuid_ext_features; *edx = env->cpuid_features; - if (env->nr_cores * env->nr_threads > 1) { - *ebx |= (env->nr_cores * env->nr_threads) << 16; + if (cs->nr_cores * cs->nr_threads > 1) { + *ebx |= (cs->nr_cores * cs->nr_threads) << 16; *edx |= 1 << 28; /* HTT bit */ } break; @@ -1705,8 +1705,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 4: /* cache info: needed for Core compatibility */ - if (env->nr_cores > 1) { - *eax = (env->nr_cores - 1) << 26; + if (cs->nr_cores > 1) { + *eax = (cs->nr_cores - 1) << 26; } else { *eax = 0; } @@ -1725,8 +1725,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 2: /* L2 cache info */ *eax |= 0x0000143; - if (env->nr_threads > 1) { - *eax |= (env->nr_threads - 1) << 14; + if (cs->nr_threads > 1) { + *eax |= (cs->nr_threads - 1) << 14; } *ebx = 0x3c0003f; *ecx = 0x0000fff; @@ -1830,7 +1830,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, * discards multiple thread information if it is set. * So dont set it here for Intel to make Linux guests happy. */ - if (env->nr_cores * env->nr_threads > 1) { + if (cs->nr_cores * cs->nr_threads > 1) { uint32_t tebx, tecx, tedx; get_cpuid_vendor(env, &tebx, &tecx, &tedx); if (tebx != CPUID_VENDOR_INTEL_1 || @@ -1878,8 +1878,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx = 0; *ecx = 0; *edx = 0; - if (env->nr_cores * env->nr_threads > 1) { - *ecx |= (env->nr_cores * env->nr_threads) - 1; + if (cs->nr_cores * cs->nr_threads > 1) { + *ecx |= (cs->nr_cores * cs->nr_threads) - 1; } break; case 0x8000000A: diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d5c61e8a84..fb63d9e402 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -581,8 +581,9 @@ static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) walking the list of CPUMIPSStates. */ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) { + CPUState *cs; CPUMIPSState *other; - int vpe_idx, nr_threads = env->nr_threads; + int vpe_idx; int tc_idx = *tc; if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) { @@ -591,8 +592,9 @@ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) return env; } - vpe_idx = tc_idx / nr_threads; - *tc = tc_idx % nr_threads; + cs = CPU(mips_env_get_cpu(env)); + vpe_idx = tc_idx / cs->nr_threads; + *tc = tc_idx % cs->nr_threads; other = qemu_get_cpu(vpe_idx); return other ? other : env; } From 66afd1ad5a7a25e573577ac45979d8a3213796c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 20:36:30 +0100 Subject: [PATCH 0459/1634] target-mips: Clean up mips_cpu_map_tc() documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function will be touched again soon, so a good understanding of env vs. other helps. Adopt gtk-doc style. Signed-off-by: Andreas Färber Reviewed-by: Eric Johnson --- target-mips/op_helper.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index fb63d9e402..1816a0ec8d 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -572,11 +572,15 @@ static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) } } -/* tc should point to an int with the value of the global TC index. - This function will transform it into a local index within the - returned CPUMIPSState. - - FIXME: This code assumes that all VPEs have the same number of TCs, +/** + * mips_cpu_map_tc: + * @env: CPU from which mapping is performed. + * @tc: Should point to an int with the value of the global TC index. + * + * This function will transform @tc into a local index within the + * returned #CPUMIPSState. + */ +/* FIXME: This code assumes that all VPEs have the same number of TCs, which depends on runtime setup. Can probably be fixed by walking the list of CPUMIPSStates. */ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) From 1b1ed8dc40635d60dd95c04658989af63542fcbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 04:22:03 +0100 Subject: [PATCH 0460/1634] cpu: Move numa_node field to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber --- cpus.c | 4 +++- exec.c | 4 +--- hw/spapr.c | 4 +++- include/exec/cpu-defs.h | 1 - include/qom/cpu.h | 2 ++ monitor.c | 4 +++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cpus.c b/cpus.c index 6aee15eb27..d68231ab13 100644 --- a/cpus.c +++ b/cpus.c @@ -1160,12 +1160,14 @@ static void tcg_exec_all(void) void set_numa_modes(void) { CPUArchState *env; + CPUState *cpu; int i; for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); for (i = 0; i < nb_numa_nodes; i++) { if (test_bit(env->cpu_index, node_cpumask[i])) { - env->numa_node = i; + cpu->numa_node = i; } } } diff --git a/exec.c b/exec.c index 34353f7527..de5b27dd77 100644 --- a/exec.c +++ b/exec.c @@ -262,9 +262,7 @@ CPUArchState *qemu_get_cpu(int cpu) void cpu_exec_init(CPUArchState *env) { -#ifndef CONFIG_USER_ONLY CPUState *cpu = ENV_GET_CPU(env); -#endif CPUArchState **penv; int cpu_index; @@ -279,7 +277,7 @@ void cpu_exec_init(CPUArchState *env) cpu_index++; } env->cpu_index = cpu_index; - env->numa_node = 0; + cpu->numa_node = 0; QTAILQ_INIT(&env->breakpoints); QTAILQ_INIT(&env->watchpoints); #ifndef CONFIG_USER_ONLY diff --git a/hw/spapr.c b/hw/spapr.c index b5e15b884a..a61c71e931 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -140,6 +140,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; CPUPPCState *env; + CPUState *cpu; char cpu_model[32]; int smt = kvmppc_smt_threads(); uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; @@ -147,11 +148,12 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) assert(spapr->cpu_model); for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); uint32_t associativity[] = {cpu_to_be32(0x5), cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(env->numa_node), + cpu_to_be32(cpu->numa_node), cpu_to_be32(env->cpu_index)}; if ((env->cpu_index % smt) != 0) { diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index c02687b610..ce178eaa79 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -195,7 +195,6 @@ typedef struct CPUWatchpoint { CPUArchState *next_cpu; /* next CPU sharing TB cache */ \ int cpu_index; /* CPU index (informative) */ \ uint32_t host_tid; /* host thread ID */ \ - int numa_node; /* NUMA node this cpu is belonging to */ \ int running; /* Nonzero if cpu is currently running(usermode). */ \ /* user data */ \ void *opaque; \ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 806b01a01d..30d1e0c663 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -59,6 +59,7 @@ struct kvm_run; * CPUState: * @nr_cores: Number of cores within this CPU package. * @nr_threads: Number of threads within this CPU. + * @numa_node: NUMA node this CPU is belonging to. * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. @@ -73,6 +74,7 @@ struct CPUState { int nr_cores; int nr_threads; + int numa_node; struct QemuThread *thread; #ifdef _WIN32 diff --git a/monitor.c b/monitor.c index b7ac3a37a8..016910deef 100644 --- a/monitor.c +++ b/monitor.c @@ -1783,12 +1783,14 @@ static void do_info_numa(Monitor *mon) { int i; CPUArchState *env; + CPUState *cpu; monitor_printf(mon, "%d nodes\n", nb_numa_nodes); for (i = 0; i < nb_numa_nodes; i++) { monitor_printf(mon, "node %d cpus:", i); for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->numa_node == i) { + cpu = ENV_GET_CPU(env); + if (cpu->numa_node == i) { monitor_printf(mon, " %d", env->cpu_index); } } From 55e5c2850293547203874098f7cec148ffd12dfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 06:18:02 +0100 Subject: [PATCH 0461/1634] cpu: Move cpu_index field to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note that target-alpha accesses this field from TCG, now using a negative offset. Therefore the field is placed last in CPUState. Pass PowerPCCPU to [kvm]ppc_fixup_cpu() to facilitate this change. Move common parts of mips cpu_state_reset() to mips_cpu_reset(). Acked-by: Richard Henderson (for alpha) [AF: Rebased onto ppc CPU subclasses and openpic changes] Signed-off-by: Andreas Färber --- cpus.c | 14 +++++++++----- exec.c | 13 +++++++------ gdbstub.c | 3 ++- hw/alpha_typhoon.c | 4 +++- hw/arm_gic.c | 3 ++- hw/arm_mptimer.c | 8 +++++--- hw/openpic.c | 5 ++++- hw/ppc/e500.c | 17 +++++++++++------ hw/ppce500_spin.c | 8 +++++--- hw/pxa.h | 2 +- hw/pxa2xx.c | 4 ++-- hw/pxa2xx_gpio.c | 5 +++-- hw/spapr.c | 11 ++++++----- hw/spapr_hcall.c | 4 +++- hw/spapr_rtas.c | 8 +++++--- hw/xics.c | 22 ++++++++++++---------- include/exec/cpu-defs.h | 1 - include/exec/gdbstub.h | 3 ++- include/qom/cpu.h | 2 ++ kvm-all.c | 2 +- monitor.c | 15 ++++++++++----- target-alpha/translate.c | 2 +- target-arm/cpu.c | 2 +- target-arm/helper.c | 3 ++- target-cris/cpu.c | 2 +- target-i386/cpu.c | 7 ++++--- target-i386/helper.c | 15 ++++++++------- target-i386/misc_helper.c | 5 ++++- target-lm32/cpu.c | 2 +- target-m68k/cpu.c | 2 +- target-microblaze/cpu.c | 2 +- target-mips/cpu.c | 8 ++++++++ target-mips/translate.c | 17 +++++++---------- target-openrisc/cpu.c | 2 +- target-ppc/kvm.c | 12 +++++++----- target-ppc/kvm_ppc.h | 4 ++-- target-ppc/translate_init.c | 10 ++++++---- target-s390x/cpu.c | 2 +- target-sh4/cpu.c | 2 +- target-sparc/cpu.c | 2 +- 40 files changed, 153 insertions(+), 102 deletions(-) diff --git a/cpus.c b/cpus.c index d68231ab13..bbb8961708 100644 --- a/cpus.c +++ b/cpus.c @@ -390,13 +390,15 @@ void hw_error(const char *fmt, ...) { va_list ap; CPUArchState *env; + CPUState *cpu; va_start(ap, fmt); fprintf(stderr, "qemu: hardware error: "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); - for(env = first_cpu; env != NULL; env = env->next_cpu) { - fprintf(stderr, "CPU #%d:\n", env->cpu_index); + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); + fprintf(stderr, "CPU #%d:\n", cpu->cpu_index); cpu_dump_state(env, stderr, fprintf, CPU_DUMP_FPU); } va_end(ap); @@ -1166,7 +1168,7 @@ void set_numa_modes(void) for (env = first_cpu; env != NULL; env = env->next_cpu) { cpu = ENV_GET_CPU(env); for (i = 0; i < nb_numa_nodes; i++) { - if (test_bit(env->cpu_index, node_cpumask[i])) { + if (test_bit(cpu->cpu_index, node_cpumask[i])) { cpu->numa_node = i; } } @@ -1215,7 +1217,7 @@ CpuInfoList *qmp_query_cpus(Error **errp) info = g_malloc0(sizeof(*info)); info->value = g_malloc0(sizeof(*info->value)); - info->value->CPU = env->cpu_index; + info->value->CPU = cpu->cpu_index; info->value->current = (env == first_cpu); info->value->halted = env->halted; info->value->thread_id = cpu->thread_id; @@ -1253,6 +1255,7 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, FILE *f; uint32_t l; CPUArchState *env; + CPUState *cpu; uint8_t buf[1024]; if (!has_cpu) { @@ -1260,7 +1263,8 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, } for (env = first_cpu; env; env = env->next_cpu) { - if (cpu_index == env->cpu_index) { + cpu = ENV_GET_CPU(env); + if (cpu_index == cpu->cpu_index) { break; } } diff --git a/exec.c b/exec.c index de5b27dd77..e5265e635c 100644 --- a/exec.c +++ b/exec.c @@ -247,13 +247,16 @@ static const VMStateDescription vmstate_cpu_common = { }; #endif -CPUArchState *qemu_get_cpu(int cpu) +CPUArchState *qemu_get_cpu(int index) { CPUArchState *env = first_cpu; + CPUState *cpu; while (env) { - if (env->cpu_index == cpu) + cpu = ENV_GET_CPU(env); + if (cpu->cpu_index == index) { break; + } env = env->next_cpu; } @@ -276,7 +279,7 @@ void cpu_exec_init(CPUArchState *env) penv = &(*penv)->next_cpu; cpu_index++; } - env->cpu_index = cpu_index; + cpu->cpu_index = cpu_index; cpu->numa_node = 0; QTAILQ_INIT(&env->breakpoints); QTAILQ_INIT(&env->watchpoints); @@ -529,7 +532,6 @@ CPUArchState *cpu_copy(CPUArchState *env) { CPUArchState *new_env = cpu_init(env->cpu_model_str); CPUArchState *next_cpu = new_env->next_cpu; - int cpu_index = new_env->cpu_index; #if defined(TARGET_HAS_ICE) CPUBreakpoint *bp; CPUWatchpoint *wp; @@ -537,9 +539,8 @@ CPUArchState *cpu_copy(CPUArchState *env) memcpy(new_env, env, sizeof(CPUArchState)); - /* Preserve chaining and index. */ + /* Preserve chaining. */ new_env->next_cpu = next_cpu; - new_env->cpu_index = cpu_index; /* Clone all break/watchpoints. Note: Once we support ptrace with hw-debug register access, make sure diff --git a/gdbstub.c b/gdbstub.c index e62dc798c3..6cd26f1619 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2401,9 +2401,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) thread = strtoull(p+16, (char **)&p, 16); env = find_cpu(thread); if (env != NULL) { + CPUState *cpu = ENV_GET_CPU(env); cpu_synchronize_state(env); len = snprintf((char *)mem_buf, sizeof(mem_buf), - "CPU#%d [%s]", env->cpu_index, + "CPU#%d [%s]", cpu->cpu_index, env->halted ? "halted " : "running"); memtohex(buf, mem_buf, len); put_packet(s, buf); diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index dafb35ddd1..bf9aabfc08 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -75,6 +75,7 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) { CPUAlphaState *env = cpu_single_env; TyphoonState *s = opaque; + CPUState *cpu; uint64_t ret = 0; if (addr & 4) { @@ -95,7 +96,8 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) case 0x0080: /* MISC: Miscellaneous Register. */ - ret = s->cchip.misc | (env->cpu_index & 3); + cpu = ENV_GET_CPU(env); + ret = s->cchip.misc | (cpu->cpu_index & 3); break; case 0x00c0: diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 466dbf7398..90e43d0728 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -39,7 +39,8 @@ static const uint8_t gic_id[] = { static inline int gic_get_current_cpu(GICState *s) { if (s->num_cpu > 1) { - return cpu_single_env->cpu_index; + CPUState *cpu = ENV_GET_CPU(cpu_single_env); + return cpu->cpu_index; } return 0; } diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 0cd3853a36..cdfd62363e 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -49,11 +49,13 @@ typedef struct { static inline int get_current_cpu(arm_mptimer_state *s) { - if (cpu_single_env->cpu_index >= s->num_cpu) { + CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env); + + if (cpu_single_cpu->cpu_index >= s->num_cpu) { hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n", - s->num_cpu, cpu_single_env->cpu_index); + s->num_cpu, cpu_single_cpu->cpu_index); } - return cpu_single_env->cpu_index; + return cpu_single_cpu->cpu_index; } static inline void timerblock_update_irq(timerblock *tb) diff --git a/hw/openpic.c b/hw/openpic.c index 23fa8f9635..f6cc07bd6e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -153,11 +153,14 @@ static const int debug_openpic = 0; static int get_current_cpu(void) { + CPUState *cpu_single_cpu; + if (!cpu_single_env) { return -1; } - return cpu_single_env->cpu_index; + cpu_single_cpu = ENV_GET_CPU(cpu_single_env); + return cpu_single_cpu->cpu_index; } static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 3a9e1c7b43..7b3e2e6723 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -239,25 +239,28 @@ static int ppce500_load_device_tree(CPUPPCState *env, /* We need to generate the cpu nodes in reverse order, so Linux can pick the first node as boot node and be happy */ for (i = smp_cpus - 1; i >= 0; i--) { + CPUState *cpu = NULL; char cpu_name[128]; uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index == i) { + cpu = ENV_GET_CPU(env); + if (cpu->cpu_index == i) { break; } } - if (!env) { + if (cpu == NULL) { continue; } - snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index); + snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", + cpu->cpu_index); qemu_devtree_add_subnode(fdt, cpu_name); qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu"); - qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index); + qemu_devtree_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index); qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size", env->dcache_line_size); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size", @@ -265,7 +268,7 @@ static int ppce500_load_device_tree(CPUPPCState *env, qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0); - if (env->cpu_index) { + if (cpu->cpu_index) { qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr", @@ -479,6 +482,7 @@ void ppce500_init(PPCE500Params *params) irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); for (i = 0; i < smp_cpus; i++) { PowerPCCPU *cpu; + CPUState *cs; qemu_irq *input; cpu = cpu_ppc_init(params->cpu_model); @@ -487,6 +491,7 @@ void ppce500_init(PPCE500Params *params) exit(1); } env = &cpu->env; + cs = CPU(cpu); if (!firstenv) { firstenv = env; @@ -496,7 +501,7 @@ void ppce500_init(PPCE500Params *params) input = (qemu_irq *)env->irq_inputs; irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; - env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; + env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i; env->mpic_iack = MPC8544_CCSRBAR_BASE + MPC8544_MPIC_REGS_OFFSET + 0x200A0; diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 1b2c34f92c..4c206e2834 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -124,21 +124,23 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value, SpinState *s = opaque; int env_idx = addr / sizeof(SpinInfo); CPUPPCState *env; + CPUState *cpu = NULL; SpinInfo *curspin = &s->spin[env_idx]; uint8_t *curspin_p = (uint8_t*)curspin; for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index == env_idx) { + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index == env_idx) { break; } } - if (!env) { + if (cpu == NULL) { /* Unknown CPU */ return; } - if (!env->cpu_index) { + if (cpu->cpu_index == 0) { /* primary CPU doesn't spin */ return; } diff --git a/hw/pxa.h b/hw/pxa.h index c2577d1d94..668232cead 100644 --- a/hw/pxa.h +++ b/hw/pxa.h @@ -69,7 +69,7 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu); /* pxa2xx_gpio.c */ DeviceState *pxa2xx_gpio_init(hwaddr base, - CPUARMState *env, DeviceState *pic, int lines); + ARMCPU *cpu, DeviceState *pic, int lines); void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler); /* pxa2xx_dma.c */ diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index f3dffef5ab..492805f2fa 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -2045,7 +2045,7 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11), NULL); - s->gpio = pxa2xx_gpio_init(0x40e00000, &s->cpu->env, s->pic, 121); + s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121); dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { @@ -2176,7 +2176,7 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3), NULL); - s->gpio = pxa2xx_gpio_init(0x40e00000, &s->cpu->env, s->pic, 85); + s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85); dinfo = drive_get(IF_SD, 0, 0); if (!dinfo) { diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 016833dfa1..c02c295af4 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -250,13 +250,14 @@ static const MemoryRegionOps pxa_gpio_ops = { }; DeviceState *pxa2xx_gpio_init(hwaddr base, - CPUARMState *env, DeviceState *pic, int lines) + ARMCPU *cpu, DeviceState *pic, int lines) { + CPUState *cs = CPU(cpu); DeviceState *dev; dev = qdev_create(NULL, "pxa2xx-gpio"); qdev_prop_set_int32(dev, "lines", lines); - qdev_prop_set_int32(dev, "ncpu", env->cpu_index); + qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); qdev_init_nofail(dev); sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); diff --git a/hw/spapr.c b/hw/spapr.c index a61c71e931..76aa09ba81 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -148,20 +148,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) assert(spapr->cpu_model); for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); + cpu = CPU(ppc_env_get_cpu(env)); uint32_t associativity[] = {cpu_to_be32(0x5), cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(0x0), cpu_to_be32(cpu->numa_node), - cpu_to_be32(env->cpu_index)}; + cpu_to_be32(cpu->cpu_index)}; - if ((env->cpu_index % smt) != 0) { + if ((cpu->cpu_index % smt) != 0) { continue; } snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model, - env->cpu_index); + cpu->cpu_index); offset = fdt_path_offset(fdt, cpu_model); if (offset < 0) { @@ -310,7 +310,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model, spapr->cpu_model = g_strdup(modelname); for (env = first_cpu; env != NULL; env = env->next_cpu) { - int index = env->cpu_index; + CPUState *cpu = CPU(ppc_env_get_cpu(env)); + int index = cpu->cpu_index; uint32_t servers_prop[smp_threads]; uint32_t gservers_prop[smp_threads * 2]; char *nodename; diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index afb12973f2..2889742788 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -467,9 +467,11 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong vpa = args[2]; target_ulong ret = H_PARAMETER; CPUPPCState *tenv; + CPUState *tcpu; for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) { - if (tenv->cpu_index == procno) { + tcpu = CPU(ppc_env_get_cpu(tenv)); + if (tcpu->cpu_index == procno) { break; } } diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 81eecd0940..5ec787f29d 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -131,6 +131,7 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, { target_ulong id; CPUPPCState *env; + CPUState *cpu; if (nargs != 1 || nret != 2) { rtas_st(rets, 0, -3); @@ -139,7 +140,8 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, id = rtas_ld(args, 0); for (env = first_cpu; env; env = env->next_cpu) { - if (env->cpu_index != id) { + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index != id) { continue; } @@ -176,9 +178,9 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, r3 = rtas_ld(args, 2); for (env = first_cpu; env; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); + cpu = CPU(ppc_env_get_cpu(env)); - if (env->cpu_index != id) { + if (cpu->cpu_index != id) { continue; } diff --git a/hw/xics.c b/hw/xics.c index 55899ce77d..9ef0d61377 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -357,10 +357,10 @@ void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); target_ulong cppr = args[0]; - icp_set_cppr(spapr->icp, env->cpu_index, cppr); + icp_set_cppr(spapr->icp, cs->cpu_index, cppr); return H_SUCCESS; } @@ -376,14 +376,13 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr, icp_set_mfrr(spapr->icp, server, mfrr); return H_SUCCESS; - } static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; - uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index); + CPUState *cs = CPU(cpu); + uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); args[0] = xirr; return H_SUCCESS; @@ -392,10 +391,10 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPREnvironment *spapr, static target_ulong h_eoi(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); target_ulong xirr = args[0]; - icp_eoi(spapr->icp, env->cpu_index, xirr); + icp_eoi(spapr->icp, cs->cpu_index, xirr); return H_SUCCESS; } @@ -525,14 +524,16 @@ static void xics_reset(void *opaque) struct icp_state *xics_system_init(int nr_irqs) { CPUPPCState *env; + CPUState *cpu; int max_server_num; struct icp_state *icp; struct ics_state *ics; max_server_num = -1; for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index > max_server_num) { - max_server_num = env->cpu_index; + cpu = CPU(ppc_env_get_cpu(env)); + if (cpu->cpu_index > max_server_num) { + max_server_num = cpu->cpu_index; } } @@ -541,7 +542,8 @@ struct icp_state *xics_system_init(int nr_irqs) icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); for (env = first_cpu; env != NULL; env = env->next_cpu) { - struct icp_server_state *ss = &icp->ss[env->cpu_index]; + cpu = CPU(ppc_env_get_cpu(env)); + struct icp_server_state *ss = &icp->ss[cpu->cpu_index]; switch (PPC_INPUT(env)) { case PPC_FLAGS_INPUT_POWER7: diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ce178eaa79..d0cf85a83c 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -193,7 +193,6 @@ typedef struct CPUWatchpoint { int exception_index; \ \ CPUArchState *next_cpu; /* next CPU sharing TB cache */ \ - int cpu_index; /* CPU index (informative) */ \ uint32_t host_tid; /* host thread ID */ \ int running; /* Nonzero if cpu is currently running(usermode). */ \ /* user data */ \ diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 668de66000..49231feb29 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -35,7 +35,8 @@ static inline int cpu_index(CPUArchState *env) #if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL) return env->host_tid; #else - return env->cpu_index + 1; + CPUState *cpu = ENV_GET_CPU(env); + return cpu->cpu_index + 1; #endif } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 30d1e0c663..d5e0a4057a 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -57,6 +57,7 @@ struct kvm_run; /** * CPUState: + * @cpu_index: CPU index (informative). * @nr_cores: Number of cores within this CPU package. * @nr_threads: Number of threads within this CPU. * @numa_node: NUMA node this CPU is belonging to. @@ -96,6 +97,7 @@ struct CPUState { struct kvm_run *kvm_run; /* TODO Move common fields from CPUArchState here. */ + int cpu_index; /* used by alpha TCG */ }; diff --git a/kvm-all.c b/kvm-all.c index fc0c6e7798..4ba77dea52 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -223,7 +223,7 @@ int kvm_init_vcpu(CPUArchState *env) DPRINTF("kvm_init_vcpu\n"); - ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, env->cpu_index); + ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, cpu->cpu_index); if (ret < 0) { DPRINTF("kvm_create_vcpu failed\n"); goto err; diff --git a/monitor.c b/monitor.c index 016910deef..77ac451a23 100644 --- a/monitor.c +++ b/monitor.c @@ -872,9 +872,11 @@ EventInfoList *qmp_query_events(Error **errp) int monitor_set_cpu(int cpu_index) { CPUArchState *env; + CPUState *cpu; - for(env = first_cpu; env != NULL; env = env->next_cpu) { - if (env->cpu_index == cpu_index) { + for (env = first_cpu; env != NULL; env = env->next_cpu) { + cpu = ENV_GET_CPU(env); + if (cpu->cpu_index == cpu_index) { cur_mon->mon_cpu = env; return 0; } @@ -893,7 +895,8 @@ static CPUArchState *mon_get_cpu(void) int monitor_get_cpu_index(void) { - return mon_get_cpu()->cpu_index; + CPUState *cpu = ENV_GET_CPU(mon_get_cpu()); + return cpu->cpu_index; } static void do_info_registers(Monitor *mon) @@ -1791,7 +1794,7 @@ static void do_info_numa(Monitor *mon) for (env = first_cpu; env != NULL; env = env->next_cpu) { cpu = ENV_GET_CPU(env); if (cpu->numa_node == i) { - monitor_printf(mon, " %d", env->cpu_index); + monitor_printf(mon, " %d", cpu->cpu_index); } } monitor_printf(mon, "\n"); @@ -1993,6 +1996,7 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) { X86CPU *cpu; CPUX86State *cenv; + CPUState *cs; int cpu_index = qdict_get_int(qdict, "cpu_index"); int bank = qdict_get_int(qdict, "bank"); uint64_t status = qdict_get_int(qdict, "status"); @@ -2006,7 +2010,8 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) } for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { cpu = x86_env_get_cpu(cenv); - if (cenv->cpu_index == cpu_index) { + cs = CPU(cpu); + if (cs->cpu_index == cpu_index) { cpu_x86_inject_mce(mon, cpu, bank, status, mcg_status, addr, misc, flags); break; diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 5cb40b7ab6..f687b95c63 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1579,7 +1579,7 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) case 0x3C: /* WHAMI */ tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env, - offsetof(CPUAlphaState, cpu_index)); + -offsetof(AlphaCPU, env) + offsetof(CPUState, cpu_index)); break; default: diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 94536bb0cc..07588a13b2 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -64,7 +64,7 @@ static void arm_cpu_reset(CPUState *s) CPUARMState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-arm/helper.c b/target-arm/helper.c index 66ab78e3f1..37c34a11c4 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -902,7 +902,8 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = { static int mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { - uint32_t mpidr = env->cpu_index; + CPUState *cs = CPU(arm_env_get_cpu(env)); + uint32_t mpidr = cs->cpu_index; /* We don't support setting cluster ID ([8..11]) * so these bits always RAZ. */ diff --git a/target-cris/cpu.c b/target-cris/cpu.c index c596609bd4..3f64a5747e 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -35,7 +35,7 @@ static void cris_cpu_reset(CPUState *s) uint32_t vr; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 9f98a41e5c..992b61405f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1936,7 +1936,7 @@ static void x86_cpu_reset(CPUState *s) int i; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP); } @@ -2010,7 +2010,7 @@ static void x86_cpu_reset(CPUState *s) #if !defined(CONFIG_USER_ONLY) /* We hard-wire the BSP to the first CPU. */ - if (env->cpu_index == 0) { + if (s->cpu_index == 0) { apic_designate_bsp(env->apic_state); } @@ -2148,6 +2148,7 @@ void x86_cpu_realize(Object *obj, Error **errp) static void x86_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); X86CPU *cpu = X86_CPU(obj); CPUX86State *env = &cpu->env; static int inited; @@ -2179,7 +2180,7 @@ static void x86_cpu_initfn(Object *obj) x86_cpuid_get_tsc_freq, x86_cpuid_set_tsc_freq, NULL, NULL, NULL); - env->cpuid_apic_id = env->cpu_index; + env->cpuid_apic_id = cs->cpu_index; /* init various static tables used in TCG mode */ if (tcg_enabled() && !inited) { diff --git a/target-i386/helper.c b/target-i386/helper.c index dca1360962..fa622e114d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1059,7 +1059,7 @@ void breakpoint_handler(CPUX86State *env) typedef struct MCEInjectionParams { Monitor *mon; - CPUX86State *env; + X86CPU *cpu; int bank; uint64_t status; uint64_t mcg_status; @@ -1071,7 +1071,8 @@ typedef struct MCEInjectionParams { static void do_inject_x86_mce(void *data) { MCEInjectionParams *params = data; - CPUX86State *cenv = params->env; + CPUX86State *cenv = ¶ms->cpu->env; + CPUState *cpu = CPU(params->cpu); uint64_t *banks = cenv->mce_banks + 4 * params->bank; cpu_synchronize_state(cenv); @@ -1094,7 +1095,7 @@ static void do_inject_x86_mce(void *data) if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) { monitor_printf(params->mon, "CPU %d: Uncorrected error reporting disabled\n", - cenv->cpu_index); + cpu->cpu_index); return; } @@ -1106,7 +1107,7 @@ static void do_inject_x86_mce(void *data) monitor_printf(params->mon, "CPU %d: Uncorrected error reporting disabled for" " bank %d\n", - cenv->cpu_index, params->bank); + cpu->cpu_index, params->bank); return; } @@ -1115,7 +1116,7 @@ static void do_inject_x86_mce(void *data) monitor_printf(params->mon, "CPU %d: Previous MCE still in progress, raising" " triple fault\n", - cenv->cpu_index); + cpu->cpu_index); qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); qemu_system_reset_request(); return; @@ -1148,7 +1149,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, CPUX86State *cenv = &cpu->env; MCEInjectionParams params = { .mon = mon, - .env = cenv, + .cpu = cpu, .bank = bank, .status = status, .mcg_status = mcg_status, @@ -1188,7 +1189,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, if (cenv == env) { continue; } - params.env = env; + params.cpu = x86_env_get_cpu(env); run_on_cpu(CPU(cpu), do_inject_x86_mce, ¶ms); } } diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index db3126b79b..719cacda8f 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -580,14 +580,17 @@ void helper_monitor(CPUX86State *env, target_ulong ptr) void helper_mwait(CPUX86State *env, int next_eip_addend) { + CPUState *cpu; + if ((uint32_t)ECX != 0) { raise_exception(env, EXCP0D_GPF); } cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0); EIP += next_eip_addend; + cpu = CPU(x86_env_get_cpu(env)); /* XXX: not complete but not completely erroneous */ - if (env->cpu_index != 0 || env->next_cpu != NULL) { + if (cpu->cpu_index != 0 || env->next_cpu != NULL) { /* more than one CPU: do not sleep because another CPU may wake this one */ } else { diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index caa4834075..eca2dca427 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -30,7 +30,7 @@ static void lm32_cpu_reset(CPUState *s) CPULM32State *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 3e70bb0ead..ce89674a08 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -35,7 +35,7 @@ static void m68k_cpu_reset(CPUState *s) CPUM68KState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 34b3a9bfdc..0f858fd869 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -32,7 +32,7 @@ static void mb_cpu_reset(CPUState *s) CPUMBState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 004406232b..10ff46d6a7 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -29,8 +29,16 @@ static void mips_cpu_reset(CPUState *s) MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu); CPUMIPSState *env = &cpu->env; + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); + log_cpu_state(env, 0); + } + mcc->parent_reset(s); + memset(env, 0, offsetof(CPUMIPSState, breakpoints)); + tlb_flush(env, 1); + cpu_state_reset(env); } diff --git a/target-mips/translate.c b/target-mips/translate.c index 6281e70471..206ba83401 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15878,13 +15878,10 @@ MIPSCPU *cpu_mips_init(const char *cpu_model) void cpu_state_reset(CPUMIPSState *env) { - if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); - log_cpu_state(env, 0); - } - - memset(env, 0, offsetof(CPUMIPSState, breakpoints)); - tlb_flush(env, 1); +#ifndef CONFIG_USER_ONLY + MIPSCPU *cpu = mips_env_get_cpu(env); + CPUState *cs = CPU(cpu); +#endif /* Reset registers to their default values */ env->CP0_PRid = env->cpu_model->CP0_PRid; @@ -15953,7 +15950,7 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_Random = env->tlb->nb_tlb - 1; env->tlb->tlb_in_use = env->tlb->nb_tlb; env->CP0_Wired = 0; - env->CP0_EBase = 0x80000000 | (env->cpu_index & 0x3FF); + env->CP0_EBase = 0x80000000 | (cs->cpu_index & 0x3FF); env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL); /* vectored interrupts not implemented, timer on int 7, no performance counters. */ @@ -15976,13 +15973,13 @@ void cpu_state_reset(CPUMIPSState *env) /* Only TC0 on VPE 0 starts as active. */ for (i = 0; i < ARRAY_SIZE(env->tcs); i++) { - env->tcs[i].CP0_TCBind = env->cpu_index << CP0TCBd_CurVPE; + env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE; env->tcs[i].CP0_TCHalt = 1; } env->active_tc.CP0_TCHalt = 1; env->halted = 1; - if (!env->cpu_index) { + if (cs->cpu_index == 0) { /* VPE0 starts up enabled. */ env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index ba35b17581..56544d8ab5 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -27,7 +27,7 @@ static void openrisc_cpu_reset(CPUState *s) OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(cpu); if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", cpu->env.cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(&cpu->env, 0); } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 4846acfc0d..19e9f25b19 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -766,8 +766,9 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) dprintf("injected interrupt %d\n", irq); r = kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &irq); - if (r < 0) - printf("cpu %d fail inject %x\n", env->cpu_index, irq); + if (r < 0) { + printf("cpu %d fail inject %x\n", cs->cpu_index, irq); + } /* Always wake up soon in case the interrupt was level based */ qemu_mod_timer(idle_timer, qemu_get_clock_ns(vm_clock) + @@ -1275,14 +1276,15 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) } } -int kvmppc_fixup_cpu(CPUPPCState *env) +int kvmppc_fixup_cpu(PowerPCCPU *cpu) { + CPUState *cs = CPU(cpu); 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); + cs->cpu_index = (cs->cpu_index / smp_threads) * smt + + (cs->cpu_index % smp_threads); return 0; } diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 4b2172360a..3db21fc889 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -33,7 +33,7 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); int kvmppc_reset_htab(int shift_hint); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ -int kvmppc_fixup_cpu(CPUPPCState *env); +int kvmppc_fixup_cpu(PowerPCCPU *cpu); #else @@ -122,7 +122,7 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env) #endif /* !CONFIG_USER_ONLY */ -static inline int kvmppc_fixup_cpu(CPUPPCState *env) +static inline int kvmppc_fixup_cpu(PowerPCCPU *cpu) { return -1; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2b03756ee1..3f199c4bb9 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10005,8 +10005,10 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n) return 0; } -static int ppc_fixup_cpu(CPUPPCState *env) +static int ppc_fixup_cpu(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->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 @@ -10036,12 +10038,12 @@ static void ppc_cpu_realize(Object *obj, Error **errp) Error *local_err = NULL; if (kvm_enabled()) { - if (kvmppc_fixup_cpu(env) != 0) { + if (kvmppc_fixup_cpu(cpu) != 0) { error_setg(errp, "Unable to virtualize selected CPU with KVM"); return; } } else { - if (ppc_fixup_cpu(env) != 0) { + if (ppc_fixup_cpu(cpu) != 0) { error_setg(errp, "Unable to emulate selected CPU with TCG"); return; } @@ -10460,7 +10462,7 @@ static void ppc_cpu_reset(CPUState *s) target_ulong msr; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 249f063d94..2ed23127d1 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -33,7 +33,7 @@ static void s390_cpu_reset(CPUState *s) CPUS390XState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index a1a177fa88..e4858a03ed 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -31,7 +31,7 @@ static void superh_cpu_reset(CPUState *s) CPUSH4State *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 882d30642a..f404aa8b5f 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -31,7 +31,7 @@ static void sparc_cpu_reset(CPUState *s) CPUSPARCState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { - qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } From 504134d27f15aa94f6d2b5c45eaa804a8dfb5a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 06:38:45 +0100 Subject: [PATCH 0462/1634] kvm: Pass CPUState to kvm_init_vcpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPUArchState is no longer needed, and it thereby no longer depends on NEED_CPU_H. Signed-off-by: Andreas Färber --- cpus.c | 2 +- include/sysemu/kvm.h | 5 +++-- kvm-all.c | 3 +-- kvm-stub.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpus.c b/cpus.c index bbb8961708..a4390c3c3f 100644 --- a/cpus.c +++ b/cpus.c @@ -742,7 +742,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) cpu->thread_id = qemu_get_thread_id(); cpu_single_env = env; - r = kvm_init_vcpu(env); + r = kvm_init_vcpu(cpu); if (r < 0) { fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r)); exit(1); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 3db19ffdac..2fe8f8a44b 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -17,6 +17,7 @@ #include #include "config-host.h" #include "qemu/queue.h" +#include "qom/cpu.h" #ifdef CONFIG_KVM #include @@ -120,9 +121,9 @@ int kvm_has_many_ioeventfds(void); int kvm_has_gsi_routing(void); int kvm_has_intx_set_mask(void); -#ifdef NEED_CPU_H -int kvm_init_vcpu(CPUArchState *env); +int kvm_init_vcpu(CPUState *cpu); +#ifdef NEED_CPU_H int kvm_cpu_exec(CPUArchState *env); #if !defined(CONFIG_USER_ONLY) diff --git a/kvm-all.c b/kvm-all.c index 4ba77dea52..6e2164bec2 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -214,9 +214,8 @@ static void kvm_reset_vcpu(void *opaque) kvm_arch_reset_vcpu(cpu); } -int kvm_init_vcpu(CPUArchState *env) +int kvm_init_vcpu(CPUState *cpu) { - CPUState *cpu = ENV_GET_CPU(env); KVMState *s = kvm_state; long mmap_size; int ret; diff --git a/kvm-stub.c b/kvm-stub.c index 81f8967180..47f8dca7d5 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -24,7 +24,7 @@ bool kvm_irqfds_allowed; bool kvm_msi_via_irqfd_allowed; bool kvm_gsi_routing_allowed; -int kvm_init_vcpu(CPUArchState *env) +int kvm_init_vcpu(CPUState *cpu) { return -ENOSYS; } From 4a1e40b5091bcff5f8ea3fe9963eaa8e76b16389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 19:39:30 +0100 Subject: [PATCH 0463/1634] xen: Simplify halting of first CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the global first_cpu variable to halt the CPU rather than using a local first_cpu initialized from qemu_get_cpu(0). This will allow to change qemu_get_cpu() return type to CPUState despite use of the CPU_COMMON halted field in the reset handler. Signed-off-by: Andreas Färber --- xen-all.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xen-all.c b/xen-all.c index 19bcfd1510..110f958a53 100644 --- a/xen-all.c +++ b/xen-all.c @@ -585,9 +585,7 @@ static void xen_reset_vcpu(void *opaque) void xen_vcpu_init(void) { - CPUArchState *first_cpu; - - if ((first_cpu = qemu_get_cpu(0))) { + if (first_cpu != NULL) { qemu_register_reset(xen_reset_vcpu, first_cpu); xen_reset_vcpu(first_cpu); } From 38d8f5c84e7c02f2523005dddc31939ca18232dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 19:47:15 +0100 Subject: [PATCH 0464/1634] exec: Return CPUState from qemu_get_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the declaration to qemu/cpu.h and add documentation. The implementation still depends on CPUArchState for CPU iteration. Signed-off-by: Andreas Färber --- exec.c | 6 +++--- hw/pxa2xx_gpio.c | 2 +- include/exec/cpu-all.h | 1 - include/qom/cpu.h | 10 ++++++++++ target-mips/op_helper.c | 11 ++++++++--- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/exec.c b/exec.c index e5265e635c..5689613d0a 100644 --- a/exec.c +++ b/exec.c @@ -247,10 +247,10 @@ static const VMStateDescription vmstate_cpu_common = { }; #endif -CPUArchState *qemu_get_cpu(int index) +CPUState *qemu_get_cpu(int index) { CPUArchState *env = first_cpu; - CPUState *cpu; + CPUState *cpu = NULL; while (env) { cpu = ENV_GET_CPU(env); @@ -260,7 +260,7 @@ CPUArchState *qemu_get_cpu(int index) env = env->next_cpu; } - return env; + return cpu; } void cpu_exec_init(CPUArchState *env) diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index c02c295af4..eec2ea3f1c 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -277,7 +277,7 @@ static int pxa2xx_gpio_initfn(SysBusDevice *dev) s = FROM_SYSBUS(PXA2xxGPIOInfo, dev); - s->cpu = arm_env_get_cpu(qemu_get_cpu(s->ncpu)); + s->cpu = ARM_CPU(qemu_get_cpu(s->ncpu)); qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines); qdev_init_gpio_out(&dev->qdev, s->handler, s->lines); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 439e88deb4..249e0464f2 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -354,7 +354,6 @@ int page_check_range(target_ulong start, target_ulong len, int flags); #endif CPUArchState *cpu_copy(CPUArchState *env); -CPUArchState *qemu_get_cpu(int cpu); #define CPU_DUMP_CODE 0x00010000 #define CPU_DUMP_FPU 0x00020000 /* dump FPU register state, not just integer */ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index d5e0a4057a..773caf9fa1 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -156,5 +156,15 @@ bool cpu_is_stopped(CPUState *cpu); */ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); +/** + * qemu_get_cpu: + * @index: The CPUState@cpu_index value of the CPU to obtain. + * + * Gets a CPU matching @index. + * + * Returns: The CPU or %NULL if there is no matching CPU. + */ +CPUState *qemu_get_cpu(int index); + #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 1816a0ec8d..1bca4a159e 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -585,8 +585,9 @@ static inline void mips_tc_sleep(MIPSCPU *cpu, int tc) walking the list of CPUMIPSStates. */ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) { + MIPSCPU *cpu; CPUState *cs; - CPUMIPSState *other; + CPUState *other_cs; int vpe_idx; int tc_idx = *tc; @@ -599,8 +600,12 @@ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) cs = CPU(mips_env_get_cpu(env)); vpe_idx = tc_idx / cs->nr_threads; *tc = tc_idx % cs->nr_threads; - other = qemu_get_cpu(vpe_idx); - return other ? other : env; + other_cs = qemu_get_cpu(vpe_idx); + if (other_cs == NULL) { + return env; + } + cpu = MIPS_CPU(other_cs); + return &cpu->env; } /* The per VPE CP0_Status register shares some fields with the per TC From 9ca5892328a40bfa9c24c847441761c4729ae3f3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 7 Jan 2013 16:20:42 -0200 Subject: [PATCH 0465/1634] kvm: Add fake KVM constants to avoid #ifdefs on KVM-specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any KVM-specific code that use these constants must check if kvm_enabled() is true before using them. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- include/sysemu/kvm.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 2fe8f8a44b..6bdd51373e 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -22,6 +22,20 @@ #ifdef CONFIG_KVM #include #include +#else +/* These constants must never be used at runtime if kvm_enabled() is false. + * They exist so we don't need #ifdefs around KVM-specific code that already + * checks kvm_enabled() properly. + */ +#define KVM_CPUID_SIGNATURE 0 +#define KVM_CPUID_FEATURES 0 +#define KVM_FEATURE_CLOCKSOURCE 0 +#define KVM_FEATURE_NOP_IO_DELAY 0 +#define KVM_FEATURE_MMU_OP 0 +#define KVM_FEATURE_CLOCKSOURCE2 0 +#define KVM_FEATURE_ASYNC_PF 0 +#define KVM_FEATURE_STEAL_TIME 0 +#define KVM_FEATURE_PV_EOI 0 #endif extern int kvm_allowed; From 6a4784ce6b95b013a13504ead9ab62975faf6eff Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 7 Jan 2013 16:20:44 -0200 Subject: [PATCH 0466/1634] target-i386: Disable kvm_mmu by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KVM_CAP_PV_MMU capability reporting was removed from the kernel since v2.6.33 (see commit a68a6a7282373), and was completely removed from the kernel since v3.3 (see commit fb92045843). It doesn't make sense to keep it enabled by default, as it would cause unnecessary hassle when using the "enforce" flag. This disables kvm_mmu on all machine-types. With this fix, the possible scenarios when migrating from QEMU <= 1.3 to QEMU 1.4 are: ------------+----------+---------------------------------------------------- src kernel | dst kern.| Result ------------+----------+---------------------------------------------------- >= 2.6.33 | any | kvm_mmu was already disabled and will stay disabled <= 2.6.32 | >= 3.3 | correct live migration is impossible <= 2.6.32 | <= 3.2 | kvm_mmu will be disabled on next guest reboot * ------------+----------+---------------------------------------------------- * If they are running kernel <= 2.6.32 and want kvm_mmu to be kept enabled on guest reboot, they can explicitly add +kvm_mmu to the QEMU command-line. Using 2.6.33 and higher, it is not possible to enable kvm_mmu explicitly anymore. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 992b61405f..cb385fb83e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -159,7 +159,6 @@ int enforce_cpuid = 0; #if defined(CONFIG_KVM) static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) | (1 << KVM_FEATURE_NOP_IO_DELAY) | - (1 << KVM_FEATURE_MMU_OP) | (1 << KVM_FEATURE_CLOCKSOURCE2) | (1 << KVM_FEATURE_ASYNC_PF) | (1 << KVM_FEATURE_STEAL_TIME) | From 5ef5787627c07d053c2628fe720e814561fbfbe3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 7 Jan 2013 16:20:45 -0200 Subject: [PATCH 0467/1634] target-i386/cpu: Introduce FeatureWord typedefs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces a FeatureWord enum, FeatureWordInfo struct (with generation information about a feature word), and a FeatureWordArray typedef, and changes add_flagname_to_bitmaps() code and cpu_x86_parse_featurestr() to use the new typedefs instead of separate variables for each feature word. This will help us keep the code at kvm_check_features_against_host(), cpu_x86_parse_featurestr() and add_flagname_to_bitmaps() sane while adding new feature name arrays. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 97 +++++++++++++++++++++++------------------------ target-i386/cpu.h | 15 ++++++++ 2 files changed, 63 insertions(+), 49 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index cb385fb83e..e17709cc6e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -124,6 +124,20 @@ static const char *cpuid_7_0_ebx_feature_name[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; +typedef struct FeatureWordInfo { + const char **feat_names; +} FeatureWordInfo; + +static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + [FEAT_1_EDX] = { .feat_names = feature_name }, + [FEAT_1_ECX] = { .feat_names = ext_feature_name }, + [FEAT_8000_0001_EDX] = { .feat_names = ext2_feature_name }, + [FEAT_8000_0001_ECX] = { .feat_names = ext3_feature_name }, + [FEAT_KVM] = { .feat_names = kvm_feature_name }, + [FEAT_SVM] = { .feat_names = svm_feature_name }, + [FEAT_7_0_EBX] = { .feat_names = cpuid_7_0_ebx_feature_name }, +}; + const char *get_register_name_32(unsigned int reg) { static const char *reg_names[CPU_NB_REGS32] = { @@ -271,23 +285,20 @@ static bool lookup_feature(uint32_t *pval, const char *s, const char *e, return found; } -static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features, - uint32_t *ext_features, - uint32_t *ext2_features, - uint32_t *ext3_features, - uint32_t *kvm_features, - uint32_t *svm_features, - uint32_t *cpuid_7_0_ebx_features) +static void add_flagname_to_bitmaps(const char *flagname, + FeatureWordArray words) { - if (!lookup_feature(features, flagname, NULL, feature_name) && - !lookup_feature(ext_features, flagname, NULL, ext_feature_name) && - !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) && - !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) && - !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) && - !lookup_feature(svm_features, flagname, NULL, svm_feature_name) && - !lookup_feature(cpuid_7_0_ebx_features, flagname, NULL, - cpuid_7_0_ebx_feature_name)) - fprintf(stderr, "CPU feature %s not found\n", flagname); + FeatureWord w; + for (w = 0; w < FEATURE_WORDS; w++) { + FeatureWordInfo *wi = &feature_word_info[w]; + if (wi->feat_names && + lookup_feature(&words[w], flagname, NULL, wi->feat_names)) { + break; + } + } + if (w == FEATURE_WORDS) { + fprintf(stderr, "CPU feature %s not found\n", flagname); + } } typedef struct x86_def_t { @@ -1283,35 +1294,23 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) unsigned int i; char *featurestr; /* Single 'key=value" string being parsed */ /* Features to be added */ - uint32_t plus_features = 0, plus_ext_features = 0; - uint32_t plus_ext2_features = 0, plus_ext3_features = 0; - uint32_t plus_kvm_features = kvm_default_features, plus_svm_features = 0; - uint32_t plus_7_0_ebx_features = 0; + FeatureWordArray plus_features = { + [FEAT_KVM] = kvm_default_features, + }; /* Features to be removed */ - uint32_t minus_features = 0, minus_ext_features = 0; - uint32_t minus_ext2_features = 0, minus_ext3_features = 0; - uint32_t minus_kvm_features = 0, minus_svm_features = 0; - uint32_t minus_7_0_ebx_features = 0; + FeatureWordArray minus_features = { 0 }; uint32_t numvalue; - add_flagname_to_bitmaps("hypervisor", &plus_features, - &plus_ext_features, &plus_ext2_features, &plus_ext3_features, - &plus_kvm_features, &plus_svm_features, &plus_7_0_ebx_features); + add_flagname_to_bitmaps("hypervisor", plus_features); featurestr = features ? strtok(features, ",") : NULL; while (featurestr) { char *val; if (featurestr[0] == '+') { - add_flagname_to_bitmaps(featurestr + 1, &plus_features, - &plus_ext_features, &plus_ext2_features, - &plus_ext3_features, &plus_kvm_features, - &plus_svm_features, &plus_7_0_ebx_features); + add_flagname_to_bitmaps(featurestr + 1, plus_features); } else if (featurestr[0] == '-') { - add_flagname_to_bitmaps(featurestr + 1, &minus_features, - &minus_ext_features, &minus_ext2_features, - &minus_ext3_features, &minus_kvm_features, - &minus_svm_features, &minus_7_0_ebx_features); + add_flagname_to_bitmaps(featurestr + 1, minus_features); } else if ((val = strchr(featurestr, '='))) { *val = 0; val++; if (!strcmp(featurestr, "family")) { @@ -1411,20 +1410,20 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } featurestr = strtok(NULL, ","); } - x86_cpu_def->features |= plus_features; - x86_cpu_def->ext_features |= plus_ext_features; - x86_cpu_def->ext2_features |= plus_ext2_features; - x86_cpu_def->ext3_features |= plus_ext3_features; - x86_cpu_def->kvm_features |= plus_kvm_features; - x86_cpu_def->svm_features |= plus_svm_features; - x86_cpu_def->cpuid_7_0_ebx_features |= plus_7_0_ebx_features; - x86_cpu_def->features &= ~minus_features; - x86_cpu_def->ext_features &= ~minus_ext_features; - x86_cpu_def->ext2_features &= ~minus_ext2_features; - x86_cpu_def->ext3_features &= ~minus_ext3_features; - x86_cpu_def->kvm_features &= ~minus_kvm_features; - x86_cpu_def->svm_features &= ~minus_svm_features; - x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features; + x86_cpu_def->features |= plus_features[FEAT_1_EDX]; + x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX]; + x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX]; + x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX]; + x86_cpu_def->kvm_features |= plus_features[FEAT_KVM]; + x86_cpu_def->svm_features |= plus_features[FEAT_SVM]; + x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; + x86_cpu_def->features &= ~minus_features[FEAT_1_EDX]; + x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX]; + x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; + x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; + x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM]; + x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM]; + x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; if (check_cpuid && kvm_enabled()) { if (kvm_check_features_against_host(x86_cpu_def) && enforce_cpuid) goto error; diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e56921bbe3..e4a7c50089 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -361,6 +361,21 @@ #define MSR_VM_HSAVE_PA 0xc0010117 +/* CPUID feature words */ +typedef enum FeatureWord { + FEAT_1_EDX, /* CPUID[1].EDX */ + FEAT_1_ECX, /* CPUID[1].ECX */ + FEAT_7_0_EBX, /* CPUID[EAX=7,ECX=0].EBX */ + FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ + FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ + FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ + FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ + FEAT_SVM, /* CPUID[8000_000A].EDX */ + FEATURE_WORDS, +} FeatureWord; + +typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + /* cpuid_features bits */ #define CPUID_FP87 (1 << 0) #define CPUID_VME (1 << 1) From bffd67b01d96d3a59bf74a2d38f00e59d4b9c774 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 7 Jan 2013 16:20:46 -0200 Subject: [PATCH 0468/1634] target-i386: kvm_check_features_against_host(): Use feature_word_info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of carrying the CPUID leaf/register and feature name array on the model_features_t struct, move that information into feature_word_info so it can be reused by other functions. The goal is to eventually kill model_features_t entirely, but to do that we have to either convert x86_def_t.features to an array or use offsetof() inside FeatureWordInfo (to replace the pointers inside model_features_t). So by now just move most of the model_features_t fields to FeatureWordInfo except for the two pointers to local arguments. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 73 +++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index e17709cc6e..0e531f91b4 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -126,16 +126,39 @@ static const char *cpuid_7_0_ebx_feature_name[] = { typedef struct FeatureWordInfo { const char **feat_names; + uint32_t cpuid_eax; /* Input EAX for CPUID */ + int cpuid_reg; /* R_* register constant */ } FeatureWordInfo; static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { - [FEAT_1_EDX] = { .feat_names = feature_name }, - [FEAT_1_ECX] = { .feat_names = ext_feature_name }, - [FEAT_8000_0001_EDX] = { .feat_names = ext2_feature_name }, - [FEAT_8000_0001_ECX] = { .feat_names = ext3_feature_name }, - [FEAT_KVM] = { .feat_names = kvm_feature_name }, - [FEAT_SVM] = { .feat_names = svm_feature_name }, - [FEAT_7_0_EBX] = { .feat_names = cpuid_7_0_ebx_feature_name }, + [FEAT_1_EDX] = { + .feat_names = feature_name, + .cpuid_eax = 1, .cpuid_reg = R_EDX, + }, + [FEAT_1_ECX] = { + .feat_names = ext_feature_name, + .cpuid_eax = 1, .cpuid_reg = R_ECX, + }, + [FEAT_8000_0001_EDX] = { + .feat_names = ext2_feature_name, + .cpuid_eax = 0x80000001, .cpuid_reg = R_EDX, + }, + [FEAT_8000_0001_ECX] = { + .feat_names = ext3_feature_name, + .cpuid_eax = 0x80000001, .cpuid_reg = R_ECX, + }, + [FEAT_KVM] = { + .feat_names = kvm_feature_name, + .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, + }, + [FEAT_SVM] = { + .feat_names = svm_feature_name, + .cpuid_eax = 0x8000000A, .cpuid_reg = R_EDX, + }, + [FEAT_7_0_EBX] = { + .feat_names = cpuid_7_0_ebx_feature_name, + .cpuid_eax = 7, .cpuid_reg = R_EBX, + }, }; const char *get_register_name_32(unsigned int reg) @@ -162,9 +185,7 @@ const char *get_register_name_32(unsigned int reg) typedef struct model_features_t { uint32_t *guest_feat; uint32_t *host_feat; - const char **flag_names; - uint32_t cpuid; - int reg; + FeatureWord feat_word; } model_features_t; int check_cpuid = 0; @@ -962,19 +983,19 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) #endif /* CONFIG_KVM */ } -static int unavailable_host_feature(struct model_features_t *f, uint32_t mask) +static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask) { int i; for (i = 0; i < 32; ++i) if (1 << i & mask) { - const char *reg = get_register_name_32(f->reg); + const char *reg = get_register_name_32(f->cpuid_reg); assert(reg); fprintf(stderr, "warning: host doesn't support requested feature: " "CPUID.%02XH:%s%s%s [bit %d]\n", - f->cpuid, reg, - f->flag_names[i] ? "." : "", - f->flag_names[i] ? f->flag_names[i] : "", i); + f->cpuid_eax, reg, + f->feat_names[i] ? "." : "", + f->feat_names[i] ? f->feat_names[i] : "", i); break; } return 0; @@ -992,25 +1013,29 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) int rv, i; struct model_features_t ft[] = { {&guest_def->features, &host_def.features, - feature_name, 0x00000001, R_EDX}, + FEAT_1_EDX }, {&guest_def->ext_features, &host_def.ext_features, - ext_feature_name, 0x00000001, R_ECX}, + FEAT_1_ECX }, {&guest_def->ext2_features, &host_def.ext2_features, - ext2_feature_name, 0x80000001, R_EDX}, + FEAT_8000_0001_EDX }, {&guest_def->ext3_features, &host_def.ext3_features, - ext3_feature_name, 0x80000001, R_ECX} + FEAT_8000_0001_ECX }, }; assert(kvm_enabled()); kvm_cpu_fill_host(&host_def); - for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) - for (mask = 1; mask; mask <<= 1) + for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) { + FeatureWord w = ft[i].feat_word; + FeatureWordInfo *wi = &feature_word_info[w]; + for (mask = 1; mask; mask <<= 1) { if (*ft[i].guest_feat & mask && !(*ft[i].host_feat & mask)) { - unavailable_host_feature(&ft[i], mask); - rv = 1; - } + unavailable_host_feature(wi, mask); + rv = 1; + } + } + } return rv; } From 89e49c8bea9ec81d2cca25f81f5e15c3a1d8b69c Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 7 Jan 2013 16:20:47 -0200 Subject: [PATCH 0469/1634] target-i386/cpu.c: Add feature name array for ext4_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Feature names were taken from the X86_FEATURE_* constants in the Linux kernel code. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0e531f91b4..8ec992919f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -95,6 +95,17 @@ static const char *ext3_feature_name[] = { NULL, NULL, NULL, NULL, }; +static const char *ext4_feature_name[] = { + NULL, NULL, "xstore", "xstore-en", + NULL, NULL, "xcrypt", "xcrypt-en", + "ace2", "ace2-en", "phe", "phe-en", + "pmm", "pmm-en", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +}; + static const char *kvm_feature_name[] = { "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", "kvm_steal_time", "kvm_pv_eoi", NULL, @@ -147,6 +158,10 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .feat_names = ext3_feature_name, .cpuid_eax = 0x80000001, .cpuid_reg = R_ECX, }, + [FEAT_C000_0001_EDX] = { + .feat_names = ext4_feature_name, + .cpuid_eax = 0xC0000001, .cpuid_reg = R_EDX, + }, [FEAT_KVM] = { .feat_names = kvm_feature_name, .cpuid_eax = KVM_CPUID_FEATURES, .cpuid_reg = R_EAX, @@ -1439,6 +1454,7 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX]; x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX]; x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX]; + x86_cpu_def->ext4_features |= plus_features[FEAT_C000_0001_EDX]; x86_cpu_def->kvm_features |= plus_features[FEAT_KVM]; x86_cpu_def->svm_features |= plus_features[FEAT_SVM]; x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; @@ -1446,6 +1462,7 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX]; x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; + x86_cpu_def->ext4_features &= ~minus_features[FEAT_C000_0001_EDX]; x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM]; x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM]; x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; From 07ca59450c9a0c5df65665ce46aa8487af59a1dd Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 7 Jan 2013 16:20:48 -0200 Subject: [PATCH 0470/1634] target-i386: check/enforce: Check all feature words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the following feature words to the list of flags to be checked by kvm_check_features_against_host(): - cpuid_7_0_ebx_features - ext4_features - kvm_features - svm_features This will ensure the "enforce" flag works as it should: it won't allow QEMU to be started unless every flag that was requested by the user or defined in the CPU model is supported by the host. This patch may cause existing configurations where "enforce" wasn't preventing QEMU from being started to abort QEMU. But that's exactly the point of this patch: if a flag was not supported by the host and QEMU wasn't aborting, it was a bug in the "enforce" code. Signed-off-by: Eduardo Habkost Reviewed-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8ec992919f..9a48e3f007 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1016,8 +1016,9 @@ static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask) return 0; } -/* best effort attempt to inform user requested cpu flags aren't making - * their way to the guest. +/* Check if all requested cpu flags are making their way to the guest + * + * Returns 0 if all flags are supported by the host, non-zero otherwise. * * This function may be called only if KVM is enabled. */ @@ -1035,6 +1036,14 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) FEAT_8000_0001_EDX }, {&guest_def->ext3_features, &host_def.ext3_features, FEAT_8000_0001_ECX }, + {&guest_def->ext4_features, &host_def.ext4_features, + FEAT_C000_0001_EDX }, + {&guest_def->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features, + FEAT_7_0_EBX }, + {&guest_def->svm_features, &host_def.svm_features, + FEAT_SVM }, + {&guest_def->kvm_features, &host_def.kvm_features, + FEAT_KVM }, }; assert(kvm_enabled()); From 077c68c32897ea02b88c9a919627d93d3878ef15 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 11 Jan 2013 03:10:15 +0100 Subject: [PATCH 0471/1634] target-i386: Move setting defaults out of cpu_x86_parse_featurestr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change, needed for simplifying conversion to properties. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 9a48e3f007..e75b293f0f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1343,15 +1343,11 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) unsigned int i; char *featurestr; /* Single 'key=value" string being parsed */ /* Features to be added */ - FeatureWordArray plus_features = { - [FEAT_KVM] = kvm_default_features, - }; + FeatureWordArray plus_features = { 0 }; /* Features to be removed */ FeatureWordArray minus_features = { 0 }; uint32_t numvalue; - add_flagname_to_bitmaps("hypervisor", plus_features); - featurestr = features ? strtok(features, ",") : NULL; while (featurestr) { @@ -1607,6 +1603,9 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) goto error; } + def->kvm_features |= kvm_default_features; + def->ext_features |= CPUID_EXT_HYPERVISOR; + if (cpu_x86_parse_featurestr(def, features) < 0) { goto error; } From fa2db3c494270c1892365eef370d06a4559619e0 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 11 Jan 2013 03:10:16 +0100 Subject: [PATCH 0472/1634] target-i386: cpu_x86_register() consolidate freeing resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Freeing resources in one place would require setting 'error' to not NULL, so add some more error reporting before jumping to exit branch. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index e75b293f0f..3a68470f53 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1594,20 +1594,23 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) model_pieces = g_strsplit(cpu_model, ",", 2); if (!model_pieces[0]) { - goto error; + error_setg(&error, "Invalid/empty CPU model name"); + goto out; } name = model_pieces[0]; features = model_pieces[1]; if (cpu_x86_find_by_name(def, name) < 0) { - goto error; + error_setg(&error, "Unable to find CPU definition: %s", name); + goto out; } def->kvm_features |= kvm_default_features; def->ext_features |= CPUID_EXT_HYPERVISOR; if (cpu_x86_parse_featurestr(def, features) < 0) { - goto error; + error_setg(&error, "Invalid cpu_model string format: %s", cpu_model); + goto out; } assert(def->vendor1); env->cpuid_vendor1 = def->vendor1; @@ -1632,17 +1635,15 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) "tsc-frequency", &error); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); + +out: + g_strfreev(model_pieces); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); error_free(error); - goto error; + return -1; } - - g_strfreev(model_pieces); return 0; -error: - g_strfreev(model_pieces); - return -1; } #if !defined(CONFIG_USER_ONLY) From 5ec01c2e96910e1588d1a0de8609b9dda7618c7f Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 11 Jan 2013 03:10:17 +0100 Subject: [PATCH 0473/1634] target-i386: Move kvm_check_features_against_host() check to realize time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kvm_check_features_against_host() should be called when features can't be changed, and when features are converted to properties it would be possible to change them until realize time, so correct way is to call kvm_check_features_against_host() in x86_cpu_realize(). Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 3a68470f53..333745b456 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1022,27 +1022,28 @@ static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask) * * This function may be called only if KVM is enabled. */ -static int kvm_check_features_against_host(x86_def_t *guest_def) +static int kvm_check_features_against_host(X86CPU *cpu) { + CPUX86State *env = &cpu->env; x86_def_t host_def; uint32_t mask; int rv, i; struct model_features_t ft[] = { - {&guest_def->features, &host_def.features, + {&env->cpuid_features, &host_def.features, FEAT_1_EDX }, - {&guest_def->ext_features, &host_def.ext_features, + {&env->cpuid_ext_features, &host_def.ext_features, FEAT_1_ECX }, - {&guest_def->ext2_features, &host_def.ext2_features, + {&env->cpuid_ext2_features, &host_def.ext2_features, FEAT_8000_0001_EDX }, - {&guest_def->ext3_features, &host_def.ext3_features, + {&env->cpuid_ext3_features, &host_def.ext3_features, FEAT_8000_0001_ECX }, - {&guest_def->ext4_features, &host_def.ext4_features, + {&env->cpuid_ext4_features, &host_def.ext4_features, FEAT_C000_0001_EDX }, - {&guest_def->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features, + {&env->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features, FEAT_7_0_EBX }, - {&guest_def->svm_features, &host_def.svm_features, + {&env->cpuid_svm_features, &host_def.svm_features, FEAT_SVM }, - {&guest_def->kvm_features, &host_def.kvm_features, + {&env->cpuid_kvm_features, &host_def.kvm_features, FEAT_KVM }, }; @@ -1471,10 +1472,6 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM]; x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM]; x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; - if (check_cpuid && kvm_enabled()) { - if (kvm_check_features_against_host(x86_cpu_def) && enforce_cpuid) - goto error; - } return 0; error: @@ -2177,6 +2174,11 @@ void x86_cpu_realize(Object *obj, Error **errp) #ifdef CONFIG_KVM filter_features_for_kvm(cpu); #endif + if (check_cpuid && kvm_check_features_against_host(cpu) + && enforce_cpuid) { + error_setg(errp, "Host's CPU doesn't support requested features"); + return; + } } #ifndef CONFIG_USER_ONLY From 8d2497c3552e19a60e7a75d20976471ecb2a8e2b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 14 Jan 2013 17:31:31 +0100 Subject: [PATCH 0474/1634] qcow2: Fix segfault on zero-length write One of the recent refactoring patches (commit f50f88b9) didn't take care to initialise l2meta properly, so with zero-length writes, which don't even enter the write loop, qemu just segfaulted. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/qcow2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/qcow2.c b/block/qcow2.c index d603f98a9c..f6abff6111 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -759,7 +759,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, QEMUIOVector hd_qiov; uint64_t bytes_done = 0; uint8_t *cluster_data = NULL; - QCowL2Meta *l2meta; + QCowL2Meta *l2meta = NULL; trace_qcow2_writev_start_req(qemu_coroutine_self(), sector_num, remaining_sectors); From 428065ce50643a56bff043501809b62b035f0b17 Mon Sep 17 00:00:00 2001 From: liguang Date: Tue, 15 Jan 2013 13:39:55 +0800 Subject: [PATCH 0475/1634] target-i386: Define DR7 bit field constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implicit use of dr7 bit field is a little hard to understand, so define constants for them and use them consistently. Signed-off-by: liguang Signed-off-by: Andreas Färber --- target-i386/cpu.h | 6 ++++++ target-i386/helper.c | 18 +++++++++--------- target-i386/machine.c | 5 +++-- target-i386/misc_helper.c | 4 ++-- target-i386/seg_helper.c | 6 +++--- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e4a7c50089..6682022d81 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -231,6 +231,12 @@ #define DR7_TYPE_SHIFT 16 #define DR7_LEN_SHIFT 18 #define DR7_FIXED_1 0x00000400 +#define DR7_LOCAL_BP_MASK 0x55 +#define DR7_MAX_BP 4 +#define DR7_TYPE_BP_INST 0x0 +#define DR7_TYPE_DATA_WR 0x1 +#define DR7_TYPE_IO_RW 0x2 +#define DR7_TYPE_DATA_RW 0x3 #define PG_PRESENT_BIT 0 #define PG_RW_BIT 1 diff --git a/target-i386/helper.c b/target-i386/helper.c index fa622e114d..1fceb91d34 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -969,18 +969,18 @@ void hw_breakpoint_insert(CPUX86State *env, int index) int type, err = 0; switch (hw_breakpoint_type(env->dr[7], index)) { - case 0: + case DR7_TYPE_BP_INST: if (hw_breakpoint_enabled(env->dr[7], index)) err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU, &env->cpu_breakpoint[index]); break; - case 1: + case DR7_TYPE_DATA_WR: type = BP_CPU | BP_MEM_WRITE; goto insert_wp; - case 2: + case DR7_TYPE_IO_RW: /* No support for I/O watchpoints yet */ break; - case 3: + case DR7_TYPE_DATA_RW: type = BP_CPU | BP_MEM_ACCESS; insert_wp: err = cpu_watchpoint_insert(env, env->dr[index], @@ -997,15 +997,15 @@ void hw_breakpoint_remove(CPUX86State *env, int index) if (!env->cpu_breakpoint[index]) return; switch (hw_breakpoint_type(env->dr[7], index)) { - case 0: + case DR7_TYPE_BP_INST: if (hw_breakpoint_enabled(env->dr[7], index)) cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]); break; - case 1: - case 3: + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[index]); break; - case 2: + case DR7_TYPE_IO_RW: /* No support for I/O watchpoints yet */ break; } @@ -1018,7 +1018,7 @@ int check_hw_breakpoints(CPUX86State *env, int force_dr6_update) int hit_enabled = 0; dr6 = env->dr[6] & ~0xf; - for (reg = 0; reg < 4; reg++) { + for (reg = 0; reg < DR7_MAX_BP; reg++) { type = hw_breakpoint_type(env->dr[7], reg); if ((type == 0 && env->dr[reg] == env->eip) || ((type & 1) && env->cpu_watchpoint[reg] && diff --git a/target-i386/machine.c b/target-i386/machine.c index 8354572c7b..8df6a6b645 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -265,10 +265,11 @@ static int cpu_post_load(void *opaque, int version_id) cpu_breakpoint_remove_all(env, BP_CPU); cpu_watchpoint_remove_all(env, BP_CPU); - for (i = 0; i < 4; i++) + for (i = 0; i < DR7_MAX_BP; i++) { hw_breakpoint_insert(env, i); - + } tlb_flush(env, 1); + return 0; } diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index 719cacda8f..b3f4e4f27c 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -197,11 +197,11 @@ void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0) env->dr[reg] = t0; hw_breakpoint_insert(env, reg); } else if (reg == 7) { - for (i = 0; i < 4; i++) { + for (i = 0; i < DR7_MAX_BP; i++) { hw_breakpoint_remove(env, i); } env->dr[7] = t0; - for (i = 0; i < 4; i++) { + for (i = 0; i < DR7_MAX_BP; i++) { hw_breakpoint_insert(env, i); } } else { diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index c2a99ee9bc..c40bd964c0 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -465,13 +465,13 @@ static void switch_tss(CPUX86State *env, int tss_selector, #ifndef CONFIG_USER_ONLY /* reset local breakpoints */ - if (env->dr[7] & 0x55) { - for (i = 0; i < 4; i++) { + if (env->dr[7] & DR7_LOCAL_BP_MASK) { + for (i = 0; i < DR7_MAX_BP; i++) { if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) { hw_breakpoint_remove(env, i); } } - env->dr[7] &= ~0x55; + env->dr[7] &= ~DR7_LOCAL_BP_MASK; } #endif } From 5902564ac983d67d7d898356971698b50b8f0b91 Mon Sep 17 00:00:00 2001 From: liguang Date: Tue, 15 Jan 2013 08:01:07 +0100 Subject: [PATCH 0476/1634] target-i386: Introduce hw_{local,global}_breakpoint_enabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hw_breakpoint_enabled() returned a bit field indicating whether a local breakpoint and/or global breakpoint was enabled. Avoid this number magic by using explicit boolean helper functions hw_local_breakpoint_enabled() and hw_global_breakpoint_enabled(), to aid readability. Reuse them for the hw_breakpoint_enabled() implementation and change its return type to bool. While at it, fix Coding Style issues (missing braces). Signed-off-by: liguang Signed-off-by: Andreas Färber --- target-i386/cpu.h | 15 +++++++++++++-- target-i386/helper.c | 9 ++++++--- target-i386/seg_helper.c | 3 ++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 6682022d81..1e850a7538 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1014,9 +1014,20 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, #define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault void cpu_x86_set_a20(CPUX86State *env, int a20_state); -static inline int hw_breakpoint_enabled(unsigned long dr7, int index) +static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) { - return (dr7 >> (index * 2)) & 3; + return (dr7 >> (index * 2)) & 1; +} + +static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index) +{ + return (dr7 >> (index * 2)) & 2; + +} +static inline bool hw_breakpoint_enabled(unsigned long dr7, int index) +{ + return hw_global_breakpoint_enabled(dr7, index) || + hw_local_breakpoint_enabled(dr7, index); } static inline int hw_breakpoint_type(unsigned long dr7, int index) diff --git a/target-i386/helper.c b/target-i386/helper.c index 1fceb91d34..ebdd6a563a 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -970,9 +970,10 @@ void hw_breakpoint_insert(CPUX86State *env, int index) switch (hw_breakpoint_type(env->dr[7], index)) { case DR7_TYPE_BP_INST: - if (hw_breakpoint_enabled(env->dr[7], index)) + if (hw_breakpoint_enabled(env->dr[7], index)) { err = cpu_breakpoint_insert(env, env->dr[index], BP_CPU, &env->cpu_breakpoint[index]); + } break; case DR7_TYPE_DATA_WR: type = BP_CPU | BP_MEM_WRITE; @@ -998,8 +999,9 @@ void hw_breakpoint_remove(CPUX86State *env, int index) return; switch (hw_breakpoint_type(env->dr[7], index)) { case DR7_TYPE_BP_INST: - if (hw_breakpoint_enabled(env->dr[7], index)) + if (hw_breakpoint_enabled(env->dr[7], index)) { cpu_breakpoint_remove_by_ref(env, env->cpu_breakpoint[index]); + } break; case DR7_TYPE_DATA_WR: case DR7_TYPE_DATA_RW: @@ -1024,8 +1026,9 @@ int check_hw_breakpoints(CPUX86State *env, int force_dr6_update) ((type & 1) && env->cpu_watchpoint[reg] && (env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT))) { dr6 |= 1 << reg; - if (hw_breakpoint_enabled(env->dr[7], reg)) + if (hw_breakpoint_enabled(env->dr[7], reg)) { hit_enabled = 1; + } } } if (hit_enabled || force_dr6_update) diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index c40bd964c0..3247deeb60 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -467,7 +467,8 @@ static void switch_tss(CPUX86State *env, int tss_selector, /* reset local breakpoints */ if (env->dr[7] & DR7_LOCAL_BP_MASK) { for (i = 0; i < DR7_MAX_BP; i++) { - if (hw_breakpoint_enabled(env->dr[7], i) == 0x1) { + if (hw_local_breakpoint_enabled(env->dr[7], i) && + !hw_global_breakpoint_enabled(env->dr[7], i)) { hw_breakpoint_remove(env, i); } } From 1cc21a180b9ea9204e99ad5c58604cb458e572a9 Mon Sep 17 00:00:00 2001 From: liguang Date: Tue, 15 Jan 2013 08:24:02 +0100 Subject: [PATCH 0477/1634] target-i386: Avoid goto in hw_breakpoint_insert() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Go To Statement Considered Harmful" -- E. Dijkstra To avoid an unnecessary goto within the switch statement, move watchpoint insertion out of the switch statement. Improves readability. While at it, fix Coding Style issues (missing braces, indentation). Signed-off-by: liguang Signed-off-by: Andreas Färber --- target-i386/helper.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/target-i386/helper.c b/target-i386/helper.c index ebdd6a563a..a10b562bc9 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -966,7 +966,7 @@ hwaddr cpu_get_phys_page_debug(CPUX86State *env, target_ulong addr) void hw_breakpoint_insert(CPUX86State *env, int index) { - int type, err = 0; + int type = 0, err = 0; switch (hw_breakpoint_type(env->dr[7], index)) { case DR7_TYPE_BP_INST: @@ -977,20 +977,24 @@ void hw_breakpoint_insert(CPUX86State *env, int index) break; case DR7_TYPE_DATA_WR: type = BP_CPU | BP_MEM_WRITE; - goto insert_wp; + break; case DR7_TYPE_IO_RW: - /* No support for I/O watchpoints yet */ + /* No support for I/O watchpoints yet */ break; case DR7_TYPE_DATA_RW: type = BP_CPU | BP_MEM_ACCESS; - insert_wp: + break; + } + + if (type != 0) { err = cpu_watchpoint_insert(env, env->dr[index], hw_breakpoint_len(env->dr[7], index), type, &env->cpu_watchpoint[index]); - break; } - if (err) + + if (err) { env->cpu_breakpoint[index] = NULL; + } } void hw_breakpoint_remove(CPUX86State *env, int index) From e175bce587936bf479889881488821ea8d61c89c Mon Sep 17 00:00:00 2001 From: liguang Date: Tue, 15 Jan 2013 13:39:56 +0800 Subject: [PATCH 0478/1634] target-i386: Use switch in check_hw_breakpoints() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace an if statement using magic numbers for breakpoint type with a more explicit switch statement. This is to aid readability. Change the return type and force_dr6_update argument type to bool. While at it, fix Coding Style issues (missing braces). Signed-off-by: liguang Signed-off-by: Andreas Färber --- target-i386/cpu.h | 2 +- target-i386/helper.c | 44 ++++++++++++++++++++++++++++----------- target-i386/misc_helper.c | 2 +- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1e850a7538..4e091cdec3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1043,7 +1043,7 @@ static inline int hw_breakpoint_len(unsigned long dr7, int index) void hw_breakpoint_insert(CPUX86State *env, int index); void hw_breakpoint_remove(CPUX86State *env, int index); -int check_hw_breakpoints(CPUX86State *env, int force_dr6_update); +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update); void breakpoint_handler(CPUX86State *env); /* will be suppressed */ diff --git a/target-i386/helper.c b/target-i386/helper.c index a10b562bc9..547c25ee9d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1017,26 +1017,45 @@ void hw_breakpoint_remove(CPUX86State *env, int index) } } -int check_hw_breakpoints(CPUX86State *env, int force_dr6_update) +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update) { target_ulong dr6; - int reg, type; - int hit_enabled = 0; + int reg; + bool hit_enabled = false; dr6 = env->dr[6] & ~0xf; for (reg = 0; reg < DR7_MAX_BP; reg++) { - type = hw_breakpoint_type(env->dr[7], reg); - if ((type == 0 && env->dr[reg] == env->eip) || - ((type & 1) && env->cpu_watchpoint[reg] && - (env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT))) { + bool bp_match = false; + bool wp_match = false; + + switch (hw_breakpoint_type(env->dr[7], reg)) { + case DR7_TYPE_BP_INST: + if (env->dr[reg] == env->eip) { + bp_match = true; + } + break; + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: + if (env->cpu_watchpoint[reg] && + env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) { + wp_match = true; + } + break; + case DR7_TYPE_IO_RW: + break; + } + if (bp_match || wp_match) { dr6 |= 1 << reg; if (hw_breakpoint_enabled(env->dr[7], reg)) { - hit_enabled = 1; + hit_enabled = true; } } } - if (hit_enabled || force_dr6_update) + + if (hit_enabled || force_dr6_update) { env->dr[6] = dr6; + } + return hit_enabled; } @@ -1047,16 +1066,17 @@ void breakpoint_handler(CPUX86State *env) if (env->watchpoint_hit) { if (env->watchpoint_hit->flags & BP_CPU) { env->watchpoint_hit = NULL; - if (check_hw_breakpoints(env, 0)) + if (check_hw_breakpoints(env, false)) { raise_exception(env, EXCP01_DB); - else + } else { cpu_resume_from_signal(env, NULL); + } } } else { QTAILQ_FOREACH(bp, &env->breakpoints, entry) if (bp->pc == env->eip) { if (bp->flags & BP_CPU) { - check_hw_breakpoints(env, 1); + check_hw_breakpoints(env, true); raise_exception(env, EXCP01_DB); } break; diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index b3f4e4f27c..b6d574019a 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -110,7 +110,7 @@ void helper_into(CPUX86State *env, int next_eip_addend) void helper_single_step(CPUX86State *env) { #ifndef CONFIG_USER_ONLY - check_hw_breakpoints(env, 1); + check_hw_breakpoints(env, true); env->dr[6] |= DR6_BS; #endif raise_exception(env, EXCP01_DB); From 029d091e4975af60ff9622717af19c5910f2f4e9 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Fri, 11 Jan 2013 13:29:55 +0100 Subject: [PATCH 0479/1634] block: fix initialization in bdrv_io_limits_enable() bdrv_io_limits_enable() starts a new slice, but does not set io_base correctly for that slice. Here is how io_base is used: bytes_base = bs->nr_bytes[is_write] - bs->io_base.bytes[is_write]; bytes_res = (unsigned) nb_sectors * BDRV_SECTOR_SIZE; if (bytes_base + bytes_res <= bytes_limit) { /* no wait */ } else { /* operation needs to be throttled */ } As a result, any I/O operations that are triggered between now and bs->slice_end are incorrectly limited. If 10 MB of data has been written since the VM was started, QEMU thinks that 10 MB of data has been written in this slice. This leads to a I/O lockup in the guest. We fix this by delaying the start of a new slice to the next call of bdrv_exceed_io_limits(). Signed-off-by: Peter Lieven Reviewed-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/block.c b/block.c index b5e64ecf11..4a90dd1a78 100644 --- a/block.c +++ b/block.c @@ -155,10 +155,6 @@ void bdrv_io_limits_enable(BlockDriverState *bs) { qemu_co_queue_init(&bs->throttled_reqs); bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs); - bs->slice_time = 5 * BLOCK_IO_SLICE_TIME; - bs->slice_start = qemu_get_clock_ns(vm_clock); - bs->slice_end = bs->slice_start + bs->slice_time; - memset(&bs->io_base, 0, sizeof(bs->io_base)); bs->io_limits_enabled = true; } From 3d4fa43e648f3b169e7ab5dd4e21312e510805d7 Mon Sep 17 00:00:00 2001 From: Kusanagi Kouichi Date: Mon, 14 Jan 2013 16:26:52 +0100 Subject: [PATCH 0480/1634] raw-posix: support discard on more filesystems Linux 2.6.38 introduced the filesystem independent interface to deallocate part of a file. As of Linux 3.7, btrfs, ext4, ocfs2, tmpfs and xfs support it. Even though the system calls here are in practice issued on Linux, the code is structured to allow plugging in alternatives for other Unix variants. EOPNOTSUPP is used unconditionally in this patch, but it is supported in both OpenBSD and Mac OS X since forever (see for example http://lists.debian.org/debian-glibc/2006/02/msg00337.html). Signed-off-by: Kusanagi Kouichi Signed-off-by: Stefan Hajnoczi --- block/raw-posix.c | 26 ++++++++++++++++++++++++-- configure | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index c3d7fda7b7..e8d79afe5f 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -59,6 +59,9 @@ #ifdef CONFIG_FIEMAP #include #endif +#ifdef CONFIG_FALLOCATE_PUNCH_HOLE +#include +#endif #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include @@ -1074,15 +1077,34 @@ static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors) static coroutine_fn int raw_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { -#ifdef CONFIG_XFS + int ret = -EOPNOTSUPP; + +#if defined(CONFIG_FALLOCATE_PUNCH_HOLE) || defined(CONFIG_XFS) BDRVRawState *s = bs->opaque; +#ifdef CONFIG_XFS if (s->is_xfs) { return xfs_discard(s, sector_num, nb_sectors); } #endif - return 0; +#ifdef CONFIG_FALLOCATE_PUNCH_HOLE + do { + if (fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + sector_num << BDRV_SECTOR_BITS, + (int64_t)nb_sectors << BDRV_SECTOR_BITS) == 0) { + return 0; + } + } while (errno == EINTR); + + ret = -errno; +#endif +#endif + + if (ret == -EOPNOTSUPP) { + return 0; + } + return ret; } static QEMUOptionParameter raw_create_options[] = { diff --git a/configure b/configure index c908f66583..40d250ccac 100755 --- a/configure +++ b/configure @@ -2581,6 +2581,22 @@ if compile_prog "" "" ; then fallocate=yes fi +# check for fallocate hole punching +fallocate_punch_hole=no +cat > $TMPC << EOF +#include +#include + +int main(void) +{ + fallocate(0, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 0); + return 0; +} +EOF +if compile_prog "" "" ; then + fallocate_punch_hole=yes +fi + # check for sync_file_range sync_file_range=no cat > $TMPC << EOF @@ -3490,6 +3506,9 @@ fi if test "$fallocate" = "yes" ; then echo "CONFIG_FALLOCATE=y" >> $config_host_mak fi +if test "$fallocate_punch_hole" = "yes" ; then + echo "CONFIG_FALLOCATE_PUNCH_HOLE=y" >> $config_host_mak +fi if test "$sync_file_range" = "yes" ; then echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak fi From c85191e5c9e14d65cc4281ef3b31f480227aa6dd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Jan 2013 16:26:53 +0100 Subject: [PATCH 0481/1634] raw-posix: remember whether discard failed Avoid sending system calls repeatedly if they shall fail. This does not apply to XFS: if the filesystem-specific ioctl fails, something weird is happening. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/raw-posix.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index e8d79afe5f..b647cfbb2f 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -141,6 +141,7 @@ typedef struct BDRVRawState { #ifdef CONFIG_XFS bool is_xfs : 1; #endif + bool has_discard : 1; } BDRVRawState; typedef struct BDRVRawReopenState { @@ -292,6 +293,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, } #endif + s->has_discard = 1; #ifdef CONFIG_XFS if (platform_test_xfs_fd(s->fd)) { s->is_xfs = 1; @@ -1078,10 +1080,12 @@ static coroutine_fn int raw_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) { int ret = -EOPNOTSUPP; - -#if defined(CONFIG_FALLOCATE_PUNCH_HOLE) || defined(CONFIG_XFS) BDRVRawState *s = bs->opaque; + if (!s->has_discard) { + return 0; + } + #ifdef CONFIG_XFS if (s->is_xfs) { return xfs_discard(s, sector_num, nb_sectors); @@ -1098,7 +1102,6 @@ static coroutine_fn int raw_co_discard(BlockDriverState *bs, } while (errno == EINTR); ret = -errno; -#endif #endif if (ret == -EOPNOTSUPP) { From fcd9d4555252c47a337357dfce0806e5dde99d96 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Jan 2013 16:26:54 +0100 Subject: [PATCH 0482/1634] raw: support discard on block devices Block devices use a ioctl instead of fallocate, so add a separate implementation. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/raw-posix.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/block/raw-posix.c b/block/raw-posix.c index b647cfbb2f..1d32139c9b 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1345,6 +1345,40 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs, return thread_pool_submit_aio(aio_worker, acb, cb, opaque); } +static coroutine_fn int hdev_co_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors) +{ + BDRVRawState *s = bs->opaque; + int ret; + + if (s->has_discard == 0) { + return 0; + } + ret = fd_open(bs); + if (ret < 0) { + return ret; + } + + ret = -EOPNOTSUPP; +#ifdef BLKDISCARD + do { + uint64_t range[2] = { sector_num * 512, (uint64_t)nb_sectors * 512 }; + if (ioctl(s->fd, BLKDISCARD, range) == 0) { + return 0; + } + } while (errno == EINTR); + + ret = -errno; +#endif + if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP || + ret == -ENOTTY) { + s->has_discard = 0; + ret = 0; + } + return ret; + +} + #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) static int fd_open(BlockDriverState *bs) { @@ -1413,6 +1447,8 @@ static BlockDriver bdrv_host_device = { .create_options = raw_create_options, .bdrv_has_zero_init = hdev_has_zero_init, + .bdrv_co_discard = hdev_co_discard, + .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, .bdrv_aio_flush = raw_aio_flush, From 8238010b265886249f9f3d45e890788319b7736e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Jan 2013 16:26:55 +0100 Subject: [PATCH 0483/1634] block: make discard asynchronous This is easy with the thread pool, because we can use s->is_xfs and s->has_discard from the worker function. QEMU has a widespread assumption that each I/O operation writes less than 2^32 bytes. This patch doesn't fix it throughout of course, but it starts correcting struct RawPosixAIOData so that there is no regression with respect to the synchronous discard implementation. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/raw-aio.h | 5 +- block/raw-posix.c | 164 ++++++++++++++++++++++++---------------------- 2 files changed, 88 insertions(+), 81 deletions(-) diff --git a/block/raw-aio.h b/block/raw-aio.h index e77f361148..c61f1595d9 100644 --- a/block/raw-aio.h +++ b/block/raw-aio.h @@ -20,11 +20,14 @@ #define QEMU_AIO_WRITE 0x0002 #define QEMU_AIO_IOCTL 0x0004 #define QEMU_AIO_FLUSH 0x0008 +#define QEMU_AIO_DISCARD 0x0010 #define QEMU_AIO_TYPE_MASK \ - (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH) + (QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH| \ + QEMU_AIO_DISCARD) /* AIO flags */ #define QEMU_AIO_MISALIGNED 0x1000 +#define QEMU_AIO_BLKDEV 0x2000 /* linux-aio.c - Linux native implementation */ diff --git a/block/raw-posix.c b/block/raw-posix.c index 1d32139c9b..679fcc5113 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -163,7 +163,7 @@ typedef struct RawPosixAIOData { void *aio_ioctl_buf; }; int aio_niov; - size_t aio_nbytes; + uint64_t aio_nbytes; #define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */ off_t aio_offset; int aio_type; @@ -623,6 +623,72 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb) return nbytes; } +#ifdef CONFIG_XFS +static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes) +{ + struct xfs_flock64 fl; + + memset(&fl, 0, sizeof(fl)); + fl.l_whence = SEEK_SET; + fl.l_start = offset; + fl.l_len = bytes; + + if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) { + DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno)); + return -errno; + } + + return 0; +} +#endif + +static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb) +{ + int ret = -EOPNOTSUPP; + BDRVRawState *s = aiocb->bs->opaque; + + if (s->has_discard == 0) { + return 0; + } + + if (aiocb->aio_type & QEMU_AIO_BLKDEV) { +#ifdef BLKDISCARD + do { + uint64_t range[2] = { aiocb->aio_offset, aiocb->aio_nbytes }; + if (ioctl(aiocb->aio_fildes, BLKDISCARD, range) == 0) { + return 0; + } + } while (errno == EINTR); + + ret = -errno; +#endif + } else { +#ifdef CONFIG_XFS + if (s->is_xfs) { + return xfs_discard(s, aiocb->aio_offset, aiocb->aio_nbytes); + } +#endif + +#ifdef CONFIG_FALLOCATE_PUNCH_HOLE + do { + if (fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + aiocb->aio_offset, aiocb->aio_nbytes) == 0) { + return 0; + } + } while (errno == EINTR); + + ret = -errno; +#endif + } + + if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP || + ret == -ENOTTY) { + s->has_discard = 0; + ret = 0; + } + return ret; +} + static int aio_worker(void *arg) { RawPosixAIOData *aiocb = arg; @@ -657,6 +723,9 @@ static int aio_worker(void *arg) case QEMU_AIO_IOCTL: ret = handle_aiocb_ioctl(aiocb); break; + case QEMU_AIO_DISCARD: + ret = handle_aiocb_discard(aiocb); + break; default: fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); ret = -EINVAL; @@ -1057,57 +1126,14 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, } } -#ifdef CONFIG_XFS -static int xfs_discard(BDRVRawState *s, int64_t sector_num, int nb_sectors) +static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { - struct xfs_flock64 fl; - - memset(&fl, 0, sizeof(fl)); - fl.l_whence = SEEK_SET; - fl.l_start = sector_num << 9; - fl.l_len = (int64_t)nb_sectors << 9; - - if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) { - DEBUG_BLOCK_PRINT("cannot punch hole (%s)\n", strerror(errno)); - return -errno; - } - - return 0; -} -#endif - -static coroutine_fn int raw_co_discard(BlockDriverState *bs, - int64_t sector_num, int nb_sectors) -{ - int ret = -EOPNOTSUPP; BDRVRawState *s = bs->opaque; - if (!s->has_discard) { - return 0; - } - -#ifdef CONFIG_XFS - if (s->is_xfs) { - return xfs_discard(s, sector_num, nb_sectors); - } -#endif - -#ifdef CONFIG_FALLOCATE_PUNCH_HOLE - do { - if (fallocate(s->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, - sector_num << BDRV_SECTOR_BITS, - (int64_t)nb_sectors << BDRV_SECTOR_BITS) == 0) { - return 0; - } - } while (errno == EINTR); - - ret = -errno; -#endif - - if (ret == -EOPNOTSUPP) { - return 0; - } - return ret; + return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors, + cb, opaque, QEMU_AIO_DISCARD); } static QEMUOptionParameter raw_create_options[] = { @@ -1130,12 +1156,12 @@ static BlockDriver bdrv_file = { .bdrv_reopen_abort = raw_reopen_abort, .bdrv_close = raw_close, .bdrv_create = raw_create, - .bdrv_co_discard = raw_co_discard, .bdrv_co_is_allocated = raw_co_is_allocated, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, .bdrv_aio_flush = raw_aio_flush, + .bdrv_aio_discard = raw_aio_discard, .bdrv_truncate = raw_truncate, .bdrv_getlength = raw_getlength, @@ -1345,38 +1371,17 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs, return thread_pool_submit_aio(aio_worker, acb, cb, opaque); } -static coroutine_fn int hdev_co_discard(BlockDriverState *bs, - int64_t sector_num, int nb_sectors) +static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) { BDRVRawState *s = bs->opaque; - int ret; - if (s->has_discard == 0) { - return 0; + if (fd_open(bs) < 0) { + return NULL; } - ret = fd_open(bs); - if (ret < 0) { - return ret; - } - - ret = -EOPNOTSUPP; -#ifdef BLKDISCARD - do { - uint64_t range[2] = { sector_num * 512, (uint64_t)nb_sectors * 512 }; - if (ioctl(s->fd, BLKDISCARD, range) == 0) { - return 0; - } - } while (errno == EINTR); - - ret = -errno; -#endif - if (ret == -ENODEV || ret == -ENOSYS || ret == -EOPNOTSUPP || - ret == -ENOTTY) { - s->has_discard = 0; - ret = 0; - } - return ret; - + return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors, + cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -1447,11 +1452,10 @@ static BlockDriver bdrv_host_device = { .create_options = raw_create_options, .bdrv_has_zero_init = hdev_has_zero_init, - .bdrv_co_discard = hdev_co_discard, - .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, .bdrv_aio_flush = raw_aio_flush, + .bdrv_aio_discard = hdev_aio_discard, .bdrv_truncate = raw_truncate, .bdrv_getlength = raw_getlength, From 80bc2e8d807939bee89d1a5ca0dbe89946d39ed1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Jan 2013 16:26:56 +0100 Subject: [PATCH 0484/1634] ide: fix TRIM with empty range entry ATA-ACS-3 says "If the two byte range length is zero, then the LBA Range Entry shall be discarded as padding." iovecs are used as if they are linearized, so it is incorrect to discard the rest of this iovec. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- hw/ide/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 6f1938a0a8..cb77dfcd4e 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -374,7 +374,7 @@ BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, uint16_t count = entry >> 48; if (count == 0) { - break; + continue; } ret = bdrv_discard(bs, sector, count); From 501378c3af16e8e83a9dd500c11e594f4d1dbe79 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Jan 2013 16:26:57 +0100 Subject: [PATCH 0485/1634] ide: issue discard asynchronously but serialize the pieces Now that discard can take a long time, make it asynchronous. Each LBA range entry is processed separately because discard can be an expensive operation. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- hw/ide/core.c | 79 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index cb77dfcd4e..14ad0799c3 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -325,14 +325,26 @@ typedef struct TrimAIOCB { BlockDriverAIOCB common; QEMUBH *bh; int ret; + QEMUIOVector *qiov; + BlockDriverAIOCB *aiocb; + int i, j; } TrimAIOCB; static void trim_aio_cancel(BlockDriverAIOCB *acb) { TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common); + /* Exit the loop in case bdrv_aio_cancel calls ide_issue_trim_cb again. */ + iocb->j = iocb->qiov->niov - 1; + iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1; + + /* Tell ide_issue_trim_cb not to trigger the completion, too. */ qemu_bh_delete(iocb->bh); iocb->bh = NULL; + + if (iocb->aiocb) { + bdrv_aio_cancel(iocb->aiocb); + } qemu_aio_release(iocb); } @@ -349,43 +361,60 @@ static void ide_trim_bh_cb(void *opaque) qemu_bh_delete(iocb->bh); iocb->bh = NULL; - qemu_aio_release(iocb); } +static void ide_issue_trim_cb(void *opaque, int ret) +{ + TrimAIOCB *iocb = opaque; + if (ret >= 0) { + while (iocb->j < iocb->qiov->niov) { + int j = iocb->j; + while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) { + int i = iocb->i; + uint64_t *buffer = iocb->qiov->iov[j].iov_base; + + /* 6-byte LBA + 2-byte range per entry */ + uint64_t entry = le64_to_cpu(buffer[i]); + uint64_t sector = entry & 0x0000ffffffffffffULL; + uint16_t count = entry >> 48; + + if (count == 0) { + continue; + } + + /* Got an entry! Submit and exit. */ + iocb->aiocb = bdrv_aio_discard(iocb->common.bs, sector, count, + ide_issue_trim_cb, opaque); + return; + } + + iocb->j++; + iocb->i = -1; + } + } else { + iocb->ret = ret; + } + + iocb->aiocb = NULL; + if (iocb->bh) { + qemu_bh_schedule(iocb->bh); + } +} + BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque) { TrimAIOCB *iocb; - int i, j, ret; iocb = qemu_aio_get(&trim_aiocb_info, bs, cb, opaque); iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); iocb->ret = 0; - - for (j = 0; j < qiov->niov; j++) { - uint64_t *buffer = qiov->iov[j].iov_base; - - for (i = 0; i < qiov->iov[j].iov_len / 8; i++) { - /* 6-byte LBA + 2-byte range per entry */ - uint64_t entry = le64_to_cpu(buffer[i]); - uint64_t sector = entry & 0x0000ffffffffffffULL; - uint16_t count = entry >> 48; - - if (count == 0) { - continue; - } - - ret = bdrv_discard(bs, sector, count); - if (!iocb->ret) { - iocb->ret = ret; - } - } - } - - qemu_bh_schedule(iocb->bh); - + iocb->qiov = qiov; + iocb->i = -1; + iocb->j = 0; + ide_issue_trim_cb(iocb, 0); return &iocb->common; } From df702c9b4c1d049b12d7cf2f2ee607ff32f766cb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 14 Jan 2013 16:26:58 +0100 Subject: [PATCH 0486/1634] block: clear dirty bitmap when discarding Note that resetting bits in the dirty bitmap is done _before_ actually processing the request. Writes, instead, set bits after the request is completed. This way, when there are concurrent write and discard requests, the outcome will always be that the blocks are marked dirty. This scenario should never happen, but it is safer to do it this way. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 4a90dd1a78..6fa7c90144 100644 --- a/block.c +++ b/block.c @@ -4170,7 +4170,13 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, return -EIO; } else if (bs->read_only) { return -EROFS; - } else if (bs->drv->bdrv_co_discard) { + } + + if (bs->dirty_bitmap) { + set_dirty_bitmap(bs, sector_num, nb_sectors, 0); + } + + if (bs->drv->bdrv_co_discard) { return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors); } else if (bs->drv->bdrv_aio_discard) { BlockDriverAIOCB *acb; From a87eec766d99c33fc49ecc6dbce40f304168ac3f Mon Sep 17 00:00:00 2001 From: Alex Rozenman Date: Tue, 8 Jan 2013 01:28:02 +0200 Subject: [PATCH 0487/1634] Add libcacard/trace/generated-tracers.c to .gitignore Signed-off-by: Alex Rozenman Signed-off-by: Stefan Hajnoczi --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5fea65dc14..53fe9c3078 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ trace/generated-tracers.h trace/generated-tracers.c trace/generated-tracers-dtrace.h trace/generated-tracers-dtrace.dtrace +libcacard/trace/generated-tracers.c *-timestamp *-softmmu *-darwin-user From 3e84b4832180db2aa6187b6b971054bc3ca68be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 15 Jan 2013 02:55:10 +0100 Subject: [PATCH 0488/1634] qom: Make object_resolve_path_component() path argument const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A usage with a hardcoded partial path such as object_resolve_path_component(obj, "foo") is totally valid but currently leads to a compilation error. Fix this. Signed-off-by: Andreas Färber Signed-off-by: Stefan Hajnoczi --- include/qom/object.h | 2 +- qom/object.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index d43b289a40..1ef2f0edd4 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -900,7 +900,7 @@ Object *object_resolve_path_type(const char *path, const char *typename, * * Returns: The resolved object or NULL on path lookup failure. */ -Object *object_resolve_path_component(Object *parent, gchar *part); +Object *object_resolve_path_component(Object *parent, const gchar *part); /** * object_property_add_child: diff --git a/qom/object.c b/qom/object.c index 351b88c817..03e6f24d28 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1017,7 +1017,7 @@ gchar *object_get_canonical_path(Object *obj) return newpath; } -Object *object_resolve_path_component(Object *parent, gchar *part) +Object *object_resolve_path_component(Object *parent, const gchar *part) { ObjectProperty *prop = object_property_find(parent, part, NULL); if (prop == NULL) { From 477830727821e4bc337f4ac1fd222ffe0b900e1a Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Tue, 15 Jan 2013 16:28:55 +0800 Subject: [PATCH 0489/1634] sheepdog: multiplex the rw FD to flush cache This will reduce sockfds connected to the sheep server to one, which simply the future hacks. Cc: MORITA Kazutaka Cc: Kevin Wolf Cc: Stefan Hajnoczi Signed-off-by: Liu Yuan Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 82 ++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 462c4b2d5d..04661da2dd 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -266,6 +266,7 @@ typedef struct AIOReq { enum AIOCBState { AIOCB_WRITE_UDATA, AIOCB_READ_UDATA, + AIOCB_FLUSH_CACHE, }; struct SheepdogAIOCB { @@ -299,7 +300,6 @@ typedef struct BDRVSheepdogState { char *addr; char *port; int fd; - int flush_fd; CoMutex lock; Coroutine *co_send; @@ -736,6 +736,13 @@ static void coroutine_fn aio_read_response(void *opaque) goto out; } break; + case AIOCB_FLUSH_CACHE: + if (rsp.result == SD_RES_INVALID_PARMS) { + dprintf("disable cache since the server doesn't support it\n"); + s->cache_flags = SD_FLAG_CMD_DIRECT; + rsp.result = SD_RES_SUCCESS; + } + break; } if (rsp.result != SD_RES_SUCCESS) { @@ -950,7 +957,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, { int nr_copies = s->inode.nr_copies; SheepdogObjReq hdr; - unsigned int wlen; + unsigned int wlen = 0; int ret; uint64_t oid = aio_req->oid; unsigned int datalen = aio_req->data_len; @@ -964,18 +971,23 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, memset(&hdr, 0, sizeof(hdr)); - if (aiocb_type == AIOCB_READ_UDATA) { - wlen = 0; + switch (aiocb_type) { + case AIOCB_FLUSH_CACHE: + hdr.opcode = SD_OP_FLUSH_VDI; + break; + case AIOCB_READ_UDATA: hdr.opcode = SD_OP_READ_OBJ; hdr.flags = flags; - } else if (create) { + break; + case AIOCB_WRITE_UDATA: + if (create) { + hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ; + } else { + hdr.opcode = SD_OP_WRITE_OBJ; + } wlen = datalen; - hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ; - hdr.flags = SD_FLAG_CMD_WRITE | flags; - } else { - wlen = datalen; - hdr.opcode = SD_OP_WRITE_OBJ; hdr.flags = SD_FLAG_CMD_WRITE | flags; + break; } if (s->cache_flags) { @@ -1127,15 +1139,6 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) s->cache_flags = SD_FLAG_CMD_DIRECT; } - if (s->cache_flags == SD_FLAG_CMD_CACHE) { - s->flush_fd = connect_to_sdog(s->addr, s->port); - if (s->flush_fd < 0) { - error_report("failed to connect"); - ret = s->flush_fd; - goto out; - } - } - if (snapid || tag[0] != '\0') { dprintf("%" PRIx32 " snapshot inode was open.\n", vid); s->is_snapshot = true; @@ -1397,9 +1400,6 @@ static void sd_close(BlockDriverState *bs) qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); - if (s->cache_flags) { - closesocket(s->flush_fd); - } g_free(s->addr); } @@ -1711,39 +1711,31 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num, static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) { BDRVSheepdogState *s = bs->opaque; - SheepdogObjReq hdr = { 0 }; - SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr; - SheepdogInode *inode = &s->inode; + SheepdogAIOCB *acb; + AIOReq *aio_req; int ret; - unsigned int wlen = 0, rlen = 0; if (s->cache_flags != SD_FLAG_CMD_CACHE) { return 0; } - hdr.opcode = SD_OP_FLUSH_VDI; - hdr.oid = vid_to_vdi_oid(inode->vdi_id); + acb = sd_aio_setup(bs, NULL, 0, 0, NULL, NULL); + acb->aiocb_type = AIOCB_FLUSH_CACHE; + acb->aio_done_func = sd_finish_aiocb; - ret = do_req(s->flush_fd, (SheepdogReq *)&hdr, NULL, &wlen, &rlen); - if (ret) { - error_report("failed to send a request to the sheep"); + aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), + 0, 0, 0, 0, 0); + QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); + ret = add_aio_request(s, aio_req, NULL, 0, false, acb->aiocb_type); + if (ret < 0) { + error_report("add_aio_request is failed"); + free_aio_req(s, aio_req); + qemu_aio_release(acb); return ret; } - if (rsp->result == SD_RES_INVALID_PARMS) { - dprintf("disable write cache since the server doesn't support it\n"); - - s->cache_flags = SD_FLAG_CMD_DIRECT; - closesocket(s->flush_fd); - return 0; - } - - if (rsp->result != SD_RES_SUCCESS) { - error_report("%s", sd_strerror(rsp->result)); - return -EIO; - } - - return 0; + qemu_coroutine_yield(); + return acb->ret; } static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) From f700f8e3463b5d61383121fa6f79564d6132b10d Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Mon, 14 Jan 2013 14:01:03 +0800 Subject: [PATCH 0490/1634] sheepdog: clean up sd_aio_setup() The last two parameters of sd_aio_setup() are never used, so remove them. Cc: MORITA Kazutaka Cc: Kevin Wolf Cc: Stefan Hajnoczi Signed-off-by: Liu Yuan Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 04661da2dd..3e49bb83bb 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -427,12 +427,11 @@ static const AIOCBInfo sd_aiocb_info = { }; static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t sector_num, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) + int64_t sector_num, int nb_sectors) { SheepdogAIOCB *acb; - acb = qemu_aio_get(&sd_aiocb_info, bs, cb, opaque); + acb = qemu_aio_get(&sd_aiocb_info, bs, NULL, NULL); acb->qiov = qiov; @@ -1672,7 +1671,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, bs->total_sectors = sector_num + nb_sectors; } - acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL); + acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors); acb->aio_done_func = sd_write_done; acb->aiocb_type = AIOCB_WRITE_UDATA; @@ -1693,7 +1692,7 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num, SheepdogAIOCB *acb; int ret; - acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors, NULL, NULL); + acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors); acb->aiocb_type = AIOCB_READ_UDATA; acb->aio_done_func = sd_finish_aiocb; @@ -1719,7 +1718,7 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) return 0; } - acb = sd_aio_setup(bs, NULL, 0, 0, NULL, NULL); + acb = sd_aio_setup(bs, NULL, 0, 0); acb->aiocb_type = AIOCB_FLUSH_CACHE; acb->aio_done_func = sd_finish_aiocb; From 94c8ff3a01d9bd1005f066a0ee3fe43c842a43b7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Jan 2013 14:23:37 +0100 Subject: [PATCH 0491/1634] w32: Make qemu_vfree() accept NULL like the POSIX implementation On POSIX, qemu_vfree() accepts NULL, because it's merely wrapper around free(). As far as I can tell, the Windows implementation doesn't. Breeds bugs that bite only under Windows. Make the Windows implementation behave like the POSIX implementation. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- util/oslib-win32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/oslib-win32.c b/util/oslib-win32.c index e7e283e875..640194c0cf 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -71,7 +71,9 @@ void *qemu_vmalloc(size_t size) void qemu_vfree(void *ptr) { trace_qemu_vfree(ptr); - VirtualFree(ptr, 0, MEM_RELEASE); + if (ptr) { + VirtualFree(ptr, 0, MEM_RELEASE); + } } /* FIXME: add proper locking */ From db4c34c3df5107ec4900ff07f70c540479a7eeca Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Jan 2013 14:23:38 +0100 Subject: [PATCH 0492/1634] scsi-disk: qemu_vfree(NULL) is fine, simplify Signed-off-by: Markus Armbruster Acked-by: Paolo Bonzini Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- hw/scsi-disk.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index f8d7ef3374..96db9a73c7 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -85,9 +85,7 @@ static void scsi_free_request(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - if (r->iov.iov_base) { - qemu_vfree(r->iov.iov_base); - } + qemu_vfree(r->iov.iov_base); } /* Helper function for command completion with sense. */ From 7479acdbce2ecf6cbd0b7d72b81608c8fc51b1ae Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Jan 2013 14:23:39 +0100 Subject: [PATCH 0493/1634] win32-aio: Fix how win32_aio_process_completion() frees buffer win32_aio_submit() allocates it with qemu_blockalign(), therefore it must be freed with qemu_vfree(), not g_free(). Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/win32-aio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/win32-aio.c b/block/win32-aio.c index 46a5db78cc..03833700b4 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -87,7 +87,7 @@ static void win32_aio_process_completion(QEMUWin32AIOState *s, memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len); p += qiov->iov[i].iov_len; } - g_free(waiocb->buf); + qemu_vfree(waiocb->buf); } } From 7191bf311ea9722cdcc3b2229788eff69d896bd0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Jan 2013 15:29:10 +0100 Subject: [PATCH 0494/1634] block: Fix how mirror_run() frees its buffer It allocates with qemu_blockalign(), therefore it must free with qemu_vfree(), not g_free(). Signed-off-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- block/mirror.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/mirror.c b/block/mirror.c index 8aeacbf12c..6180aa30e5 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -225,7 +225,7 @@ static void coroutine_fn mirror_run(void *opaque) } immediate_exit: - g_free(s->buf); + qemu_vfree(s->buf); bdrv_set_dirty_tracking(bs, false); bdrv_iostatus_disable(s->target); if (s->should_complete && ret == 0) { From ecbe251fa0eb4905c4a82c887e37057243b9fbad Mon Sep 17 00:00:00 2001 From: Vadim Evard Date: Tue, 15 Jan 2013 16:17:24 +0400 Subject: [PATCH 0495/1634] configure: try pkg-config for curses Static linkikng against ncurses may require explicit -ltinfo. In case -lcurses and -lncurses both didn't work give pkg-config a chance. Fixes #1094786 for me. Signed-off-by: Vadim Evard Signed-off-by: Stefan Hajnoczi --- configure | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure b/configure index c908f66583..40473a9bd7 100755 --- a/configure +++ b/configure @@ -2039,7 +2039,7 @@ fi if test "$mingw32" = "yes" ; then curses_list="-lpdcurses" else - curses_list="-lncurses -lcurses" + curses_list="-lncurses:-lcurses:$($pkg_config --libs ncurses)" fi if test "$curses" != "no" ; then @@ -2052,13 +2052,16 @@ int main(void) { return s != 0; } EOF + IFS=: for curses_lib in $curses_list; do + unset IFS if compile_prog "" "$curses_lib" ; then curses_found=yes libs_softmmu="$curses_lib $libs_softmmu" break fi done + unset IFS if test "$curses_found" = "yes" ; then curses=yes else From ecd584b836937eb45f7e7e487595002486a09cb7 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Wed, 19 Dec 2012 12:09:21 +0000 Subject: [PATCH 0496/1634] hw/dma.c: Fix conversion of ioport_register* to MemoryRegion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit 582299336879504353e60c7937fbc70fea93f3da introduced a 1-shift for some offset in DMA emulation. Before the previous commit, which converted ioport_register_* to MemoryRegion, the DMA controller registered 8 ioports with the following formula: base + ((8 + i) << d->shift) where 0 <= i < 8 When an IO occured within a Memory Region, DMA callback receives an offset relative to the start address. Here the start address is: base + (8 << d->shift). The offset should be: (i << d->shift). After the shift is reverted, the offsets are 0..7 not 1..8. Fixes LP#1089996. Reported-by: Andreas Gustafsson Signed-off-by: Julien Grall Tested-by: Stefan Hajnoczi Signed-off-by: Andreas Färber --- hw/dma.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/dma.c b/hw/dma.c index 0634baa552..5bdf4358e3 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -201,7 +201,7 @@ static void write_cont(void *opaque, hwaddr nport, uint64_t data, iport = (nport >> d->dshift) & 0x0f; switch (iport) { - case 0x01: /* command */ + case 0x00: /* command */ if ((data != 0) && (data & CMD_NOT_SUPPORTED)) { dolog("command %"PRIx64" not supported\n", data); return; @@ -209,7 +209,7 @@ static void write_cont(void *opaque, hwaddr nport, uint64_t data, d->command = data; break; - case 0x02: + case 0x01: ichan = data & 3; if (data & 4) { d->status |= 1 << (ichan + 4); @@ -221,7 +221,7 @@ static void write_cont(void *opaque, hwaddr nport, uint64_t data, DMA_run(); break; - case 0x03: /* single mask */ + case 0x02: /* single mask */ if (data & 4) d->mask |= 1 << (data & 3); else @@ -229,7 +229,7 @@ static void write_cont(void *opaque, hwaddr nport, uint64_t data, DMA_run(); break; - case 0x04: /* mode */ + case 0x03: /* mode */ { ichan = data & 3; #ifdef DEBUG_DMA @@ -248,23 +248,23 @@ static void write_cont(void *opaque, hwaddr nport, uint64_t data, break; } - case 0x05: /* clear flip flop */ + case 0x04: /* clear flip flop */ d->flip_flop = 0; break; - case 0x06: /* reset */ + case 0x05: /* reset */ d->flip_flop = 0; d->mask = ~0; d->status = 0; d->command = 0; break; - case 0x07: /* clear mask for all channels */ + case 0x06: /* clear mask for all channels */ d->mask = 0; DMA_run(); break; - case 0x08: /* write mask for all channels */ + case 0x07: /* write mask for all channels */ d->mask = data; DMA_run(); break; @@ -289,11 +289,11 @@ static uint64_t read_cont(void *opaque, hwaddr nport, unsigned size) iport = (nport >> d->dshift) & 0x0f; switch (iport) { - case 0x08: /* status */ + case 0x00: /* status */ val = d->status; d->status &= 0xf0; break; - case 0x0f: /* mask */ + case 0x01: /* mask */ val = d->mask; break; default: @@ -468,7 +468,7 @@ void DMA_schedule(int nchan) static void dma_reset(void *opaque) { struct dma_cont *d = opaque; - write_cont(d, (0x06 << d->dshift), 0, 1); + write_cont(d, (0x05 << d->dshift), 0, 1); } static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) From 7a652efa1b55ea671125696aabf8f1bd6e9a97f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Fri, 4 Jan 2013 22:29:40 +0100 Subject: [PATCH 0497/1634] xen_platform: Do not use old_portio-style callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hervé Poussineau Signed-off-by: Andreas Färber --- hw/xen_platform.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/hw/xen_platform.c b/hw/xen_platform.c index ca66047d82..8866468c99 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -279,7 +279,8 @@ static void platform_fixed_ioport_init(PCIXenPlatformState* s) /* Xen Platform PCI Device */ -static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr) +static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr, + unsigned int size) { if (addr == 0) { return platform_fixed_ioport_readb(opaque, 0); @@ -288,30 +289,28 @@ static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr) } } -static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void xen_platform_ioport_writeb(void *opaque, hwaddr addr, + uint64_t val, unsigned int size) { PCIXenPlatformState *s = opaque; switch (addr) { case 0: /* Platform flags */ - platform_fixed_ioport_writeb(opaque, 0, val); + platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val); break; case 8: - log_writeb(s, val); + log_writeb(s, (uint32_t)val); break; default: break; } } -static MemoryRegionPortio xen_pci_portio[] = { - { 0, 0x100, 1, .read = xen_platform_ioport_readb, }, - { 0, 0x100, 1, .write = xen_platform_ioport_writeb, }, - PORTIO_END_OF_LIST() -}; - static const MemoryRegionOps xen_pci_io_ops = { - .old_portio = xen_pci_portio, + .read = xen_platform_ioport_readb, + .write = xen_platform_ioport_writeb, + .impl.min_access_size = 1, + .impl.max_access_size = 1, }; static void platform_ioport_bar_setup(PCIXenPlatformState *d) From c3a29809e4d8924a0cfffd7f1af3c2f3c46f5889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Fri, 4 Jan 2013 22:29:41 +0100 Subject: [PATCH 0498/1634] acpi_piix4: Do not use old_portio-style callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hervé Poussineau [AF: Used HWADDR_PRIx for hwaddr PIIX4_DPRINTF()] Signed-off-by: Andreas Färber --- hw/acpi_piix4.c | 90 ++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 2f84b4ed4c..0d33849e95 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -531,68 +531,58 @@ static const MemoryRegionOps piix4_gpe_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static uint32_t pci_up_read(void *opaque, uint32_t addr) +static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size) { PIIX4PMState *s = opaque; - uint32_t val; + uint32_t val = 0; - /* Manufacture an "up" value to cause a device check on any hotplug - * slot with a device. Extra device checks are harmless. */ - val = s->pci0_slot_device_present & s->pci0_hotplug_enable; + switch (addr) { + case PCI_UP_BASE - PCI_HOTPLUG_ADDR: + /* Manufacture an "up" value to cause a device check on any hotplug + * slot with a device. Extra device checks are harmless. */ + val = s->pci0_slot_device_present & s->pci0_hotplug_enable; + PIIX4_DPRINTF("pci_up_read %x\n", val); + break; + case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR: + val = s->pci0_status.down; + PIIX4_DPRINTF("pci_down_read %x\n", val); + break; + case PCI_EJ_BASE - PCI_HOTPLUG_ADDR: + /* No feature defined yet */ + PIIX4_DPRINTF("pci_features_read %x\n", val); + break; + case PCI_RMV_BASE - PCI_HOTPLUG_ADDR: + val = s->pci0_hotplug_enable; + break; + default: + break; + } - PIIX4_DPRINTF("pci_up_read %x\n", val); return val; } -static uint32_t pci_down_read(void *opaque, uint32_t addr) +static void pci_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { - PIIX4PMState *s = opaque; - uint32_t val = s->pci0_status.down; - - PIIX4_DPRINTF("pci_down_read %x\n", val); - return val; -} - -static uint32_t pci_features_read(void *opaque, uint32_t addr) -{ - /* No feature defined yet */ - PIIX4_DPRINTF("pci_features_read %x\n", 0); - return 0; -} - -static void pciej_write(void *opaque, uint32_t addr, uint32_t val) -{ - acpi_piix_eject_slot(opaque, val); - - PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val); -} - -static uint32_t pcirmv_read(void *opaque, uint32_t addr) -{ - PIIX4PMState *s = opaque; - - return s->pci0_hotplug_enable; + switch (addr) { + case PCI_EJ_BASE - PCI_HOTPLUG_ADDR: + acpi_piix_eject_slot(opaque, (uint32_t)data); + PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== % " PRIu64 "\n", + addr, data); + break; + default: + break; + } } static const MemoryRegionOps piix4_pci_ops = { - .old_portio = (MemoryRegionPortio[]) { - { - .offset = PCI_UP_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, - .read = pci_up_read, - },{ - .offset = PCI_DOWN_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, - .read = pci_down_read, - },{ - .offset = PCI_EJ_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, - .read = pci_features_read, - .write = pciej_write, - },{ - .offset = PCI_RMV_BASE - PCI_HOTPLUG_ADDR, .len = 4, .size = 4, - .read = pcirmv_read, - }, - PORTIO_END_OF_LIST() - }, + .read = pci_read, + .write = pci_write, .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, From dabe3143e0f36a78a65c0dce1e298e31df1be6c4 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 15 Jan 2013 19:50:13 +0200 Subject: [PATCH 0499/1634] kvm: add stub for kvm_irqchip_update_msi_route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ppc64 build needs this stub to build with virtio enabled. Signed-off-by: Michael S. Tsirkin Tested-by: Andreas Färber Signed-off-by: Anthony Liguori --- kvm-all.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kvm-all.c b/kvm-all.c index 6e2164bec2..6278d615b1 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1181,6 +1181,11 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign) { abort(); } + +int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg) +{ + return -ENOSYS; +} #endif /* !KVM_CAP_IRQ_ROUTING */ int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n, int virq) From cc69bda6c97a1c193348eb381f4bffdfd1c8a948 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Jan 2013 15:42:32 +0100 Subject: [PATCH 0500/1634] sdl: Fix heap smash in sdl_zoom_rgb{16,32} for int > 32 bits Careless use of malloc(): allocate Uint32[N], assign to int *, use int[N]. Fix by converting to g_new(). Functions can't fail anymore, so make them return void. Caller ignored the value anyway. Signed-off-by: Markus Armbruster Signed-off-by: Anthony Liguori --- ui/sdl_zoom.c | 9 +++++---- ui/sdl_zoom_template.h | 16 +++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/ui/sdl_zoom.c b/ui/sdl_zoom.c index 122027cb36..2625c4557e 100644 --- a/ui/sdl_zoom.c +++ b/ui/sdl_zoom.c @@ -13,13 +13,14 @@ #include "sdl_zoom.h" #include "qemu/osdep.h" +#include #include #include -static int sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth, - SDL_Rect *dst_rect); -static int sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth, - SDL_Rect *dst_rect); +static void sdl_zoom_rgb16(SDL_Surface *src, SDL_Surface *dst, int smooth, + SDL_Rect *dst_rect); +static void sdl_zoom_rgb32(SDL_Surface *src, SDL_Surface *dst, int smooth, + SDL_Rect *dst_rect); #define BPP 32 #include "sdl_zoom_template.h" diff --git a/ui/sdl_zoom_template.h b/ui/sdl_zoom_template.h index 64bbca849b..3bb508b51e 100644 --- a/ui/sdl_zoom_template.h +++ b/ui/sdl_zoom_template.h @@ -51,7 +51,7 @@ (((a) & (dpf->Amask >> dpf->Ashift)) << dpf->Ashift); \ } while (0); -static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smooth, +static void glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smooth, SDL_Rect *dst_rect) { int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep, sstep_jump; @@ -71,13 +71,8 @@ static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smoot sy = (int) (65536.0 * (float) src->h / (float) dst->h); } - if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) { - return (-1); - } - if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) { - free(sax); - return (-1); - } + sax = g_new(int, dst->w + 1); + say = g_new(int, dst->h + 1); sp = csp = (SDL_TYPE *) src->pixels; dp = (SDL_TYPE *) (dst->pixels + dst_rect->y * dst->pitch + @@ -216,9 +211,8 @@ static int glue(sdl_zoom_rgb, BPP)(SDL_Surface *src, SDL_Surface *dst, int smoot } } - free(sax); - free(say); - return (0); + g_free(sax); + g_free(say); } #undef SDL_TYPE From c23c15d30b901bb447cdcada96cae64c0046d146 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Jan 2013 15:24:15 +0100 Subject: [PATCH 0501/1634] acl: Fix acl_remove not to mess up the ACL It leaks memory and fails to adjust qemu_acl member nentries. Future acl_add become confused: can misreport the position, and can silently fail to add. Cc: qemu-stable@nongnu.org Signed-off-by: Markus Armbruster Signed-off-by: Anthony Liguori --- util/acl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/acl.c b/util/acl.c index 81ac25599b..21b2205fa1 100644 --- a/util/acl.c +++ b/util/acl.c @@ -168,6 +168,9 @@ int qemu_acl_remove(qemu_acl *acl, i++; if (strcmp(entry->match, match) == 0) { QTAILQ_REMOVE(&acl->entries, entry, next); + acl->nentries--; + g_free(entry->match); + g_free(entry); return i; } } From 038794cfe1c0eece8968418077e4af601acd5aff Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 15 Jan 2013 15:24:16 +0100 Subject: [PATCH 0502/1634] acl: Free memory allocated with g_malloc() with g_free() Signed-off-by: Markus Armbruster Signed-off-by: Anthony Liguori --- util/acl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/acl.c b/util/acl.c index 21b2205fa1..a7f33ff7bb 100644 --- a/util/acl.c +++ b/util/acl.c @@ -103,8 +103,8 @@ void qemu_acl_reset(qemu_acl *acl) acl->defaultDeny = 1; QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) { QTAILQ_REMOVE(&acl->entries, entry, next); - free(entry->match); - free(entry); + g_free(entry->match); + g_free(entry); } acl->nentries = 0; } From e4ada29e909787f629626660b1561f6a680187d3 Mon Sep 17 00:00:00 2001 From: Avik Sil Date: Tue, 8 Jan 2013 12:36:30 +0530 Subject: [PATCH 0503/1634] Make default boot order machine specific This patch makes default boot order machine specific instead of set globally. The default boot order can be set per machine in QEMUMachine boot_order. This also allows a machine to receive a NULL boot order when -boot isn't used and take an appropriate action accordingly. This helps machine boots from the devices as set in guest's non-volatile memory location in case no boot order is provided by the user. Reviewed-by: Anthony Liguori Signed-off-by: Avik Sil Signed-off-by: Anthony Liguori --- hw/alpha_dp264.c | 1 + hw/an5206.c | 1 + hw/axis_dev88.c | 1 + hw/boards.h | 4 ++++ hw/collie.c | 1 + hw/dummy_m68k.c | 1 + hw/exynos4_boards.c | 2 ++ hw/gumstix.c | 2 ++ hw/highbank.c | 1 + hw/integratorcp.c | 1 + hw/kzm.c | 1 + hw/leon3.c | 1 + hw/lm32_boards.c | 6 ++++-- hw/mainstone.c | 1 + hw/mcf5208.c | 1 + hw/milkymist.c | 3 ++- hw/mips_fulong2e.c | 1 + hw/mips_jazz.c | 2 ++ hw/mips_malta.c | 1 + hw/mips_mipssim.c | 1 + hw/mips_r4k.c | 1 + hw/musicpal.c | 1 + hw/nseries.c | 2 ++ hw/null-machine.c | 1 + hw/omap_sx1.c | 2 ++ hw/openrisc_sim.c | 1 + hw/palm.c | 1 + hw/pc_piix.c | 13 +++++++++++++ hw/petalogix_ml605_mmu.c | 3 ++- hw/petalogix_s3adsp1800_mmu.c | 3 ++- hw/ppc/e500plat.c | 1 + hw/ppc/mpc8544ds.c | 1 + hw/ppc405_boards.c | 1 + hw/ppc440_bamboo.c | 1 + hw/ppc_newworld.c | 1 + hw/ppc_oldworld.c | 1 + hw/ppc_prep.c | 1 + hw/puv3.c | 1 + hw/r2d.c | 1 + hw/realview.c | 4 ++++ hw/s390-virtio.c | 1 + hw/shix.c | 1 + hw/spapr.c | 1 + hw/spitz.c | 4 ++++ hw/stellaris.c | 2 ++ hw/sun4m.c | 12 ++++++++++++ hw/sun4u.c | 3 +++ hw/tosa.c | 1 + hw/versatilepb.c | 2 ++ hw/vexpress.c | 2 ++ hw/virtex_ml507.c | 1 + hw/xen_machine_pv.c | 1 + hw/xilinx_zynq.c | 3 ++- hw/xtensa_lx60.c | 2 ++ hw/xtensa_sim.c | 1 + hw/z2.c | 1 + vl.c | 6 ++++-- 57 files changed, 110 insertions(+), 8 deletions(-) diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index e2980e9893..1cd549c69f 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -171,6 +171,7 @@ static QEMUMachine clipper_machine = { .init = clipper_init, .max_cpus = 4, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void clipper_machine_init(void) diff --git a/hw/an5206.c b/hw/an5206.c index dcfe34b3ae..750115a3aa 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -86,6 +86,7 @@ static QEMUMachine an5206_machine = { .name = "an5206", .desc = "Arnewsh 5206", .init = an5206_init, + DEFAULT_MACHINE_OPTIONS, }; static void an5206_machine_init(void) diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index 2ca606b835..941898158c 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -355,6 +355,7 @@ static QEMUMachine axisdev88_machine = { .desc = "AXIS devboard 88", .init = axisdev88_init, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void axisdev88_machine_init(void) diff --git a/hw/boards.h b/hw/boards.h index 4540e952f7..3ff9665b1f 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -6,6 +6,9 @@ #include "sysemu/blockdev.h" #include "qdev.h" +#define DEFAULT_MACHINE_OPTIONS \ + .boot_order = "cad" + typedef struct QEMUMachineInitArgs { ram_addr_t ram_size; const char *boot_device; @@ -35,6 +38,7 @@ typedef struct QEMUMachine { no_sdcard:1; int is_default; const char *default_machine_opts; + const char *boot_order; GlobalProperty *compat_props; struct QEMUMachine *next; const char *hw_version; diff --git a/hw/collie.c b/hw/collie.c index 804d61a421..d19db590fe 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -62,6 +62,7 @@ static QEMUMachine collie_machine = { .name = "collie", .desc = "Collie PDA (SA-1110)", .init = collie_init, + DEFAULT_MACHINE_OPTIONS, }; static void collie_machine_init(void) diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 7878cc3e15..3a88805d0f 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -73,6 +73,7 @@ static QEMUMachine dummy_m68k_machine = { .name = "dummy", .desc = "Dummy board", .init = dummy_m68k_init, + DEFAULT_MACHINE_OPTIONS, }; static void dummy_m68k_machine_init(void) diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index b26796847b..968bcc3c32 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -150,12 +150,14 @@ static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS] = { .desc = "Samsung NURI board (Exynos4210)", .init = nuri_init, .max_cpus = EXYNOS4210_NCPUS, + DEFAULT_MACHINE_OPTIONS, }, [EXYNOS4_BOARD_SMDKC210] = { .name = "smdkc210", .desc = "Samsung SMDKC210 board (Exynos4210)", .init = smdkc210_init, .max_cpus = EXYNOS4210_NCPUS, + DEFAULT_MACHINE_OPTIONS, }, }; diff --git a/hw/gumstix.c b/hw/gumstix.c index 6fb068386c..bea16058f7 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -122,12 +122,14 @@ static QEMUMachine connex_machine = { .name = "connex", .desc = "Gumstix Connex (PXA255)", .init = connex_init, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine verdex_machine = { .name = "verdex", .desc = "Gumstix Verdex (PXA270)", .init = verdex_init, + DEFAULT_MACHINE_OPTIONS, }; static void gumstix_machine_init(void) diff --git a/hw/highbank.c b/hw/highbank.c index 98deca8bce..7bc6b444cc 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -331,6 +331,7 @@ static QEMUMachine highbank_machine = { .init = highbank_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static void highbank_machine_init(void) diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 6c824dc36e..9e3630a43d 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -512,6 +512,7 @@ static QEMUMachine integratorcp_machine = { .desc = "ARM Integrator/CP (ARM926EJ-S)", .init = integratorcp_init, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void integratorcp_machine_init(void) diff --git a/hw/kzm.c b/hw/kzm.c index fd00af921e..fb3316551d 100644 --- a/hw/kzm.c +++ b/hw/kzm.c @@ -146,6 +146,7 @@ static QEMUMachine kzm_machine = { .name = "kzm", .desc = "ARM KZM Emulation Baseboard (ARM1136)", .init = kzm_init, + DEFAULT_MACHINE_OPTIONS, }; static void kzm_machine_init(void) diff --git a/hw/leon3.c b/hw/leon3.c index 79b3a41def..f16a8bb4ec 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -212,6 +212,7 @@ static QEMUMachine leon3_generic_machine = { .name = "leon3_generic", .desc = "Leon-3 generic", .init = leon3_generic_hw_init, + DEFAULT_MACHINE_OPTIONS, }; static void leon3_machine_init(void) diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index 42e8b6b52a..2bc06d7b7b 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -287,14 +287,16 @@ static QEMUMachine lm32_evr_machine = { .name = "lm32-evr", .desc = "LatticeMico32 EVR32 eval system", .init = lm32_evr_init, - .is_default = 1 + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine lm32_uclinux_machine = { .name = "lm32-uclinux", .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems", .init = lm32_uclinux_init, - .is_default = 0 + .is_default = 0, + DEFAULT_MACHINE_OPTIONS, }; static void lm32_machine_init(void) diff --git a/hw/mainstone.c b/hw/mainstone.c index a5ddbeff9d..d1ff6e76d6 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -179,6 +179,7 @@ static QEMUMachine mainstone2_machine = { .name = "mainstone", .desc = "Mainstone II (PXA27x)", .init = mainstone_init, + DEFAULT_MACHINE_OPTIONS, }; static void mainstone_machine_init(void) diff --git a/hw/mcf5208.c b/hw/mcf5208.c index c1816cc9d1..2c9a5dc98a 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -292,6 +292,7 @@ static QEMUMachine mcf5208evb_machine = { .desc = "MCF5206EVB", .init = mcf5208evb_init, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void mcf5208evb_machine_init(void) diff --git a/hw/milkymist.c b/hw/milkymist.c index 0c23b672f3..c04eb35fdd 100644 --- a/hw/milkymist.c +++ b/hw/milkymist.c @@ -206,7 +206,8 @@ static QEMUMachine milkymist_machine = { .name = "milkymist", .desc = "Milkymist One", .init = milkymist_init, - .is_default = 0 + .is_default = 0, + DEFAULT_MACHINE_OPTIONS, }; static void milkymist_machine_init(void) diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 4d8ee8c09c..8b532e1e0d 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -400,6 +400,7 @@ static QEMUMachine mips_fulong2e_machine = { .name = "fulong2e", .desc = "Fulong 2e mini pc", .init = mips_fulong2e_init, + DEFAULT_MACHINE_OPTIONS, }; static void mips_fulong2e_machine_init(void) diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 63df2a734b..72f70cae52 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -325,6 +325,7 @@ static QEMUMachine mips_magnum_machine = { .desc = "MIPS Magnum", .init = mips_magnum_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine mips_pica61_machine = { @@ -332,6 +333,7 @@ static QEMUMachine mips_pica61_machine = { .desc = "Acer Pica 61", .init = mips_pica61_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static void mips_jazz_machine_init(void) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 771d1256d7..2a150dfb84 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -1020,6 +1020,7 @@ static QEMUMachine mips_malta_machine = { .init = mips_malta_init, .max_cpus = 16, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void mips_malta_register_types(void) diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 67066c0ca1..8fd6692e82 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -229,6 +229,7 @@ static QEMUMachine mips_mipssim_machine = { .name = "mipssim", .desc = "MIPS MIPSsim platform", .init = mips_mipssim_init, + DEFAULT_MACHINE_OPTIONS, }; static void mips_mipssim_machine_init(void) diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 59c43e591c..5df7eb4469 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -302,6 +302,7 @@ static QEMUMachine mips_machine = { .name = "mips", .desc = "mips r4k platform", .init = mips_r4k_init, + DEFAULT_MACHINE_OPTIONS, }; static void mips_machine_init(void) diff --git a/hw/musicpal.c b/hw/musicpal.c index 24a1722703..035865f058 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1658,6 +1658,7 @@ static QEMUMachine musicpal_machine = { .name = "musicpal", .desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)", .init = musicpal_init, + DEFAULT_MACHINE_OPTIONS, }; static void musicpal_machine_init(void) diff --git a/hw/nseries.c b/hw/nseries.c index d96b750ccd..6b717cfe1e 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -1411,12 +1411,14 @@ static QEMUMachine n800_machine = { .name = "n800", .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)", .init = n800_init, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine n810_machine = { .name = "n810", .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)", .init = n810_init, + DEFAULT_MACHINE_OPTIONS, }; static void nseries_machine_init(void) diff --git a/hw/null-machine.c b/hw/null-machine.c index d813c089e7..bdf109fef1 100644 --- a/hw/null-machine.c +++ b/hw/null-machine.c @@ -24,6 +24,7 @@ static QEMUMachine machine_none = { .desc = "empty machine", .init = machine_none_init, .max_cpus = 0, + DEFAULT_MACHINE_OPTIONS, }; static void register_machines(void) diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 0f03121505..30998c5ff3 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -219,12 +219,14 @@ static QEMUMachine sx1_machine_v2 = { .name = "sx1", .desc = "Siemens SX1 (OMAP310) V2", .init = sx1_init_v2, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine sx1_machine_v1 = { .name = "sx1-v1", .desc = "Siemens SX1 (OMAP310) V1", .init = sx1_init_v1, + DEFAULT_MACHINE_OPTIONS, }; static void sx1_machine_init(void) diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index d2b2379ae2..fb47cdc82d 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -139,6 +139,7 @@ static QEMUMachine openrisc_sim_machine = { .init = openrisc_sim_init, .max_cpus = 1, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void openrisc_sim_machine_init(void) diff --git a/hw/palm.c b/hw/palm.c index 5219e37394..a633dfc4b1 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -280,6 +280,7 @@ static QEMUMachine palmte_machine = { .name = "cheetah", .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)", .init = palmte_init, + DEFAULT_MACHINE_OPTIONS, }; static void palmte_machine_init(void) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index e630aeab9d..0a6923dcef 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -289,6 +289,7 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { .init = pc_init_pci_1_3, .max_cpus = 255, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_1_3 \ @@ -307,6 +308,7 @@ static QEMUMachine pc_machine_v1_3 = { PC_COMPAT_1_3, { /* end of list */ } }, + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_1_2 \ @@ -346,6 +348,7 @@ static QEMUMachine pc_machine_v1_2 = { PC_COMPAT_1_2, { /* end of list */ } }, + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_1_1 \ @@ -389,6 +392,7 @@ static QEMUMachine pc_machine_v1_1 = { PC_COMPAT_1_1, { /* end of list */ } }, + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_1_0 \ @@ -425,6 +429,7 @@ static QEMUMachine pc_machine_v1_0 = { { /* end of list */ } }, .hw_version = "1.0", + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_0_15 \ @@ -440,6 +445,7 @@ static QEMUMachine pc_machine_v0_15 = { { /* end of list */ } }, .hw_version = "0.15", + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_0_14 \ @@ -481,6 +487,7 @@ static QEMUMachine pc_machine_v0_14 = { { /* end of list */ } }, .hw_version = "0.14", + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_0_13 \ @@ -518,6 +525,7 @@ static QEMUMachine pc_machine_v0_13 = { { /* end of list */ } }, .hw_version = "0.13", + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_0_12 \ @@ -551,6 +559,7 @@ static QEMUMachine pc_machine_v0_12 = { { /* end of list */ } }, .hw_version = "0.12", + DEFAULT_MACHINE_OPTIONS, }; #define PC_COMPAT_0_11 \ @@ -584,6 +593,7 @@ static QEMUMachine pc_machine_v0_11 = { { /* end of list */ } }, .hw_version = "0.11", + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine pc_machine_v0_10 = { @@ -617,6 +627,7 @@ static QEMUMachine pc_machine_v0_10 = { { /* end of list */ } }, .hw_version = "0.10", + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine isapc_machine = { @@ -632,6 +643,7 @@ static QEMUMachine isapc_machine = { }, { /* end of list */ } }, + DEFAULT_MACHINE_OPTIONS, }; #ifdef CONFIG_XEN @@ -641,6 +653,7 @@ static QEMUMachine xenfv_machine = { .init = pc_xen_hvm_init, .max_cpus = HVM_MAX_VCPUS, .default_machine_opts = "accel=xen", + DEFAULT_MACHINE_OPTIONS, }; #endif diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index 1cfdb2f302..9cad07476e 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -173,7 +173,8 @@ static QEMUMachine petalogix_ml605_machine = { .name = "petalogix-ml605", .desc = "PetaLogix linux refdesign for xilinx ml605 little endian", .init = petalogix_ml605_init, - .is_default = 0 + .is_default = 0, + DEFAULT_MACHINE_OPTIONS, }; static void petalogix_ml605_machine_init(void) diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c index 27ecfe7752..8605fb8c00 100644 --- a/hw/petalogix_s3adsp1800_mmu.c +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -115,7 +115,8 @@ static QEMUMachine petalogix_s3adsp1800_machine = { .name = "petalogix-s3adsp1800", .desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800", .init = petalogix_s3adsp1800_init, - .is_default = 1 + .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void petalogix_s3adsp1800_machine_init(void) diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 4deb02ac38..2dcc4a9852 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -54,6 +54,7 @@ static QEMUMachine e500plat_machine = { .desc = "generic paravirt e500 platform", .init = e500plat_init, .max_cpus = 15, + DEFAULT_MACHINE_OPTIONS, }; static void e500plat_machine_init(void) diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index f9ae20f5a3..8e05e55c87 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -54,6 +54,7 @@ static QEMUMachine ppce500_machine = { .desc = "mpc8544ds", .init = mpc8544ds_init, .max_cpus = 15, + DEFAULT_MACHINE_OPTIONS, }; static void ppce500_machine_init(void) diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 8f7f0d07d1..45ed3769a3 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -649,6 +649,7 @@ static QEMUMachine taihu_machine = { .name = "taihu", .desc = "taihu", .init = taihu_405ep_init, + DEFAULT_MACHINE_OPTIONS, }; static void ppc405_machine_init(void) diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index d1e4f0e811..73b5ac725c 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -295,6 +295,7 @@ static QEMUMachine bamboo_machine = { .name = "bamboo", .desc = "bamboo", .init = bamboo_init, + DEFAULT_MACHINE_OPTIONS, }; static void bamboo_machine_init(void) diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index fabcc08b40..7a465a7ebb 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -442,6 +442,7 @@ static QEMUMachine core99_machine = { #ifdef TARGET_PPC64 .is_default = 1, #endif + DEFAULT_MACHINE_OPTIONS, }; static void core99_machine_init(void) diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index fff5129ca9..de34e7530a 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -341,6 +341,7 @@ static QEMUMachine heathrow_machine = { #ifndef TARGET_PPC64 .is_default = 1, #endif + DEFAULT_MACHINE_OPTIONS, }; static void heathrow_machine_init(void) diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 417583a96d..a35fbedbdc 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -669,6 +669,7 @@ static QEMUMachine prep_machine = { .desc = "PowerPC PREP platform", .init = ppc_prep_init, .max_cpus = MAX_CPUS, + DEFAULT_MACHINE_OPTIONS, }; static void prep_machine_init(void) diff --git a/hw/puv3.c b/hw/puv3.c index 7814bc5051..c722510d7e 100644 --- a/hw/puv3.c +++ b/hw/puv3.c @@ -124,6 +124,7 @@ static QEMUMachine puv3_machine = { .desc = "PKUnity Version-3 based on UniCore32", .init = puv3_init, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void puv3_machine_init(void) diff --git a/hw/r2d.c b/hw/r2d.c index 7cf1893d19..72b593f597 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -347,6 +347,7 @@ static QEMUMachine r2d_machine = { .name = "r2d", .desc = "r2d-plus board", .init = r2d_init, + DEFAULT_MACHINE_OPTIONS, }; static void r2d_machine_init(void) diff --git a/hw/realview.c b/hw/realview.c index 872b3b468a..cecb67e4d5 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -365,6 +365,7 @@ static QEMUMachine realview_eb_machine = { .desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)", .init = realview_eb_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine realview_eb_mpcore_machine = { @@ -373,12 +374,14 @@ static QEMUMachine realview_eb_mpcore_machine = { .init = realview_eb_mpcore_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine realview_pb_a8_machine = { .name = "realview-pb-a8", .desc = "ARM RealView Platform Baseboard for Cortex-A8", .init = realview_pb_a8_init, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine realview_pbx_a9_machine = { @@ -387,6 +390,7 @@ static QEMUMachine realview_pbx_a9_machine = { .init = realview_pbx_a9_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static void realview_machine_init(void) diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 20827761d0..0e93cc3641 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -330,6 +330,7 @@ static QEMUMachine s390_machine = { .use_virtcon = 1, .max_cpus = 255, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void s390_machine_init(void) diff --git a/hw/shix.c b/hw/shix.c index 86d703ad70..6f2d55a155 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -92,6 +92,7 @@ static QEMUMachine shix_machine = { .desc = "shix card", .init = shix_init, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static void shix_machine_init(void) diff --git a/hw/spapr.c b/hw/spapr.c index 76aa09ba81..6476598878 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -964,6 +964,7 @@ static QEMUMachine spapr_machine = { .block_default_type = IF_SCSI, .max_cpus = MAX_CPUS, .no_parallel = 1, + DEFAULT_MACHINE_OPTIONS, }; static void spapr_machine_init(void) diff --git a/hw/spitz.c b/hw/spitz.c index f1659c4502..ab7ca80f6c 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -959,24 +959,28 @@ static QEMUMachine akitapda_machine = { .name = "akita", .desc = "Akita PDA (PXA270)", .init = akita_init, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine spitzpda_machine = { .name = "spitz", .desc = "Spitz PDA (PXA270)", .init = spitz_init, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine borzoipda_machine = { .name = "borzoi", .desc = "Borzoi PDA (PXA270)", .init = borzoi_init, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine terrierpda_machine = { .name = "terrier", .desc = "Terrier PDA (PXA270)", .init = terrier_init, + DEFAULT_MACHINE_OPTIONS, }; static void spitz_machine_init(void) diff --git a/hw/stellaris.c b/hw/stellaris.c index 12e4568534..b5e78ffb68 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1331,12 +1331,14 @@ static QEMUMachine lm3s811evb_machine = { .name = "lm3s811evb", .desc = "Stellaris LM3S811EVB", .init = lm3s811evb_init, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine lm3s6965evb_machine = { .name = "lm3s6965evb", .desc = "Stellaris LM3S6965EVB", .init = lm3s6965evb_init, + DEFAULT_MACHINE_OPTIONS, }; static void stellaris_machine_init(void) diff --git a/hw/sun4m.c b/hw/sun4m.c index 5925d292c3..6f5de44a89 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -1428,6 +1428,7 @@ static QEMUMachine ss5_machine = { .init = ss5_init, .block_default_type = IF_SCSI, .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine ss10_machine = { @@ -1436,6 +1437,7 @@ static QEMUMachine ss10_machine = { .init = ss10_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine ss600mp_machine = { @@ -1444,6 +1446,7 @@ static QEMUMachine ss600mp_machine = { .init = ss600mp_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine ss20_machine = { @@ -1452,6 +1455,7 @@ static QEMUMachine ss20_machine = { .init = ss20_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine voyager_machine = { @@ -1459,6 +1463,7 @@ static QEMUMachine voyager_machine = { .desc = "Sun4m platform, SPARCstation Voyager", .init = vger_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine ss_lx_machine = { @@ -1466,6 +1471,7 @@ static QEMUMachine ss_lx_machine = { .desc = "Sun4m platform, SPARCstation LX", .init = ss_lx_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine ss4_machine = { @@ -1473,6 +1479,7 @@ static QEMUMachine ss4_machine = { .desc = "Sun4m platform, SPARCstation 4", .init = ss4_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine scls_machine = { @@ -1480,6 +1487,7 @@ static QEMUMachine scls_machine = { .desc = "Sun4m platform, SPARCClassic", .init = scls_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine sbook_machine = { @@ -1487,6 +1495,7 @@ static QEMUMachine sbook_machine = { .desc = "Sun4m platform, SPARCbook", .init = sbook_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static const struct sun4d_hwdef sun4d_hwdefs[] = { @@ -1711,6 +1720,7 @@ static QEMUMachine ss1000_machine = { .init = ss1000_init, .block_default_type = IF_SCSI, .max_cpus = 8, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine ss2000_machine = { @@ -1719,6 +1729,7 @@ static QEMUMachine ss2000_machine = { .init = ss2000_init, .block_default_type = IF_SCSI, .max_cpus = 20, + DEFAULT_MACHINE_OPTIONS, }; static const struct sun4c_hwdef sun4c_hwdefs[] = { @@ -1897,6 +1908,7 @@ static QEMUMachine ss2_machine = { .desc = "Sun4c platform, SPARCstation 2", .init = ss2_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static void sun4m_register_types(void) diff --git a/hw/sun4u.c b/hw/sun4u.c index 3a06d70795..cb75d03278 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -978,6 +978,7 @@ static QEMUMachine sun4u_machine = { .init = sun4u_init, .max_cpus = 1, // XXX for now .is_default = 1, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine sun4v_machine = { @@ -985,6 +986,7 @@ static QEMUMachine sun4v_machine = { .desc = "Sun4v platform", .init = sun4v_init, .max_cpus = 1, // XXX for now + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine niagara_machine = { @@ -992,6 +994,7 @@ static QEMUMachine niagara_machine = { .desc = "Sun4v platform, Niagara", .init = niagara_init, .max_cpus = 1, // XXX for now + DEFAULT_MACHINE_OPTIONS, }; static void sun4u_register_types(void) diff --git a/hw/tosa.c b/hw/tosa.c index 7048b797d3..efea109795 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -251,6 +251,7 @@ static QEMUMachine tosapda_machine = { .name = "tosa", .desc = "Tosa PDA (PXA255)", .init = tosa_init, + DEFAULT_MACHINE_OPTIONS, }; static void tosapda_machine_init(void) diff --git a/hw/versatilepb.c b/hw/versatilepb.c index bf72ebb305..7a1b20b36c 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -359,6 +359,7 @@ static QEMUMachine versatilepb_machine = { .desc = "ARM Versatile/PB (ARM926EJ-S)", .init = vpb_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine versatileab_machine = { @@ -366,6 +367,7 @@ static QEMUMachine versatileab_machine = { .desc = "ARM Versatile/AB (ARM926EJ-S)", .init = vab_init, .block_default_type = IF_SCSI, + DEFAULT_MACHINE_OPTIONS, }; static void versatile_machine_init(void) diff --git a/hw/vexpress.c b/hw/vexpress.c index 93c3176667..6bbe8c38f9 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -479,6 +479,7 @@ static QEMUMachine vexpress_a9_machine = { .init = vexpress_a9_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine vexpress_a15_machine = { @@ -487,6 +488,7 @@ static QEMUMachine vexpress_a15_machine = { .init = vexpress_a15_init, .block_default_type = IF_SCSI, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static void vexpress_machine_init(void) diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 78450d7c40..8c4e8e4313 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -263,6 +263,7 @@ static QEMUMachine virtex_machine = { .name = "virtex-ml507", .desc = "Xilinx Virtex ML507 reference design", .init = virtex_init, + DEFAULT_MACHINE_OPTIONS, }; static void virtex_machine_init(void) diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 9feecd5a27..66e898123e 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -115,6 +115,7 @@ static QEMUMachine xenpv_machine = { .init = xen_init_pv, .max_cpus = 1, .default_machine_opts = "accel=xen", + DEFAULT_MACHINE_OPTIONS, }; static void xenpv_machine_init(void) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index da0a7d0aa1..8dede9fe89 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -203,7 +203,8 @@ static QEMUMachine zynq_machine = { .init = zynq_init, .block_default_type = IF_SCSI, .max_cpus = 1, - .no_sdcard = 1 + .no_sdcard = 1, + DEFAULT_MACHINE_OPTIONS, }; static void zynq_machine_init(void) diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index 0b9a52851a..a85fe9b738 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -295,6 +295,7 @@ static QEMUMachine xtensa_lx60_machine = { .desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")", .init = xtensa_lx60_init, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static QEMUMachine xtensa_lx200_machine = { @@ -302,6 +303,7 @@ static QEMUMachine xtensa_lx200_machine = { .desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")", .init = xtensa_lx200_init, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static void xtensa_lx_machines_init(void) diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c index 14fe85b2fc..864e57c52c 100644 --- a/hw/xtensa_sim.c +++ b/hw/xtensa_sim.c @@ -106,6 +106,7 @@ static QEMUMachine xtensa_sim_machine = { .is_default = true, .init = xtensa_sim_init, .max_cpus = 4, + DEFAULT_MACHINE_OPTIONS, }; static void xtensa_sim_machine_init(void) diff --git a/hw/z2.c b/hw/z2.c index 496e47df6c..731550f2d8 100644 --- a/hw/z2.c +++ b/hw/z2.c @@ -373,6 +373,7 @@ static QEMUMachine z2_machine = { .name = "z2", .desc = "Zipit Z2 (PXA27x)", .init = z2_init, + DEFAULT_MACHINE_OPTIONS, }; static void z2_machine_init(void) diff --git a/vl.c b/vl.c index 59ce063601..15e0280daa 100644 --- a/vl.c +++ b/vl.c @@ -2712,7 +2712,7 @@ int main(int argc, char **argv, char **envp) const char *icount_option = NULL; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; - char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */ + char boot_devices[33] = ""; DisplayState *ds; int cyls, heads, secs, translation; QemuOpts *hda_opts = NULL, *opts, *machine_opts; @@ -4084,7 +4084,9 @@ int main(int argc, char **argv, char **envp) qdev_machine_init(); QEMUMachineInitArgs args = { .ram_size = ram_size, - .boot_device = boot_devices, + .boot_device = (boot_devices[0] == '\0') ? + machine->boot_order : + boot_devices, .kernel_filename = kernel_filename, .kernel_cmdline = kernel_cmdline, .initrd_filename = initrd_filename, From 2c9ee0291f8ca7e18f8e96a34e8f4be7867219d2 Mon Sep 17 00:00:00 2001 From: Avik Sil Date: Tue, 8 Jan 2013 12:36:31 +0530 Subject: [PATCH 0504/1634] pseries: set no default boot order This patch removes the default boot order for pseries machine. This allows the machine to handle a NULL boot order in case no -boot option is provided. Thus it helps SLOF firmware to verify if boot order is specified in command line or not. If no boot order is provided SLOF tries to boot from the device set in the nvram. Reviewed-by: Anthony Liguori Acked-by: Alexander Graf Signed-off-by: Avik Sil Signed-off-by: Anthony Liguori --- hw/spapr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 6476598878..21c261be4a 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -287,7 +287,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); } - _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + if (boot_device) { + _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + } _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width))); _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height))); _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth))); @@ -964,7 +966,7 @@ static QEMUMachine spapr_machine = { .block_default_type = IF_SCSI, .max_cpus = MAX_CPUS, .no_parallel = 1, - DEFAULT_MACHINE_OPTIONS, + .boot_order = NULL, }; static void spapr_machine_init(void) From 7983c8a335dd09fec49f99a44d4404aa87828c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 9 Jan 2013 03:58:10 +0100 Subject: [PATCH 0505/1634] qdev: Fold state enum into bool realized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Whether the device was initialized or not is QOM-level information and currently unused. Drop it from device. This leaves the boolean state of whether or not DeviceClass::init was called or not, a.k.a. "realized". Suggested-by: Anthony Liguori Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- hw/qdev-addr.c | 2 +- hw/qdev-core.h | 18 ++++++++++-------- hw/qdev-properties-system.c | 4 ++-- hw/qdev-properties.c | 24 ++++++++++++------------ hw/qdev.c | 12 ++++++------ 5 files changed, 31 insertions(+), 29 deletions(-) diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index 3bfe101d79..b4388f6a66 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -40,7 +40,7 @@ static void set_taddr(Object *obj, Visitor *v, void *opaque, Error *local_err = NULL; int64_t value; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } diff --git a/hw/qdev-core.h b/hw/qdev-core.h index 853bd08a1f..cb6b30b82d 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -8,11 +8,6 @@ #include "hw/irq.h" #include "qapi/error.h" -enum DevState { - DEV_STATE_CREATED = 1, - DEV_STATE_INITIALIZED, -}; - enum { DEV_NVECTORS_UNSPECIFIED = -1, }; @@ -49,13 +44,20 @@ typedef struct DeviceClass { const char *bus_type; } DeviceClass; -/* This structure should not be accessed directly. We declare it here - so that it can be embedded in individual device state structures. */ +/** + * DeviceState: + * @realized: Indicates whether the device has been fully constructed. + * + * This structure should not be accessed directly. We declare it here + * so that it can be embedded in individual device state structures. + */ struct DeviceState { + /*< private >*/ Object parent_obj; + /*< public >*/ const char *id; - enum DevState state; + bool realized; QemuOpts *opts; int hotplugged; BusState *parent_bus; diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c index c73c713080..ce0f7933e6 100644 --- a/hw/qdev-properties-system.c +++ b/hw/qdev-properties-system.c @@ -42,7 +42,7 @@ static void set_pointer(Object *obj, Visitor *v, Property *prop, char *str; int ret; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -254,7 +254,7 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque, int32_t id; NetClientState *hubport; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index f724357ccb..a8a31f56e4 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -32,7 +32,7 @@ static void set_enum(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; int *ptr = qdev_get_prop_ptr(dev, prop); - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -85,7 +85,7 @@ static void set_bit(Object *obj, Visitor *v, void *opaque, Error *local_err = NULL; bool value; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -125,7 +125,7 @@ static void set_uint8(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -192,7 +192,7 @@ static void set_uint16(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -225,7 +225,7 @@ static void set_uint32(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -250,7 +250,7 @@ static void set_int32(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -323,7 +323,7 @@ static void set_uint64(Object *obj, Visitor *v, void *opaque, Property *prop = opaque; uint64_t *ptr = qdev_get_prop_ptr(dev, prop); - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -413,7 +413,7 @@ static void set_string(Object *obj, Visitor *v, void *opaque, Error *local_err = NULL; char *str; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -477,7 +477,7 @@ static void set_mac(Object *obj, Visitor *v, void *opaque, int i, pos; char *str, *p; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -569,7 +569,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, Error *local_err = NULL; char *str; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -640,7 +640,7 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque, const int64_t min = 512; const int64_t max = 32768; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -708,7 +708,7 @@ static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque, unsigned long dom = 0, bus = 0; unsigned int slot = 0, func = 0; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } diff --git a/hw/qdev.c b/hw/qdev.c index 1b68d0234a..37a083d3db 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -151,7 +151,7 @@ int qdev_init(DeviceState *dev) DeviceClass *dc = DEVICE_GET_CLASS(dev); int rc; - assert(dev->state == DEV_STATE_CREATED); + assert(!dev->realized); rc = dc->init(dev); if (rc < 0) { @@ -174,7 +174,7 @@ int qdev_init(DeviceState *dev) dev->instance_id_alias, dev->alias_required_for_version); } - dev->state = DEV_STATE_INITIALIZED; + dev->realized = true; if (dev->hotplugged) { device_reset(dev); } @@ -184,7 +184,7 @@ int qdev_init(DeviceState *dev) void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version) { - assert(dev->state == DEV_STATE_CREATED); + assert(!dev->realized); dev->instance_id_alias = alias_id; dev->alias_required_for_version = required_for_version; } @@ -546,7 +546,7 @@ static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque, char *ptr = NULL; int ret; - if (dev->state != DEV_STATE_CREATED) { + if (dev->realized) { error_set(errp, QERR_PERMISSION_DENIED); return; } @@ -653,7 +653,7 @@ static void device_initfn(Object *obj) } dev->instance_id_alias = -1; - dev->state = DEV_STATE_CREATED; + dev->realized = false; class = object_get_class(OBJECT(dev)); do { @@ -676,7 +676,7 @@ static void device_finalize(Object *obj) BusState *bus; DeviceClass *dc = DEVICE_GET_CLASS(dev); - if (dev->state == DEV_STATE_INITIALIZED) { + if (dev->realized) { while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); qbus_free(bus); From 249d41720b7dfbb5951b430b9eefdbee7464f515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 9 Jan 2013 03:58:11 +0100 Subject: [PATCH 0506/1634] qdev: Prepare "realized" property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the QOM realizefn suggested by Anthony. Detailed documentation is supplied in the qdev header. For now this implements a default DeviceClass::realize callback that just wraps DeviceClass::init, which it deprecates. Once all devices have been converted to DeviceClass::realize, DeviceClass::init is to be removed. Signed-off-by: Paolo Bonzini Signed-off-by: Andreas Färber Cc: Anthony Liguori Signed-off-by: Anthony Liguori --- hw/qdev-core.h | 52 ++++++++++++++++++++++++++- hw/qdev.c | 98 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 124 insertions(+), 26 deletions(-) diff --git a/hw/qdev-core.h b/hw/qdev-core.h index cb6b30b82d..3d75ae2e3a 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -20,11 +20,59 @@ enum { typedef int (*qdev_initfn)(DeviceState *dev); typedef int (*qdev_event)(DeviceState *dev); typedef void (*qdev_resetfn)(DeviceState *dev); +typedef void (*DeviceRealize)(DeviceState *dev, Error **errp); +typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp); struct VMStateDescription; +/** + * DeviceClass: + * @props: Properties accessing state fields. + * @realize: Callback function invoked when the #DeviceState:realized + * property is changed to %true. The default invokes @init if not %NULL. + * @unrealize: Callback function invoked when the #DeviceState:realized + * property is changed to %false. + * @init: Callback function invoked when the #DeviceState::realized property + * is changed to %true. Deprecated, new types inheriting directly from + * TYPE_DEVICE should use @realize instead, new leaf types should consult + * their respective parent type. + * + * # Realization # + * Devices are constructed in two stages, + * 1) object instantiation via object_initialize() and + * 2) device realization via #DeviceState:realized property. + * The former may not fail (it might assert or exit), the latter may return + * error information to the caller and must be re-entrant. + * Trivial field initializations should go into #TypeInfo.instance_init. + * Operations depending on @props static properties should go into @realize. + * After successful realization, setting static properties will fail. + * + * As an interim step, the #DeviceState:realized property is set by deprecated + * functions qdev_init() and qdev_init_nofail(). + * In the future, devices will propagate this state change to their children + * and along busses they expose. + * The point in time will be deferred to machine creation, so that values + * set in @realize will not be introspectable beforehand. Therefore devices + * must not create children during @realize; they should initialize them via + * object_initialize() in their own #TypeInfo.instance_init and forward the + * realization events appropriately. + * + * The @init callback is considered private to a particular bus implementation + * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an + * "init" callback on their parent class instead. + * Any type may override the @realize and/or @unrealize callbacks but needs + * to call (and thus save) the parent type's implementation if so desired. + * Usually this means storing the previous value of, e.g., @realized inside + * the type's class structure and overwriting it with a function that first + * invokes the stored callback, then performs any additional steps. + * If a type derived directly from TYPE_DEVICE implements @realize, it does + * not need to implement @init and therefore does not need to store and call + * #DeviceClass' default @realize callback. + */ typedef struct DeviceClass { + /*< private >*/ ObjectClass parent_class; + /*< public >*/ const char *fw_name; const char *desc; @@ -33,12 +81,14 @@ typedef struct DeviceClass { /* callbacks */ void (*reset)(DeviceState *dev); + DeviceRealize realize; + DeviceUnrealize unrealize; /* device state */ const struct VMStateDescription *vmsd; /* Private to qdev / bus. */ - qdev_initfn init; + qdev_initfn init; /* TODO remove, once users are converted to realize */ qdev_event unplug; qdev_event exit; const char *bus_type; diff --git a/hw/qdev.c b/hw/qdev.c index 37a083d3db..97610167c2 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -148,39 +148,32 @@ DeviceState *qdev_try_create(BusState *bus, const char *type) Return 0 on success. */ int qdev_init(DeviceState *dev) { - DeviceClass *dc = DEVICE_GET_CLASS(dev); - int rc; + Error *local_err = NULL; assert(!dev->realized); - rc = dc->init(dev); - if (rc < 0) { + object_property_set_bool(OBJECT(dev), true, "realized", &local_err); + if (local_err != NULL) { + error_free(local_err); qdev_free(dev); - return rc; - } - - if (!OBJECT(dev)->parent) { - static int unattached_count = 0; - gchar *name = g_strdup_printf("device[%d]", unattached_count++); - - object_property_add_child(container_get(qdev_get_machine(), - "/unattached"), - name, OBJECT(dev), NULL); - g_free(name); - } - - if (qdev_get_vmsd(dev)) { - vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev, - dev->instance_id_alias, - dev->alias_required_for_version); - } - dev->realized = true; - if (dev->hotplugged) { - device_reset(dev); + return -1; } return 0; } +static void device_realize(DeviceState *dev, Error **err) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (dc->init) { + int rc = dc->init(dev); + if (rc < 0) { + error_setg(err, "Device initialization failed."); + return; + } + } +} + void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int required_for_version) { @@ -641,6 +634,55 @@ void qdev_property_add_static(DeviceState *dev, Property *prop, assert_no_error(local_err); } +static bool device_get_realized(Object *obj, Error **err) +{ + DeviceState *dev = DEVICE(obj); + return dev->realized; +} + +static void device_set_realized(Object *obj, bool value, Error **err) +{ + DeviceState *dev = DEVICE(obj); + DeviceClass *dc = DEVICE_GET_CLASS(dev); + Error *local_err = NULL; + + if (value && !dev->realized) { + if (dc->realize) { + dc->realize(dev, &local_err); + } + + if (!obj->parent && local_err == NULL) { + static int unattached_count; + gchar *name = g_strdup_printf("device[%d]", unattached_count++); + + object_property_add_child(container_get(qdev_get_machine(), + "/unattached"), + name, obj, &local_err); + g_free(name); + } + + if (qdev_get_vmsd(dev) && local_err == NULL) { + vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev, + dev->instance_id_alias, + dev->alias_required_for_version); + } + if (dev->hotplugged && local_err == NULL) { + device_reset(dev); + } + } else if (!value && dev->realized) { + if (dc->unrealize) { + dc->unrealize(dev, &local_err); + } + } + + if (local_err != NULL) { + error_propagate(err, local_err); + return; + } + + dev->realized = value; +} + static void device_initfn(Object *obj) { DeviceState *dev = DEVICE(obj); @@ -655,6 +697,9 @@ static void device_initfn(Object *obj) dev->instance_id_alias = -1; dev->realized = false; + object_property_add_bool(obj, "realized", + device_get_realized, device_set_realized, NULL); + class = object_get_class(OBJECT(dev)); do { for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) { @@ -714,7 +759,10 @@ static void device_unparent(Object *obj) static void device_class_init(ObjectClass *class, void *data) { + DeviceClass *dc = DEVICE_CLASS(class); + class->unparent = device_unparent; + dc->realize = device_realize; } void device_reset(DeviceState *dev) From bd2d80b2b75b36955d536564ceb593f5bdae2f12 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 15 Oct 2012 09:28:05 +0200 Subject: [PATCH 0507/1634] chardev: add error reporting for qemu_chr_new_from_opts Signed-off-by: Gerd Hoffmann --- include/char/char.h | 3 ++- qemu-char.c | 24 +++++++++++++++--------- vl.c | 9 ++++++--- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/include/char/char.h b/include/char/char.h index baa5d035fd..1952a10063 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -89,7 +89,8 @@ struct CharDriverState { * Returns: a new character backend */ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, - void (*init)(struct CharDriverState *s)); + void (*init)(struct CharDriverState *s), + Error **errp); /** * @qemu_chr_new: diff --git a/qemu-char.c b/qemu-char.c index 3be4970423..b3ff4700ff 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2779,19 +2779,20 @@ static const struct { }; CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, - void (*init)(struct CharDriverState *s)) + void (*init)(struct CharDriverState *s), + Error **errp) { CharDriverState *chr; int i; if (qemu_opts_id(opts) == NULL) { - fprintf(stderr, "chardev: no id specified\n"); + error_setg(errp, "chardev: no id specified\n"); return NULL; } if (qemu_opt_get(opts, "backend") == NULL) { - fprintf(stderr, "chardev: \"%s\" missing backend\n", - qemu_opts_id(opts)); + error_setg(errp, "chardev: \"%s\" missing backend\n", + qemu_opts_id(opts)); return NULL; } for (i = 0; i < ARRAY_SIZE(backend_table); i++) { @@ -2799,15 +2800,15 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, break; } if (i == ARRAY_SIZE(backend_table)) { - fprintf(stderr, "chardev: backend \"%s\" not found\n", - qemu_opt_get(opts, "backend")); + error_setg(errp, "chardev: backend \"%s\" not found\n", + qemu_opt_get(opts, "backend")); return NULL; } chr = backend_table[i].open(opts); if (!chr) { - fprintf(stderr, "chardev: opening backend \"%s\" failed\n", - qemu_opt_get(opts, "backend")); + error_setg(errp, "chardev: opening backend \"%s\" failed\n", + qemu_opt_get(opts, "backend")); return NULL; } @@ -2837,6 +2838,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in const char *p; CharDriverState *chr; QemuOpts *opts; + Error *err = NULL; if (strstart(filename, "chardev:", &p)) { return qemu_chr_find(p); @@ -2846,7 +2848,11 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in if (!opts) return NULL; - chr = qemu_chr_new_from_opts(opts, init); + chr = qemu_chr_new_from_opts(opts, init, &err); + if (error_is_set(&err)) { + fprintf(stderr, "%s\n", error_get_pretty(err)); + error_free(err); + } if (chr && qemu_opt_get_bool(opts, "mux", 0)) { monitor_init(chr, MONITOR_USE_READLINE); } diff --git a/vl.c b/vl.c index 15e0280daa..8ce2b10541 100644 --- a/vl.c +++ b/vl.c @@ -2238,11 +2238,14 @@ static int device_init_func(QemuOpts *opts, void *opaque) static int chardev_init_func(QemuOpts *opts, void *opaque) { - CharDriverState *chr; + Error *local_err = NULL; - chr = qemu_chr_new_from_opts(opts, NULL); - if (!chr) + qemu_chr_new_from_opts(opts, NULL, &local_err); + if (error_is_set(&local_err)) { + fprintf(stderr, "%s\n", error_get_pretty(local_err)); + error_free(local_err); return -1; + } return 0; } From 2274ae9d1a841c9d214b7c877d28e2f037a9b26e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 15 Oct 2012 09:30:59 +0200 Subject: [PATCH 0508/1634] chardev: fix QemuOpts lifecycle qemu_chr_new_from_opts handles QemuOpts release now, so callers don't have to worry. It will either be saved in CharDriverState, then released in qemu_chr_delete, or in the error case released instantly. Signed-off-by: Gerd Hoffmann --- include/char/char.h | 1 + qemu-char.c | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/char/char.h b/include/char/char.h index 1952a10063..c91ce3c98a 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -75,6 +75,7 @@ struct CharDriverState { char *filename; int opened; int avail_connections; + QemuOpts *opts; QTAILQ_ENTRY(CharDriverState) next; }; diff --git a/qemu-char.c b/qemu-char.c index b3ff4700ff..16b33acbc5 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2787,13 +2787,13 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, if (qemu_opts_id(opts) == NULL) { error_setg(errp, "chardev: no id specified\n"); - return NULL; + goto err; } if (qemu_opt_get(opts, "backend") == NULL) { error_setg(errp, "chardev: \"%s\" missing backend\n", qemu_opts_id(opts)); - return NULL; + goto err; } for (i = 0; i < ARRAY_SIZE(backend_table); i++) { if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0) @@ -2802,14 +2802,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, if (i == ARRAY_SIZE(backend_table)) { error_setg(errp, "chardev: backend \"%s\" not found\n", qemu_opt_get(opts, "backend")); - return NULL; + goto err; } chr = backend_table[i].open(opts); if (!chr) { error_setg(errp, "chardev: opening backend \"%s\" failed\n", qemu_opt_get(opts, "backend")); - return NULL; + goto err; } if (!chr->filename) @@ -2830,7 +2830,12 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, chr->avail_connections = 1; } chr->label = g_strdup(qemu_opts_id(opts)); + chr->opts = opts; return chr; + +err: + qemu_opts_del(opts); + return NULL; } CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s)) @@ -2856,7 +2861,6 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in if (chr && qemu_opt_get_bool(opts, "mux", 0)) { monitor_init(chr, MONITOR_USE_READLINE); } - qemu_opts_del(opts); return chr; } @@ -2884,10 +2888,14 @@ void qemu_chr_fe_close(struct CharDriverState *chr) void qemu_chr_delete(CharDriverState *chr) { QTAILQ_REMOVE(&chardevs, chr, next); - if (chr->chr_close) + if (chr->chr_close) { chr->chr_close(chr); + } g_free(chr->filename); g_free(chr->label); + if (chr->opts) { + qemu_opts_del(chr->opts); + } g_free(chr); } From e551498e7283fc7f12a0f9cd5645517bfe9008f6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 16:35:42 +0100 Subject: [PATCH 0509/1634] chardev: reduce chardev ifdef mess a bit Signed-off-by: Gerd Hoffmann --- qemu-char.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 16b33acbc5..ea15d357d0 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -856,6 +856,8 @@ static void cfmakeraw (struct termios *termios_p) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ || defined(__GLIBC__) +#define HAVE_CHARDEV_TTY 1 + typedef struct { int fd; int connected; @@ -1244,14 +1246,12 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) chr->chr_close = qemu_chr_close_tty; return chr; } -#else /* ! __linux__ && ! __sun__ */ -static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) -{ - return NULL; -} #endif /* __linux__ || __sun__ */ #if defined(__linux__) + +#define HAVE_CHARDEV_PARPORT 1 + typedef struct { int fd; int mode; @@ -1395,6 +1395,9 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) #endif /* __linux__ */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) + +#define HAVE_CHARDEV_PARPORT 1 + static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) { int fd = (int)(intptr_t)chr->opaque; @@ -2755,19 +2758,16 @@ static const struct { #else { .name = "file", .open = qemu_chr_open_file_out }, { .name = "pipe", .open = qemu_chr_open_pipe }, - { .name = "pty", .open = qemu_chr_open_pty }, { .name = "stdio", .open = qemu_chr_open_stdio }, #endif #ifdef CONFIG_BRLAPI { .name = "braille", .open = chr_baum_init }, #endif -#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \ - || defined(__FreeBSD_kernel__) +#ifdef HAVE_CHARDEV_TTY { .name = "tty", .open = qemu_chr_open_tty }, + { .name = "pty", .open = qemu_chr_open_pty }, #endif -#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) \ - || defined(__FreeBSD_kernel__) +#ifdef HAVE_CHARDEV_PARPORT { .name = "parport", .open = qemu_chr_open_pp }, #endif #ifdef CONFIG_SPICE From f1a1a35638bf045a2b158c0cb23d92ef39c06792 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 10:33:56 +0100 Subject: [PATCH 0510/1634] chardev: add qmp hotplug commands, with null chardev support Add chardev-add and chardev-remove qmp commands. Hotplugging a null chardev is supported for now, more will be added later. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 49 ++++++++++++++++++++++++++++++++++++++++++++ qemu-char.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 50 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index 5dfa052391..462511e904 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3017,3 +3017,52 @@ # Since: 1.3.0 ## { 'command': 'nbd-server-stop' } + +## +# @ChardevBackend: +# +# Configuration info for the new chardev backend. +# +# Since: 1.4 +## +{ 'type': 'ChardevDummy', 'data': { } } + +{ 'union': 'ChardevBackend', 'data': { 'null' : 'ChardevDummy' } } + +## +# @ChardevReturn: +# +# Return info about the chardev backend just created. +# +# Since: 1.4 +## +{ 'type' : 'ChardevReturn', 'data': { } } + +## +# @chardev-add: +# +# Add a file chardev +# +# @id: the chardev's ID, must be unique +# @backend: backend type and parameters +# +# Returns: chardev info. +# +# Since: 1.4 +## +{ 'command': 'chardev-add', 'data': {'id' : 'str', + 'backend' : 'ChardevBackend' }, + 'returns': 'ChardevReturn' } + +## +# @chardev-remove: +# +# Remove a chardev +# +# @id: the chardev's ID, must exist and not be in use +# +# Returns: Nothing on success +# +# Since: 1.4 +## +{ 'command': 'chardev-remove', 'data': {'id': 'str'} } diff --git a/qemu-char.c b/qemu-char.c index ea15d357d0..73a5e37aa7 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3010,3 +3010,56 @@ QemuOptsList qemu_chardev_opts = { { /* end of list */ } }, }; + +ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, + Error **errp) +{ + ChardevReturn *ret = g_new0(ChardevReturn, 1); + CharDriverState *chr = NULL; + + chr = qemu_chr_find(id); + if (chr) { + error_setg(errp, "Chardev '%s' already exists", id); + g_free(ret); + return NULL; + } + + switch (backend->kind) { + case CHARDEV_BACKEND_KIND_NULL: + chr = qemu_chr_open_null(NULL); + break; + default: + error_setg(errp, "unknown chardev backend (%d)", backend->kind); + break; + } + + if (chr == NULL && !error_is_set(errp)) { + error_setg(errp, "Failed to create chardev"); + } + if (chr) { + chr->label = g_strdup(id); + chr->avail_connections = 1; + QTAILQ_INSERT_TAIL(&chardevs, chr, next); + return ret; + } else { + g_free(ret); + return NULL; + } +} + +void qmp_chardev_remove(const char *id, Error **errp) +{ + CharDriverState *chr; + + chr = qemu_chr_find(id); + if (NULL == chr) { + error_setg(errp, "Chardev '%s' not found", id); + return; + } + if (chr->chr_can_read || chr->chr_read || + chr->chr_event || chr->handler_opaque) { + error_setg(errp, "Chardev '%s' is busy", id); + return; + } + qemu_chr_delete(chr); +} diff --git a/qmp-commands.hx b/qmp-commands.hx index 5c692d0cb5..c9ab37c9b9 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2654,3 +2654,53 @@ EQMP .args_type = "", .mhandler.cmd_new = qmp_marshal_input_query_target, }, + + { + .name = "chardev-add", + .args_type = "id:s,backend:q", + .mhandler.cmd_new = qmp_marshal_input_chardev_add, + }, + +SQMP +chardev-add +---------------- + +Add a chardev. + +Arguments: + +- "id": the chardev's ID, must be unique (json-string) +- "backend": chardev backend type + parameters + +Example: + +-> { "execute" : "chardev-add", + "arguments" : { "id" : "foo", + "backend" : { "type" : "null", "data" : {} } } } +<- { "return": {} } + +EQMP + + { + .name = "chardev-remove", + .args_type = "id:s", + .mhandler.cmd_new = qmp_marshal_input_chardev_remove, + }, + + +SQMP +chardev-remove +-------------- + +Remove a chardev. + +Arguments: + +- "id": the chardev's ID, must exist and not be in use (json-string) + +Example: + +-> { "execute": "chardev-remove", "arguments": { "id" : "foo" } } +<- { "return": {} } + +EQMP From f10889089153edf032476b45229477866a9ca0b1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 10:33:40 +0100 Subject: [PATCH 0511/1634] chardev: add hmp hotplug commands Add chardev-add and chardev-remove commands to the human monitor. chardev-add accepts the same syntax as -chardev, chardev-remove expects a chardev id. Signed-off-by: Gerd Hoffmann --- hmp-commands.hx | 32 ++++++++++++++++++++++++++++++++ hmp.c | 23 +++++++++++++++++++++++ hmp.h | 2 ++ 3 files changed, 57 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index 010b8c9ba5..67569eff4a 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1482,6 +1482,38 @@ Password is invalidated at the given time. @var{nsec} are the seconds passed since 1970, i.e. unix epoch. @end table +ETEXI + + { + .name = "chardev-add", + .args_type = "args:s", + .params = "args", + .help = "add chardev", + .mhandler.cmd = hmp_chardev_add, + }, + +STEXI +@item chardev_add args +@findex chardev_add + +chardev_add accepts the same parameters as the -chardev command line switch. + +ETEXI + + { + .name = "chardev-remove", + .args_type = "id:s", + .params = "id", + .help = "remove chardev", + .mhandler.cmd = hmp_chardev_remove, + }, + +STEXI +@item chardev_remove id +@findex chardev_remove + +Removes the chardev @var{id}. + ETEXI { diff --git a/hmp.c b/hmp.c index 9e9e62450e..68929b4acf 100644 --- a/hmp.c +++ b/hmp.c @@ -1336,3 +1336,26 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict) qmp_nbd_server_stop(&errp); hmp_handle_error(mon, &errp); } + +void hmp_chardev_add(Monitor *mon, const QDict *qdict) +{ + const char *args = qdict_get_str(qdict, "args"); + Error *err = NULL; + QemuOpts *opts; + + opts = qemu_opts_parse(qemu_find_opts("chardev"), args, 1); + if (opts == NULL) { + error_setg(&err, "Parsing chardev args failed\n"); + } else { + qemu_chr_new_from_opts(opts, NULL, &err); + } + hmp_handle_error(mon, &err); +} + +void hmp_chardev_remove(Monitor *mon, const QDict *qdict) +{ + Error *local_err = NULL; + + qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err); + hmp_handle_error(mon, &local_err); +} diff --git a/hmp.h b/hmp.h index 21f3e05d09..700fbdc777 100644 --- a/hmp.h +++ b/hmp.h @@ -80,5 +80,7 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict); void hmp_nbd_server_start(Monitor *mon, const QDict *qdict); void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); +void hmp_chardev_add(Monitor *mon, const QDict *qdict); +void hmp_chardev_remove(Monitor *mon, const QDict *qdict); #endif From ffbdbe59acc5f175d6c05a5d90f0b7c865fafd5b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 13:13:57 +0100 Subject: [PATCH 0512/1634] chardev: add file chardev support to chardev-add (qmp) Add support for file chardevs. Output file is mandatory, input file is optional. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 16 ++++++++++++- qemu-char.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 8 ++++++- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 462511e904..c70c11840a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3018,6 +3018,19 @@ ## { 'command': 'nbd-server-stop' } +## +# @ChardevFile: +# +# Configuration info for file chardevs. +# +# @in: #optional The name of the input file +# @out: The name of the output file +# +# Since: 1.4 +## +{ 'type': 'ChardevFile', 'data': { '*in' : 'str', + 'out' : 'str' } } + ## # @ChardevBackend: # @@ -3027,7 +3040,8 @@ ## { 'type': 'ChardevDummy', 'data': { } } -{ 'union': 'ChardevBackend', 'data': { 'null' : 'ChardevDummy' } } +{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', + 'null' : 'ChardevDummy' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 73a5e37aa7..d447d96805 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3011,6 +3011,64 @@ QemuOptsList qemu_chardev_opts = { }, }; +#ifdef _WIN32 + +static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) +{ + HANDLE out; + + if (file->in) { + error_setg(errp, "input file not supported"); + return NULL; + } + + out = CreateFile(file->out, GENERIC_WRITE, FILE_SHARE_READ, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (out == INVALID_HANDLE_VALUE) { + error_setg(errp, "open %s failed", file->out); + return NULL; + } + return qemu_chr_open_win_file(out); +} + +#else /* WIN32 */ + +static int qmp_chardev_open_file_source(char *src, int flags, + Error **errp) +{ + int fd = -1; + + TFR(fd = qemu_open(src, flags, 0666)); + if (fd == -1) { + error_setg(errp, "open %s: %s", src, strerror(errno)); + } + return fd; +} + +static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) +{ + int flags, in = -1, out = -1; + + flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY; + out = qmp_chardev_open_file_source(file->out, flags, errp); + if (error_is_set(errp)) { + return NULL; + } + + if (file->in) { + flags = O_RDONLY; + in = qmp_chardev_open_file_source(file->in, flags, errp); + if (error_is_set(errp)) { + qemu_close(out); + return NULL; + } + } + + return qemu_chr_open_fd(in, out); +} + +#endif /* WIN32 */ + ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { @@ -3025,6 +3083,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } switch (backend->kind) { + case CHARDEV_BACKEND_KIND_FILE: + chr = qmp_chardev_open_file(backend->file, errp); + break; case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; diff --git a/qmp-commands.hx b/qmp-commands.hx index c9ab37c9b9..4d382f4ffc 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2672,13 +2672,19 @@ Arguments: - "id": the chardev's ID, must be unique (json-string) - "backend": chardev backend type + parameters -Example: +Examples: -> { "execute" : "chardev-add", "arguments" : { "id" : "foo", "backend" : { "type" : "null", "data" : {} } } } <- { "return": {} } +-> { "execute" : "chardev-add", + "arguments" : { "id" : "bar", + "backend" : { "type" : "file", + "data" : { "out" : "/tmp/bar.log" } } } } +<- { "return": {} } + EQMP { From d59044ef74d577797d087bc6ffb156cec89ed39a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 19 Dec 2012 13:50:29 +0100 Subject: [PATCH 0513/1634] chardev: add serial chardev support to chardev-add (qmp) Similar to file, except that no separate in/out files are supported because it's pointless for direct device access. Also the special tty ioctl hooks (pass through linespeed settings etc) are activated on Unix. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 17 +++++++++++++ qemu-char.c | 62 +++++++++++++++++++++++++++++++++++++++++------- qemu-options.hx | 9 ++++--- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index c70c11840a..bbbbd33d75 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3031,6 +3031,22 @@ { 'type': 'ChardevFile', 'data': { '*in' : 'str', 'out' : 'str' } } +## +# @ChardevPort: +# +# Configuration info for device chardevs. +# +# @device: The name of the special file for the device, +# i.e. /dev/ttyS0 on Unix or COM1: on Windows +# @type: What kind of device this is. +# +# Since: 1.4 +## +{ 'enum': 'ChardevPortKind', 'data': [ 'serial' ] } + +{ 'type': 'ChardevPort', 'data': { 'device' : 'str', + 'type' : 'ChardevPortKind'} } + ## # @ChardevBackend: # @@ -3041,6 +3057,7 @@ { 'type': 'ChardevDummy', 'data': { } } { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', + 'port' : 'ChardevPort', 'null' : 'ChardevDummy' } } ## diff --git a/qemu-char.c b/qemu-char.c index d447d96805..839839892c 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1230,21 +1230,27 @@ static void qemu_chr_close_tty(CharDriverState *chr) } } +static CharDriverState *qemu_chr_open_tty_fd(int fd) +{ + CharDriverState *chr; + + tty_serial_init(fd, 115200, 'N', 8, 1); + chr = qemu_chr_open_fd(fd, fd); + chr->chr_ioctl = tty_serial_ioctl; + chr->chr_close = qemu_chr_close_tty; + return chr; +} + static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) { const char *filename = qemu_opt_get(opts, "path"); - CharDriverState *chr; int fd; TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK)); if (fd < 0) { return NULL; } - tty_serial_init(fd, 115200, 'N', 8, 1); - chr = qemu_chr_open_fd(fd, fd); - chr->chr_ioctl = tty_serial_ioctl; - chr->chr_close = qemu_chr_close_tty; - return chr; + return qemu_chr_open_tty_fd(fd); } #endif /* __linux__ || __sun__ */ @@ -1666,9 +1672,8 @@ static int win_chr_poll(void *opaque) return 0; } -static CharDriverState *qemu_chr_open_win(QemuOpts *opts) +static CharDriverState *qemu_chr_open_win_path(const char *filename) { - const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; WinCharState *s; @@ -1687,6 +1692,11 @@ static CharDriverState *qemu_chr_open_win(QemuOpts *opts) return chr; } +static CharDriverState *qemu_chr_open_win(QemuOpts *opts) +{ + return qemu_chr_open_win_path(qemu_opt_get(opts, "path")); +} + static int win_chr_pipe_poll(void *opaque) { CharDriverState *chr = opaque; @@ -2765,6 +2775,7 @@ static const struct { #endif #ifdef HAVE_CHARDEV_TTY { .name = "tty", .open = qemu_chr_open_tty }, + { .name = "serial", .open = qemu_chr_open_tty }, { .name = "pty", .open = qemu_chr_open_pty }, #endif #ifdef HAVE_CHARDEV_PARPORT @@ -3031,6 +3042,17 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_win_file(out); } +static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) +{ + switch (port->type) { + case CHARDEV_PORT_KIND_SERIAL: + return qemu_chr_open_win_path(port->device); + default: + error_setg(errp, "unknown chardev port (%d)", port->type); + return NULL; + } +} + #else /* WIN32 */ static int qmp_chardev_open_file_source(char *src, int flags, @@ -3067,6 +3089,27 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_fd(in, out); } +static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) +{ + int flags, fd; + + switch (port->type) { +#ifdef HAVE_CHARDEV_TTY + case CHARDEV_PORT_KIND_SERIAL: + flags = O_RDWR; + fd = qmp_chardev_open_file_source(port->device, flags, errp); + if (error_is_set(errp)) { + return NULL; + } + socket_set_nonblock(fd); + return qemu_chr_open_tty_fd(fd); +#endif + default: + error_setg(errp, "unknown chardev port (%d)", port->type); + return NULL; + } +} + #endif /* WIN32 */ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, @@ -3086,6 +3129,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_FILE: chr = qmp_chardev_open_file(backend->file, errp); break; + case CHARDEV_BACKEND_KIND_PORT: + chr = qmp_chardev_open_port(backend->port, errp); + break; case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; diff --git a/qemu-options.hx b/qemu-options.hx index 9df0cde64c..17cc1ad903 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1742,6 +1742,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #endif #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + "-chardev serial,id=id,path=path[,mux=on|off]\n" "-chardev tty,id=id,path=path[,mux=on|off]\n" #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) @@ -1910,8 +1911,8 @@ take any options. Send traffic from the guest to a serial device on the host. -@option{serial} is -only available on Windows hosts. +On Unix hosts serial will actually accept any tty device, +not only serial lines. @option{path} specifies the name of the serial device to open. @@ -1937,10 +1938,8 @@ Connect to a local BrlAPI server. @option{braille} does not take any options. @item -chardev tty ,id=@var{id} ,path=@var{path} -Connect to a local tty device. - @option{tty} is only available on Linux, Sun, FreeBSD, NetBSD, OpenBSD and -DragonFlyBSD hosts. +DragonFlyBSD hosts. It is an alias for -serial. @option{path} specifies the path to the tty. @option{path} is required. From 88a946d32dd9e4c6c0ad56e19f2822bd5c8b416e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 10 Jan 2013 14:20:58 +0100 Subject: [PATCH 0514/1634] chardev: add parallel chardev support to chardev-add (qmp) Also alias the old parport name to parallel for -chardev. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 3 ++- qemu-char.c | 44 ++++++++++++++++++++++++++++---------------- qemu-options.hx | 5 ++++- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index bbbbd33d75..320fa6baf1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3042,7 +3042,8 @@ # # Since: 1.4 ## -{ 'enum': 'ChardevPortKind', 'data': [ 'serial' ] } +{ 'enum': 'ChardevPortKind', 'data': [ 'serial', + 'parallel' ] } { 'type': 'ChardevPort', 'data': { 'device' : 'str', 'type' : 'ChardevPortKind'} } diff --git a/qemu-char.c b/qemu-char.c index 839839892c..7091e05ee2 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1367,17 +1367,10 @@ static void pp_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pp_fd(int fd) { - const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; ParallelCharDriver *drv; - int fd; - - TFR(fd = qemu_open(filename, O_RDWR)); - if (fd < 0) { - return NULL; - } if (ioctl(fd, PPCLAIM) < 0) { close(fd); @@ -1441,16 +1434,9 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pp_fd(int fd) { - const char *filename = qemu_opt_get(opts, "path"); CharDriverState *chr; - int fd; - - fd = qemu_open(filename, O_RDWR); - if (fd < 0) { - return NULL; - } chr = g_malloc0(sizeof(CharDriverState)); chr->opaque = (void *)(intptr_t)fd; @@ -2750,6 +2736,22 @@ fail: return NULL; } +#ifdef HAVE_CHARDEV_PARPORT + +static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) +{ + const char *filename = qemu_opt_get(opts, "path"); + int fd; + + fd = qemu_open(filename, O_RDWR); + if (fd < 0) { + return NULL; + } + return qemu_chr_open_pp_fd(fd); +} + +#endif + static const struct { const char *name; CharDriverState *(*open)(QemuOpts *opts); @@ -2779,6 +2781,7 @@ static const struct { { .name = "pty", .open = qemu_chr_open_pty }, #endif #ifdef HAVE_CHARDEV_PARPORT + { .name = "parallel", .open = qemu_chr_open_pp }, { .name = "parport", .open = qemu_chr_open_pp }, #endif #ifdef CONFIG_SPICE @@ -3103,6 +3106,15 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) } socket_set_nonblock(fd); return qemu_chr_open_tty_fd(fd); +#endif +#ifdef HAVE_CHARDEV_PARPORT + case CHARDEV_PORT_KIND_PARALLEL: + flags = O_RDWR; + fd = qmp_chardev_open_file_source(port->device, flags, errp); + if (error_is_set(errp)) { + return NULL; + } + return qemu_chr_open_pp_fd(fd); #endif default: error_setg(errp, "unknown chardev port (%d)", port->type); diff --git a/qemu-options.hx b/qemu-options.hx index 17cc1ad903..40cd68399d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1746,6 +1746,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev tty,id=id,path=path[,mux=on|off]\n" #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) + "-chardev parallel,id=id,path=path[,mux=on|off]\n" "-chardev parport,id=id,path=path[,mux=on|off]\n" #endif #if defined(CONFIG_SPICE) @@ -1776,6 +1777,7 @@ Backend is one of: @option{stdio}, @option{braille}, @option{tty}, +@option{parallel}, @option{parport}, @option{spicevmc}. @option{spiceport}. @@ -1943,9 +1945,10 @@ DragonFlyBSD hosts. It is an alias for -serial. @option{path} specifies the path to the tty. @option{path} is required. +@item -chardev parallel ,id=@var{id} ,path=@var{path} @item -chardev parport ,id=@var{id} ,path=@var{path} -@option{parport} is only available on Linux, FreeBSD and DragonFlyBSD hosts. +@option{parallel} is only available on Linux, FreeBSD and DragonFlyBSD hosts. Connect to a local parallel port. From f6bd5d6ec514939c421fcd411d1a39bc7dad0948 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 20 Dec 2012 13:53:12 +0100 Subject: [PATCH 0515/1634] chardev: add socket chardev support to chardev-add (qmp) qemu_chr_open_socket is split into two functions. All initialization after creating the socket file handler is split away into the new qemu_chr_open_socket_fd function. chr->filename doesn't get filled from QemuOpts any more. Qemu gathers the information using getsockname and getnameinfo instead. This way it will also work correctly for file handles passed via file descriptor passing. Finally qmp_chardev_open_socket() is the actual qmp hotplug implementation which basically just calls socket_listen or socket_connect and the new qemu_chr_open_socket_fd function. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 28 +++++++- qemu-char.c | 166 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 138 insertions(+), 56 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 320fa6baf1..5c3e3eb469 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3048,6 +3048,27 @@ { 'type': 'ChardevPort', 'data': { 'device' : 'str', 'type' : 'ChardevPortKind'} } +## +# @ChardevSocket: +# +# Configuration info for socket chardevs. +# +# @addr: socket address to listen on (server=true) +# or connect to (server=false) +# @server: #optional create server socket (default: true) +# @wait: #optional wait for connect (not used for server +# sockets, default: false) +# @nodelay: #optional set TCP_NODELAY socket option (default: false) +# @telnet: #optional enable telnet protocol (default: false) +# +# Since: 1.4 +## +{ 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress', + '*server' : 'bool', + '*wait' : 'bool', + '*nodelay' : 'bool', + '*telnet' : 'bool' } } + ## # @ChardevBackend: # @@ -3057,9 +3078,10 @@ ## { 'type': 'ChardevDummy', 'data': { } } -{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', - 'port' : 'ChardevPort', - 'null' : 'ChardevDummy' } } +{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', + 'port' : 'ChardevPort', + 'socket' : 'ChardevSocket', + 'null' : 'ChardevDummy' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 7091e05ee2..36d7e29953 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2438,10 +2438,88 @@ static void tcp_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) +static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, + bool is_listen, bool is_telnet, + bool is_waitconnect, + Error **errp) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; + char host[NI_MAXHOST], serv[NI_MAXSERV]; + const char *left = "", *right = ""; + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + + memset(&ss, 0, ss_len); + if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) != 0) { + error_setg(errp, "getsockname: %s", strerror(errno)); + return NULL; + } + + chr = g_malloc0(sizeof(CharDriverState)); + s = g_malloc0(sizeof(TCPCharDriver)); + + s->connected = 0; + s->fd = -1; + s->listen_fd = -1; + s->msgfd = -1; + + chr->filename = g_malloc(256); + switch (ss.ss_family) { +#ifndef _WIN32 + case AF_UNIX: + s->is_unix = 1; + snprintf(chr->filename, 256, "unix:%s%s", + ((struct sockaddr_un *)(&ss))->sun_path, + is_listen ? ",server" : ""); + break; +#endif + case AF_INET6: + left = "["; + right = "]"; + /* fall through */ + case AF_INET: + s->do_nodelay = do_nodelay; + getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host), + serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); + snprintf(chr->filename, 256, "%s:%s:%s%s%s%s", + is_telnet ? "telnet" : "tcp", + left, host, right, serv, + is_listen ? ",server" : ""); + break; + } + + chr->opaque = s; + chr->chr_write = tcp_chr_write; + chr->chr_close = tcp_chr_close; + chr->get_msgfd = tcp_get_msgfd; + chr->chr_add_client = tcp_chr_add_client; + + if (is_listen) { + s->listen_fd = fd; + qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); + if (is_telnet) { + s->do_telnetopt = 1; + } + } else { + s->connected = 1; + s->fd = fd; + socket_set_nodelay(fd); + tcp_chr_connect(chr); + } + + if (is_listen && is_waitconnect) { + printf("QEMU waiting for connection on: %s\n", + chr->filename); + tcp_chr_accept(chr); + socket_set_nonblock(s->listen_fd); + } + return chr; +} + +static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) +{ + CharDriverState *chr = NULL; Error *local_err = NULL; int fd = -1; int is_listen; @@ -2458,9 +2536,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (!is_listen) is_waitconnect = 0; - chr = g_malloc0(sizeof(CharDriverState)); - s = g_malloc0(sizeof(TCPCharDriver)); - if (is_unix) { if (is_listen) { fd = unix_listen_opts(opts, &local_err); @@ -2481,56 +2556,14 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (!is_waitconnect) socket_set_nonblock(fd); - s->connected = 0; - s->fd = -1; - s->listen_fd = -1; - s->msgfd = -1; - s->is_unix = is_unix; - s->do_nodelay = do_nodelay && !is_unix; - - chr->opaque = s; - chr->chr_write = tcp_chr_write; - chr->chr_close = tcp_chr_close; - chr->get_msgfd = tcp_get_msgfd; - chr->chr_add_client = tcp_chr_add_client; - - if (is_listen) { - s->listen_fd = fd; - qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); - if (is_telnet) - s->do_telnetopt = 1; - - } else { - s->connected = 1; - s->fd = fd; - socket_set_nodelay(fd); - tcp_chr_connect(chr); - } - - /* for "info chardev" monitor command */ - chr->filename = g_malloc(256); - if (is_unix) { - snprintf(chr->filename, 256, "unix:%s%s", - qemu_opt_get(opts, "path"), - qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); - } else if (is_telnet) { - snprintf(chr->filename, 256, "telnet:%s:%s%s", - qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), - qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); - } else { - snprintf(chr->filename, 256, "tcp:%s:%s%s", - qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), - qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); - } - - if (is_listen && is_waitconnect) { - printf("QEMU waiting for connection on: %s\n", - chr->filename); - tcp_chr_accept(chr); - socket_set_nonblock(s->listen_fd); + chr = qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, is_telnet, + is_waitconnect, &local_err); + if (error_is_set(&local_err)) { + goto fail; } return chr; + fail: if (local_err) { qerror_report_err(local_err); @@ -2539,8 +2572,10 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) if (fd >= 0) { closesocket(fd); } - g_free(s); - g_free(chr); + if (chr) { + g_free(chr->opaque); + g_free(chr); + } return NULL; } @@ -3124,6 +3159,28 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) #endif /* WIN32 */ +static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, + Error **errp) +{ + SocketAddress *addr = sock->addr; + bool do_nodelay = sock->has_nodelay ? sock->nodelay : false; + bool is_listen = sock->has_server ? sock->server : true; + bool is_telnet = sock->has_telnet ? sock->telnet : false; + bool is_waitconnect = sock->has_wait ? sock->wait : false; + int fd; + + if (is_listen) { + fd = socket_listen(addr, errp); + } else { + fd = socket_connect(addr, errp, NULL, NULL); + } + if (error_is_set(errp)) { + return NULL; + } + return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, + is_telnet, is_waitconnect, errp); +} + ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { @@ -3144,6 +3201,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_PORT: chr = qmp_chardev_open_port(backend->port, errp); break; + case CHARDEV_BACKEND_KIND_SOCKET: + chr = qmp_chardev_open_socket(backend->socket, errp); + break; case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; From 0a1a7fabda7f0fa05ef09051be29e92e81f929ad Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 20 Dec 2012 14:39:13 +0100 Subject: [PATCH 0516/1634] chardev: add pty chardev support to chardev-add (qmp) The ptsname is returned directly, so there is no need to use query-chardev to figure the pty device path. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 3 ++- qemu-char.c | 13 +++++++++++++ qmp-commands.hx | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/qapi-schema.json b/qapi-schema.json index 5c3e3eb469..6d7252b9e8 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3081,6 +3081,7 @@ { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', 'port' : 'ChardevPort', 'socket' : 'ChardevSocket', + 'pty' : 'ChardevDummy', 'null' : 'ChardevDummy' } } ## @@ -3090,7 +3091,7 @@ # # Since: 1.4 ## -{ 'type' : 'ChardevReturn', 'data': { } } +{ 'type' : 'ChardevReturn', 'data': { '*pty' : 'str' } } ## # @chardev-add: diff --git a/qemu-char.c b/qemu-char.c index 36d7e29953..9ba0573c6a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3204,6 +3204,19 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_SOCKET: chr = qmp_chardev_open_socket(backend->socket, errp); break; +#ifdef HAVE_CHARDEV_TTY + case CHARDEV_BACKEND_KIND_PTY: + { + /* qemu_chr_open_pty sets "path" in opts */ + QemuOpts *opts; + opts = qemu_opts_create_nofail(qemu_find_opts("chardev")); + chr = qemu_chr_open_pty(opts); + ret->pty = g_strdup(qemu_opt_get(opts, "path")); + ret->has_pty = true; + qemu_opts_del(opts); + break; + } +#endif case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; diff --git a/qmp-commands.hx b/qmp-commands.hx index 4d382f4ffc..cbf12804be 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2685,6 +2685,11 @@ Examples: "data" : { "out" : "/tmp/bar.log" } } } } <- { "return": {} } +-> { "execute" : "chardev-add", + "arguments" : { "id" : "baz", + "backend" : { "type" : "pty", "data" : {} } } } +<- { "return": { "pty" : "/dev/pty/42" } } + EQMP { From 2ba7f73006371312109991869b13bf8f4b4659c4 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 10 Jan 2013 21:42:48 +0100 Subject: [PATCH 0517/1634] alpha-linux-user: Translate fcntl l_type The values of F_RDLCK, F_WRLCK, F_UNLCK, F_EXLCK, F_SHLCK differ between alpha and other linux architectures. This patch allows to run "dpkg" (database lock). Signed-off-by: Laurent Vivier Signed-off-by: Richard Henderson --- linux-user/syscall.c | 28 ++++++++++++++++++++++------ linux-user/syscall_defs.h | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3167a87549..94f79dd3a1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4512,6 +4512,16 @@ static int target_to_host_fcntl_cmd(int cmd) return -TARGET_EINVAL; } +#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a } +static const bitmask_transtbl flock_tbl[] = { + TRANSTBL_CONVERT(F_RDLCK), + TRANSTBL_CONVERT(F_WRLCK), + TRANSTBL_CONVERT(F_UNLCK), + TRANSTBL_CONVERT(F_EXLCK), + TRANSTBL_CONVERT(F_SHLCK), + { 0, 0, 0, 0 } +}; + static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) { struct flock fl; @@ -4528,7 +4538,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_GETLK: if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) return -TARGET_EFAULT; - fl.l_type = tswap16(target_fl->l_type); + fl.l_type = + target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapal(target_fl->l_start); fl.l_len = tswapal(target_fl->l_len); @@ -4538,7 +4549,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) if (ret == 0) { if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0)) return -TARGET_EFAULT; - target_fl->l_type = tswap16(fl.l_type); + target_fl->l_type = + host_to_target_bitmask(tswap16(fl.l_type), flock_tbl); target_fl->l_whence = tswap16(fl.l_whence); target_fl->l_start = tswapal(fl.l_start); target_fl->l_len = tswapal(fl.l_len); @@ -4551,7 +4563,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_SETLKW: if (!lock_user_struct(VERIFY_READ, target_fl, arg, 1)) return -TARGET_EFAULT; - fl.l_type = tswap16(target_fl->l_type); + fl.l_type = + target_to_host_bitmask(tswap16(target_fl->l_type), flock_tbl); fl.l_whence = tswap16(target_fl->l_whence); fl.l_start = tswapal(target_fl->l_start); fl.l_len = tswapal(target_fl->l_len); @@ -4563,7 +4576,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_GETLK64: if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) return -TARGET_EFAULT; - fl64.l_type = tswap16(target_fl64->l_type) >> 1; + fl64.l_type = + target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswap64(target_fl64->l_start); fl64.l_len = tswap64(target_fl64->l_len); @@ -4573,7 +4587,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) if (ret == 0) { if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0)) return -TARGET_EFAULT; - target_fl64->l_type = tswap16(fl64.l_type) >> 1; + target_fl64->l_type = + host_to_target_bitmask(tswap16(fl64.l_type), flock_tbl) >> 1; target_fl64->l_whence = tswap16(fl64.l_whence); target_fl64->l_start = tswap64(fl64.l_start); target_fl64->l_len = tswap64(fl64.l_len); @@ -4585,7 +4600,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg) case TARGET_F_SETLKW64: if (!lock_user_struct(VERIFY_READ, target_fl64, arg, 1)) return -TARGET_EFAULT; - fl64.l_type = tswap16(target_fl64->l_type) >> 1; + fl64.l_type = + target_to_host_bitmask(tswap16(target_fl64->l_type), flock_tbl) >> 1; fl64.l_whence = tswap16(target_fl64->l_whence); fl64.l_start = tswap64(target_fl64->l_start); fl64.l_len = tswap64(target_fl64->l_len); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index f8f553915d..92c01a9603 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2017,6 +2017,12 @@ struct target_statfs64 { #define TARGET_F_SETLKW 9 #define TARGET_F_SETOWN 5 /* for sockets. */ #define TARGET_F_GETOWN 6 /* for sockets. */ + +#define TARGET_F_RDLCK 1 +#define TARGET_F_WRLCK 2 +#define TARGET_F_UNLCK 8 +#define TARGET_F_EXLCK 16 +#define TARGET_F_SHLCK 32 #elif defined(TARGET_MIPS) #define TARGET_F_GETLK 14 #define TARGET_F_SETLK 6 @@ -2031,6 +2037,18 @@ struct target_statfs64 { #define TARGET_F_GETOWN 9 /* for sockets. */ #endif +#ifndef TARGET_F_RDLCK +#define TARGET_F_RDLCK 0 +#define TARGET_F_WRLCK 1 +#define TARGET_F_UNLCK 2 +#endif + +#ifndef TARGET_F_EXLCK +#define TARGET_F_EXLCK 4 +#define TARGET_F_SHLCK 8 +#endif + + #define TARGET_F_SETSIG 10 /* for sockets. */ #define TARGET_F_GETSIG 11 /* for sockets. */ From 9468a5d4904223af2c47131f32e3a0555142e4e3 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 10 Jan 2013 22:30:50 +0100 Subject: [PATCH 0518/1634] alpha-linux-user: Correct select Alpha, like s390x, passes all select arguments in registers. Signed-off-by: Laurent Vivier Signed-off-by: Richard Henderson --- linux-user/syscall.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 94f79dd3a1..693e66fc4f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6227,8 +6227,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(settimeofday(&tv, NULL)); } break; -#if defined(TARGET_NR_select) && !defined(TARGET_S390X) && !defined(TARGET_S390) +#if defined(TARGET_NR_select) case TARGET_NR_select: +#if defined(TARGET_S390X) || defined(TARGET_ALPHA) + ret = do_select(arg1, arg2, arg3, arg4, arg5); +#else { struct target_sel_arg_struct *sel; abi_ulong inp, outp, exp, tvp; @@ -6244,6 +6247,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user_struct(sel, arg1, 0); ret = do_select(nsel, inp, outp, exp, tvp); } +#endif break; #endif #ifdef TARGET_NR_pselect6 @@ -7167,12 +7171,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif /* TARGET_NR_getdents64 */ -#if defined(TARGET_NR__newselect) || defined(TARGET_S390X) -#ifdef TARGET_S390X - case TARGET_NR_select: -#else +#if defined(TARGET_NR__newselect) case TARGET_NR__newselect: -#endif ret = do_select(arg1, arg2, arg3, arg4, arg5); break; #endif From b8e76b35d47d03f6f9bb3a7455316aaed8b25795 Mon Sep 17 00:00:00 2001 From: Knut Omang Date: Wed, 16 Jan 2013 16:34:34 +0100 Subject: [PATCH 0519/1634] Add new DEFAULT_MACHINE_OPTIONS to q35 and ppc405 Without this default q35/ppc405 based machines would no longer boot after commit e4ada29e909787f629626660b1561f6a680187d3 Signed-off-by: Knut Omang Reviewed-by: Markus Armbruster Signed-off-by: Anthony Liguori --- hw/pc_q35.c | 1 + hw/ppc405_boards.c | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/pc_q35.c b/hw/pc_q35.c index 52d997613f..d82353e84f 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -214,6 +214,7 @@ static QEMUMachine pc_q35_machine = { .desc = "Standard PC (Q35 + ICH9, 2009)", .init = pc_q35_init, .max_cpus = 255, + DEFAULT_MACHINE_OPTIONS, }; static void pc_q35_machine_init(void) diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index 45ed3769a3..cf371db053 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -362,6 +362,7 @@ static QEMUMachine ref405ep_machine = { .name = "ref405ep", .desc = "ref405ep", .init = ref405ep_init, + DEFAULT_MACHINE_OPTIONS, }; /*****************************************************************************/ From 4ecf8aa5a06a830b05c035a5d6184bf991931d20 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 16 Jan 2013 18:22:29 +0100 Subject: [PATCH 0520/1634] pseries: Replace non-portable asprintf by g_strdup_printf g_strdup_printf already handles OOM errors, so some error handling in QEMU code can be removed. Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- hw/spapr.c | 7 ++----- hw/spapr_vio.c | 29 ++++++----------------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 21c261be4a..d80b792b37 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -328,14 +328,11 @@ static void *spapr_create_fdt_skel(const char *cpu_model, continue; } - if (asprintf(&nodename, "%s@%x", modelname, index) < 0) { - fprintf(stderr, "Allocation failure\n"); - exit(1); - } + nodename = g_strdup_printf("%s@%x", modelname, index); _FDT((fdt_begin_node(fdt, nodename))); - free(nodename); + g_free(nodename); _FDT((fdt_property_cell(fdt, "reg", index))); _FDT((fdt_property_string(fdt, "device_type", "cpu"))); diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 3a1a4864e6..2054219c95 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -80,9 +80,7 @@ static char *vio_format_dev_name(VIOsPAPRDevice *dev) char *name; /* Device tree style name device@reg */ - if (asprintf(&name, "%s@%x", pc->dt_name, dev->reg) < 0) { - return NULL; - } + name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg); return name; } @@ -101,12 +99,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } 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); + g_free(dt_name); if (node_off < 0) { return node_off; } @@ -444,9 +438,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev) /* 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; } @@ -646,20 +637,12 @@ int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus) } name = vio_format_dev_name(dev); - if (!name) { - return -ENOMEM; - } - - if (asprintf(&path, "/vdevice/%s", name) < 0) { - path = NULL; - ret = -ENOMEM; - goto out; - } + path = g_strdup_printf("/vdevice/%s", name); ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path); -out: - free(name); - free(path); + + g_free(name); + g_free(path); return ret; } From 955d7b26779d6654f6ba2c456bac9fd49fa0cd8a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 18:20:57 +0100 Subject: [PATCH 0521/1634] ui: Drop useless null tests in parse_keyboard_layout() Spotted by Coverity. Signed-off-by: Markus Armbruster Signed-off-by: Anthony Liguori --- ui/keymaps.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ui/keymaps.c b/ui/keymaps.c index 9625d82fa1..f373cc53d9 100644 --- a/ui/keymaps.c +++ b/ui/keymaps.c @@ -127,25 +127,27 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, // fprintf(stderr, "Warning: unknown keysym %s\n", line); } else { const char *rest = end_of_keysym + 1; - char *rest2; - int keycode = strtol(rest, &rest2, 0); + int keycode = strtol(rest, NULL, 0); - if (rest && strstr(rest, "numlock")) { + if (strstr(rest, "numlock")) { add_to_key_range(&k->keypad_range, keycode); add_to_key_range(&k->numlock_range, keysym); //fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode); } - if (rest && strstr(rest, "shift")) + if (strstr(rest, "shift")) { keycode |= SCANCODE_SHIFT; - if (rest && strstr(rest, "altgr")) + } + if (strstr(rest, "altgr")) { keycode |= SCANCODE_ALTGR; - if (rest && strstr(rest, "ctrl")) + } + if (strstr(rest, "ctrl")) { keycode |= SCANCODE_CTRL; + } add_keysym(line, keysym, keycode, k); - if (rest && strstr(rest, "addupper")) { + if (strstr(rest, "addupper")) { char *c; for (c = line; *c; c++) *c = qemu_toupper(*c); From a1cbfd554e11bb8af38c2f3e1f1574bf4c563cd2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 18:20:25 +0100 Subject: [PATCH 0522/1634] usb-storage: Drop useless null test in usb_msd_handle_data() scsi_req_new() never returns null, and scsi_req_enqueue() dereferences the pointer, so checking for null is useless. Spotted by Coverity. Signed-off-by: Markus Armbruster Signed-off-by: Anthony Liguori --- hw/usb/dev-storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 1b87352db0..b839798eaf 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -427,7 +427,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) scsi_req_print(s->req); #endif scsi_req_enqueue(s->req); - if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { + if (s->req->cmd.xfer != SCSI_XFER_NONE) { scsi_req_continue(s->req); } break; From 457b65432700281b061086a2a8527bf1f59163a9 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 16 Jan 2013 18:17:33 +0100 Subject: [PATCH 0523/1634] audio: Replace non-portable asprintf in debug code by g_strdup_printf sw->name already uses the correct g_free to free the allocated memory. Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- audio/audio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 1510b598a6..02bb8861f8 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -828,8 +828,9 @@ static int audio_attach_capture (HWVoiceOut *hw) QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); QLIST_INSERT_HEAD (&hw->cap_head, sc, entries); #ifdef DEBUG_CAPTURE - asprintf (&sw->name, "for %p %d,%d,%d", - hw, sw->info.freq, sw->info.bits, sw->info.nchannels); + sw->name = g_strdup_printf ("for %p %d,%d,%d", + hw, sw->info.freq, sw->info.bits, + sw->info.nchannels); dolog ("Added %s active = %d\n", sw->name, sw->active); #endif if (sw->active) { From 2bf7b4572b39a494403190636b4e7d44967504c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 01:57:54 +0100 Subject: [PATCH 0524/1634] libqtest: Prepare I2C libqos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a simple I2C API and a driver implementation for omap_i2c. Signed-off-by: Andreas Färber Reviewed-by: Anthony Liguori Signed-off-by: Anthony Liguori --- tests/Makefile | 1 + tests/libi2c-omap.c | 166 ++++++++++++++++++++++++++++++++++++++++++++ tests/libi2c.c | 22 ++++++ tests/libi2c.h | 30 ++++++++ 4 files changed, 219 insertions(+) create mode 100644 tests/libi2c-omap.c create mode 100644 tests/libi2c.c create mode 100644 tests/libi2c.h diff --git a/tests/Makefile b/tests/Makefile index d97a571c8b..53c5873b3b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -116,6 +116,7 @@ QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TA check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y)) qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a +qtest-obj-y += tests/libi2c.o tests/libi2c-omap.o $(check-qtest-y): $(qtest-obj-y) .PHONY: check-help diff --git a/tests/libi2c-omap.c b/tests/libi2c-omap.c new file mode 100644 index 0000000000..9be57e92c4 --- /dev/null +++ b/tests/libi2c-omap.c @@ -0,0 +1,166 @@ +/* + * QTest I2C driver + * + * Copyright (c) 2012 Andreas Färber + * + * 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 "libi2c.h" + +#include +#include + +#include "qemu/osdep.h" +#include "libqtest.h" + +enum OMAPI2CRegisters { + OMAP_I2C_REV = 0x00, + OMAP_I2C_STAT = 0x08, + OMAP_I2C_CNT = 0x18, + OMAP_I2C_DATA = 0x1c, + OMAP_I2C_CON = 0x24, + OMAP_I2C_SA = 0x2c, +}; + +enum OMAPI2CSTATBits { + OMAP_I2C_STAT_NACK = 1 << 1, + OMAP_I2C_STAT_ARDY = 1 << 2, + OMAP_I2C_STAT_RRDY = 1 << 3, + OMAP_I2C_STAT_XRDY = 1 << 4, + OMAP_I2C_STAT_ROVR = 1 << 11, + OMAP_I2C_STAT_SBD = 1 << 15, +}; + +enum OMAPI2CCONBits { + OMAP_I2C_CON_STT = 1 << 0, + OMAP_I2C_CON_STP = 1 << 1, + OMAP_I2C_CON_TRX = 1 << 9, + OMAP_I2C_CON_MST = 1 << 10, + OMAP_I2C_CON_BE = 1 << 14, + OMAP_I2C_CON_I2C_EN = 1 << 15, +}; + +typedef struct OMAPI2C { + I2CAdapter parent; + + uint64_t addr; +} OMAPI2C; + + +static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr) +{ + uint16_t data = addr; + + memwrite(s->addr + OMAP_I2C_SA, &data, 2); + memread(s->addr + OMAP_I2C_SA, &data, 2); + g_assert_cmphex(data, ==, addr); +} + +static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr, + const uint8_t *buf, uint16_t len) +{ + OMAPI2C *s = (OMAPI2C *)i2c; + uint16_t data; + + omap_i2c_set_slave_addr(s, addr); + + data = len; + memwrite(s->addr + OMAP_I2C_CNT, &data, 2); + + data = OMAP_I2C_CON_I2C_EN | + OMAP_I2C_CON_TRX | + OMAP_I2C_CON_MST | + OMAP_I2C_CON_STT | + OMAP_I2C_CON_STP; + memwrite(s->addr + OMAP_I2C_CON, &data, 2); + memread(s->addr + OMAP_I2C_CON, &data, 2); + g_assert((data & OMAP_I2C_CON_STP) != 0); + + memread(s->addr + OMAP_I2C_STAT, &data, 2); + g_assert((data & OMAP_I2C_STAT_NACK) == 0); + + while (len > 1) { + memread(s->addr + OMAP_I2C_STAT, &data, 2); + g_assert((data & OMAP_I2C_STAT_XRDY) != 0); + + memwrite(s->addr + OMAP_I2C_DATA, buf, 2); + buf = (uint8_t *)buf + 2; + len -= 2; + } + if (len == 1) { + memread(s->addr + OMAP_I2C_STAT, &data, 2); + g_assert((data & OMAP_I2C_STAT_XRDY) != 0); + + memwrite(s->addr + OMAP_I2C_DATA, buf, 1); + } + + memread(s->addr + OMAP_I2C_CON, &data, 2); + g_assert((data & OMAP_I2C_CON_STP) == 0); +} + +static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr, + uint8_t *buf, uint16_t len) +{ + OMAPI2C *s = (OMAPI2C *)i2c; + uint16_t data, stat; + + omap_i2c_set_slave_addr(s, addr); + + data = len; + memwrite(s->addr + OMAP_I2C_CNT, &data, 2); + + data = OMAP_I2C_CON_I2C_EN | + OMAP_I2C_CON_MST | + OMAP_I2C_CON_STT | + OMAP_I2C_CON_STP; + memwrite(s->addr + OMAP_I2C_CON, &data, 2); + memread(s->addr + OMAP_I2C_CON, &data, 2); + g_assert((data & OMAP_I2C_CON_STP) == 0); + + memread(s->addr + OMAP_I2C_STAT, &data, 2); + g_assert((data & OMAP_I2C_STAT_NACK) == 0); + + memread(s->addr + OMAP_I2C_CNT, &data, 2); + g_assert_cmpuint(data, ==, len); + + while (len > 0) { + memread(s->addr + OMAP_I2C_STAT, &data, 2); + g_assert((data & OMAP_I2C_STAT_RRDY) != 0); + g_assert((data & OMAP_I2C_STAT_ROVR) == 0); + + memread(s->addr + OMAP_I2C_DATA, &data, 2); + + memread(s->addr + OMAP_I2C_STAT, &stat, 2); + if (unlikely(len == 1)) { + *buf = data & 0xf; + buf++; + len--; + } else { + memcpy(buf, &data, 2); + buf += 2; + len -= 2; + } + } + + memread(s->addr + OMAP_I2C_CON, &data, 2); + g_assert((data & OMAP_I2C_CON_STP) == 0); +} + +I2CAdapter *omap_i2c_create(uint64_t addr) +{ + OMAPI2C *s = g_malloc0(sizeof(*s)); + I2CAdapter *i2c = (I2CAdapter *)s; + uint16_t data; + + s->addr = addr; + + i2c->send = omap_i2c_send; + i2c->recv = omap_i2c_recv; + + /* verify the mmio address by looking for a known signature */ + memread(addr + OMAP_I2C_REV, &data, 2); + g_assert_cmphex(data, ==, 0x34); + + return i2c; +} diff --git a/tests/libi2c.c b/tests/libi2c.c new file mode 100644 index 0000000000..13ec85c0cb --- /dev/null +++ b/tests/libi2c.c @@ -0,0 +1,22 @@ +/* + * QTest I2C driver + * + * Copyright (c) 2012 Andreas Färber + * + * 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 "libi2c.h" +#include "libqtest.h" + +void i2c_send(I2CAdapter *i2c, uint8_t addr, + const uint8_t *buf, uint16_t len) +{ + i2c->send(i2c, addr, buf, len); +} + +void i2c_recv(I2CAdapter *i2c, uint8_t addr, + uint8_t *buf, uint16_t len) +{ + i2c->recv(i2c, addr, buf, len); +} diff --git a/tests/libi2c.h b/tests/libi2c.h new file mode 100644 index 0000000000..1ce9af4053 --- /dev/null +++ b/tests/libi2c.h @@ -0,0 +1,30 @@ +/* + * I2C libqos + * + * Copyright (c) 2012 Andreas Färber + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef LIBQOS_I2C_H +#define LIBQOS_I2C_H + +#include + +typedef struct I2CAdapter I2CAdapter; +struct I2CAdapter { + void (*send)(I2CAdapter *adapter, uint8_t addr, + const uint8_t *buf, uint16_t len); + void (*recv)(I2CAdapter *adapter, uint8_t addr, + uint8_t *buf, uint16_t len); +}; + +void i2c_send(I2CAdapter *i2c, uint8_t addr, + const uint8_t *buf, uint16_t len); +void i2c_recv(I2CAdapter *i2c, uint8_t addr, + uint8_t *buf, uint16_t len); + +/* libi2c-omap.c */ +I2CAdapter *omap_i2c_create(uint64_t addr); + +#endif From 6d0b430176e3571af0e1596276078f05bfe1c5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 01:57:55 +0100 Subject: [PATCH 0525/1634] tmp105: Split out I2C message constants from header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows value sharing with qtest. Signed-off-by: Andreas Färber Reviewed-by: Anthony Liguori Signed-off-by: Anthony Liguori --- hw/tmp105.h | 34 +------------------------------- hw/tmp105_regs.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 33 deletions(-) create mode 100644 hw/tmp105_regs.h diff --git a/hw/tmp105.h b/hw/tmp105.h index 51eff4be1c..982d1c927a 100644 --- a/hw/tmp105.h +++ b/hw/tmp105.h @@ -15,39 +15,7 @@ #define QEMU_TMP105_H #include "i2c.h" - -/** - * TMP105Reg: - * @TMP105_REG_TEMPERATURE: Temperature register - * @TMP105_REG_CONFIG: Configuration register - * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst) - * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS) - * - * The following temperature sensors are - * compatible with the TMP105 registers: - * - adt75 - * - ds1775 - * - ds75 - * - lm75 - * - lm75a - * - max6625 - * - max6626 - * - mcp980x - * - stds75 - * - tcn75 - * - tmp100 - * - tmp101 - * - tmp105 - * - tmp175 - * - tmp275 - * - tmp75 - **/ -typedef enum TMP105Reg { - TMP105_REG_TEMPERATURE = 0, - TMP105_REG_CONFIG, - TMP105_REG_T_LOW, - TMP105_REG_T_HIGH, -} TMP105Reg; +#include "tmp105_regs.h" /** * tmp105_set: diff --git a/hw/tmp105_regs.h b/hw/tmp105_regs.h new file mode 100644 index 0000000000..9b55abaf90 --- /dev/null +++ b/hw/tmp105_regs.h @@ -0,0 +1,50 @@ +/* + * Texas Instruments TMP105 Temperature Sensor I2C messages + * + * Browse the data sheet: + * + * http://www.ti.com/lit/gpn/tmp105 + * + * Copyright (C) 2012 Alex Horn + * Copyright (C) 2008-2012 Andrzej Zaborowski + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ +#ifndef QEMU_TMP105_MSGS_H +#define QEMU_TMP105_MSGS_H + +/** + * TMP105Reg: + * @TMP105_REG_TEMPERATURE: Temperature register + * @TMP105_REG_CONFIG: Configuration register + * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst) + * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS) + * + * The following temperature sensors are + * compatible with the TMP105 registers: + * - adt75 + * - ds1775 + * - ds75 + * - lm75 + * - lm75a + * - max6625 + * - max6626 + * - mcp980x + * - stds75 + * - tcn75 + * - tmp100 + * - tmp101 + * - tmp105 + * - tmp175 + * - tmp275 + * - tmp75 + **/ +typedef enum TMP105Reg { + TMP105_REG_TEMPERATURE = 0, + TMP105_REG_CONFIG, + TMP105_REG_T_LOW, + TMP105_REG_T_HIGH, +} TMP105Reg; + +#endif From cb5ef3fa1871522a0886627033459e94bd537fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 01:57:56 +0100 Subject: [PATCH 0526/1634] tmp105: Fix I2C protocol bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An early length postincrement in the TMP105's I2C TX path led to transfers of more than one byte to place the second byte in the third byte's place within the buffer and the third byte to get discarded. Fix this by explictly incrementing the length after the checks but before the callback is called, which again checks the length. Adjust the Coding Style while at it. Signed-off-by: Alex Horn Signed-off-by: Andreas Färber Reviewed-by: Anthony Liguori Signed-off-by: Anthony Liguori --- hw/tmp105.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/tmp105.c b/hw/tmp105.c index 0ade4eb6bd..10d94c903c 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -153,11 +153,14 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data) { TMP105State *s = (TMP105State *) i2c; - if (!s->len ++) + if (s->len == 0) { s->pointer = data; - else { - if (s->len <= 2) + s->len++; + } else { + if (s->len <= 2) { s->buf[s->len - 1] = data; + } + s->len++; tmp105_write(s); } From 6e9989034b176a8e4cfdccd85892abfa73977ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 01:57:57 +0100 Subject: [PATCH 0527/1634] tests: Add tmp105 qtest test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exercise all four commands of the TMP105, testing for an issue in the I2C TX path. The test case uses the N800's OMAP I2C and is the first for ARM. Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- tests/Makefile | 3 ++ tests/tmp105-test.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/tmp105-test.c diff --git a/tests/Makefile b/tests/Makefile index 53c5873b3b..d86e95a400 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -60,6 +60,8 @@ gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) gcov-files-sparc-y += hw/m48t59.c +check-qtest-arm-y = tests/tmp105-test$(EXESUF) +qcov-files-arm-y += hw/tmp105.c GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h @@ -108,6 +110,7 @@ tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/fdc-test$(EXESUF): tests/fdc-test.o tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o +tests/tmp105-test$(EXESUF): tests/tmp105-test.o # QTest rules diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c new file mode 100644 index 0000000000..a6ad213de8 --- /dev/null +++ b/tests/tmp105-test.c @@ -0,0 +1,76 @@ +/* + * QTest testcase for the TMP105 temperature sensor + * + * Copyright (c) 2012 Andreas Färber + * + * 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 "libqtest.h" +#include "libi2c.h" +#include "hw/tmp105_regs.h" + +#include + +#define OMAP2_I2C_1_BASE 0x48070000 + +#define N8X0_ADDR 0x48 + +static I2CAdapter *i2c; +static uint8_t addr; + +static void send_and_receive(void) +{ + uint8_t cmd[3]; + uint8_t resp[2]; + + cmd[0] = TMP105_REG_TEMPERATURE; + i2c_send(i2c, addr, cmd, 1); + i2c_recv(i2c, addr, resp, 2); + g_assert_cmpuint(((uint16_t)resp[0] << 8) | resp[1], ==, 0); + + cmd[0] = TMP105_REG_CONFIG; + cmd[1] = 0x0; /* matches the reset value */ + i2c_send(i2c, addr, cmd, 2); + i2c_recv(i2c, addr, resp, 1); + g_assert_cmphex(resp[0], ==, cmd[1]); + + cmd[0] = TMP105_REG_T_LOW; + cmd[1] = 0x12; + cmd[2] = 0x34; + i2c_send(i2c, addr, cmd, 3); + i2c_recv(i2c, addr, resp, 2); + g_assert_cmphex(resp[0], ==, cmd[1]); + g_assert_cmphex(resp[1], ==, cmd[2]); + + cmd[0] = TMP105_REG_T_HIGH; + cmd[1] = 0x42; + cmd[2] = 0x31; + i2c_send(i2c, addr, cmd, 3); + i2c_recv(i2c, addr, resp, 2); + g_assert_cmphex(resp[0], ==, cmd[1]); + g_assert_cmphex(resp[1], ==, cmd[2]); +} + +int main(int argc, char **argv) +{ + QTestState *s = NULL; + int ret; + + g_test_init(&argc, &argv, NULL); + + s = qtest_start("-display none -machine n800"); + i2c = omap_i2c_create(OMAP2_I2C_1_BASE); + addr = N8X0_ADDR; + + qtest_add_func("/tmp105/tx-rx", send_and_receive); + + ret = g_test_run(); + + if (s) { + qtest_quit(s); + } + g_free(i2c); + + return ret; +} From 2aad80eeb788c7c3f71c57e78352f0fdadf8fe28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 01:57:58 +0100 Subject: [PATCH 0528/1634] tmp105: QOM'ify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce TYPE_ constant and cast macro. Move the state struct to the new header to allow for future embedding. Signed-off-by: Andreas Färber Reviewed-by: Anthony Liguori Signed-off-by: Anthony Liguori --- hw/tmp105.c | 36 ++++++++++++------------------------ hw/tmp105.h | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/hw/tmp105.c b/hw/tmp105.c index 10d94c903c..a16f53888a 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -22,20 +22,6 @@ #include "i2c.h" #include "tmp105.h" -typedef struct { - I2CSlave i2c; - uint8_t len; - uint8_t buf[2]; - qemu_irq pin; - - uint8_t pointer; - uint8_t config; - int16_t temperature; - int16_t limit[2]; - int faults; - uint8_t alarm; -} TMP105State; - static void tmp105_interrupt_update(TMP105State *s) { qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */ @@ -68,7 +54,7 @@ static void tmp105_alarm_update(TMP105State *s) /* Units are 0.001 centigrades relative to 0 C. */ void tmp105_set(I2CSlave *i2c, int temp) { - TMP105State *s = (TMP105State *) i2c; + TMP105State *s = TMP105(i2c); if (temp >= 128000 || temp < -128000) { fprintf(stderr, "%s: values is out of range (%i.%03i C)\n", @@ -141,17 +127,18 @@ static void tmp105_write(TMP105State *s) static int tmp105_rx(I2CSlave *i2c) { - TMP105State *s = (TMP105State *) i2c; + TMP105State *s = TMP105(i2c); - if (s->len < 2) + if (s->len < 2) { return s->buf[s->len ++]; - else + } else { return 0xff; + } } static int tmp105_tx(I2CSlave *i2c, uint8_t data) { - TMP105State *s = (TMP105State *) i2c; + TMP105State *s = TMP105(i2c); if (s->len == 0) { s->pointer = data; @@ -169,10 +156,11 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data) static void tmp105_event(I2CSlave *i2c, enum i2c_event event) { - TMP105State *s = (TMP105State *) i2c; + TMP105State *s = TMP105(i2c); - if (event == I2C_START_RECV) + if (event == I2C_START_RECV) { tmp105_read(s); + } s->len = 0; } @@ -208,7 +196,7 @@ static const VMStateDescription vmstate_tmp105 = { static void tmp105_reset(I2CSlave *i2c) { - TMP105State *s = (TMP105State *) i2c; + TMP105State *s = TMP105(i2c); s->temperature = 0; s->pointer = 0; @@ -221,7 +209,7 @@ static void tmp105_reset(I2CSlave *i2c) static int tmp105_init(I2CSlave *i2c) { - TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c); + TMP105State *s = TMP105(i2c); qdev_init_gpio_out(&i2c->qdev, &s->pin, 1); @@ -243,7 +231,7 @@ static void tmp105_class_init(ObjectClass *klass, void *data) } static const TypeInfo tmp105_info = { - .name = "tmp105", + .name = TYPE_TMP105, .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(TMP105State), .class_init = tmp105_class_init, diff --git a/hw/tmp105.h b/hw/tmp105.h index 982d1c927a..c21396f500 100644 --- a/hw/tmp105.h +++ b/hw/tmp105.h @@ -17,6 +17,33 @@ #include "i2c.h" #include "tmp105_regs.h" +#define TYPE_TMP105 "tmp105" +#define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105) + +/** + * TMP105State: + * @config: Bits 5 and 6 (value 32 and 64) determine the precision of the + * temperature. See Table 8 in the data sheet. + * + * @see_also: http://www.ti.com/lit/gpn/tmp105 + */ +typedef struct TMP105State { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + + uint8_t len; + uint8_t buf[2]; + qemu_irq pin; + + uint8_t pointer; + uint8_t config; + int16_t temperature; + int16_t limit[2]; + int faults; + uint8_t alarm; +} TMP105State; + /** * tmp105_set: * @i2c: dispatcher to TMP105 hardware model From eb60d1c55268f489b32e6b694e84e2017b75a3d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 01:57:59 +0100 Subject: [PATCH 0529/1634] tmp105: Add temperature QOM property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This obsoletes tmp105_set() and allows for better error handling. Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- hw/tmp105.c | 36 ++++++++++++++++++++++++++++++------ hw/tmp105.h | 15 --------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/hw/tmp105.c b/hw/tmp105.c index a16f53888a..3ad2d2f04c 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -21,6 +21,7 @@ #include "hw.h" #include "i2c.h" #include "tmp105.h" +#include "qapi/visitor.h" static void tmp105_interrupt_update(TMP105State *s) { @@ -51,15 +52,30 @@ static void tmp105_alarm_update(TMP105State *s) tmp105_interrupt_update(s); } -/* Units are 0.001 centigrades relative to 0 C. */ -void tmp105_set(I2CSlave *i2c, int temp) +static void tmp105_get_temperature(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { - TMP105State *s = TMP105(i2c); + TMP105State *s = TMP105(obj); + int64_t value = s->temperature; + visit_type_int(v, &value, name, errp); +} + +/* Units are 0.001 centigrades relative to 0 C. */ +static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + TMP105State *s = TMP105(obj); + int64_t temp; + + visit_type_int(v, &temp, name, errp); + if (error_is_set(errp)) { + return; + } if (temp >= 128000 || temp < -128000) { - fprintf(stderr, "%s: values is out of range (%i.%03i C)\n", - __FUNCTION__, temp / 1000, temp % 1000); - exit(-1); + error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range", + temp / 1000, temp % 1000); + return; } s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4; @@ -218,6 +234,13 @@ static int tmp105_init(I2CSlave *i2c) return 0; } +static void tmp105_initfn(Object *obj) +{ + object_property_add(obj, "temperature", "int", + tmp105_get_temperature, + tmp105_set_temperature, NULL, NULL, NULL); +} + static void tmp105_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -234,6 +257,7 @@ static const TypeInfo tmp105_info = { .name = TYPE_TMP105, .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(TMP105State), + .instance_init = tmp105_initfn, .class_init = tmp105_class_init, }; diff --git a/hw/tmp105.h b/hw/tmp105.h index c21396f500..d2189191e2 100644 --- a/hw/tmp105.h +++ b/hw/tmp105.h @@ -44,19 +44,4 @@ typedef struct TMP105State { uint8_t alarm; } TMP105State; -/** - * tmp105_set: - * @i2c: dispatcher to TMP105 hardware model - * @temp: temperature with 0.001 centigrades units in the range -40 C to +125 C - * - * Sets the temperature of the TMP105 hardware model. - * - * Bits 5 and 6 (value 32 and 64) in the register indexed by TMP105_REG_CONFIG - * determine the precision of the temperature. See Table 8 in the data sheet. - * - * @see_also: I2C_SLAVE macro - * @see_also: http://www.ti.com/lit/gpn/tmp105 - */ -void tmp105_set(I2CSlave *i2c, int temp); - #endif From af381ebeacdefcec0d2b44bdbb9d6e01e35f691f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 15 Jan 2013 09:49:36 +0100 Subject: [PATCH 0530/1634] build: fix Win32 clean build The version.o file did not appear explicitly as a dependency, and this caused clean builds to fail. Force its build by making the Makefile depend on version.o. (We cannot add it to libqemuutil.a, because it doesn't export any symbol and thus would not be pulled by the linker). Cc: Blue Swirl Cc: Stefan Weil Tested-by: Stefan Weil Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 7622a4cfa4..cfa2fa6383 100644 --- a/Makefile +++ b/Makefile @@ -153,6 +153,7 @@ version.o: $(SRC_PATH)/version.rc config-host.h $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC $(TARGET_DIR)$@") version-obj-$(CONFIG_WIN32) += version.o +Makefile: $(version-obj-y) ###################################################################### # Build libraries From a4cbfe24e4d9f86622ba81b8c5b599c92c682fbc Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 13 Jan 2013 16:35:41 +0000 Subject: [PATCH 0531/1634] bswap: improve gluing OpenBSD system compiler (gcc 4.2.1) has problems with concatenation of macro arguments in macro functions: CC aes.o In file included from /src/qemu/include/qemu-common.h:126, from /src/qemu/aes.c:30: /src/qemu/include/qemu/bswap.h: In function 'leul_to_cpu': /src/qemu/include/qemu/bswap.h:461: warning: implicit declaration of function 'bswapHOST_LONG_BITS' /src/qemu/include/qemu/bswap.h:461: warning: nested extern declaration of 'bswapHOST_LONG_BITS' Function leul_to_cpu() is only used in kvm-all.c, so the warnings are not fatal on OpenBSD without -Werror. Fix by applying glue(). Also add do {} while(0) wrapping and fix semicolon use while at it. Signed-off-by: Blue Swirl Signed-off-by: Anthony Liguori --- include/qemu/bswap.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index be9b035353..e6d4798142 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -72,45 +72,45 @@ static inline void bswap64s(uint64_t *s) #if defined(HOST_WORDS_BIGENDIAN) #define be_bswap(v, size) (v) -#define le_bswap(v, size) bswap ## size(v) +#define le_bswap(v, size) glue(bswap, size)(v) #define be_bswaps(v, size) -#define le_bswaps(p, size) *p = bswap ## size(*p); +#define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) #else #define le_bswap(v, size) (v) -#define be_bswap(v, size) bswap ## size(v) +#define be_bswap(v, size) glue(bswap, size)(v) #define le_bswaps(v, size) -#define be_bswaps(p, size) *p = bswap ## size(*p); +#define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) #endif #define CPU_CONVERT(endian, size, type)\ static inline type endian ## size ## _to_cpu(type v)\ {\ - return endian ## _bswap(v, size);\ + return glue(endian, _bswap)(v, size);\ }\ \ static inline type cpu_to_ ## endian ## size(type v)\ {\ - return endian ## _bswap(v, size);\ + return glue(endian, _bswap)(v, size);\ }\ \ static inline void endian ## size ## _to_cpus(type *p)\ {\ - endian ## _bswaps(p, size)\ + glue(endian, _bswaps)(p, size);\ }\ \ static inline void cpu_to_ ## endian ## size ## s(type *p)\ {\ - endian ## _bswaps(p, size)\ + glue(endian, _bswaps)(p, size);\ }\ \ static inline type endian ## size ## _to_cpup(const type *p)\ {\ - return endian ## size ## _to_cpu(*p);\ + return glue(glue(endian, size), _to_cpu)(*p);\ }\ \ static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ {\ - *p = cpu_to_ ## endian ## size(v);\ + *p = glue(glue(cpu_to_, endian), size)(v);\ } CPU_CONVERT(be, 16, uint16_t) From 6d759117d3fd28e38c49c56c9de206cc718d32fa Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Tue, 15 Jan 2013 10:47:24 -0500 Subject: [PATCH 0532/1634] block: fix null-pointer bug on error case in block commit This is a bug that was caught by a coverity run by Markus. In the error case when we errored out to exit_restore_open early in the function, 'overlay_bs' was still NULL at that point, although it is used to look up flags and perform a bdrv_reopen(). Move the overlay_bs lookup to where it is needed, and check for NULL before restoring the flags. Also get rid of the unneeded parameter initialization. Reported-By: Markus Armbruster Signed-off-by: Jeff Cody Signed-off-by: Stefan Hajnoczi --- block/commit.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/block/commit.c b/block/commit.c index 61ebdba54f..553447efe7 100644 --- a/block/commit.c +++ b/block/commit.c @@ -65,7 +65,7 @@ static void coroutine_fn commit_run(void *opaque) BlockDriverState *active = s->active; BlockDriverState *top = s->top; BlockDriverState *base = s->base; - BlockDriverState *overlay_bs = NULL; + BlockDriverState *overlay_bs; int64_t sector_num, end; int ret = 0; int n = 0; @@ -92,8 +92,6 @@ static void coroutine_fn commit_run(void *opaque) } } - overlay_bs = bdrv_find_overlay(active, top); - end = s->common.len >> BDRV_SECTOR_BITS; buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE); @@ -156,7 +154,8 @@ exit_restore_reopen: if (s->base_flags != bdrv_get_flags(base)) { bdrv_reopen(base, s->base_flags, NULL); } - if (s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { + overlay_bs = bdrv_find_overlay(active, top); + if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); } From 6bf3ee07ff55aa795010a8e071826f38e9a26112 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 16 Jan 2013 10:54:34 +0100 Subject: [PATCH 0533/1634] ide: Remove wrong assertion The Bus Master IDE Active bit (BM_STATUS_DMAING) is not only set when the request is still in flight, but also when it has completed and the size of the physical memory regions in the PRDT was larger than the transfer size. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- hw/ide/pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index e6226e3197..59fd53992a 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -311,7 +311,6 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) if (bm->bus->dma->aiocb) { bdrv_drain_all(); assert(bm->bus->dma->aiocb == NULL); - assert((bm->status & BM_STATUS_DMAING) == 0); } } else { bm->cur_addr = bm->addr; From 2ea9b58f0bc62445b7ace2381b4c4db7d5597e19 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 16 Jan 2013 19:25:51 +0100 Subject: [PATCH 0534/1634] aio: Fix return value of aio_poll() aio_poll() must return true if any work is still pending, even if it didn't make progress, so that bdrv_drain_all() doesn't stop waiting too early. The possibility of stopping early occasionally lead to a failed assertion in bdrv_drain_all(), when some in-flight request was missed and the function didn't really drain all requests. In order to make that change, the return value as specified in the function comment must change for blocking = false; fortunately, the return value of blocking = false callers is only used in test cases, so this change shouldn't cause any trouble. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- aio-posix.c | 3 ++- aio-win32.c | 3 ++- include/block/aio.h | 6 ++---- tests/test-aio.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/aio-posix.c b/aio-posix.c index 88d09e1cfb..fe4dbb4523 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -264,5 +264,6 @@ bool aio_poll(AioContext *ctx, bool blocking) } } - return progress; + assert(progress || busy); + return true; } diff --git a/aio-win32.c b/aio-win32.c index f5ea027f8c..38723bf1d3 100644 --- a/aio-win32.c +++ b/aio-win32.c @@ -214,5 +214,6 @@ bool aio_poll(AioContext *ctx, bool blocking) events[ret - WAIT_OBJECT_0] = events[--count]; } - return progress; + assert(progress || busy); + return true; } diff --git a/include/block/aio.h b/include/block/aio.h index 0933f05878..8eda924599 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -173,16 +173,14 @@ bool aio_pending(AioContext *ctx); * aio as a result of executing I/O completion or bh callbacks. * * If there is no pending AIO operation or completion (bottom half), - * return false. If there are pending bottom halves, return true. + * return false. If there are pending AIO operations of bottom halves, + * return true. * * If there are no pending bottom halves, but there are pending AIO * operations, it may not be possible to make any progress without * blocking. If @blocking is true, this function will wait until one * or more AIO events have completed, to ensure something has moved * before returning. - * - * If @blocking is false, this function will also return false if the - * function cannot make any progress without blocking. */ bool aio_poll(AioContext *ctx, bool blocking); diff --git a/tests/test-aio.c b/tests/test-aio.c index e4ebef76b9..c1738706cd 100644 --- a/tests/test-aio.c +++ b/tests/test-aio.c @@ -315,13 +315,13 @@ static void test_wait_event_notifier_noflush(void) event_notifier_set(&data.e); g_assert(aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 1); - g_assert(!aio_poll(ctx, false)); + g_assert(aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 1); event_notifier_set(&data.e); g_assert(aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 2); - g_assert(!aio_poll(ctx, false)); + g_assert(aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 2); event_notifier_set(&dummy.e); From bcbbd234d42f1111e42b91376db61922d42e7e9e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 16 Jan 2013 21:19:59 +0100 Subject: [PATCH 0535/1634] win32-aio: Fix vectored reads Copying data in the right direction really helps a lot! Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/win32-aio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/win32-aio.c b/block/win32-aio.c index 03833700b4..e4b7b75d29 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -84,7 +84,7 @@ static void win32_aio_process_completion(QEMUWin32AIOState *s, int i; for (i = 0; i < qiov->niov; ++i) { - memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len); + memcpy(qiov->iov[i].iov_base, p, qiov->iov[i].iov_len); p += qiov->iov[i].iov_len; } qemu_vfree(waiocb->buf); From e8bccad5ac6095b5af7946cd72d9aacb57f7c0a3 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 16 Jan 2013 21:20:00 +0100 Subject: [PATCH 0536/1634] win32-aio: Fix memory leak The buffer is allocated for both reads and writes, and obviously it should be freed even if an error occurs. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/win32-aio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/win32-aio.c b/block/win32-aio.c index e4b7b75d29..b9236ea74d 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -87,8 +87,8 @@ static void win32_aio_process_completion(QEMUWin32AIOState *s, memcpy(qiov->iov[i].iov_base, p, qiov->iov[i].iov_len); p += qiov->iov[i].iov_len; } - qemu_vfree(waiocb->buf); } + qemu_vfree(waiocb->buf); } From 84f2d0ea0f39bc140a6c69ba8e3ffd6b10cae6fa Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Mon, 14 Jan 2013 14:06:25 +0800 Subject: [PATCH 0537/1634] HMP: add QDict to info callback handler This patch change all info call back function to take additional QDict * parameter, which allow those command take parameter. Now it is set to NULL at default case. Signed-off-by: Wenchao Xia Signed-off-by: Luiz Capitulino --- hmp.c | 36 ++++++++++++++++++------------------ hmp.h | 36 ++++++++++++++++++------------------ hw/i8259.c | 4 ++-- hw/lm32_pic.c | 4 ++-- hw/lm32_pic.h | 4 ++-- hw/loader.c | 2 +- hw/loader.h | 3 ++- hw/pc.h | 4 ++-- hw/pcmcia.h | 2 +- hw/qdev-monitor.c | 4 ++-- hw/qdev-monitor.h | 4 ++-- hw/sun4m.c | 4 ++-- hw/sun4m.h | 4 ++-- hw/usb.h | 2 +- hw/usb/bus.c | 2 +- hw/usb/host-bsd.c | 2 +- hw/usb/host-linux.c | 2 +- include/net/net.h | 2 +- include/net/slirp.h | 2 +- include/sysemu/sysemu.h | 4 ++-- monitor.c | 32 ++++++++++++++++---------------- net/net.c | 2 +- net/slirp.c | 2 +- savevm.c | 2 +- vl.c | 2 +- 25 files changed, 84 insertions(+), 83 deletions(-) diff --git a/hmp.c b/hmp.c index 68929b4acf..c7b6ba02fc 100644 --- a/hmp.c +++ b/hmp.c @@ -31,7 +31,7 @@ static void hmp_handle_error(Monitor *mon, Error **errp) } } -void hmp_info_name(Monitor *mon) +void hmp_info_name(Monitor *mon, const QDict *qdict) { NameInfo *info; @@ -42,7 +42,7 @@ void hmp_info_name(Monitor *mon) qapi_free_NameInfo(info); } -void hmp_info_version(Monitor *mon) +void hmp_info_version(Monitor *mon, const QDict *qdict) { VersionInfo *info; @@ -55,7 +55,7 @@ void hmp_info_version(Monitor *mon) qapi_free_VersionInfo(info); } -void hmp_info_kvm(Monitor *mon) +void hmp_info_kvm(Monitor *mon, const QDict *qdict) { KvmInfo *info; @@ -70,7 +70,7 @@ void hmp_info_kvm(Monitor *mon) qapi_free_KvmInfo(info); } -void hmp_info_status(Monitor *mon) +void hmp_info_status(Monitor *mon, const QDict *qdict) { StatusInfo *info; @@ -89,7 +89,7 @@ void hmp_info_status(Monitor *mon) qapi_free_StatusInfo(info); } -void hmp_info_uuid(Monitor *mon) +void hmp_info_uuid(Monitor *mon, const QDict *qdict) { UuidInfo *info; @@ -98,7 +98,7 @@ void hmp_info_uuid(Monitor *mon) qapi_free_UuidInfo(info); } -void hmp_info_chardev(Monitor *mon) +void hmp_info_chardev(Monitor *mon, const QDict *qdict) { ChardevInfoList *char_info, *info; @@ -111,7 +111,7 @@ void hmp_info_chardev(Monitor *mon) qapi_free_ChardevInfoList(char_info); } -void hmp_info_mice(Monitor *mon) +void hmp_info_mice(Monitor *mon, const QDict *qdict) { MouseInfoList *mice_list, *mouse; @@ -131,7 +131,7 @@ void hmp_info_mice(Monitor *mon) qapi_free_MouseInfoList(mice_list); } -void hmp_info_migrate(Monitor *mon) +void hmp_info_migrate(Monitor *mon, const QDict *qdict) { MigrationInfo *info; MigrationCapabilityStatusList *caps, *cap; @@ -209,7 +209,7 @@ void hmp_info_migrate(Monitor *mon) qapi_free_MigrationCapabilityStatusList(caps); } -void hmp_info_migrate_capabilities(Monitor *mon) +void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict) { MigrationCapabilityStatusList *caps, *cap; @@ -228,13 +228,13 @@ void hmp_info_migrate_capabilities(Monitor *mon) qapi_free_MigrationCapabilityStatusList(caps); } -void hmp_info_migrate_cache_size(Monitor *mon) +void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n", qmp_query_migrate_cache_size(NULL) >> 10); } -void hmp_info_cpus(Monitor *mon) +void hmp_info_cpus(Monitor *mon, const QDict *qdict) { CpuInfoList *cpu_list, *cpu; @@ -272,7 +272,7 @@ void hmp_info_cpus(Monitor *mon) qapi_free_CpuInfoList(cpu_list); } -void hmp_info_block(Monitor *mon) +void hmp_info_block(Monitor *mon, const QDict *qdict) { BlockInfoList *block_list, *info; @@ -326,7 +326,7 @@ void hmp_info_block(Monitor *mon) qapi_free_BlockInfoList(block_list); } -void hmp_info_blockstats(Monitor *mon) +void hmp_info_blockstats(Monitor *mon, const QDict *qdict) { BlockStatsList *stats_list, *stats; @@ -360,7 +360,7 @@ void hmp_info_blockstats(Monitor *mon) qapi_free_BlockStatsList(stats_list); } -void hmp_info_vnc(Monitor *mon) +void hmp_info_vnc(Monitor *mon, const QDict *qdict) { VncInfo *info; Error *err = NULL; @@ -406,7 +406,7 @@ out: qapi_free_VncInfo(info); } -void hmp_info_spice(Monitor *mon) +void hmp_info_spice(Monitor *mon, const QDict *qdict) { SpiceChannelList *chan; SpiceInfo *info; @@ -453,7 +453,7 @@ out: qapi_free_SpiceInfo(info); } -void hmp_info_balloon(Monitor *mon) +void hmp_info_balloon(Monitor *mon, const QDict *qdict) { BalloonInfo *info; Error *err = NULL; @@ -570,7 +570,7 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev) } } -void hmp_info_pci(Monitor *mon) +void hmp_info_pci(Monitor *mon, const QDict *qdict) { PciInfoList *info_list, *info; Error *err = NULL; @@ -593,7 +593,7 @@ void hmp_info_pci(Monitor *mon) qapi_free_PciInfoList(info_list); } -void hmp_info_block_jobs(Monitor *mon) +void hmp_info_block_jobs(Monitor *mon, const QDict *qdict) { BlockJobInfoList *list; Error *err = NULL; diff --git a/hmp.h b/hmp.h index 700fbdc777..44be683fcc 100644 --- a/hmp.h +++ b/hmp.h @@ -18,24 +18,24 @@ #include "qapi-types.h" #include "qapi/qmp/qdict.h" -void hmp_info_name(Monitor *mon); -void hmp_info_version(Monitor *mon); -void hmp_info_kvm(Monitor *mon); -void hmp_info_status(Monitor *mon); -void hmp_info_uuid(Monitor *mon); -void hmp_info_chardev(Monitor *mon); -void hmp_info_mice(Monitor *mon); -void hmp_info_migrate(Monitor *mon); -void hmp_info_migrate_capabilities(Monitor *mon); -void hmp_info_migrate_cache_size(Monitor *mon); -void hmp_info_cpus(Monitor *mon); -void hmp_info_block(Monitor *mon); -void hmp_info_blockstats(Monitor *mon); -void hmp_info_vnc(Monitor *mon); -void hmp_info_spice(Monitor *mon); -void hmp_info_balloon(Monitor *mon); -void hmp_info_pci(Monitor *mon); -void hmp_info_block_jobs(Monitor *mon); +void hmp_info_name(Monitor *mon, const QDict *qdict); +void hmp_info_version(Monitor *mon, const QDict *qdict); +void hmp_info_kvm(Monitor *mon, const QDict *qdict); +void hmp_info_status(Monitor *mon, const QDict *qdict); +void hmp_info_uuid(Monitor *mon, const QDict *qdict); +void hmp_info_chardev(Monitor *mon, const QDict *qdict); +void hmp_info_mice(Monitor *mon, const QDict *qdict); +void hmp_info_migrate(Monitor *mon, const QDict *qdict); +void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict); +void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict); +void hmp_info_cpus(Monitor *mon, const QDict *qdict); +void hmp_info_block(Monitor *mon, const QDict *qdict); +void hmp_info_blockstats(Monitor *mon, const QDict *qdict); +void hmp_info_vnc(Monitor *mon, const QDict *qdict); +void hmp_info_spice(Monitor *mon, const QDict *qdict); +void hmp_info_balloon(Monitor *mon, const QDict *qdict); +void hmp_info_pci(Monitor *mon, const QDict *qdict); +void hmp_info_block_jobs(Monitor *mon, const QDict *qdict); void hmp_quit(Monitor *mon, const QDict *qdict); void hmp_stop(Monitor *mon, const QDict *qdict); void hmp_system_reset(Monitor *mon, const QDict *qdict); diff --git a/hw/i8259.c b/hw/i8259.c index 264879e097..54fe14447b 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -407,7 +407,7 @@ static void pic_init(PICCommonState *s) qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8); } -void pic_info(Monitor *mon) +void pic_info(Monitor *mon, const QDict *qdict) { int i; PICCommonState *s; @@ -425,7 +425,7 @@ void pic_info(Monitor *mon) } } -void irq_info(Monitor *mon) +void irq_info(Monitor *mon, const QDict *qdict) { #ifndef DEBUG_IRQ_COUNT monitor_printf(mon, "irq statistic code not compiled.\n"); diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c index 8f13355821..42f298ad51 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -39,7 +39,7 @@ struct LM32PicState { typedef struct LM32PicState LM32PicState; static LM32PicState *pic; -void lm32_do_pic_info(Monitor *mon) +void lm32_do_pic_info(Monitor *mon, const QDict *qdict) { if (pic == NULL) { return; @@ -49,7 +49,7 @@ void lm32_do_pic_info(Monitor *mon) pic->im, pic->ip, pic->irq_state); } -void lm32_irq_info(Monitor *mon) +void lm32_irq_info(Monitor *mon, const QDict *qdict) { int i; uint32_t count; diff --git a/hw/lm32_pic.h b/hw/lm32_pic.h index 14456f37cb..555680304e 100644 --- a/hw/lm32_pic.h +++ b/hw/lm32_pic.h @@ -8,7 +8,7 @@ uint32_t lm32_pic_get_im(DeviceState *d); void lm32_pic_set_ip(DeviceState *d, uint32_t ip); void lm32_pic_set_im(DeviceState *d, uint32_t im); -void lm32_do_pic_info(Monitor *mon); -void lm32_irq_info(Monitor *mon); +void lm32_do_pic_info(Monitor *mon, const QDict *qdict); +void lm32_irq_info(Monitor *mon, const QDict *qdict); #endif /* QEMU_HW_LM32_PIC_H */ diff --git a/hw/loader.c b/hw/loader.c index 3f59fcd14a..995edc3f98 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -778,7 +778,7 @@ void *rom_ptr(hwaddr addr) return rom->data + (addr - rom->addr); } -void do_info_roms(Monitor *mon) +void do_info_roms(Monitor *mon, const QDict *qdict) { Rom *rom; diff --git a/hw/loader.h b/hw/loader.h index 26480ad8dd..5e61c95b84 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -1,5 +1,6 @@ #ifndef LOADER_H #define LOADER_H +#include "qapi/qmp/qdict.h" /* loader.c */ int get_image_size(const char *filename); @@ -30,7 +31,7 @@ int rom_load_all(void); void rom_set_fw(void *f); int rom_copy(uint8_t *dest, hwaddr addr, size_t size); void *rom_ptr(hwaddr addr); -void do_info_roms(Monitor *mon); +void do_info_roms(Monitor *mon, const QDict *qdict); #define rom_add_file_fixed(_f, _a, _i) \ rom_add_file(_f, NULL, _a, _i) diff --git a/hw/pc.h b/hw/pc.h index 4134aa94e5..fbcf43d717 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -40,8 +40,8 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq); qemu_irq *kvm_i8259_init(ISABus *bus); int pic_read_irq(DeviceState *d); int pic_get_output(DeviceState *d); -void pic_info(Monitor *mon); -void irq_info(Monitor *mon); +void pic_info(Monitor *mon, const QDict *qdict); +void irq_info(Monitor *mon, const QDict *qdict); /* Global System Interrupts */ diff --git a/hw/pcmcia.h b/hw/pcmcia.h index aac1d77cc7..f91669305e 100644 --- a/hw/pcmcia.h +++ b/hw/pcmcia.h @@ -14,7 +14,7 @@ typedef struct { void pcmcia_socket_register(PCMCIASocket *socket); void pcmcia_socket_unregister(PCMCIASocket *socket); -void pcmcia_info(Monitor *mon); +void pcmcia_info(Monitor *mon, const QDict *qdict); struct PCMCIACardState { void *state; diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index 93283ee57a..1db5ee0f18 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -564,13 +564,13 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent) } #undef qdev_printf -void do_info_qtree(Monitor *mon) +void do_info_qtree(Monitor *mon, const QDict *qdict) { if (sysbus_get_default()) qbus_print(mon, sysbus_get_default(), 0); } -void do_info_qdm(Monitor *mon) +void do_info_qdm(Monitor *mon, const QDict *qdict) { object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL); } diff --git a/hw/qdev-monitor.h b/hw/qdev-monitor.h index fae1b1ec84..9ec485028e 100644 --- a/hw/qdev-monitor.h +++ b/hw/qdev-monitor.h @@ -6,8 +6,8 @@ /*** monitor commands ***/ -void do_info_qtree(Monitor *mon); -void do_info_qdm(Monitor *mon); +void do_info_qtree(Monitor *mon, const QDict *qdict); +void do_info_qdm(Monitor *mon, const QDict *qdict); int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data); int qdev_device_help(QemuOpts *opts); diff --git a/hw/sun4m.c b/hw/sun4m.c index 6f5de44a89..95c505821b 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -216,13 +216,13 @@ static void nvram_init(M48t59State *nvram, uint8_t *macaddr, static DeviceState *slavio_intctl; -void sun4m_pic_info(Monitor *mon) +void sun4m_pic_info(Monitor *mon, const QDict *qdict) { if (slavio_intctl) slavio_pic_info(mon, slavio_intctl); } -void sun4m_irq_info(Monitor *mon) +void sun4m_irq_info(Monitor *mon, const QDict *qdict) { if (slavio_intctl) slavio_irq_info(mon, slavio_intctl); diff --git a/hw/sun4m.h b/hw/sun4m.h index 47eb945f07..0361eeed41 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -27,8 +27,8 @@ void slavio_pic_info(Monitor *mon, DeviceState *dev); void slavio_irq_info(Monitor *mon, DeviceState *dev); /* sun4m.c */ -void sun4m_pic_info(Monitor *mon); -void sun4m_irq_info(Monitor *mon); +void sun4m_pic_info(Monitor *mon, const QDict *qdict); +void sun4m_irq_info(Monitor *mon, const QDict *qdict); /* sparc32_dma.c */ #include "sparc32_dma.h" diff --git a/hw/usb.h b/hw/usb.h index 50c297f341..bc42639b16 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -435,7 +435,7 @@ int set_usb_string(uint8_t *buf, const char *str); /* usb-linux.c */ USBDevice *usb_host_device_open(USBBus *bus, const char *devname); int usb_host_device_close(const char *devname); -void usb_host_info(Monitor *mon); +void usb_host_info(Monitor *mon, const QDict *qdict); /* usb-bt.c */ USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci); diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 2dc76756a0..e58cd9ade2 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -542,7 +542,7 @@ static char *usb_get_fw_dev_path(DeviceState *qdev) return fw_path; } -void usb_info(Monitor *mon) +void usb_info(Monitor *mon, const QDict *qdict) { USBBus *bus; USBDevice *dev; diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index 172aecbffd..07f0e01cc0 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -633,7 +633,7 @@ static int usb_host_info_device(void *opaque, return 0; } -void usb_host_info(Monitor *mon) +void usb_host_info(Monitor *mon, const QDict *qdict) { usb_host_scan(mon, usb_host_info_device); } diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index ad75ce0702..a2cff8a74d 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1998,7 +1998,7 @@ static void hex2str(int val, char *str, size_t size) } } -void usb_host_info(Monitor *mon) +void usb_host_info(Monitor *mon, const QDict *qdict) { struct USBAutoFilter *f; struct USBHostDevice *s; diff --git a/include/net/net.h b/include/net/net.h index de42dd76da..4a92b6c3d2 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -112,7 +112,7 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender, void *opaque); void print_net_client(Monitor *mon, NetClientState *nc); -void do_info_network(Monitor *mon); +void do_info_network(Monitor *mon, const QDict *qdict); /* NIC info */ diff --git a/include/net/slirp.h b/include/net/slirp.h index 54b655c272..0502389c68 100644 --- a/include/net/slirp.h +++ b/include/net/slirp.h @@ -40,7 +40,7 @@ int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret int net_slirp_smb(const char *exported_dir); -void do_info_usernet(Monitor *mon); +void do_info_usernet(Monitor *mon, const QDict *qdict); #endif diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index c07d4ee458..cd12f0931b 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -68,7 +68,7 @@ void qemu_add_machine_init_done_notifier(Notifier *notify); void do_savevm(Monitor *mon, const QDict *qdict); int load_vmstate(const char *name); void do_delvm(Monitor *mon, const QDict *qdict); -void do_info_snapshots(Monitor *mon); +void do_info_snapshots(Monitor *mon, const QDict *qdict); void qemu_announce_self(void); @@ -171,7 +171,7 @@ extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; void do_usb_add(Monitor *mon, const QDict *qdict); void do_usb_del(Monitor *mon, const QDict *qdict); -void usb_info(Monitor *mon); +void usb_info(Monitor *mon, const QDict *qdict); void rtc_change_mon_event(struct tm *tm); diff --git a/monitor.c b/monitor.c index 77ac451a23..4468bdee1c 100644 --- a/monitor.c +++ b/monitor.c @@ -123,7 +123,7 @@ typedef struct mon_cmd_t { const char *help; void (*user_print)(Monitor *mon, const QObject *data); union { - void (*info)(Monitor *mon); + void (*info)(Monitor *mon, const QDict *qdict); void (*cmd)(Monitor *mon, const QDict *qdict); int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data); int (*cmd_async)(Monitor *mon, const QDict *params, @@ -825,7 +825,7 @@ static void do_info(Monitor *mon, const QDict *qdict) goto help; } - cmd->mhandler.info(mon); + cmd->mhandler.info(mon, NULL); return; help: @@ -899,19 +899,19 @@ int monitor_get_cpu_index(void) return cpu->cpu_index; } -static void do_info_registers(Monitor *mon) +static void do_info_registers(Monitor *mon, const QDict *qdict) { CPUArchState *env; env = mon_get_cpu(); cpu_dump_state(env, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU); } -static void do_info_jit(Monitor *mon) +static void do_info_jit(Monitor *mon, const QDict *qdict) { dump_exec_info((FILE *)mon, monitor_fprintf); } -static void do_info_history(Monitor *mon) +static void do_info_history(Monitor *mon, const QDict *qdict) { int i; const char *str; @@ -930,7 +930,7 @@ static void do_info_history(Monitor *mon) #if defined(TARGET_PPC) /* XXX: not implemented in other targets */ -static void do_info_cpu_stats(Monitor *mon) +static void do_info_cpu_stats(Monitor *mon, const QDict *qdict) { CPUArchState *env; @@ -939,7 +939,7 @@ static void do_info_cpu_stats(Monitor *mon) } #endif -static void do_trace_print_events(Monitor *mon) +static void do_trace_print_events(Monitor *mon, const QDict *qdict) { trace_print_events((FILE *)mon, &monitor_fprintf); } @@ -1491,7 +1491,7 @@ static void tlb_info_64(Monitor *mon, CPUArchState *env) } #endif -static void tlb_info(Monitor *mon) +static void tlb_info(Monitor *mon, const QDict *qdict) { CPUArchState *env; @@ -1714,7 +1714,7 @@ static void mem_info_64(Monitor *mon, CPUArchState *env) } #endif -static void mem_info(Monitor *mon) +static void mem_info(Monitor *mon, const QDict *qdict) { CPUArchState *env; @@ -1753,7 +1753,7 @@ static void print_tlb(Monitor *mon, int idx, tlb_t *tlb) tlb->d, tlb->wt); } -static void tlb_info(Monitor *mon) +static void tlb_info(Monitor *mon, const QDict *qdict) { CPUArchState *env = mon_get_cpu(); int i; @@ -1769,7 +1769,7 @@ static void tlb_info(Monitor *mon) #endif #if defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_XTENSA) -static void tlb_info(Monitor *mon) +static void tlb_info(Monitor *mon, const QDict *qdict) { CPUArchState *env1 = mon_get_cpu(); @@ -1777,12 +1777,12 @@ static void tlb_info(Monitor *mon) } #endif -static void do_info_mtree(Monitor *mon) +static void do_info_mtree(Monitor *mon, const QDict *qdict) { mtree_info((fprintf_function)monitor_printf, mon); } -static void do_info_numa(Monitor *mon) +static void do_info_numa(Monitor *mon, const QDict *qdict) { int i; CPUArchState *env; @@ -1808,7 +1808,7 @@ static void do_info_numa(Monitor *mon) int64_t qemu_time; int64_t dev_time; -static void do_info_profile(Monitor *mon) +static void do_info_profile(Monitor *mon, const QDict *qdict) { int64_t total; total = qemu_time; @@ -1822,7 +1822,7 @@ static void do_info_profile(Monitor *mon) dev_time = 0; } #else -static void do_info_profile(Monitor *mon) +static void do_info_profile(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "Internal profiler not compiled\n"); } @@ -1831,7 +1831,7 @@ static void do_info_profile(Monitor *mon) /* Capture support */ static QLIST_HEAD (capture_list_head, CaptureState) capture_head; -static void do_info_capture(Monitor *mon) +static void do_info_capture(Monitor *mon, const QDict *qdict) { int i; CaptureState *s; diff --git a/net/net.c b/net/net.c index 02b5458a1b..cdd9b04989 100644 --- a/net/net.c +++ b/net/net.c @@ -852,7 +852,7 @@ void print_net_client(Monitor *mon, NetClientState *nc) NetClientOptionsKind_lookup[nc->info->type], nc->info_str); } -void do_info_network(Monitor *mon) +void do_info_network(Monitor *mon, const QDict *qdict) { NetClientState *nc, *peer; NetClientOptionsKind type; diff --git a/net/slirp.c b/net/slirp.c index c14259f004..4df550faf6 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -670,7 +670,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, return -1; } -void do_info_usernet(Monitor *mon) +void do_info_usernet(Monitor *mon, const QDict *qdict) { SlirpState *s; diff --git a/savevm.c b/savevm.c index 4e970ca0db..d9ff1d9b72 100644 --- a/savevm.c +++ b/savevm.c @@ -2307,7 +2307,7 @@ void do_delvm(Monitor *mon, const QDict *qdict) } } -void do_info_snapshots(Monitor *mon) +void do_info_snapshots(Monitor *mon, const QDict *qdict) { BlockDriverState *bs, *bs1; QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s; diff --git a/vl.c b/vl.c index 8ce2b10541..f4cf7e8a85 100644 --- a/vl.c +++ b/vl.c @@ -1449,7 +1449,7 @@ void pcmcia_socket_unregister(PCMCIASocket *socket) } } -void pcmcia_info(Monitor *mon) +void pcmcia_info(Monitor *mon, const QDict *qdict) { struct pcmcia_socket_entry_s *iter; From 5f11cb002a342e4fc0f87bb36fbabbc19bf04728 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Mon, 14 Jan 2013 14:06:26 +0800 Subject: [PATCH 0538/1634] HMP: delete info handler Now cmd and info handler have same format, so delete info handler. Signed-off-by: Wenchao Xia Signed-off-by: Luiz Capitulino --- monitor.c | 91 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/monitor.c b/monitor.c index 4468bdee1c..6e87b5c9cf 100644 --- a/monitor.c +++ b/monitor.c @@ -123,7 +123,6 @@ typedef struct mon_cmd_t { const char *help; void (*user_print)(Monitor *mon, const QObject *data); union { - void (*info)(Monitor *mon, const QDict *qdict); void (*cmd)(Monitor *mon, const QDict *qdict); int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data); int (*cmd_async)(Monitor *mon, const QDict *params, @@ -825,7 +824,7 @@ static void do_info(Monitor *mon, const QDict *qdict) goto help; } - cmd->mhandler.info(mon, NULL); + cmd->mhandler.cmd(mon, NULL); return; help: @@ -2442,63 +2441,63 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the version of QEMU", - .mhandler.info = hmp_info_version, + .mhandler.cmd = hmp_info_version, }, { .name = "network", .args_type = "", .params = "", .help = "show the network state", - .mhandler.info = do_info_network, + .mhandler.cmd = do_info_network, }, { .name = "chardev", .args_type = "", .params = "", .help = "show the character devices", - .mhandler.info = hmp_info_chardev, + .mhandler.cmd = hmp_info_chardev, }, { .name = "block", .args_type = "", .params = "", .help = "show the block devices", - .mhandler.info = hmp_info_block, + .mhandler.cmd = hmp_info_block, }, { .name = "blockstats", .args_type = "", .params = "", .help = "show block device statistics", - .mhandler.info = hmp_info_blockstats, + .mhandler.cmd = hmp_info_blockstats, }, { .name = "block-jobs", .args_type = "", .params = "", .help = "show progress of ongoing block device operations", - .mhandler.info = hmp_info_block_jobs, + .mhandler.cmd = hmp_info_block_jobs, }, { .name = "registers", .args_type = "", .params = "", .help = "show the cpu registers", - .mhandler.info = do_info_registers, + .mhandler.cmd = do_info_registers, }, { .name = "cpus", .args_type = "", .params = "", .help = "show infos for each CPU", - .mhandler.info = hmp_info_cpus, + .mhandler.cmd = hmp_info_cpus, }, { .name = "history", .args_type = "", .params = "", .help = "show the command line history", - .mhandler.info = do_info_history, + .mhandler.cmd = do_info_history, }, #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_MIPS) || \ defined(TARGET_LM32) || (defined(TARGET_SPARC) && !defined(TARGET_SPARC64)) @@ -2508,11 +2507,11 @@ static mon_cmd_t info_cmds[] = { .params = "", .help = "show the interrupts statistics (if available)", #ifdef TARGET_SPARC - .mhandler.info = sun4m_irq_info, + .mhandler.cmd = sun4m_irq_info, #elif defined(TARGET_LM32) - .mhandler.info = lm32_irq_info, + .mhandler.cmd = lm32_irq_info, #else - .mhandler.info = irq_info, + .mhandler.cmd = irq_info, #endif }, { @@ -2521,11 +2520,11 @@ static mon_cmd_t info_cmds[] = { .params = "", .help = "show i8259 (PIC) state", #ifdef TARGET_SPARC - .mhandler.info = sun4m_pic_info, + .mhandler.cmd = sun4m_pic_info, #elif defined(TARGET_LM32) - .mhandler.info = lm32_do_pic_info, + .mhandler.cmd = lm32_do_pic_info, #else - .mhandler.info = pic_info, + .mhandler.cmd = pic_info, #endif }, #endif @@ -2534,7 +2533,7 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show PCI info", - .mhandler.info = hmp_info_pci, + .mhandler.cmd = hmp_info_pci, }, #if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \ defined(TARGET_PPC) || defined(TARGET_XTENSA) @@ -2543,7 +2542,7 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show virtual to physical memory mappings", - .mhandler.info = tlb_info, + .mhandler.cmd = tlb_info, }, #endif #if defined(TARGET_I386) @@ -2552,7 +2551,7 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the active virtual memory mappings", - .mhandler.info = mem_info, + .mhandler.cmd = mem_info, }, #endif { @@ -2560,91 +2559,91 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show memory tree", - .mhandler.info = do_info_mtree, + .mhandler.cmd = do_info_mtree, }, { .name = "jit", .args_type = "", .params = "", .help = "show dynamic compiler info", - .mhandler.info = do_info_jit, + .mhandler.cmd = do_info_jit, }, { .name = "kvm", .args_type = "", .params = "", .help = "show KVM information", - .mhandler.info = hmp_info_kvm, + .mhandler.cmd = hmp_info_kvm, }, { .name = "numa", .args_type = "", .params = "", .help = "show NUMA information", - .mhandler.info = do_info_numa, + .mhandler.cmd = do_info_numa, }, { .name = "usb", .args_type = "", .params = "", .help = "show guest USB devices", - .mhandler.info = usb_info, + .mhandler.cmd = usb_info, }, { .name = "usbhost", .args_type = "", .params = "", .help = "show host USB devices", - .mhandler.info = usb_host_info, + .mhandler.cmd = usb_host_info, }, { .name = "profile", .args_type = "", .params = "", .help = "show profiling information", - .mhandler.info = do_info_profile, + .mhandler.cmd = do_info_profile, }, { .name = "capture", .args_type = "", .params = "", .help = "show capture information", - .mhandler.info = do_info_capture, + .mhandler.cmd = do_info_capture, }, { .name = "snapshots", .args_type = "", .params = "", .help = "show the currently saved VM snapshots", - .mhandler.info = do_info_snapshots, + .mhandler.cmd = do_info_snapshots, }, { .name = "status", .args_type = "", .params = "", .help = "show the current VM status (running|paused)", - .mhandler.info = hmp_info_status, + .mhandler.cmd = hmp_info_status, }, { .name = "pcmcia", .args_type = "", .params = "", .help = "show guest PCMCIA status", - .mhandler.info = pcmcia_info, + .mhandler.cmd = pcmcia_info, }, { .name = "mice", .args_type = "", .params = "", .help = "show which guest mouse is receiving events", - .mhandler.info = hmp_info_mice, + .mhandler.cmd = hmp_info_mice, }, { .name = "vnc", .args_type = "", .params = "", .help = "show the vnc server status", - .mhandler.info = hmp_info_vnc, + .mhandler.cmd = hmp_info_vnc, }, #if defined(CONFIG_SPICE) { @@ -2652,7 +2651,7 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the spice server status", - .mhandler.info = hmp_info_spice, + .mhandler.cmd = hmp_info_spice, }, #endif { @@ -2660,14 +2659,14 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the current VM name", - .mhandler.info = hmp_info_name, + .mhandler.cmd = hmp_info_name, }, { .name = "uuid", .args_type = "", .params = "", .help = "show the current VM UUID", - .mhandler.info = hmp_info_uuid, + .mhandler.cmd = hmp_info_uuid, }, #if defined(TARGET_PPC) { @@ -2675,7 +2674,7 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show CPU statistics", - .mhandler.info = do_info_cpu_stats, + .mhandler.cmd = do_info_cpu_stats, }, #endif #if defined(CONFIG_SLIRP) @@ -2684,7 +2683,7 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show user network stack connection states", - .mhandler.info = do_info_usernet, + .mhandler.cmd = do_info_usernet, }, #endif { @@ -2692,56 +2691,56 @@ static mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show migration status", - .mhandler.info = hmp_info_migrate, + .mhandler.cmd = hmp_info_migrate, }, { .name = "migrate_capabilities", .args_type = "", .params = "", .help = "show current migration capabilities", - .mhandler.info = hmp_info_migrate_capabilities, + .mhandler.cmd = hmp_info_migrate_capabilities, }, { .name = "migrate_cache_size", .args_type = "", .params = "", .help = "show current migration xbzrle cache size", - .mhandler.info = hmp_info_migrate_cache_size, + .mhandler.cmd = hmp_info_migrate_cache_size, }, { .name = "balloon", .args_type = "", .params = "", .help = "show balloon information", - .mhandler.info = hmp_info_balloon, + .mhandler.cmd = hmp_info_balloon, }, { .name = "qtree", .args_type = "", .params = "", .help = "show device tree", - .mhandler.info = do_info_qtree, + .mhandler.cmd = do_info_qtree, }, { .name = "qdm", .args_type = "", .params = "", .help = "show qdev device model list", - .mhandler.info = do_info_qdm, + .mhandler.cmd = do_info_qdm, }, { .name = "roms", .args_type = "", .params = "", .help = "show roms", - .mhandler.info = do_info_roms, + .mhandler.cmd = do_info_roms, }, { .name = "trace-events", .args_type = "", .params = "", .help = "show available trace-events & their state", - .mhandler.info = do_trace_print_events, + .mhandler.cmd = do_trace_print_events, }, { .name = NULL, From 5f3d335fbdaccc5044bdfe0c6aefb865e48b9100 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Mon, 14 Jan 2013 14:06:27 +0800 Subject: [PATCH 0539/1634] HMP: add infrastructure for sub command This patch make parsing of hmp command aware of that it may have sub command. Also discard simple encapsulation function monitor_find_command(). For case "@command ", space after @command is filtered out. Signed-off-by: Wenchao Xia Signed-off-by: Luiz Capitulino --- monitor.c | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/monitor.c b/monitor.c index 6e87b5c9cf..a77dd3b5d1 100644 --- a/monitor.c +++ b/monitor.c @@ -129,6 +129,11 @@ typedef struct mon_cmd_t { MonitorCompletion *cb, void *opaque); } mhandler; int flags; + /* @sub_table is a list of 2nd level of commands. If it do not exist, + * mhandler should be used. If it exist, sub_table[?].mhandler should be + * used, and mhandler of 1st level plays the role of help function. + */ + struct mon_cmd_t *sub_table; } mon_cmd_t; /* file descriptors passed via SCM_RIGHTS */ @@ -3541,18 +3546,27 @@ static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table, return NULL; } -static const mon_cmd_t *monitor_find_command(const char *cmdname) -{ - return search_dispatch_table(mon_cmds, cmdname); -} - static const mon_cmd_t *qmp_find_cmd(const char *cmdname) { return search_dispatch_table(qmp_cmds, cmdname); } +/* + * Parse @cmdline according to command table @table. + * If @cmdline is blank, return NULL. + * If it can't be parsed, report to @mon, and return NULL. + * Else, insert command arguments into @qdict, and return the command. + * If sub-command table exist, and if @cmdline contains addtional string for + * sub-command, this function will try search sub-command table. if no + * addtional string for sub-command exist, this function will return the found + * one in @table. + * Do not assume the returned command points into @table! It doesn't + * when the command is a sub-command. + */ static const mon_cmd_t *monitor_parse_command(Monitor *mon, const char *cmdline, + int start, + mon_cmd_t *table, QDict *qdict) { const char *p, *typestr; @@ -3563,20 +3577,35 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, char *key; #ifdef DEBUG - monitor_printf(mon, "command='%s'\n", cmdline); + monitor_printf(mon, "command='%s', start='%d'\n", cmdline, start); #endif /* extract the command name */ - p = get_command_name(cmdline, cmdname, sizeof(cmdname)); + p = get_command_name(cmdline + start, cmdname, sizeof(cmdname)); if (!p) return NULL; - cmd = monitor_find_command(cmdname); + cmd = search_dispatch_table(table, cmdname); if (!cmd) { - monitor_printf(mon, "unknown command: '%s'\n", cmdname); + monitor_printf(mon, "unknown command: '%.*s'\n", + (int)(p - cmdline), cmdline); return NULL; } + /* filter out following useless space */ + while (qemu_isspace(*p)) { + p++; + } + /* search sub command */ + if (cmd->sub_table != NULL) { + /* check if user set additional command */ + if (*p == '\0') { + return cmd; + } + return monitor_parse_command(mon, cmdline, p - cmdline, + cmd->sub_table, qdict); + } + /* parse the parameters */ typestr = cmd->args_type; for(;;) { @@ -3932,7 +3961,7 @@ static void handle_user_command(Monitor *mon, const char *cmdline) qdict = qdict_new(); - cmd = monitor_parse_command(mon, cmdline, qdict); + cmd = monitor_parse_command(mon, cmdline, 0, mon_cmds, qdict); if (!cmd) goto out; From a13ced59a4f305e37bd89f27f2b18f915889cad1 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Mon, 14 Jan 2013 14:06:28 +0800 Subject: [PATCH 0540/1634] HMP: move define of mon_cmds Because mon_cmds may use info_cmds, so adjust the declare sequence of them. Signed-off-by: Wenchao Xia Signed-off-by: Luiz Capitulino --- monitor.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/monitor.c b/monitor.c index a77dd3b5d1..ef1b7ac062 100644 --- a/monitor.c +++ b/monitor.c @@ -2433,12 +2433,6 @@ int monitor_handle_fd_param(Monitor *mon, const char *fdname) return fd; } -/* mon_cmds and info_cmds would be sorted at runtime */ -static mon_cmd_t mon_cmds[] = { -#include "hmp-commands.h" - { NULL, NULL, }, -}; - /* Please update hmp-commands.hx when adding or changing commands */ static mon_cmd_t info_cmds[] = { { @@ -2752,6 +2746,12 @@ static mon_cmd_t info_cmds[] = { }, }; +/* mon_cmds and info_cmds would be sorted at runtime */ +static mon_cmd_t mon_cmds[] = { +#include "hmp-commands.h" + { NULL, NULL, }, +}; + static const mon_cmd_t qmp_cmds[] = { #include "qmp-commands-old.h" { /* NULL */ }, From 84c44613f9ad8d13e0d2dbee767051527072dc12 Mon Sep 17 00:00:00 2001 From: Wenchao Xia Date: Mon, 14 Jan 2013 14:06:29 +0800 Subject: [PATCH 0541/1634] HMP: add sub command table to info Now info command takes a table of sub info commands, and changed do_info() to do_info_help() to do help funtion only. Note that now "info " returns error instead of list of info topics. Signed-off-by: Wenchao Xia Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 3 ++- monitor.c | 22 +--------------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 67569eff4a..0934b9b915 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1521,7 +1521,8 @@ ETEXI .args_type = "item:s?", .params = "[subcommand]", .help = "show various information about the system state", - .mhandler.cmd = do_info, + .mhandler.cmd = do_info_help, + .sub_table = info_cmds, }, STEXI diff --git a/monitor.c b/monitor.c index ef1b7ac062..20bd19b05f 100644 --- a/monitor.c +++ b/monitor.c @@ -811,28 +811,8 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd, } } -static void do_info(Monitor *mon, const QDict *qdict) +static void do_info_help(Monitor *mon, const QDict *qdict) { - const mon_cmd_t *cmd; - const char *item = qdict_get_try_str(qdict, "item"); - - if (!item) { - goto help; - } - - for (cmd = info_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(item, cmd->name)) - break; - } - - if (cmd->name == NULL) { - goto help; - } - - cmd->mhandler.cmd(mon, NULL); - return; - -help: help_cmd(mon, "info"); } From fb3409de22c7c167dced51175500bc4b1a78dcc2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 11:25:45 +0100 Subject: [PATCH 0542/1634] Unlock ramlist lock also in error case Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake --- arch_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch_init.c b/arch_init.c index 86f85443d7..8c833b67e9 100644 --- a/arch_init.c +++ b/arch_init.c @@ -642,12 +642,13 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) i++; } + qemu_mutex_unlock_ramlist(); + if (ret < 0) { bytes_transferred += total_sent; return ret; } - qemu_mutex_unlock_ramlist(); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); total_sent += 8; bytes_transferred += total_sent; From 9c339485f0abb96595f4d91880b177726463300c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 11:26:04 +0100 Subject: [PATCH 0543/1634] Protect migration_bitmap_sync() with the ramlist lock Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake --- arch_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch_init.c b/arch_init.c index 8c833b67e9..dada6ded1a 100644 --- a/arch_init.c +++ b/arch_init.c @@ -658,9 +658,8 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) static int ram_save_complete(QEMUFile *f, void *opaque) { - migration_bitmap_sync(); - qemu_mutex_lock_ramlist(); + migration_bitmap_sync(); /* try transferring iterative blocks of memory */ From f65a874756bb3e4b57571a33a51d8887bbee7981 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 11:31:03 +0100 Subject: [PATCH 0544/1634] use XFER_LIMIT_RATIO consistently commit 5b4e1eb769eee892b44d3f6b2369b05196442f59 missed this use. Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake --- migration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration.c b/migration.c index c69e864fcd..d6ec3e8fdc 100644 --- a/migration.c +++ b/migration.c @@ -650,7 +650,7 @@ static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate) new_rate = SIZE_MAX; } - s->xfer_limit = new_rate / 10; + s->xfer_limit = new_rate / XFER_LIMIT_RATIO; out: return s->xfer_limit; From b9c961a8ff3973b97964431491bc3f4f427cd66a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 11:29:03 +0100 Subject: [PATCH 0545/1634] migration: make function static Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake --- include/migration/migration.h | 2 -- migration.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index 2d5b630cce..95261c1886 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -87,8 +87,6 @@ void migrate_fd_error(MigrationState *s); void migrate_fd_connect(MigrationState *s); -ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, - size_t size); int migrate_fd_close(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); diff --git a/migration.c b/migration.c index d6ec3e8fdc..1f4c6ee16f 100644 --- a/migration.c +++ b/migration.c @@ -302,8 +302,8 @@ static void migrate_fd_completed(MigrationState *s) notifier_list_notify(&migration_state_notifiers, s); } -ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, - size_t size) +static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, + size_t size) { ssize_t ret; From 25242635acb0b803392ad5669b5624815af3fd07 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 10 Nov 2012 18:58:40 +0100 Subject: [PATCH 0546/1634] migration: remove double call to migrate_fd_close The call in buffered_close is enough, because buffered_close is called already by migrate_fd_cleanup. Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake --- migration.c | 1 - 1 file changed, 1 deletion(-) diff --git a/migration.c b/migration.c index 1f4c6ee16f..5513dde18d 100644 --- a/migration.c +++ b/migration.c @@ -605,7 +605,6 @@ static int buffered_close(void *opaque) if (ret >= 0) { ret = ret2; } - ret = migrate_fd_close(s); s->complete = true; return ret; } From 1e973051b96bac5eef46393eec15b68796e7c7d3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Dec 2012 11:30:39 +0100 Subject: [PATCH 0547/1634] migration: fix off-by-one in buffered_rate_limit Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake --- migration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration.c b/migration.c index 5513dde18d..380f3cb618 100644 --- a/migration.c +++ b/migration.c @@ -632,7 +632,7 @@ static int buffered_rate_limit(void *opaque) return ret; } - if (s->bytes_xfer > s->xfer_limit) { + if (s->bytes_xfer >= s->xfer_limit) { return 1; } From afe419319de1e5e98b131368ba14f85f98ab3a76 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 14 Jan 2013 13:36:28 +0100 Subject: [PATCH 0548/1634] qemu-file: Only set last_error if it is not already set Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini --- savevm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/savevm.c b/savevm.c index 4e970ca0db..611e997d42 100644 --- a/savevm.c +++ b/savevm.c @@ -419,7 +419,9 @@ int qemu_file_get_error(QEMUFile *f) static void qemu_file_set_error(QEMUFile *f, int ret) { - f->last_error = ret; + if (f->last_error == 0) { + f->last_error = ret; + } } /** Flushes QEMUFile buffer From 76f5933aea281a52149b39a1a78a43565dc9715c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 3 Oct 2012 20:16:24 +0200 Subject: [PATCH 0549/1634] migration: move beginning stage to the migration thread Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini --- include/migration/migration.h | 1 - migration.c | 28 +++++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index 95261c1886..a8c9639732 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -54,7 +54,6 @@ struct MigrationState bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; bool complete; - bool first_time; }; void process_incoming_migration(QEMUFile *f); diff --git a/migration.c b/migration.c index 380f3cb618..7ae1d939d6 100644 --- a/migration.c +++ b/migration.c @@ -674,17 +674,6 @@ static bool migrate_fd_put_ready(MigrationState *s, uint64_t max_size) qemu_mutex_unlock_iothread(); return false; } - if (s->first_time) { - s->first_time = false; - DPRINTF("beginning savevm\n"); - ret = qemu_savevm_state_begin(s->file, &s->params); - if (ret < 0) { - DPRINTF("failed, %d\n", ret); - migrate_fd_error(s); - qemu_mutex_unlock_iothread(); - return false; - } - } DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); @@ -733,6 +722,17 @@ static void *buffered_file_thread(void *opaque) int64_t initial_time = qemu_get_clock_ms(rt_clock); int64_t max_size = 0; bool last_round = false; + int ret; + + qemu_mutex_lock_iothread(); + DPRINTF("beginning savevm\n"); + ret = qemu_savevm_state_begin(s->file, &s->params); + if (ret < 0) { + DPRINTF("failed, %d\n", ret); + qemu_mutex_unlock_iothread(); + goto out; + } + qemu_mutex_unlock_iothread(); while (true) { int64_t current_time = qemu_get_clock_ms(rt_clock); @@ -768,6 +768,10 @@ static void *buffered_file_thread(void *opaque) } } +out: + if (ret < 0) { + migrate_fd_error(s); + } g_free(s->buffer); return NULL; } @@ -789,8 +793,6 @@ void migrate_fd_connect(MigrationState *s) s->buffer_size = 0; s->buffer_capacity = 0; - s->first_time = true; - s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; s->complete = false; From f7b67be36d01f8f506dc93213855b31dad17708c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 10 Dec 2012 22:29:14 +0100 Subject: [PATCH 0550/1634] migration: Add buffered_flush error handling Now that we have error handling we can do proper handling of buffered_flush(). Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini --- migration.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index 7ae1d939d6..17eb27d199 100644 --- a/migration.c +++ b/migration.c @@ -757,7 +757,8 @@ static void *buffered_file_thread(void *opaque) /* usleep expects microseconds */ g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); } - if (buffered_flush(s) < 0) { + ret = buffered_flush(s); + if (ret < 0) { break; } From 7de6a690e73967eb5bc5e72b2942a6be1fee2c20 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 3 Oct 2012 20:23:43 +0200 Subject: [PATCH 0551/1634] migration: move exit condition to migration thread Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini --- migration.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/migration.c b/migration.c index 17eb27d199..651edd5166 100644 --- a/migration.c +++ b/migration.c @@ -669,12 +669,6 @@ static bool migrate_fd_put_ready(MigrationState *s, uint64_t max_size) bool last_round = false; qemu_mutex_lock_iothread(); - if (s->state != MIG_STATE_ACTIVE) { - DPRINTF("put_ready returning because of non-active state\n"); - qemu_mutex_unlock_iothread(); - return false; - } - DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); DPRINTF("pending size %lu max %lu\n", pending_size, max_size); @@ -737,9 +731,17 @@ static void *buffered_file_thread(void *opaque) while (true) { int64_t current_time = qemu_get_clock_ms(rt_clock); - if (s->complete) { + qemu_mutex_lock_iothread(); + if (s->state != MIG_STATE_ACTIVE) { + DPRINTF("put_ready returning because of non-active state\n"); + qemu_mutex_unlock_iothread(); break; } + if (s->complete) { + qemu_mutex_unlock_iothread(); + break; + } + qemu_mutex_unlock_iothread(); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = s->bytes_xfer; uint64_t time_spent = current_time - initial_time; From c369f40d2cb39f4eaaf6589c1113b528256d3a09 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 3 Oct 2012 20:33:34 +0200 Subject: [PATCH 0552/1634] migration: unfold rest of migrate_fd_put_ready() into thread This will allow us finer control in next patches. Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini --- migration.c | 95 +++++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/migration.c b/migration.c index 651edd5166..6d3aeeda51 100644 --- a/migration.c +++ b/migration.c @@ -662,54 +662,6 @@ static int64_t buffered_get_rate_limit(void *opaque) return s->xfer_limit; } -static bool migrate_fd_put_ready(MigrationState *s, uint64_t max_size) -{ - int ret; - uint64_t pending_size; - bool last_round = false; - - qemu_mutex_lock_iothread(); - DPRINTF("iterate\n"); - pending_size = qemu_savevm_state_pending(s->file, max_size); - DPRINTF("pending size %lu max %lu\n", pending_size, max_size); - if (pending_size >= max_size) { - ret = qemu_savevm_state_iterate(s->file); - if (ret < 0) { - migrate_fd_error(s); - } - } else { - int old_vm_running = runstate_is_running(); - int64_t start_time, end_time; - - DPRINTF("done iterating\n"); - start_time = qemu_get_clock_ms(rt_clock); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - if (old_vm_running) { - vm_stop(RUN_STATE_FINISH_MIGRATE); - } else { - vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - } - - if (qemu_savevm_state_complete(s->file) < 0) { - migrate_fd_error(s); - } else { - migrate_fd_completed(s); - } - end_time = qemu_get_clock_ms(rt_clock); - s->total_time = end_time - s->total_time; - s->downtime = end_time - start_time; - if (s->state != MIG_STATE_COMPLETED) { - if (old_vm_running) { - vm_start(); - } - } - last_round = true; - } - qemu_mutex_unlock_iothread(); - - return last_round; -} - static void *buffered_file_thread(void *opaque) { MigrationState *s = opaque; @@ -730,6 +682,7 @@ static void *buffered_file_thread(void *opaque) while (true) { int64_t current_time = qemu_get_clock_ms(rt_clock); + uint64_t pending_size; qemu_mutex_lock_iothread(); if (s->state != MIG_STATE_ACTIVE) { @@ -741,6 +694,46 @@ static void *buffered_file_thread(void *opaque) qemu_mutex_unlock_iothread(); break; } + if (s->bytes_xfer < s->xfer_limit) { + DPRINTF("iterate\n"); + pending_size = qemu_savevm_state_pending(s->file, max_size); + DPRINTF("pending size %lu max %lu\n", pending_size, max_size); + if (pending_size >= max_size) { + ret = qemu_savevm_state_iterate(s->file); + if (ret < 0) { + qemu_mutex_unlock_iothread(); + break; + } + } else { + int old_vm_running = runstate_is_running(); + int64_t start_time, end_time; + + DPRINTF("done iterating\n"); + start_time = qemu_get_clock_ms(rt_clock); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + if (old_vm_running) { + vm_stop(RUN_STATE_FINISH_MIGRATE); + } else { + vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + } + ret = qemu_savevm_state_complete(s->file); + if (ret < 0) { + qemu_mutex_unlock_iothread(); + break; + } else { + migrate_fd_completed(s); + } + end_time = qemu_get_clock_ms(rt_clock); + s->total_time = end_time - s->total_time; + s->downtime = end_time - start_time; + if (s->state != MIG_STATE_COMPLETED) { + if (old_vm_running) { + vm_start(); + } + } + last_round = true; + } + } qemu_mutex_unlock_iothread(); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = s->bytes_xfer; @@ -763,12 +756,6 @@ static void *buffered_file_thread(void *opaque) if (ret < 0) { break; } - - DPRINTF("file is ready\n"); - if (s->bytes_xfer < s->xfer_limit) { - DPRINTF("notifying client\n"); - last_round = migrate_fd_put_ready(s, max_size); - } } out: From b22ff1fbed9d7f1f677804cbaa9ee03ca17d0013 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 17 Oct 2012 21:06:31 +0200 Subject: [PATCH 0553/1634] migration: Only go to the iterate stage if there is anything to send Signed-off-by: Orit Wasserman Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini --- migration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration.c b/migration.c index 6d3aeeda51..fe1a103abe 100644 --- a/migration.c +++ b/migration.c @@ -698,7 +698,7 @@ static void *buffered_file_thread(void *opaque) DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); DPRINTF("pending size %lu max %lu\n", pending_size, max_size); - if (pending_size >= max_size) { + if (pending_size && pending_size >= max_size) { ret = qemu_savevm_state_iterate(s->file); if (ret < 0) { qemu_mutex_unlock_iothread(); From 6522773f88a2e37800f0bf7dc3632a14649f53c6 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Mon, 14 Jan 2013 14:14:42 +0100 Subject: [PATCH 0554/1634] migration: remove argument to qemu_savevm_state_cancel Signed-off-by: Juan Quintela Reviewed-by: Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini --- include/sysemu/sysemu.h | 2 +- migration.c | 2 +- savevm.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index c07d4ee458..d65a9f1195 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -77,7 +77,7 @@ int qemu_savevm_state_begin(QEMUFile *f, const MigrationParams *params); int qemu_savevm_state_iterate(QEMUFile *f); int qemu_savevm_state_complete(QEMUFile *f); -void qemu_savevm_state_cancel(QEMUFile *f); +void qemu_savevm_state_cancel(void); uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size); int qemu_loadvm_state(QEMUFile *f); diff --git a/migration.c b/migration.c index fe1a103abe..77c1971b77 100644 --- a/migration.c +++ b/migration.c @@ -330,7 +330,7 @@ static void migrate_fd_cancel(MigrationState *s) s->state = MIG_STATE_CANCELLED; notifier_list_notify(&migration_state_notifiers, s); - qemu_savevm_state_cancel(s->file); + qemu_savevm_state_cancel(); migrate_fd_cleanup(s); } diff --git a/savevm.c b/savevm.c index 611e997d42..913a6235ab 100644 --- a/savevm.c +++ b/savevm.c @@ -1590,13 +1590,13 @@ int qemu_savevm_state_begin(QEMUFile *f, ret = se->ops->save_live_setup(f, se->opaque); if (ret < 0) { - qemu_savevm_state_cancel(f); + qemu_savevm_state_cancel(); return ret; } } ret = qemu_file_get_error(f); if (ret != 0) { - qemu_savevm_state_cancel(f); + qemu_savevm_state_cancel(); } return ret; @@ -1647,7 +1647,7 @@ int qemu_savevm_state_iterate(QEMUFile *f) } ret = qemu_file_get_error(f); if (ret != 0) { - qemu_savevm_state_cancel(f); + qemu_savevm_state_cancel(); } return ret; } @@ -1727,7 +1727,7 @@ uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size) return ret; } -void qemu_savevm_state_cancel(QEMUFile *f) +void qemu_savevm_state_cancel(void) { SaveStateEntry *se; From 781c0c3321d2bda9a9d7ffe9bf51560f0987b5a0 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 15 Jan 2013 08:47:26 +0100 Subject: [PATCH 0555/1634] Makefile: drop recursive libcacard clean Commit eb8eb53e5846a957cf333f2e1ec8cb6e0c04 ("libcacard: rewrite Makefile in non-recursive style") refactored libcacard/Makefile so it can be included by the top-level Makefile. The top-level clean target still loops over subdirectories, including libcacard/, to invoke recursive clean. Remove libcacard from the recursive clean since its files are already included at the top level. Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cfa2fa6383..73adf429d7 100644 --- a/Makefile +++ b/Makefile @@ -227,7 +227,7 @@ clean: rm -rf qapi-generated rm -rf qga/qapi-generated $(MAKE) -C tests/tcg clean - for d in $(ALL_SUBDIRS) libcacard; do \ + for d in $(ALL_SUBDIRS); do \ if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ rm -f $$d/qemu-options.def; \ done From 782beb5239c6306b166744e03478a75afb649811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Jan 2013 08:31:50 +0100 Subject: [PATCH 0556/1634] qom: Extend documentation on QOM method concepts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a documentation section "Methods" and discuss among others how to handle overriding virtual methods. Clarify DeviceClass::realize documentation and refer to the above. Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- hw/qdev-core.h | 14 ++++-- include/qom/object.h | 104 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 111 insertions(+), 7 deletions(-) diff --git a/hw/qdev-core.h b/hw/qdev-core.h index 3d75ae2e3a..731aadd677 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -60,14 +60,20 @@ struct VMStateDescription; * The @init callback is considered private to a particular bus implementation * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an * "init" callback on their parent class instead. + * * Any type may override the @realize and/or @unrealize callbacks but needs - * to call (and thus save) the parent type's implementation if so desired. - * Usually this means storing the previous value of, e.g., @realized inside - * the type's class structure and overwriting it with a function that first - * invokes the stored callback, then performs any additional steps. + * to call the parent type's implementation if keeping their functionality + * is desired. Refer to QOM documentation for further discussion and examples. + * + * + * * If a type derived directly from TYPE_DEVICE implements @realize, it does * not need to implement @init and therefore does not need to store and call * #DeviceClass' default @realize callback. + * For other types consult the documentation and implementation of the + * respective parent types. + * + * */ typedef struct DeviceClass { /*< private >*/ diff --git a/include/qom/object.h b/include/qom/object.h index 1ef2f0edd4..8e16ea8a44 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -147,9 +147,9 @@ typedef struct InterfaceInfo InterfaceInfo; * * * - * Introducing new virtual functions requires a class to define its own - * struct and to add a .class_size member to the TypeInfo. Each function - * will also have a wrapper to call it easily: + * Introducing new virtual methods requires a class to define its own + * struct and to add a .class_size member to the #TypeInfo. Each method + * will also have a wrapper function to call it easily: * * * Defining an abstract class @@ -186,6 +186,104 @@ typedef struct InterfaceInfo InterfaceInfo; * similar to normal types except for the fact that are only defined by * their classes and never carry any state. You can dynamically cast an object * to one of its #Interface types and vice versa. + * + * # Methods # + * + * A method is a function within the namespace scope of + * a class. It usually operates on the object instance by passing it as a + * strongly-typed first argument. + * If it does not operate on an object instance, it is dubbed + * class method. + * + * Methods cannot be overloaded. That is, the #ObjectClass and method name + * uniquely identity the function to be called; the signature does not vary + * except for trailing varargs. + * + * Methods are always virtual. Overriding a method in + * #TypeInfo.class_init of a subclass leads to any user of the class obtained + * via OBJECT_GET_CLASS() accessing the overridden function. + * The original function is not automatically invoked. It is the responsability + * of the overriding class to determine whether and when to invoke the method + * being overridden. + * + * To invoke the method being overridden, the preferred solution is to store + * the original value in the overriding class before overriding the method. + * This corresponds to |[ {super,base}.method(...) ]| in Java and C# + * respectively; this frees the overriding class from hardcoding its parent + * class, which someone might choose to change at some point. + * + * + * Overriding a virtual method + * + * typedef struct MyState MyState; + * + * typedef void (*MyDoSomething)(MyState *obj); + * + * typedef struct MyClass { + * ObjectClass parent_class; + * + * MyDoSomething do_something; + * } MyClass; + * + * static void my_do_something(MyState *obj) + * { + * // do something + * } + * + * static void my_class_init(ObjectClass *oc, void *data) + * { + * MyClass *mc = MY_CLASS(oc); + * + * mc->do_something = my_do_something; + * } + * + * static const TypeInfo my_type_info = { + * .name = TYPE_MY, + * .parent = TYPE_OBJECT, + * .instance_size = sizeof(MyState), + * .class_size = sizeof(MyClass), + * .class_init = my_class_init, + * }; + * + * typedef struct DerivedClass { + * MyClass parent_class; + * + * MyDoSomething parent_do_something; + * } MyClass; + * + * static void derived_do_something(MyState *obj) + * { + * DerivedClass *dc = DERIVED_GET_CLASS(obj); + * + * // do something here + * dc->parent_do_something(obj); + * // do something else here + * } + * + * static void derived_class_init(ObjectClass *oc, void *data) + * { + * MyClass *mc = MY_CLASS(oc); + * DerivedClass *dc = DERIVED_CLASS(oc); + * + * dc->parent_do_something = mc->do_something; + * mc->do_something = derived_do_something; + * } + * + * static const TypeInfo derived_type_info = { + * .name = TYPE_DERIVED, + * .parent = TYPE_MY, + * .class_size = sizeof(DerivedClass), + * .class_init = my_class_init, + * }; + * + * + * + * Alternatively, object_class_by_name() can be used to obtain the class and + * its non-overridden methods for a specific type. This would correspond to + * |[ MyClass::method(...) ]| in C++. + * + * The first example of such a QOM method was #CPUClass.reset, + * another example is #DeviceClass.realize. */ From e387f99ebc5753ebb5b7602d86e44d064873f83c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 15 Jan 2013 19:42:38 +0200 Subject: [PATCH 0557/1634] virtio-pci: fix irqfd cleanup argument order Order of arguments of kvm_virtio_pci_irqfd_release got mixed up in all calls. As a result users see assertions during cleanup. Reported-by: Laszlo Ersek Reviewed-by: Laszlo Ersek Tested-by: Laszlo Ersek Reviewed-by: Stefan Hajnoczi Tested-by: Wanlong Gao Signed-off-by: Michael S. Tsirkin Signed-off-by: Anthony Liguori --- hw/virtio-pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 09342463ad..212acd8418 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -576,7 +576,7 @@ undo: continue; } if (proxy->vdev->guest_notifier_mask) { - kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } kvm_virtio_pci_vq_vector_release(proxy, vector); } @@ -602,7 +602,7 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) * Otherwise, it was cleaned when masked in the frontend. */ if (proxy->vdev->guest_notifier_mask) { - kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } kvm_virtio_pci_vq_vector_release(proxy, vector); } @@ -651,7 +651,7 @@ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, if (proxy->vdev->guest_notifier_mask) { proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true); } else { - kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } } From 3249dbe661ba6ef108ecde97c54b4a4104d719c3 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Thu, 17 Jan 2013 18:47:52 +0400 Subject: [PATCH 0558/1634] win32-aio: use iov utility functions instead of open-coding them We have iov_from_buf() and iov_to_buf(), use them instead of open-coding these in block/win32-aio.c Signed-off-by: Stefan Hajnoczi --- block/win32-aio.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/block/win32-aio.c b/block/win32-aio.c index b9236ea74d..5d0fbbfb7d 100644 --- a/block/win32-aio.c +++ b/block/win32-aio.c @@ -29,6 +29,7 @@ #include "block/aio.h" #include "raw-aio.h" #include "qemu/event_notifier.h" +#include "qemu/iov.h" #include #include @@ -80,13 +81,7 @@ static void win32_aio_process_completion(QEMUWin32AIOState *s, if (!waiocb->is_linear) { if (ret == 0 && waiocb->is_read) { QEMUIOVector *qiov = waiocb->qiov; - char *p = waiocb->buf; - int i; - - for (i = 0; i < qiov->niov; ++i) { - memcpy(qiov->iov[i].iov_base, p, qiov->iov[i].iov_len); - p += qiov->iov[i].iov_len; - } + iov_from_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size); } qemu_vfree(waiocb->buf); } @@ -153,13 +148,7 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs, if (qiov->niov > 1) { waiocb->buf = qemu_blockalign(bs, qiov->size); if (type & QEMU_AIO_WRITE) { - char *p = waiocb->buf; - int i; - - for (i = 0; i < qiov->niov; ++i) { - memcpy(p, qiov->iov[i].iov_base, qiov->iov[i].iov_len); - p += qiov->iov[i].iov_len; - } + iov_to_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size); } waiocb->is_linear = false; } else { From cd7fdfe59f4f965665dcd9868fe3764f5256d6aa Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 15 Jan 2013 17:19:38 +0100 Subject: [PATCH 0559/1634] dataplane: avoid reentrancy during virtio_blk_data_plane_stop() When dataplane is stopping, the s->vdev->binding->set_host_notifier(..., false) call can invoke the virtqueue handler if an ioeventfd notification is pending. This causes hw/virtio-blk.c to invoke virtio_blk_data_plane_start() before virtio_blk_data_plane_stop() returns! The result is that we try to restart dataplane while trying to stop it and the following assertion is raised: msix_set_mask_notifier: Assertion `!dev->msix_mask_notifier' failed. Although the code was intended to prevent this scenario, the s->started boolean isn't enough. Add s->stopping so that we can postpone clearing s->started until we've completely stopped dataplane. This way, virtqueue handler calls during virtio_blk_data_plane_stop() are ignored. When dataplane is legitimately started again later we already self-kick ourselves to resume processing. Signed-off-by: Stefan Hajnoczi --- hw/dataplane/virtio-blk.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 4b26faa6c2..3f2da22669 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -40,6 +40,7 @@ typedef struct { struct VirtIOBlockDataPlane { bool started; + bool stopping; QEMUBH *start_bh; QemuThread thread; @@ -357,7 +358,7 @@ static void *data_plane_thread(void *opaque) do { event_poll(&s->event_poll); - } while (s->started || s->num_reqs > 0); + } while (!s->stopping || s->num_reqs > 0); return NULL; } @@ -486,10 +487,10 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) { - if (!s->started) { + if (!s->started || s->stopping) { return; } - s->started = false; + s->stopping = true; trace_virtio_blk_data_plane_stop(s); /* Stop thread or cancel pending thread creation BH */ @@ -511,4 +512,6 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, false); vring_teardown(&s->vring); + s->started = false; + s->stopping = false; } From cf139388ad5b39228793f34eea99e0ea9a2924aa Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Jan 2013 16:46:54 +0100 Subject: [PATCH 0560/1634] dataplane: support viostor virtio-pci status bit setting The viostor virtio-blk driver for Windows does not use the VIRTIO_CONFIG_S_DRIVER bit. It only sets the VIRTIO_CONFIG_S_DRIVER_OK bit. The viostor driver refreshes the virtio-pci status byte sometimes while the guest is running. We misinterpret 0x4 (VIRTIO_CONFIG_S_DRIVER_OK) as an indication that virtio-blk-data-plane should be stopped since 0x2 (VIRTIO_CONFIG_S_DRIVER) is missing. The result is that the device becomes unresponsive. Signed-off-by: Stefan Hajnoczi --- hw/virtio-blk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index df57b35f1b..34913ee40e 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -571,7 +571,8 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) uint32_t features; #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE - if (s->dataplane && !(status & VIRTIO_CONFIG_S_DRIVER)) { + if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER | + VIRTIO_CONFIG_S_DRIVER_OK))) { virtio_blk_data_plane_stop(s->dataplane); } #endif From 7f11573b9fe6c03a9ad4cd1bbaa761e564d44fce Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 7 Jan 2013 20:13:52 +0100 Subject: [PATCH 0561/1634] openpic: move gcr write into a function The GCR register contains too much functionality to be covered inside of the register switch statement. Move it out into a separate function. Signed-off-by: Alexander Graf --- hw/openpic.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index f6cc07bd6e..085c9549d1 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -644,6 +644,27 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) opp->src[n_IRQ].ivpr); } +static void openpic_gcr_write(OpenPICState *opp, uint64_t val) +{ + if (val & GCR_RESET) { + openpic_reset(&opp->busdev.qdev); + } else if (opp->mpic_mode_mask) { + CPUArchState *env; + int mpic_proxy = 0; + + opp->gcr &= ~opp->mpic_mode_mask; + opp->gcr |= val & opp->mpic_mode_mask; + + /* Set external proxy mode */ + if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { + mpic_proxy = 1; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = mpic_proxy; + } + } +} + static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) { @@ -672,23 +693,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x1000: /* FRR */ break; case 0x1020: /* GCR */ - if (val & GCR_RESET) { - openpic_reset(&opp->busdev.qdev); - } else if (opp->mpic_mode_mask) { - CPUArchState *env; - int mpic_proxy = 0; - - opp->gcr &= ~opp->mpic_mode_mask; - opp->gcr |= val & opp->mpic_mode_mask; - - /* Set external proxy mode */ - if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { - mpic_proxy = 1; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->mpic_proxy = mpic_proxy; - } - } + openpic_gcr_write(opp, val); break; case 0x1080: /* VIR */ break; From 1ac3d71302d9d49427dd068af7eccdd4de128522 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 7 Jan 2013 20:15:28 +0100 Subject: [PATCH 0562/1634] openpic: unify gcr mode mask updates The mode mask already masks out bits we don't care about, so the actual handling code can stay intact regardless. Signed-off-by: Alexander Graf --- hw/openpic.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 085c9549d1..c986b5ddcb 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -646,22 +646,23 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) static void openpic_gcr_write(OpenPICState *opp, uint64_t val) { + CPUArchState *env; + int mpic_proxy = 0; + if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); - } else if (opp->mpic_mode_mask) { - CPUArchState *env; - int mpic_proxy = 0; + return; + } - opp->gcr &= ~opp->mpic_mode_mask; - opp->gcr |= val & opp->mpic_mode_mask; + opp->gcr &= ~opp->mpic_mode_mask; + opp->gcr |= val & opp->mpic_mode_mask; - /* Set external proxy mode */ - if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { - mpic_proxy = 1; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->mpic_proxy = mpic_proxy; - } + /* Set external proxy mode */ + if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { + mpic_proxy = 1; + } + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = mpic_proxy; } } From 86e56a885aa5051c87906dfcd060c59f0af22309 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 7 Jan 2013 20:17:24 +0100 Subject: [PATCH 0563/1634] openpic: set mixed mode as supported The Raven MPIC implementation supports the "Mixed" mode to work with an i8259. While we don't implement mixed mode, we should mark it as a supported mode in the mode bitmap. Signed-off-by: Alexander Graf --- hw/openpic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/openpic.c b/hw/openpic.c index c986b5ddcb..bcafe0a12c 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -1470,6 +1470,7 @@ static int openpic_init(SysBusDevice *dev) opp->irq_ipi0 = RAVEN_IPI_IRQ; opp->irq_tim0 = RAVEN_TMR_IRQ; opp->brr1 = -1; + opp->mpic_mode_mask = GCR_MODE_MIXED; list = list_le; /* Don't map MSI region */ list[2].map = false; From 528e536ea2fd3bfe8412e39a5623e80b254f3ae0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 14 Jan 2013 20:24:16 +0100 Subject: [PATCH 0564/1634] PPC: E500: Calculate loading blob offsets properly We have 3 blobs we need to load when booting the system: - kernel - initrd - dtb We place them in physical memory in that order. At least we should. This patch fixes the location calculation up to take any module into account, fixing the dtb offset along the way. Reported-by: Stuart Yoder Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 7b3e2e6723..e5564ce03f 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -463,7 +463,8 @@ void ppce500_init(PPCE500Params *params) target_long kernel_size=0; target_ulong dt_base = 0; target_ulong initrd_base = 0; - target_long initrd_size=0; + target_long initrd_size = 0; + target_ulong cur_base = 0; int i = 0, j, k; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; qemu_irq **irqs, *mpic; @@ -626,12 +627,13 @@ void ppce500_init(PPCE500Params *params) params->kernel_filename); exit(1); } + + cur_base = loadaddr + kernel_size; } /* Load initrd. */ if (params->initrd_filename) { - initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) & - ~INITRD_PAD_MASK; + initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; initrd_size = load_image_targphys(params->initrd_filename, initrd_base, ram_size - initrd_base); @@ -640,6 +642,8 @@ void ppce500_init(PPCE500Params *params) params->initrd_filename); exit(1); } + + cur_base = initrd_base + initrd_size; } /* If we're loading a kernel directly, we must load the device tree too. */ @@ -647,7 +651,7 @@ void ppce500_init(PPCE500Params *params) struct boot_info *boot_info; int dt_size; - dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; + dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK; dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base, initrd_size); if (dt_size < 0) { From 746a870b3c44a6c5734691fec013c78520d55f15 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 16 Jan 2013 01:43:43 +0100 Subject: [PATCH 0565/1634] PPC: Provide zero SVR for -cpu e500mc and e5500 Even though our -cpu types for e500mc and e5500 are no real CPUs that actually have version registers, a guest might still want to access said version register and that has to succeed for a guest to be happy. So let's expose a zero SVR value on E500_SVR SPR reads. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3f199c4bb9..2d78529273 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8633,9 +8633,9 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2), /* PowerPC e500v2 v3.0 core */ POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2), - POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc), + POWERPC_DEF_SVR("e500mc", CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc), #ifdef TARGET_PPC64 - POWERPC_DEF("e5500", CPU_POWERPC_e5500, e5500), + POWERPC_DEF_SVR("e5500", CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500), #endif /* PowerPC e500 microcontrollers */ /* MPC8533 */ From b8dec1443ef6c52e72594c5a861a5d2fd7f05d80 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 Jan 2013 11:19:28 +0100 Subject: [PATCH 0566/1634] PPC: e500: Change in-memory order of load blobs Today, we load into memory in that order. However, Linux has a bug where it can only handle the dtb if it's within the first 64MB of where starts. So instead, let's change the order to making Linux happy. Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index e5564ce03f..c36821a99f 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -41,6 +41,7 @@ #define UIMAGE_LOAD_BASE 0 #define DTC_LOAD_PAD 0x1800000 #define DTC_PAD_MASK 0xFFFFF +#define DTB_MAX_SIZE (8 * 1024 * 1024) #define INITRD_LOAD_PAD 0x2000000 #define INITRD_PAD_MASK 0xFFFFFF @@ -629,6 +630,10 @@ void ppce500_init(PPCE500Params *params) } cur_base = loadaddr + kernel_size; + + /* Reserve space for dtb */ + dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK; + cur_base += DTB_MAX_SIZE; } /* Load initrd. */ @@ -651,13 +656,13 @@ void ppce500_init(PPCE500Params *params) struct boot_info *boot_info; int dt_size; - dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK; dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base, initrd_size); if (dt_size < 0) { fprintf(stderr, "couldn't load device tree\n"); exit(1); } + assert(dt_size < DTB_MAX_SIZE); boot_info = env->load_info; boot_info->entry = entry; From d3dccee187ffeacec1a38ed288c112ffa0e3b513 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 18 Jan 2013 00:06:26 +0100 Subject: [PATCH 0567/1634] Update Linux kernel headers Based on kvm.git a843fac (next) plus dfdebc24 (master). Signed-off-by: Alexander Graf --- linux-headers/asm-powerpc/kvm.h | 6 +++++- linux-headers/linux/kvm.h | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 2fba8a66fb..16064d00ad 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -114,7 +114,10 @@ struct kvm_regs { /* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */ #define KVM_SREGS_E_SPE (1 << 9) -/* External Proxy (EXP) -- EPR */ +/* + * DEPRECATED! USE ONE_REG FOR THIS ONE! + * External Proxy (EXP) -- EPR + */ #define KVM_SREGS_EXP (1 << 10) /* External PID (E.PD) -- EPSC/EPLC */ @@ -412,5 +415,6 @@ struct kvm_get_htab_header { #define KVM_REG_PPC_VPA_DTL (KVM_REG_PPC | KVM_REG_SIZE_U128 | 0x84) #define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) +#define KVM_REG_PPC_EPR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x86) #endif /* __LINUX_KVM_POWERPC_H */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index bfdbf4d1ad..5af935761c 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -168,6 +168,8 @@ struct kvm_pit_config { #define KVM_EXIT_PAPR_HCALL 19 #define KVM_EXIT_S390_UCONTROL 20 #define KVM_EXIT_WATCHDOG 21 +#define KVM_EXIT_S390_TSCH 22 +#define KVM_EXIT_EPR 23 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -285,6 +287,19 @@ struct kvm_run { __u64 ret; __u64 args[9]; } papr_hcall; + /* KVM_EXIT_S390_TSCH */ + struct { + __u16 subchannel_id; + __u16 subchannel_nr; + __u32 io_int_parm; + __u32 io_int_word; + __u32 ipb; + __u8 dequeued; + } s390_tsch; + /* KVM_EXIT_EPR */ + struct { + __u32 epr; + } epr; /* Fix the size of the union. */ char padding[256]; }; @@ -397,10 +412,20 @@ struct kvm_s390_psw { #define KVM_S390_PROGRAM_INT 0xfffe0001u #define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u #define KVM_S390_RESTART 0xfffe0003u +#define KVM_S390_MCHK 0xfffe1000u #define KVM_S390_INT_VIRTIO 0xffff2603u #define KVM_S390_INT_SERVICE 0xffff2401u #define KVM_S390_INT_EMERGENCY 0xffff1201u #define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u +/* Anything below 0xfffe0000u is taken by INT_IO */ +#define KVM_S390_INT_IO(ai,cssid,ssid,schid) \ + (((schid)) | \ + ((ssid) << 16) | \ + ((cssid) << 18) | \ + ((ai) << 26)) +#define KVM_S390_INT_IO_MIN 0x00000000u +#define KVM_S390_INT_IO_MAX 0xfffdffffu + struct kvm_s390_interrupt { __u32 type; @@ -635,6 +660,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_IRQFD_RESAMPLE 82 #define KVM_CAP_PPC_BOOKE_WATCHDOG 83 #define KVM_CAP_PPC_HTAB_FD 84 +#define KVM_CAP_S390_CSS_SUPPORT 85 +#define KVM_CAP_PPC_EPR 86 #ifdef KVM_CAP_IRQ_ROUTING From e49798b1bd7657722080126bfd5e787efdb3bc23 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 Jan 2013 11:32:21 +0100 Subject: [PATCH 0568/1634] openpic: export e500 epr enable into a ppc.c function Enabling and disabling the EPR capability (mpic_proxy) is a system wide operation. As such, it belongs into the ppc.c file, since that's where PPC specific machine wide logic happens. Signed-off-by: Alexander Graf --- hw/openpic.c | 11 +++++------ hw/ppc.c | 11 +++++++++++ hw/ppc.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index bcafe0a12c..cc8ec35b5d 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -40,6 +40,7 @@ #include "sysbus.h" #include "pci/msi.h" #include "qemu/bitops.h" +#include "ppc.h" //#define DEBUG_OPENPIC @@ -646,8 +647,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) static void openpic_gcr_write(OpenPICState *opp, uint64_t val) { - CPUArchState *env; - int mpic_proxy = 0; + bool mpic_proxy = false; if (val & GCR_RESET) { openpic_reset(&opp->busdev.qdev); @@ -659,11 +659,10 @@ static void openpic_gcr_write(OpenPICState *opp, uint64_t val) /* Set external proxy mode */ if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { - mpic_proxy = 1; - } - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->mpic_proxy = mpic_proxy; + mpic_proxy = true; } + + ppce500_set_mpic_proxy(mpic_proxy); } static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, diff --git a/hw/ppc.c b/hw/ppc.c index e473f9e962..1fce604c73 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -428,6 +428,17 @@ void ppce500_irq_init(CPUPPCState *env) env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, cpu, PPCE500_INPUT_NB); } + +/* Enable or Disable the E500 EPR capability */ +void ppce500_set_mpic_proxy(bool enabled) +{ + CPUPPCState *env; + + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->mpic_proxy = enabled; + } +} + /*****************************************************************************/ /* PowerPC time base and decrementer emulation */ diff --git a/hw/ppc.h b/hw/ppc.h index e73ae83b52..ee0cd16ee5 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -73,6 +73,8 @@ void ppc6xx_irq_init (CPUPPCState *env); void ppc970_irq_init (CPUPPCState *env); void ppcPOWER7_irq_init (CPUPPCState *env); +void ppce500_set_mpic_proxy(bool enabled); + /* PPC machines for OpenBIOS */ enum { ARCH_PREP = 0, From 5b95b8b9c1b0cd30a31dbeffdaec35134248b6e9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 17 Jan 2013 11:54:38 +0100 Subject: [PATCH 0569/1634] PPC: KVM: Add support for EPR with KVM This patch links KVM EPR support to the existing TCG support we have now. Signed-off-by: Alexander Graf --- hw/ppc.c | 6 ++++++ target-ppc/kvm.c | 21 +++++++++++++++++++++ target-ppc/kvm_ppc.h | 5 +++++ 3 files changed, 32 insertions(+) diff --git a/hw/ppc.c b/hw/ppc.c index 1fce604c73..c52e22f708 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -435,7 +435,13 @@ void ppce500_set_mpic_proxy(bool enabled) CPUPPCState *env; for (env = first_cpu; env != NULL; env = env->next_cpu) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + CPUState *cs = CPU(cpu); + env->mpic_proxy = enabled; + if (kvm_enabled()) { + kvmppc_set_mpic_proxy(POWERPC_CPU(cs), enabled); + } } } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 19e9f25b19..2f4f06818a 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -846,6 +846,11 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ret = 0; break; #endif + case KVM_EXIT_EPR: + dprintf("handle epr\n"); + run->epr.epr = ldl_phys(env->mpic_iack); + ret = 0; + break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; @@ -1057,6 +1062,22 @@ void kvmppc_set_papr(PowerPCCPU *cpu) } } +void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) +{ + CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct kvm_enable_cap cap = {}; + int ret; + + cap.cap = KVM_CAP_PPC_EPR; + cap.args[0] = mpic_proxy; + ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap); + + if (ret && mpic_proxy) { + cpu_abort(env, "This KVM version does not support EPR\n"); + } +} + int kvmppc_smt_threads(void) { return cap_ppc_smt ? cap_ppc_smt : 1; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 3db21fc889..c30b006674 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -25,6 +25,7 @@ int kvmppc_get_hasidle(CPUPPCState *env); int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); void kvmppc_set_papr(PowerPCCPU *cpu); +void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); int kvmppc_smt_threads(void); #ifndef CONFIG_USER_ONLY off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); @@ -81,6 +82,10 @@ static inline void kvmppc_set_papr(PowerPCCPU *cpu) { } +static inline void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) +{ +} + static inline int kvmppc_smt_threads(void) { return 1; From ccb084d3f0ec405afc6c878ace40f1ccf1e44027 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 12 Nov 2012 01:44:10 +0000 Subject: [PATCH 0570/1634] s390: new contributions GPLv2 or later IBMs s390 contributions were meant to to be gplv2 or later (since we were contributing to qemu). Several of the s390 specific files link to gpl code anyway, so lets clarify the licence statement for new contributions for those files that we have touched multiple times or will likely touch again. This patch does not touch files that mostly deal with tcg. Signed-off-by: Christian Borntraeger Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 5 ++++- target-s390x/kvm.c | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index bc3fab226b..1fa3ad3a94 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -13,7 +13,10 @@ * 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 + * Contributions after 2012-10-29 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + * + * You should have received a copy of the GNU (Lesser) General Public * License along with this library; if not, see . */ #ifndef CPU_S390X_H diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 6ec5e6d8a6..5785f7d870 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -2,6 +2,7 @@ * QEMU S390x KVM implementation * * Copyright (c) 2009 Alexander Graf + * Copyright IBM Corp. 2012 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -13,7 +14,10 @@ * 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 + * Contributions after 2012-10-29 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + * + * You should have received a copy of the GNU (Lesser) General Public * License along with this library; if not, see . */ From e674a49aae8b79bc4ea07f1bcd666bbf28b12a27 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 18 Dec 2012 07:50:57 +0000 Subject: [PATCH 0571/1634] s390: Move IPL code into a separate device Lets move the code to setup IPL for external kernel or via the zipl rom into a separate file. This allows to - define a reboot handler, setting up the PSW appropriately - enhance the boot code to IPL disks that contain a bootmap that was created with zipl under LPAR or z/VM (future patch) - reuse that code for several machines (e.g. virtio-ccw and virtio-s390) - allow different machines to provide different defaults Signed-off-by: Christian Borntraeger Signed-off-by: Jens Freimann [agraf: symbolify initial psw, adjust header file location, fix for QOM] Signed-off-by: Alexander Graf --- hw/s390-virtio.c | 98 +++-------------------- hw/s390x/Makefile.objs | 1 + hw/s390x/ipl.c | 174 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 88 deletions(-) create mode 100644 hw/s390x/ipl.c diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 0e93cc3641..13f93fbd24 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -25,7 +25,6 @@ #include "boards.h" #include "monitor/monitor.h" #include "loader.h" -#include "elf.h" #include "hw/virtio.h" #include "hw/sysbus.h" #include "sysemu/kvm.h" @@ -48,17 +47,6 @@ #define KVM_S390_VIRTIO_RESET 1 #define KVM_S390_VIRTIO_SET_STATUS 2 -#define KERN_IMAGE_START 0x010000UL -#define KERN_PARM_AREA 0x010480UL -#define INITRD_START 0x800000UL -#define INITRD_PARM_START 0x010408UL -#define INITRD_PARM_SIZE 0x010410UL -#define PARMFILE_START 0x001000UL - -#define ZIPL_START 0x009000UL -#define ZIPL_LOAD_ADDR 0x009000UL -#define ZIPL_FILENAME "s390-zipl.rom" - #define MAX_BLK_DEVS 10 static VirtIOS390Bus *s390_bus; @@ -156,15 +144,10 @@ static void s390_init(QEMUMachineInitArgs *args) { ram_addr_t my_ram_size = args->ram_size; const char *cpu_model = args->cpu_model; - const char *kernel_filename = args->kernel_filename; - const char *kernel_cmdline = args->kernel_cmdline; - const char *initrd_filename = args->initrd_filename; CPUS390XState *env = NULL; + DeviceState *dev; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - ram_addr_t kernel_size = 0; - ram_addr_t initrd_offset; - ram_addr_t initrd_size = 0; int shift = 0; uint8_t *storage_keys; void *virtio_region; @@ -185,6 +168,15 @@ static void s390_init(QEMUMachineInitArgs *args) /* get a BUS */ s390_bus = s390_virtio_bus_init(&my_ram_size); s390_sclp_init(); + dev = qdev_create(NULL, "s390-ipl"); + if (args->kernel_filename) { + qdev_prop_set_string(dev, "kernel", args->kernel_filename); + } + if (args->initrd_filename) { + qdev_prop_set_string(dev, "initrd", args->initrd_filename); + } + qdev_prop_set_string(dev, "cmdline", args->kernel_cmdline); + qdev_init_nofail(dev); /* allocate RAM */ memory_region_init_ram(ram, "s390.ram", my_ram_size); @@ -225,76 +217,6 @@ static void s390_init(QEMUMachineInitArgs *args) tmp_env->storage_keys = storage_keys; } - /* One CPU has to run */ - s390_add_running_cpu(env); - - if (kernel_filename) { - - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, NULL, - NULL, 1, ELF_MACHINE, 0); - if (kernel_size == -1UL) { - kernel_size = load_image_targphys(kernel_filename, 0, ram_size); - } - if (kernel_size == -1UL) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - /* - * we can not rely on the ELF entry point, since up to 3.2 this - * value was 0x800 (the SALIPL loader) and it wont work. For - * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine. - */ - env->psw.addr = KERN_IMAGE_START; - env->psw.mask = 0x0000000180000000ULL; - } else { - ram_addr_t bios_size = 0; - char *bios_filename; - - /* Load zipl bootloader */ - if (bios_name == NULL) { - bios_name = ZIPL_FILENAME; - } - - bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - bios_size = load_image_targphys(bios_filename, ZIPL_LOAD_ADDR, 4096); - g_free(bios_filename); - - if ((long)bios_size < 0) { - hw_error("could not load bootloader '%s'\n", bios_name); - } - - if (bios_size > 4096) { - hw_error("stage1 bootloader is > 4k\n"); - } - - env->psw.addr = ZIPL_START; - env->psw.mask = 0x0000000180000000ULL; - } - - if (initrd_filename) { - initrd_offset = INITRD_START; - while (kernel_size + 0x100000 > initrd_offset) { - initrd_offset += 0x100000; - } - initrd_size = load_image_targphys(initrd_filename, initrd_offset, - ram_size - initrd_offset); - if (initrd_size == -1UL) { - fprintf(stderr, "qemu: could not load initrd '%s'\n", - initrd_filename); - exit(1); - } - - /* we have to overwrite values in the kernel image, which are "rom" */ - stq_p(rom_ptr(INITRD_PARM_START), initrd_offset); - stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); - } - - if (rom_ptr(KERN_PARM_AREA)) { - /* we have to overwrite values in the kernel image, which are "rom" */ - memcpy(rom_ptr(KERN_PARM_AREA), kernel_cmdline, - strlen(kernel_cmdline) + 1); - } /* Create VirtIO network adapters */ for(i = 0; i < nb_nics; i++) { diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 096dfcd6a1..4a5a5d8cba 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -4,3 +4,4 @@ obj-y := $(addprefix ../,$(obj-y)) obj-y += sclp.o obj-y += event-facility.o obj-y += sclpquiesce.o sclpconsole.o +obj-y += ipl.o diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c new file mode 100644 index 0000000000..7cbbf99fde --- /dev/null +++ b/hw/s390x/ipl.c @@ -0,0 +1,174 @@ +/* + * bootloader support + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Christian Borntraeger + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include "sysemu/sysemu.h" +#include "cpu.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/sysbus.h" + +#define KERN_IMAGE_START 0x010000UL +#define KERN_PARM_AREA 0x010480UL +#define INITRD_START 0x800000UL +#define INITRD_PARM_START 0x010408UL +#define INITRD_PARM_SIZE 0x010410UL +#define PARMFILE_START 0x001000UL +#define ZIPL_FILENAME "s390-zipl.rom" +#define ZIPL_IMAGE_START 0x009000UL +#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64) + +#define TYPE_S390_IPL "s390-ipl" +#define S390_IPL(obj) \ + OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL) +#if 0 +#define S390_IPL_CLASS(klass) \ + OBJECT_CLASS_CHECK(S390IPLState, (klass), TYPE_S390_IPL) +#define S390_IPL_GET_CLASS(obj) \ + OBJECT_GET_CLASS(S390IPLState, (obj), TYPE_S390_IPL) +#endif + +typedef struct S390IPLClass { + /*< private >*/ + SysBusDeviceClass parent_class; + /*< public >*/ + + void (*parent_reset) (SysBusDevice *dev); +} S390IPLClass; + +typedef struct S390IPLState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + char *kernel; + char *initrd; + char *cmdline; +} S390IPLState; + + +static void s390_ipl_cpu(uint64_t pswaddr) +{ + CPUS390XState *env = &S390_CPU(qemu_get_cpu(0))->env; + env->psw.addr = pswaddr; + env->psw.mask = IPL_PSW_MASK; + s390_add_running_cpu(env); +} + +static int s390_ipl_init(SysBusDevice *dev) +{ + S390IPLState *ipl = S390_IPL(dev); + ram_addr_t kernel_size = 0; + + if (!ipl->kernel) { + ram_addr_t bios_size = 0; + char *bios_filename; + + /* Load zipl bootloader */ + if (bios_name == NULL) { + bios_name = ZIPL_FILENAME; + } + + bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START, 4096); + g_free(bios_filename); + + if ((long)bios_size < 0) { + hw_error("could not load bootloader '%s'\n", bios_name); + } + + if (bios_size > 4096) { + hw_error("stage1 bootloader is > 4k\n"); + } + return 0; + } else { + kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL, + NULL, 1, ELF_MACHINE, 0); + if (kernel_size == -1UL) { + kernel_size = load_image_targphys(ipl->kernel, 0, ram_size); + } + if (kernel_size == -1UL) { + fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel); + return -1; + } + /* we have to overwrite values in the kernel image, which are "rom" */ + strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline); + } + if (ipl->initrd) { + ram_addr_t initrd_offset, initrd_size; + + initrd_offset = INITRD_START; + while (kernel_size + 0x100000 > initrd_offset) { + initrd_offset += 0x100000; + } + initrd_size = load_image_targphys(ipl->initrd, initrd_offset, + ram_size - initrd_offset); + if (initrd_size == -1UL) { + fprintf(stderr, "qemu: could not load initrd '%s'\n", ipl->initrd); + exit(1); + } + + /* we have to overwrite values in the kernel image, which are "rom" */ + stq_p(rom_ptr(INITRD_PARM_START), initrd_offset); + stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); + } + + return 0; +} + +static Property s390_ipl_properties[] = { + DEFINE_PROP_STRING("kernel", S390IPLState, kernel), + DEFINE_PROP_STRING("initrd", S390IPLState, initrd), + DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline), + DEFINE_PROP_END_OF_LIST(), +}; + +static void s390_ipl_reset(DeviceState *dev) +{ + S390IPLState *ipl = S390_IPL(dev); + + if (ipl->kernel) { + /* + * we can not rely on the ELF entry point, since up to 3.2 this + * value was 0x800 (the SALIPL loader) and it wont work. For + * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine. + */ + return s390_ipl_cpu(KERN_IMAGE_START); + } else { + return s390_ipl_cpu(ZIPL_IMAGE_START); + } +} + +static void s390_ipl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = s390_ipl_init; + dc->props = s390_ipl_properties; + dc->reset = s390_ipl_reset; + dc->no_user = 1; +} + +static TypeInfo s390_ipl_info = { + .class_init = s390_ipl_class_init, + .parent = TYPE_SYS_BUS_DEVICE, + .name = "s390-ipl", + .instance_size = sizeof(S390IPLState), +}; + +static void s390_ipl_register_types(void) +{ + type_register_static(&s390_ipl_info); +} + +type_init(s390_ipl_register_types) From 904e5fd5c25537fdf910bfd5db832df5d9c23ad6 Mon Sep 17 00:00:00 2001 From: Viktor Mihajlovski Date: Tue, 18 Dec 2012 07:50:59 +0000 Subject: [PATCH 0572/1634] S390: Enable -cpu help and QMP query-cpu-definitions This enables qemu -cpu help to return a list of supported CPU models on s390 and also to query for cpu definitions in the monitor. Initially only cpu model = host is returned. This needs to be reworked into a full-fledged CPU model handling later on. This change is needed to allow libvirt exploiters (like OpenStack) to specify a CPU model. Signed-off-by: Viktor Mihajlovski Signed-off-by: Jens Freimann Reviewed-by: Christian Borntraeger [agraf: fix s390x-linux-user, adjust header locations] Signed-off-by: Alexander Graf --- hw/s390-virtio.c | 6 +++++- target-s390x/cpu.c | 26 ++++++++++++++++++++++++++ target-s390x/cpu.h | 3 +++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 13f93fbd24..3cfb97e2dc 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -2,6 +2,7 @@ * QEMU S390 virtio target * * Copyright (c) 2009 Alexander Graf + * Copyright IBM Corp 2012 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -13,7 +14,10 @@ * 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 + * Contributions after 2012-10-29 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + * + * You should have received a copy of the GNU (Lesser) General Public * License along with this library; if not, see . */ diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 2ed23127d1..420b21b6db 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -23,7 +23,33 @@ #include "cpu.h" #include "qemu-common.h" #include "qemu/timer.h" +#ifndef CONFIG_USER_ONLY +#include "sysemu/arch_init.h" +#endif +/* generate CPU information for cpu -? */ +void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ +#ifdef CONFIG_KVM + (*cpu_fprintf)(f, "s390 %16s\n", "host"); +#endif +} + +#ifndef CONFIG_USER_ONLY +CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup("host"); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + + return entry; +} +#endif /* CPUClass::reset() */ static void s390_cpu_reset(CPUState *s) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 1fa3ad3a94..d503b9e07e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -362,6 +362,9 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) #define cpu_gen_code cpu_s390x_gen_code #define cpu_signal_handler cpu_s390x_signal_handler +void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); +#define cpu_list s390_cpu_list + #include "exec/exec-all.h" #define EXCP_EXT 1 /* external interrupt */ From a158986d85bf75aa078ce3fb53e60a7fa3c6c6ee Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 1 Jan 2013 08:24:55 +0000 Subject: [PATCH 0573/1634] s390x: Remove inline function ebcdic_put and related data from cpu.h The function is only used in misc_helper.c, so move it to that file. This reduces the size of debug executables (compiled without optimization) because they get unused code and data for each compilation which includes cpu.h. Executables with optimization don't change their size. ebcdic2ascii is currently unused and could be removed (not done here). The array ascii2ebcdic must be accessed with an unsigned index, therefore (int)ascii[i] was replaced by (uint8_t)ascii[i]. The old code would have failed for a signed char less than 0. The current code only converts "QEMU" and spaces to EBCDIC, so there is no problem today. Signed-off-by: Stefan Weil Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 81 -------------------------------------- target-s390x/misc_helper.c | 81 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index d503b9e07e..23d8b44f0a 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -775,87 +775,6 @@ struct sysib_322 { #define SK_F (0x1 << 3) #define SK_ACC_MASK (0xf << 4) - -/* EBCDIC handling */ -static const uint8_t ebcdic2ascii[] = { - 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, - 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, - 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, - 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, - 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, - 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, - 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, - 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, - 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, - 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, - 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, - 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, - 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, - 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, - 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, - 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, - 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, - 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, - 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, - 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, - 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, - 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, -}; - -static const uint8_t ascii2ebcdic [] = { - 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, - 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, - 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, - 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF -}; - -static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) -{ - int i; - - for (i = 0; i < len; i++) { - p[i] = ascii2ebcdic[(int)ascii[i]]; - } -} - #define SIGP_SENSE 0x01 #define SIGP_EXTERNAL_CALL 0x02 #define SIGP_EMERGENCY 0x03 diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 3015bfe3f2..78d2c0e762 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -70,6 +70,87 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) } #ifndef CONFIG_USER_ONLY + +/* EBCDIC handling */ +static const uint8_t ebcdic2ascii[] = { + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07, +}; + +static const uint8_t ascii2ebcdic[] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +static inline void ebcdic_put(uint8_t *p, const char *ascii, int len) +{ + int i; + + for (i = 0; i < len; i++) { + p[i] = ascii2ebcdic[(uint8_t)ascii[i]]; + } +} + void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) { qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", From 70bada03047f723424c4d08d93719c1a83a43cd2 Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Mon, 7 Jan 2013 05:27:14 +0000 Subject: [PATCH 0574/1634] s390: Add CPU reset handler Add a CPU reset handler to have all CPUs in a PoP compliant state. Signed-off-by: Jens Freimann [agraf: move hw/hw.h into existing ifdef] Signed-off-by: Alexander Graf --- target-s390x/cpu.c | 35 +++++++++++++++++++++++++++++++++-- target-s390x/kvm.c | 9 ++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 420b21b6db..6810246c31 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -4,6 +4,7 @@ * Copyright (c) 2009 Ulrich Hecht * Copyright (c) 2011 Alexander Graf * Copyright (c) 2012 SUSE LINUX Products GmbH + * Copyright (c) 2012 IBM Corp. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,15 +19,21 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * + * Contributions after 2012-12-11 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. */ #include "cpu.h" #include "qemu-common.h" #include "qemu/timer.h" #ifndef CONFIG_USER_ONLY +#include "hw/hw.h" #include "sysemu/arch_init.h" #endif +#define CR0_RESET 0xE0UL +#define CR14_RESET 0xC2000000UL; + /* generate CPU information for cpu -? */ void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf) { @@ -63,14 +70,33 @@ static void s390_cpu_reset(CPUState *s) log_cpu_state(env, 0); } + s390_del_running_cpu(env); + scc->parent_reset(s); memset(env, 0, offsetof(CPUS390XState, breakpoints)); - /* FIXME: reset vector? */ + + /* architectured initial values for CR 0 and 14 */ + env->cregs[0] = CR0_RESET; + env->cregs[14] = CR14_RESET; + /* set halted to 1 to make sure we can add the cpu in + * s390_ipl_cpu code, where env->halted is set back to 0 + * after incrementing the cpu counter */ +#if !defined(CONFIG_USER_ONLY) + env->halted = 1; +#endif tlb_flush(env, 1); - s390_add_running_cpu(env); } +#if !defined(CONFIG_USER_ONLY) +static void s390_cpu_machine_reset_cb(void *opaque) +{ + S390CPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} +#endif + static void s390_cpu_initfn(Object *obj) { S390CPU *cpu = S390_CPU(obj); @@ -82,12 +108,17 @@ static void s390_cpu_initfn(Object *obj) cpu_exec_init(env); #if !defined(CONFIG_USER_ONLY) + qemu_register_reset(s390_cpu_machine_reset_cb, cpu); qemu_get_timedate(&tm, 0); env->tod_offset = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL); env->tod_basetime = 0; env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu); env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu); + /* set env->halted state to 1 to avoid decrementing the running + * cpu counter in s390_cpu_reset to a negative number at + * initial ipl */ + env->halted = 1; #endif env->cpu_num = cpu_num++; env->ext_index = -1; diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 5785f7d870..8bd308020c 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -89,7 +89,14 @@ int kvm_arch_init_vcpu(CPUState *cpu) void kvm_arch_reset_vcpu(CPUState *cpu) { - /* FIXME: add code to reset vcpu. */ + /* The initial reset call is needed here to reset in-kernel + * vcpu data that we can't access directly from QEMU + * (i.e. with older kernels which don't support sync_regs/ONE_REG). + * Before this ioctl cpu_synchronize_state() is called in common kvm + * code (kvm-all) */ + if (kvm_vcpu_ioctl(cpu, KVM_S390_INITIAL_RESET, NULL)) { + perror("Can't reset vcpu\n"); + } } int kvm_arch_put_registers(CPUState *cs, int level) From 419831d7104e6876f47f5eccb758855115086bbd Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 7 Jan 2013 16:44:27 +0100 Subject: [PATCH 0575/1634] s390x: fix indentation In one of the last commits we accidently got 3-space indentation into the tree. Fix it up so it's 4 spaces wide. Reported-by: Andreas Faerber Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 8bd308020c..a63ee46504 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -89,11 +89,11 @@ int kvm_arch_init_vcpu(CPUState *cpu) void kvm_arch_reset_vcpu(CPUState *cpu) { - /* The initial reset call is needed here to reset in-kernel - * vcpu data that we can't access directly from QEMU - * (i.e. with older kernels which don't support sync_regs/ONE_REG). - * Before this ioctl cpu_synchronize_state() is called in common kvm - * code (kvm-all) */ + /* The initial reset call is needed here to reset in-kernel + * vcpu data that we can't access directly from QEMU + * (i.e. with older kernels which don't support sync_regs/ONE_REG). + * Before this ioctl cpu_synchronize_state() is called in common kvm + * code (kvm-all) */ if (kvm_vcpu_ioctl(cpu, KVM_S390_INITIAL_RESET, NULL)) { perror("Can't reset vcpu\n"); } From d5627ce8a4fd8dd6d7afd3d4d1ff7e9f1fb86d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 7 Jan 2013 06:14:16 +0000 Subject: [PATCH 0576/1634] target-s390x: Unregister reset callback on finalization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit "s390: Add CPU reset handler" the CPU's instance_init registers a reset callback. Unregister that on instance_finalize. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-s390x/cpu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 6810246c31..0b68db8305 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -126,6 +126,15 @@ static void s390_cpu_initfn(Object *obj) cpu_reset(CPU(cpu)); } +static void s390_cpu_finalize(Object *obj) +{ +#if !defined(CONFIG_USER_ONLY) + S390CPU *cpu = S390_CPU(obj); + + qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu); +#endif +} + static void s390_cpu_class_init(ObjectClass *oc, void *data) { S390CPUClass *scc = S390_CPU_CLASS(oc); @@ -140,6 +149,7 @@ static const TypeInfo s390_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(S390CPU), .instance_init = s390_cpu_initfn, + .instance_finalize = s390_cpu_finalize, .abstract = false, .class_size = sizeof(S390CPUClass), .class_init = s390_cpu_class_init, From 28e942f86d46ccd46bf1f4836389abb3ff706dff Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 17 Jan 2013 04:23:46 +0000 Subject: [PATCH 0577/1634] s390: Add a hypercall registration interface. Allow virtio machines to register for different diag500 function codes and convert s390-virtio to use it. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390-virtio.c | 94 +++++++++++++++++++----------------- hw/s390-virtio.h | 22 +++++++++ hw/s390x/Makefile.objs | 1 + hw/s390x/s390-virtio-hcall.c | 36 ++++++++++++++ target-s390x/cpu.h | 2 +- target-s390x/kvm.c | 2 +- target-s390x/misc_helper.c | 2 +- 7 files changed, 112 insertions(+), 47 deletions(-) create mode 100644 hw/s390-virtio.h create mode 100644 hw/s390x/s390-virtio-hcall.c diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 3cfb97e2dc..5edaabb7c4 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -36,6 +36,7 @@ #include "hw/s390-virtio-bus.h" #include "hw/s390x/sclp.h" +#include "hw/s390-virtio.h" //#define DEBUG_S390 @@ -47,10 +48,6 @@ do { } while (0) #endif -#define KVM_S390_VIRTIO_NOTIFY 0 -#define KVM_S390_VIRTIO_RESET 1 -#define KVM_S390_VIRTIO_SET_STATUS 2 - #define MAX_BLK_DEVS 10 static VirtIOS390Bus *s390_bus; @@ -65,56 +62,63 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) return ipi_states[cpu_addr]; } -int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall) +static int s390_virtio_hcall_notify(const uint64_t *args) { + uint64_t mem = args[0]; int r = 0, i; - dprintf("KVM hypercall: %ld\n", hypercall); - switch (hypercall) { - case KVM_S390_VIRTIO_NOTIFY: - if (mem > ram_size) { - VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus, - mem, &i); - if (dev) { - virtio_queue_notify(dev->vdev, i); - } else { - r = -EINVAL; - } - } else { - /* Early printk */ - } - break; - case KVM_S390_VIRTIO_RESET: - { - VirtIOS390Device *dev; - - dev = s390_virtio_bus_find_mem(s390_bus, mem); - virtio_reset(dev->vdev); - stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0); - s390_virtio_device_sync(dev); - s390_virtio_reset_idx(dev); - break; - } - case KVM_S390_VIRTIO_SET_STATUS: - { - VirtIOS390Device *dev; - - dev = s390_virtio_bus_find_mem(s390_bus, mem); + if (mem > ram_size) { + VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus, mem, &i); if (dev) { - s390_virtio_device_update_status(dev); + virtio_queue_notify(dev->vdev, i); } else { r = -EINVAL; } - break; + } else { + /* Early printk */ } - default: - r = -EINVAL; - break; - } - return r; } +static int s390_virtio_hcall_reset(const uint64_t *args) +{ + uint64_t mem = args[0]; + VirtIOS390Device *dev; + + dev = s390_virtio_bus_find_mem(s390_bus, mem); + virtio_reset(dev->vdev); + stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0); + s390_virtio_device_sync(dev); + s390_virtio_reset_idx(dev); + + return 0; +} + +static int s390_virtio_hcall_set_status(const uint64_t *args) +{ + uint64_t mem = args[0]; + int r = 0; + VirtIOS390Device *dev; + + dev = s390_virtio_bus_find_mem(s390_bus, mem); + if (dev) { + s390_virtio_device_update_status(dev); + } else { + r = -EINVAL; + } + return r; +} + +static void s390_virtio_register_hcalls(void) +{ + s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY, + s390_virtio_hcall_notify); + s390_register_virtio_hypercall(KVM_S390_VIRTIO_RESET, + s390_virtio_hcall_reset); + s390_register_virtio_hypercall(KVM_S390_VIRTIO_SET_STATUS, + s390_virtio_hcall_set_status); +} + /* * The number of running CPUs. On s390 a shutdown is the state of all CPUs * being either stopped or disabled (for interrupts) waiting. We have to @@ -182,6 +186,9 @@ static void s390_init(QEMUMachineInitArgs *args) qdev_prop_set_string(dev, "cmdline", args->kernel_cmdline); qdev_init_nofail(dev); + /* register hypercalls */ + s390_virtio_register_hcalls(); + /* allocate RAM */ memory_region_init_ram(ram, "s390.ram", my_ram_size); vmstate_register_ram_global(ram); @@ -265,4 +272,3 @@ static void s390_machine_init(void) } machine_init(s390_machine_init); - diff --git a/hw/s390-virtio.h b/hw/s390-virtio.h new file mode 100644 index 0000000000..25bb610fd8 --- /dev/null +++ b/hw/s390-virtio.h @@ -0,0 +1,22 @@ +/* + * Virtio interfaces for s390 + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef HW_S390_VIRTIO_H +#define HW_S390_VIRTIO_H 1 + +#define KVM_S390_VIRTIO_NOTIFY 0 +#define KVM_S390_VIRTIO_RESET 1 +#define KVM_S390_VIRTIO_SET_STATUS 2 + +typedef int (*s390_virtio_fn)(const uint64_t *args); +void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); + +#endif diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 4a5a5d8cba..1b40c2e66e 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -1,6 +1,7 @@ obj-y = s390-virtio-bus.o s390-virtio.o obj-y := $(addprefix ../,$(obj-y)) +obj-y += s390-virtio-hcall.o obj-y += sclp.o obj-y += event-facility.o obj-y += sclpquiesce.o sclpconsole.o diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c new file mode 100644 index 0000000000..d7938c0734 --- /dev/null +++ b/hw/s390x/s390-virtio-hcall.c @@ -0,0 +1,36 @@ +/* + * Support for virtio hypercalls on s390 + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "cpu.h" +#include "hw/s390-virtio.h" + +#define MAX_DIAG_SUBCODES 255 + +static s390_virtio_fn s390_diag500_table[MAX_DIAG_SUBCODES]; + +void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn) +{ + assert(code < MAX_DIAG_SUBCODES); + assert(!s390_diag500_table[code]); + + s390_diag500_table[code] = fn; +} + +int s390_virtio_hypercall(CPUS390XState *env) +{ + s390_virtio_fn fn = s390_diag500_table[env->regs[1]]; + + if (!fn) { + return -EINVAL; + } + + return fn(&env->regs[2]); +} diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 23d8b44f0a..1f2d94218a 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -305,7 +305,7 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); -int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall); +int s390_virtio_hypercall(CPUS390XState *env); #ifdef CONFIG_KVM void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index a63ee46504..add6a58f9c 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -397,7 +397,7 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) static int handle_hypercall(CPUS390XState *env, struct kvm_run *run) { cpu_synchronize_state(env); - env->regs[2] = s390_virtio_hypercall(env, env->regs[2], env->regs[1]); + env->regs[2] = s390_virtio_hypercall(env); return 0; } diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 78d2c0e762..09301d0a6f 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -188,7 +188,7 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, switch (num) { case 0x500: /* KVM hypercall */ - r = s390_virtio_hypercall(env, mem, code); + r = s390_virtio_hypercall(env); break; case 0x44: /* yield */ From d193a14a2c94c9c4877ab100c31ec174dc78644c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Jan 2013 15:42:51 -0800 Subject: [PATCH 0578/1634] optimize: only write to state when clearing optimizer data The next patch will add to the TCG optimizer a field that should be non-zero in the default case. Thus, replace the memset of the temps array with a loop. Only the state field has to be up-to-date, because others are not used except if the state is TCG_TEMP_COPY or TCG_TEMP_CONST. [rth: Extracted the loop to a function.] Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/optimize.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 9109b813e0..9d05a72a1f 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -65,6 +65,15 @@ static void reset_temp(TCGArg temp) temps[temp].state = TCG_TEMP_UNDEF; } +/* Reset all temporaries, given that there are NB_TEMPS of them. */ +static void reset_all_temps(int nb_temps) +{ + int i; + for (i = 0; i < nb_temps; i++) { + temps[i].state = TCG_TEMP_UNDEF; + } +} + static int op_bits(TCGOpcode op) { const TCGOpDef *def = &tcg_op_defs[op]; @@ -482,7 +491,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, nb_temps = s->nb_temps; nb_globals = s->nb_globals; - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + reset_all_temps(nb_temps); nb_ops = tcg_opc_ptr - s->gen_opc_buf; gen_args = args; @@ -768,7 +777,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, tmp = do_constant_folding_cond(op, args[0], args[1], args[2]); if (tmp != 2) { if (tmp) { - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + reset_all_temps(nb_temps); s->gen_opc_buf[op_index] = INDEX_op_br; gen_args[0] = args[3]; gen_args += 1; @@ -861,7 +870,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]); if (tmp != 2) { if (tmp) { - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + reset_all_temps(nb_temps); s->gen_opc_buf[op_index] = INDEX_op_br; gen_args[0] = args[5]; gen_args += 1; @@ -875,7 +884,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, && temps[args[3]].val == 0) { /* Simplify LT/GE comparisons vs zero to a single compare vs the high word of the input. */ - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + reset_all_temps(nb_temps); s->gen_opc_buf[op_index] = INDEX_op_brcond_i32; gen_args[0] = args[1]; gen_args[1] = args[3]; @@ -940,7 +949,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, We trash everything if the operation is the end of a basic block, otherwise we only trash the output args. */ if (def->flags & TCG_OPF_BB_END) { - memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + reset_all_temps(nb_temps); } else { for (i = 0; i < def->nb_oargs; i++) { reset_temp(args[i]); From 3a9d8b179b1e43237365ede641d5aa6779ba91bc Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Jan 2013 15:42:52 -0800 Subject: [PATCH 0579/1634] optimize: track nonzero bits of registers Add a "mask" field to the tcg_temp_info struct. A bit that is zero in "mask" will always be zero in the corresponding temporary. Zero bits in the mask can be produced from moves of immediates, zero-extensions, ANDs with constants, shifts; they can then be be propagated by logical operations, shifts, sign-extensions, negations, deposit operations, and conditional moves. Other operations will just reset the mask to all-ones, i.e. unknown. [rth: s/target_ulong/tcg_target_ulong/] Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/optimize.c | 130 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 21 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 9d05a72a1f..090efbc193 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -46,6 +46,7 @@ struct tcg_temp_info { uint16_t prev_copy; uint16_t next_copy; tcg_target_ulong val; + tcg_target_ulong mask; }; static struct tcg_temp_info temps[TCG_MAX_TEMPS]; @@ -63,6 +64,7 @@ static void reset_temp(TCGArg temp) } } temps[temp].state = TCG_TEMP_UNDEF; + temps[temp].mask = -1; } /* Reset all temporaries, given that there are NB_TEMPS of them. */ @@ -71,6 +73,7 @@ static void reset_all_temps(int nb_temps) int i; for (i = 0; i < nb_temps; i++) { temps[i].state = TCG_TEMP_UNDEF; + temps[i].mask = -1; } } @@ -148,33 +151,35 @@ static bool temps_are_copies(TCGArg arg1, TCGArg arg2) static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, TCGArg dst, TCGArg src) { - reset_temp(dst); - assert(temps[src].state != TCG_TEMP_CONST); + reset_temp(dst); + temps[dst].mask = temps[src].mask; + assert(temps[src].state != TCG_TEMP_CONST); - if (s->temps[src].type == s->temps[dst].type) { - if (temps[src].state != TCG_TEMP_COPY) { - temps[src].state = TCG_TEMP_COPY; - temps[src].next_copy = src; - temps[src].prev_copy = src; - } - temps[dst].state = TCG_TEMP_COPY; - temps[dst].next_copy = temps[src].next_copy; - temps[dst].prev_copy = src; - temps[temps[dst].next_copy].prev_copy = dst; - temps[src].next_copy = dst; + if (s->temps[src].type == s->temps[dst].type) { + if (temps[src].state != TCG_TEMP_COPY) { + temps[src].state = TCG_TEMP_COPY; + temps[src].next_copy = src; + temps[src].prev_copy = src; } + temps[dst].state = TCG_TEMP_COPY; + temps[dst].next_copy = temps[src].next_copy; + temps[dst].prev_copy = src; + temps[temps[dst].next_copy].prev_copy = dst; + temps[src].next_copy = dst; + } - gen_args[0] = dst; - gen_args[1] = src; + gen_args[0] = dst; + gen_args[1] = src; } static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val) { - reset_temp(dst); - temps[dst].state = TCG_TEMP_CONST; - temps[dst].val = val; - gen_args[0] = dst; - gen_args[1] = val; + reset_temp(dst); + temps[dst].state = TCG_TEMP_CONST; + temps[dst].val = val; + temps[dst].mask = val; + gen_args[0] = dst; + gen_args[1] = val; } static TCGOpcode op_to_mov(TCGOpcode op) @@ -479,6 +484,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args, TCGOpDef *tcg_op_defs) { int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args; + tcg_target_ulong mask; TCGOpcode op; const TCGOpDef *def; TCGArg *gen_args; @@ -621,6 +627,87 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, break; } + /* Simplify using known-zero bits */ + mask = -1; + switch (op) { + CASE_OP_32_64(ext8s): + if ((temps[args[1]].mask & 0x80) != 0) { + break; + } + CASE_OP_32_64(ext8u): + mask = 0xff; + goto and_const; + CASE_OP_32_64(ext16s): + if ((temps[args[1]].mask & 0x8000) != 0) { + break; + } + CASE_OP_32_64(ext16u): + mask = 0xffff; + goto and_const; + case INDEX_op_ext32s_i64: + if ((temps[args[1]].mask & 0x80000000) != 0) { + break; + } + case INDEX_op_ext32u_i64: + mask = 0xffffffffU; + goto and_const; + + CASE_OP_32_64(and): + mask = temps[args[2]].mask; + if (temps[args[2]].state == TCG_TEMP_CONST) { + and_const: + ; + } + mask = temps[args[1]].mask & mask; + break; + + CASE_OP_32_64(sar): + if (temps[args[2]].state == TCG_TEMP_CONST) { + mask = ((tcg_target_long)temps[args[1]].mask + >> temps[args[2]].val); + } + break; + + CASE_OP_32_64(shr): + if (temps[args[2]].state == TCG_TEMP_CONST) { + mask = temps[args[1]].mask >> temps[args[2]].val; + } + break; + + CASE_OP_32_64(shl): + if (temps[args[2]].state == TCG_TEMP_CONST) { + mask = temps[args[1]].mask << temps[args[2]].val; + } + break; + + CASE_OP_32_64(neg): + /* Set to 1 all bits to the left of the rightmost. */ + mask = -(temps[args[1]].mask & -temps[args[1]].mask); + break; + + CASE_OP_32_64(deposit): + tmp = ((1ull << args[4]) - 1); + mask = ((temps[args[1]].mask & ~(tmp << args[3])) + | ((temps[args[2]].mask & tmp) << args[3])); + break; + + CASE_OP_32_64(or): + CASE_OP_32_64(xor): + mask = temps[args[1]].mask | temps[args[2]].mask; + break; + + CASE_OP_32_64(setcond): + mask = 1; + break; + + CASE_OP_32_64(movcond): + mask = temps[args[3]].mask | temps[args[4]].mask; + break; + + default: + break; + } + /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ switch (op) { CASE_OP_32_64(and): @@ -947,7 +1034,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, /* Default case: we know nothing about operation (or were unable to compute the operation result) so no propagation is done. We trash everything if the operation is the end of a basic - block, otherwise we only trash the output args. */ + block, otherwise we only trash the output args. "mask" is + the non-zero bits mask for the first output arg. */ if (def->flags & TCG_OPF_BB_END) { reset_all_temps(nb_temps); } else { From 633f6502544e3dd6a615679ce440875be7ebbc58 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Jan 2013 15:42:53 -0800 Subject: [PATCH 0580/1634] optimize: optimize using nonzero bits This adds two optimizations using the non-zero bit mask. In some cases involving shifts or ANDs the value can become zero, and can thus be optimized to a move of zero. Second, useless zero-extension or an AND with constant can be detected that would only zero bits that are already zero. The main advantage of this optimization is that it turns zero-extensions into moves, thus enabling much better copy propagation (around 1% code reduction). Here is for example a "test $0xff0000,%ecx + je" before optimization: mov_i64 tmp0,rcx movi_i64 tmp1,$0xff0000 discard cc_src and_i64 cc_dst,tmp0,tmp1 movi_i32 cc_op,$0x1c ext32u_i64 tmp0,cc_dst movi_i64 tmp12,$0x0 brcond_i64 tmp0,tmp12,eq,$0x0 and after (without patch on the left, with on the right): movi_i64 tmp1,$0xff0000 movi_i64 tmp1,$0xff0000 discard cc_src discard cc_src and_i64 cc_dst,rcx,tmp1 and_i64 cc_dst,rcx,tmp1 movi_i32 cc_op,$0x1c movi_i32 cc_op,$0x1c ext32u_i64 tmp0,cc_dst movi_i64 tmp12,$0x0 movi_i64 tmp12,$0x0 brcond_i64 tmp0,tmp12,eq,$0x0 brcond_i64 cc_dst,tmp12,eq,$0x0 Other similar cases: "test %eax, %eax + jne" where eax is already 32-bit (after optimization, without patch on the left, with on the right): discard cc_src discard cc_src mov_i64 cc_dst,rax mov_i64 cc_dst,rax movi_i32 cc_op,$0x1c movi_i32 cc_op,$0x1c ext32u_i64 tmp0,cc_dst movi_i64 tmp12,$0x0 movi_i64 tmp12,$0x0 brcond_i64 tmp0,tmp12,ne,$0x0 brcond_i64 rax,tmp12,ne,$0x0 "test $0x1, %dl + je": movi_i64 tmp1,$0x1 movi_i64 tmp1,$0x1 discard cc_src discard cc_src and_i64 cc_dst,rdx,tmp1 and_i64 cc_dst,rdx,tmp1 movi_i32 cc_op,$0x1a movi_i32 cc_op,$0x1a ext8u_i64 tmp0,cc_dst movi_i64 tmp12,$0x0 movi_i64 tmp12,$0x0 brcond_i64 tmp0,tmp12,eq,$0x0 brcond_i64 cc_dst,tmp12,eq,$0x0 In some cases TCG even outsmarts GCC. :) Here the input code has "and $0x2,%eax + movslq %eax,%rbx + test %rbx, %rbx" and the optimizer, thanks to copy propagation, does the following: movi_i64 tmp12,$0x2 movi_i64 tmp12,$0x2 and_i64 rax,rax,tmp12 and_i64 rax,rax,tmp12 mov_i64 cc_dst,rax mov_i64 cc_dst,rax ext32s_i64 tmp0,rax -> nop mov_i64 rbx,tmp0 -> mov_i64 rbx,cc_dst and_i64 cc_dst,rbx,rbx -> nop Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/optimize.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 090efbc193..973d2d679f 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -484,7 +484,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, TCGArg *args, TCGOpDef *tcg_op_defs) { int i, nb_ops, op_index, nb_temps, nb_globals, nb_call_args; - tcg_target_ulong mask; + tcg_target_ulong mask, affected; TCGOpcode op; const TCGOpDef *def; TCGArg *gen_args; @@ -629,6 +629,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, /* Simplify using known-zero bits */ mask = -1; + affected = -1; switch (op) { CASE_OP_32_64(ext8s): if ((temps[args[1]].mask & 0x80) != 0) { @@ -656,7 +657,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, mask = temps[args[2]].mask; if (temps[args[2]].state == TCG_TEMP_CONST) { and_const: - ; + affected = temps[args[1]].mask & ~mask; } mask = temps[args[1]].mask & mask; break; @@ -708,6 +709,31 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, break; } + if (mask == 0) { + assert(def->nb_oargs == 1); + s->gen_opc_buf[op_index] = op_to_movi(op); + tcg_opt_gen_movi(gen_args, args[0], 0); + args += def->nb_oargs + def->nb_iargs + def->nb_cargs; + gen_args += 2; + continue; + } + if (affected == 0) { + assert(def->nb_oargs == 1); + if (temps_are_copies(args[0], args[1])) { + s->gen_opc_buf[op_index] = INDEX_op_nop; + } else if (temps[args[1]].state != TCG_TEMP_CONST) { + s->gen_opc_buf[op_index] = op_to_mov(op); + tcg_opt_gen_mov(s, gen_args, args[0], args[1]); + gen_args += 2; + } else { + s->gen_opc_buf[op_index] = op_to_movi(op); + tcg_opt_gen_movi(gen_args, args[0], temps[args[1]].val); + gen_args += 2; + } + args += def->nb_iargs + 1; + continue; + } + /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ switch (op) { CASE_OP_32_64(and): From f6e3534327e94c1c222cbbe8011d47b73c102686 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:22 +0100 Subject: [PATCH 0581/1634] fw_cfg: Replace debug prints by tracepoints Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/fw_cfg.c | 25 ++++++------------------- trace-events | 7 +++++++ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 7c9480c4d7..2fadf36f62 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -26,19 +26,10 @@ #include "isa.h" #include "fw_cfg.h" #include "sysbus.h" +#include "trace.h" #include "qemu/error-report.h" #include "qemu/config-file.h" -/* debug firmware config */ -//#define DEBUG_FW_CFG - -#ifdef DEBUG_FW_CFG -#define FW_CFG_DPRINTF(fmt, ...) \ - do { printf("FW_CFG: " fmt , ## __VA_ARGS__); } while (0) -#else -#define FW_CFG_DPRINTF(fmt, ...) -#endif - #define FW_CFG_SIZE 2 #define FW_CFG_DATA_SIZE 1 @@ -213,7 +204,7 @@ static void fw_cfg_write(FWCfgState *s, uint8_t value) int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL); FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK]; - FW_CFG_DPRINTF("write %d\n", value); + trace_fw_cfg_write(s, value); if (s->cur_entry & FW_CFG_WRITE_CHANNEL && e->callback && s->cur_offset < e->len) { @@ -238,8 +229,7 @@ static int fw_cfg_select(FWCfgState *s, uint16_t key) ret = 1; } - FW_CFG_DPRINTF("select key %d (%sfound)\n", key, ret ? "" : "not "); - + trace_fw_cfg_select(s, key, ret); return ret; } @@ -254,8 +244,7 @@ static uint8_t fw_cfg_read(FWCfgState *s) else ret = e->data[s->cur_offset++]; - FW_CFG_DPRINTF("read %d\n", ret); - + trace_fw_cfg_read(s, ret); return ret; } @@ -470,16 +459,14 @@ int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, filename); for (i = 0; i < index; i++) { if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) { - FW_CFG_DPRINTF("%s: skip duplicate: %s\n", __FUNCTION__, - s->files->f[index].name); + trace_fw_cfg_add_file_dupe(s, s->files->f[index].name); return 1; } } s->files->f[index].size = cpu_to_be32(len); s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index); - FW_CFG_DPRINTF("%s: #%d: %s (%d bytes)\n", __FUNCTION__, - index, s->files->f[index].name, len); + trace_fw_cfg_add_file(s, index, s->files->f[index].name, len); s->files->count = cpu_to_be32(index+1); return 1; diff --git a/trace-events b/trace-events index 6eabbac0cc..cf76a11147 100644 --- a/trace-events +++ b/trace-events @@ -167,6 +167,13 @@ ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x" ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x" ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x" +# hw/fw_cfg.c +fw_cfg_write(void *s, uint8_t value) "%p %d" +fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d" +fw_cfg_read(void *s, uint8_t ret) "%p = %d" +fw_cfg_add_file_dupe(void *s, char *name) "%p %s" +fw_cfg_add_file(void *s, int index, char *name, uint32_t len) "%p #%d: %s (%d bytes)" + # hw/hd-geometry.c hd_geometry_lchs_guess(void *bs, int cyls, int heads, int secs) "bs %p LCHS %d %d %d" hd_geometry_guess(void *bs, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "bs %p CHS %u %u %u trans %d" From 4cad3867b6df2c0826ae508a9fe15dd0b9d8936a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:23 +0100 Subject: [PATCH 0582/1634] fw_cfg: Dumb down fw_cfg_add_*() not to return success / failure No caller is checking the value, so all errors get ignored, usually silently. assert() instead. Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/fw_cfg.c | 43 ++++++++++++++++--------------------------- hw/fw_cfg.h | 16 ++++++++-------- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 2fadf36f62..0361f684b4 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -373,71 +373,64 @@ static const VMStateDescription vmstate_fw_cfg = { } }; -int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len) +void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len) { int arch = !!(key & FW_CFG_ARCH_LOCAL); key &= FW_CFG_ENTRY_MASK; - if (key >= FW_CFG_MAX_ENTRY) - return 0; + assert(key < FW_CFG_MAX_ENTRY); s->entries[arch][key].data = data; s->entries[arch][key].len = len; - - return 1; } -int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value) +void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value) { uint16_t *copy; copy = g_malloc(sizeof(value)); *copy = cpu_to_le16(value); - return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); + fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); } -int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value) +void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value) { uint32_t *copy; copy = g_malloc(sizeof(value)); *copy = cpu_to_le32(value); - return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); + fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); } -int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) +void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) { uint64_t *copy; copy = g_malloc(sizeof(value)); *copy = cpu_to_le64(value); - return fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); + fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); } -int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, - void *callback_opaque, uint8_t *data, size_t len) +void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, + void *callback_opaque, uint8_t *data, size_t len) { int arch = !!(key & FW_CFG_ARCH_LOCAL); - if (!(key & FW_CFG_WRITE_CHANNEL)) - return 0; + assert(key & FW_CFG_WRITE_CHANNEL); key &= FW_CFG_ENTRY_MASK; - if (key >= FW_CFG_MAX_ENTRY || len > 65535) - return 0; + assert(key < FW_CFG_MAX_ENTRY && len <= 65535); s->entries[arch][key].data = data; s->entries[arch][key].len = len; s->entries[arch][key].callback_opaque = callback_opaque; s->entries[arch][key].callback = callback; - - return 1; } -int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, - uint32_t len) +void fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, + uint32_t len) { int i, index; @@ -448,10 +441,7 @@ int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, } index = be32_to_cpu(s->files->count); - if (index == FW_CFG_FILE_SLOTS) { - fprintf(stderr, "fw_cfg: out of file slots\n"); - return 0; - } + assert(index < FW_CFG_FILE_SLOTS); fw_cfg_add_bytes(s, FW_CFG_FILE_FIRST + index, data, len); @@ -460,7 +450,7 @@ int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, for (i = 0; i < index; i++) { if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) { trace_fw_cfg_add_file_dupe(s, s->files->f[index].name); - return 1; + return; } } @@ -469,7 +459,6 @@ int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, trace_fw_cfg_add_file(s, index, s->files->f[index].name, len); s->files->count = cpu_to_be32(index+1); - return 1; } static void fw_cfg_machine_ready(struct Notifier *n, void *data) diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h index 619a39432a..7d32f285c6 100644 --- a/hw/fw_cfg.h +++ b/hw/fw_cfg.h @@ -54,14 +54,14 @@ typedef struct FWCfgFiles { typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); typedef struct FWCfgState FWCfgState; -int fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len); -int fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value); -int fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value); -int fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value); -int fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, - void *callback_opaque, uint8_t *data, size_t len); -int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, - uint32_t len); +void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len); +void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value); +void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value); +void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value); +void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, + void *callback_opaque, uint8_t *data, size_t len); +void fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, + uint32_t len); FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, hwaddr crl_addr, hwaddr data_addr); From 44687f75434ea938e9d29fdc3696ff4bdc0978fa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:24 +0100 Subject: [PATCH 0583/1634] fw_cfg: New fw_cfg_add_string() Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/fw_cfg.c | 7 +++++++ hw/fw_cfg.h | 1 + 2 files changed, 8 insertions(+) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 0361f684b4..3d6dd5fb3a 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -385,6 +385,13 @@ void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len) s->entries[arch][key].len = len; } +void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) +{ + size_t sz = strlen(value) + 1; + + return fw_cfg_add_bytes(s, key, (uint8_t *)g_memdup(value, sz), sz); +} + void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value) { uint16_t *copy; diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h index 7d32f285c6..c2c57cd2aa 100644 --- a/hw/fw_cfg.h +++ b/hw/fw_cfg.h @@ -55,6 +55,7 @@ typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); typedef struct FWCfgState FWCfgState; void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len); +void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value); void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value); void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value); void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value); From 96f8058629d99ab689ff233c6133d6cf7f034679 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:25 +0100 Subject: [PATCH 0584/1634] pc: Fix unchecked strdup() by switching to fw_cfg_add_string() Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/pc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index ba1f19d7e8..bc5c33fa3e 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -693,9 +693,7 @@ static void load_linux(void *fw_cfg, fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1); - fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, - (uint8_t*)strdup(kernel_cmdline), - strlen(kernel_cmdline)+1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); if (protocol >= 0x202) { stl_p(header+0x228, cmdline_addr); From 0e0d2d6295076815ded8d0868b7b806380df5dda Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:26 +0100 Subject: [PATCH 0585/1634] sun4: Fix unchecked strdup() by switching to fw_cfg_add_string() Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/sun4m.c | 12 +++--------- hw/sun4u.c | 4 +--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/hw/sun4m.c b/hw/sun4m.c index 95c505821b..41730bc7a8 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -1030,9 +1030,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, if (kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); - fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, - (uint8_t*)strdup(kernel_cmdline), - strlen(kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); } else { @@ -1676,9 +1674,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, if (kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); - fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, - (uint8_t*)strdup(kernel_cmdline), - strlen(kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); } @@ -1878,9 +1874,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, if (kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR); pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline); - fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, - (uint8_t*)strdup(kernel_cmdline), - strlen(kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0); } diff --git a/hw/sun4u.c b/hw/sun4u.c index cb75d03278..d36acde545 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -886,9 +886,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, if (kernel_cmdline) { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); - fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, - (uint8_t*)strdup(kernel_cmdline), - strlen(kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); } else { fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0); } From b3dd15529de22cd4bcedb6344105e87878d971b6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:27 +0100 Subject: [PATCH 0586/1634] pc: Clean up bochs_bios_init()'s (non-)use of sizeof Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/pc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index bc5c33fa3e..34cf79d459 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -572,7 +572,7 @@ static void *bochs_bios_init(void) fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, smbios_table, smbios_len); fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table, - sizeof(struct e820_table)); + sizeof(e820_table)); fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, (uint8_t *)&hpet_cfg, sizeof(struct hpet_fw_config)); @@ -580,7 +580,7 @@ static void *bochs_bios_init(void) * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. */ - numa_fw_cfg = g_malloc0((1 + max_cpus + nb_numa_nodes) * 8); + numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes); numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); for (i = 0; i < max_cpus; i++) { for (j = 0; j < nb_numa_nodes; j++) { @@ -594,7 +594,7 @@ static void *bochs_bios_init(void) numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]); } fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, (uint8_t *)numa_fw_cfg, - (1 + max_cpus + nb_numa_nodes) * 8); + (1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg)); return fw_cfg; } From 089da572b956ef0f8f5b8d5917358e07892a77c2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:28 +0100 Subject: [PATCH 0587/1634] fw_cfg: Use void *, size_t instead of uint8_t *, uint32_t for blobs Many callers pass size_t, which gets silently truncated to uint32_t. Harmless, because all practical sizes are well below 4GiB. Clean it up anyway. Size overflow now fails assertions. Bonus: saves a whole bunch of silly casts. Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/fw_cfg.c | 31 ++++++++++++++++--------------- hw/fw_cfg.h | 8 ++++---- hw/pc.c | 13 ++++++------- trace-events | 2 +- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 3d6dd5fb3a..699383c87a 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -373,23 +373,23 @@ static const VMStateDescription vmstate_fw_cfg = { } }; -void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len) +void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len) { int arch = !!(key & FW_CFG_ARCH_LOCAL); key &= FW_CFG_ENTRY_MASK; - assert(key < FW_CFG_MAX_ENTRY); + assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX); s->entries[arch][key].data = data; - s->entries[arch][key].len = len; + s->entries[arch][key].len = (uint32_t)len; } void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value) { size_t sz = strlen(value) + 1; - return fw_cfg_add_bytes(s, key, (uint8_t *)g_memdup(value, sz), sz); + return fw_cfg_add_bytes(s, key, g_memdup(value, sz), sz); } void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value) @@ -398,7 +398,7 @@ void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value) copy = g_malloc(sizeof(value)); *copy = cpu_to_le16(value); - fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); + fw_cfg_add_bytes(s, key, copy, sizeof(value)); } void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value) @@ -407,7 +407,7 @@ void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value) copy = g_malloc(sizeof(value)); *copy = cpu_to_le32(value); - fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); + fw_cfg_add_bytes(s, key, copy, sizeof(value)); } void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) @@ -416,11 +416,11 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value) copy = g_malloc(sizeof(value)); *copy = cpu_to_le64(value); - fw_cfg_add_bytes(s, key, (uint8_t *)copy, sizeof(value)); + fw_cfg_add_bytes(s, key, copy, sizeof(value)); } void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, - void *callback_opaque, uint8_t *data, size_t len) + void *callback_opaque, void *data, size_t len) { int arch = !!(key & FW_CFG_ARCH_LOCAL); @@ -428,23 +428,24 @@ void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, key &= FW_CFG_ENTRY_MASK; - assert(key < FW_CFG_MAX_ENTRY && len <= 65535); + assert(key < FW_CFG_MAX_ENTRY && len <= UINT32_MAX); s->entries[arch][key].data = data; - s->entries[arch][key].len = len; + s->entries[arch][key].len = (uint32_t)len; s->entries[arch][key].callback_opaque = callback_opaque; s->entries[arch][key].callback = callback; } -void fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, - uint32_t len) +void fw_cfg_add_file(FWCfgState *s, const char *filename, + void *data, size_t len) { int i, index; + size_t dsize; if (!s->files) { - int dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS; + dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS; s->files = g_malloc0(dsize); - fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, (uint8_t*)s->files, dsize); + fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize); } index = be32_to_cpu(s->files->count); @@ -498,7 +499,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, if (data_addr) { sysbus_mmio_map(d, 1, data_addr); } - fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (uint8_t *)"QEMU", 4); + fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC)); fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h index c2c57cd2aa..05c8df186f 100644 --- a/hw/fw_cfg.h +++ b/hw/fw_cfg.h @@ -54,15 +54,15 @@ typedef struct FWCfgFiles { typedef void (*FWCfgCallback)(void *opaque, uint8_t *data); typedef struct FWCfgState FWCfgState; -void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, uint8_t *data, uint32_t len); +void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len); void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value); void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value); void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value); void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value); void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback, - void *callback_opaque, uint8_t *data, size_t len); -void fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data, - uint32_t len); + void *callback_opaque, void *data, size_t len); +void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data, + size_t len); FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, hwaddr crl_addr, hwaddr data_addr); diff --git a/hw/pc.c b/hw/pc.c index 34cf79d459..8fc69dbe0a 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -563,19 +563,18 @@ static void *bochs_bios_init(void) fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables, - acpi_tables_len); + fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, + acpi_tables, acpi_tables_len); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); smbios_table = smbios_get_table(&smbios_len); if (smbios_table) fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, smbios_table, smbios_len); - fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table, - sizeof(e820_table)); + fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, + &e820_table, sizeof(e820_table)); - fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, (uint8_t *)&hpet_cfg, - sizeof(struct hpet_fw_config)); + fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg)); /* allocate memory for the NUMA channel: one (64bit) word for the number * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. @@ -593,7 +592,7 @@ static void *bochs_bios_init(void) for (i = 0; i < nb_numa_nodes; i++) { numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]); } - fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, (uint8_t *)numa_fw_cfg, + fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, (1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg)); return fw_cfg; diff --git a/trace-events b/trace-events index cf76a11147..7de9106664 100644 --- a/trace-events +++ b/trace-events @@ -172,7 +172,7 @@ fw_cfg_write(void *s, uint8_t value) "%p %d" fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d" fw_cfg_read(void *s, uint8_t ret) "%p = %d" fw_cfg_add_file_dupe(void *s, char *name) "%p %s" -fw_cfg_add_file(void *s, int index, char *name, uint32_t len) "%p #%d: %s (%d bytes)" +fw_cfg_add_file(void *s, int index, char *name, size_t len) "%p #%d: %s (%zd bytes)" # hw/hd-geometry.c hd_geometry_lchs_guess(void *bs, int cyls, int heads, int secs) "bs %p LCHS %d %d %d" From 0e7a75929353b04bd2fce1be8640226883b42a10 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 14:50:29 +0100 Subject: [PATCH 0588/1634] vl: Use size_t for sizes in get_boot_devices_list() Code mixes uint32_t, int and size_t. Very unlikely to go wrong in practice, but clean it up anyway. Signed-off-by: Markus Armbruster Signed-off-by: Blue Swirl --- hw/fw_cfg.c | 2 +- include/sysemu/sysemu.h | 2 +- vl.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 699383c87a..3b31d77f3f 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -471,7 +471,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, static void fw_cfg_machine_ready(struct Notifier *n, void *data) { - uint32_t len; + size_t len; FWCfgState *s = container_of(n, FWCfgState, machine_ready); char *bootindex = get_boot_devices_list(&len); diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index cd12f0931b..6599617def 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -179,7 +179,7 @@ void register_devices(void); void add_boot_device_path(int32_t bootindex, DeviceState *dev, const char *suffix); -char *get_boot_devices_list(uint32_t *size); +char *get_boot_devices_list(size_t *size); bool usb_enabled(bool default_usb); diff --git a/vl.c b/vl.c index f4cf7e8a85..4ee1302595 100644 --- a/vl.c +++ b/vl.c @@ -1198,15 +1198,15 @@ void add_boot_device_path(int32_t bootindex, DeviceState *dev, * memory pointed by "size" is assigned total length of the array in bytes * */ -char *get_boot_devices_list(uint32_t *size) +char *get_boot_devices_list(size_t *size) { FWBootEntry *i; - uint32_t total = 0; + size_t total = 0; char *list = NULL; QTAILQ_FOREACH(i, &fw_boot_order, link) { char *devpath = NULL, *bootpath; - int len; + size_t len; if (i->dev) { devpath = qdev_get_fw_dev_path(i->dev); From e4ada482420175bc17d6ccb9f2af0e769da78e01 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 16 Jan 2013 18:37:23 +0100 Subject: [PATCH 0589/1634] Replace non-portable asprintf by g_strdup_printf g_strdup_printf already handles OOM errors, so some error handling in QEMU code can be removed. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- exec.c | 8 +++----- qga/commands-posix.c | 13 +++++-------- util/path.c | 5 +---- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/exec.c b/exec.c index 5689613d0a..b85508ba30 100644 --- a/exec.c +++ b/exec.c @@ -863,18 +863,16 @@ static void *file_ram_alloc(RAMBlock *block, return NULL; } - if (asprintf(&filename, "%s/qemu_back_mem.XXXXXX", path) == -1) { - return NULL; - } + filename = g_strdup_printf("%s/qemu_back_mem.XXXXXX", path); fd = mkstemp(filename); if (fd < 0) { perror("unable to create backing store for hugepages"); - free(filename); + g_free(filename); return NULL; } unlink(filename); - free(filename); + g_free(filename); memory = (memory+hpagesize-1) & ~(hpagesize-1); diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 77f6ee7d5f..0ad73f3430 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -939,14 +939,11 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; - if (asprintf(&info->value->hardware_address, - "%02x:%02x:%02x:%02x:%02x:%02x", - (int) mac_addr[0], (int) mac_addr[1], - (int) mac_addr[2], (int) mac_addr[3], - (int) mac_addr[4], (int) mac_addr[5]) == -1) { - error_setg_errno(errp, errno, "failed to format MAC"); - goto error; - } + info->value->hardware_address = + g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x", + (int) mac_addr[0], (int) mac_addr[1], + (int) mac_addr[2], (int) mac_addr[3], + (int) mac_addr[4], (int) mac_addr[5]); info->value->has_hardware_address = true; close(sock); diff --git a/util/path.c b/util/path.c index 4c5b0f6296..f0c69627c7 100644 --- a/util/path.c +++ b/util/path.c @@ -47,10 +47,7 @@ static struct pathelem *new_entry(const char *root, { struct pathelem *new = malloc(sizeof(*new)); new->name = strdup(name); - if (asprintf(&new->pathname, "%s/%s", root, name) == -1) { - printf("Cannot allocate memory\n"); - exit(1); - } + new->pathname = g_strdup_printf("%s/%s", root, name); new->num_entries = 0; return new; } From 5256a7208a7c2af19baf8f99bd4f06632f9f9ba9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 17 Jan 2013 20:04:16 +0000 Subject: [PATCH 0590/1634] tcg/target-arm: Add missing parens to assertions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Silence a (legitimate) complaint about missing parentheses: tcg/arm/tcg-target.c: In function ‘tcg_out_qemu_ld’: tcg/arm/tcg-target.c:1148:5: error: suggest parentheses around comparison in operand of ‘&’ [-Werror=parentheses] tcg/arm/tcg-target.c: In function ‘tcg_out_qemu_st’: tcg/arm/tcg-target.c:1357:5: error: suggest parentheses around comparison in operand of ‘&’ [-Werror=parentheses] which meant that we would mistakenly always assert if running a QEMU built with debug enabled on ARM. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- tcg/arm/tcg-target.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index c3ac85e054..d9c33d850f 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1145,7 +1145,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); /* We assume that the offset is contained within 20 bits. */ tlb_offset = offsetof(CPUArchState, tlb_table[mem_index][0].addr_read); - assert(tlb_offset & ~0xfffff == 0); + assert((tlb_offset & ~0xfffff) == 0); if (tlb_offset > 0xfff) { tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0, 0xa00 | (tlb_offset >> 12)); @@ -1354,7 +1354,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) TCG_AREG0, TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); /* We assume that the offset is contained within 20 bits. */ tlb_offset = offsetof(CPUArchState, tlb_table[mem_index][0].addr_write); - assert(tlb_offset & ~0xfffff == 0); + assert((tlb_offset & ~0xfffff) == 0); if (tlb_offset > 0xfff) { tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0, 0xa00 | (tlb_offset >> 12)); From 249fe3f3e99c2a57c7f2569edb4031e63e595c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 19:30:13 +0100 Subject: [PATCH 0591/1634] cpu-defs.h: Drop qemu_work_item prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit c64ca8140e9c21cd0d44c10fbe1247cb4ade8e6e (cpu: Move queued_work_{first,last} to CPUState) moved the qemu_work_item fields away. Clean up the now unused prototype. Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- include/exec/cpu-defs.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index d0cf85a83c..2911b9fc90 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -134,8 +134,6 @@ typedef struct icount_decr_u16 { } icount_decr_u16; #endif -struct qemu_work_item; - typedef struct CPUBreakpoint { target_ulong pc; int flags; /* BP_* */ From c1db29199e3caf5cd56daad08b8926ffa97da136 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 18 Jan 2013 23:48:10 +0100 Subject: [PATCH 0592/1634] usb: Fix compilation for MinGW (regression) 84f2d0ea added an argument to function usb_host_info. The stub function must match the declaration in usb.h. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- hw/usb/host-stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c index 58423a0f5c..8affba76c1 100644 --- a/hw/usb/host-stub.c +++ b/hw/usb/host-stub.c @@ -35,7 +35,7 @@ #include "hw/usb.h" #include "monitor/monitor.h" -void usb_host_info(Monitor *mon) +void usb_host_info(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "USB host devices not supported\n"); } From c36dd8a09fd8811ebcda453d80dc5f52402d691c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 16:43:35 +0100 Subject: [PATCH 0593/1634] block/raw-posix: Make hdev_aio_discard() available outside Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the build on OpenBSD among others. Suggested-by: Kevin Wolf Signed-off-by: Andreas Färber Cc: Paolo Bonzini Signed-off-by: Blue Swirl --- block/raw-posix.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 679fcc5113..657af95637 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1371,19 +1371,6 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs, return thread_pool_submit_aio(aio_worker, acb, cb, opaque); } -static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) -{ - BDRVRawState *s = bs->opaque; - - if (fd_open(bs) < 0) { - return NULL; - } - return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors, - cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); -} - #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) static int fd_open(BlockDriverState *bs) { @@ -1403,6 +1390,19 @@ static int fd_open(BlockDriverState *bs) #endif /* !linux && !FreeBSD */ +static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BDRVRawState *s = bs->opaque; + + if (fd_open(bs) < 0) { + return NULL; + } + return paio_submit(bs, s->fd, sector_num, NULL, nb_sectors, + cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV); +} + static int hdev_create(const char *filename, QEMUOptionParameter *options) { int fd; From b54c2873e731dd6fc81a4591cab909633b5a9eab Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 19 Jan 2013 20:23:51 +0100 Subject: [PATCH 0594/1634] tci: Fix broken build (regression) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s390x-linux-user now also uses GETPC. Instead of adding it to the list of targets which use GETPC, the macro is now defined unconditionally. This avoids future build regressions like this one: CC s390x-linux-user/target-s390x/int_helper.o cc1: warnings being treated as errors qemu/target-s390x/int_helper.c: In function ‘helper_divs32’: qemu/target-s390x/int_helper.c:47: error: implicit declaration of function ‘GETPC’ qemu/target-s390x/int_helper.c:47: error: nested extern declaration of ‘GETPC’ Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- include/exec/exec-all.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 46dca74fda..d235ef8b2e 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -284,14 +284,8 @@ extern int tb_invalidated_flag; /* The return address may point to the start of the next instruction. Subtracting one gets us the call instruction itself. */ #if defined(CONFIG_TCG_INTERPRETER) -/* Softmmu, Alpha, MIPS, SH4 and SPARC user mode emulations call GETPC(). - For all others, GETPC remains undefined (which makes TCI a little faster. */ -# if defined(CONFIG_SOFTMMU) || \ - defined(TARGET_ALPHA) || defined(TARGET_MIPS) || \ - defined(TARGET_SH4) || defined(TARGET_SPARC) extern uintptr_t tci_tb_ptr; -# define GETPC() tci_tb_ptr -# endif +# define GETPC() tci_tb_ptr #elif defined(__s390__) && !defined(__s390x__) # define GETPC() \ (((uintptr_t)__builtin_return_address(0) & 0x7fffffffUL) - 1) From 3588185b8396eb97fd9efd41c2b97775465f67c4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 21 Jan 2013 09:17:16 +0100 Subject: [PATCH 0595/1634] seabios: update to 1.7.2 release Not that many changes as we have a pretty recent git snapshot in master already: Hannes Reinecke (1): megasas: Invert PCI device selection Kevin O'Connor (2): Minor: Separate UUID display from F12 boot prompt. boot: Support "halt" in the boot order to prevent default boot attempts. Laszlo Ersek (1): display_uuid(): fix incomplete check after the loop Paolo Bonzini (1): vgabios: implement AX=1120H..1124H functions --- pc-bios/acpi-dsdt.aml | Bin 4521 -> 4521 bytes pc-bios/bios.bin | Bin 131072 -> 262144 bytes pc-bios/q35-acpi-dsdt.aml | Bin 7458 -> 7458 bytes roms/seabios | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/acpi-dsdt.aml b/pc-bios/acpi-dsdt.aml index 00224eabb7b92de601edc5cc41b444c4ca8cb9da..75dfd1e310a330c6473e363a3d2d9f31d93bfaa7 100644 GIT binary patch delta 44 wcmZ3fyi!@&CDXfHMPwQv^r^$Y)?+@bnAu(O?zWsN5z90OrC8g8%>k delta 44 wcmZ3fyi!@&CDk diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 3910875311ceaed814f902e9e4e7e29cdf340fc6..924bee30d54a711a9d849ec4c67d38bef9ca03f4 100644 GIT binary patch delta 21116 zcmdtKiC>h}_XmEThhb3%W`qGjP(epU1p^gD1O-9GB|{P1*OZ>ravNOI1R5wFCrZ86 z*zze&vocGP1SC@s1lMw@K9regE)R|i?&LPV_jv{<{rtYaf8fXKb>_Lxx#ymH?z!il zd+zd(o$ZmGtuF~aDfII!i8v{A`~U6l4$rn8MG@i=F{^MHW7^jk%Ln}UI%9_cmjTEDMafgf5+I~9f0o{8?uwJX@Jdu*jsv$L?T@7Px4l%X@@FyVR zFk>dbb-=76UG9`wXCtv9SQnS;oQvlg=^rAt3rZ7y;G;wgJikzW@}#LxBDQ zV@5zUU<6%j|f1<(Mv4QK>BtY^=$UYAi25DS>}2!#PN0TN&?U_QVE zSPEG2sOUrYkz&@3WsLd3VAleUtzhie*P)q}j4c7QK$ivpMgn#LJhG9_0WZMYfZc$j zfJQ+3HyCq!6F9(|Fw_P>8yVUI90j0=C2WYXR{e zF!l*R{D`q}fSn&vtNw$b2e|PGTCjn!)quYNX&a#}z-7R$&lodrg4zM0o6-NDqar~6 zEsSLYD!)Mgf5}+nSB%8~UI1(bEZ@r52Y_P03BV12FGf%&KySd@Ec|>4sNKd`=C>F| z+cA0o7Xc3d`a;Hn0SSPY0lmLtYz<(`4ydsRt^Xc=q!<j5I z*^i9v036xF*gtzgTh5pjU7@^}2&_*GHq zDCA6>=*-&f$t(Oi1geD|KDOJ(=ark%3RW|)l~XkG*|H>V_v97;0Rb^2(7{)EGEgXh9?k1D1I7i(^G;ZBDvo8G*2btZp;R7YG!Uw* z6XjM)@7;>N>9AfDk9igi>2zEWuifUYLt}#0dwVf?l2KD&@IgV3f)U1Gxy~}i7^Fe`Ar4_!%lvYcep%YP`ZUgoccrHDb7d3jjx6qWW6(MEta=cqq4 zE-Ph?T1;d+9$wKEmz%4!eQQl^Q&XhBh^!g0bQ0v(UPHdkGgY!v=9TMwaCnHje?O$F zuJc#J16%Y%I)8-GL;2)7Ul$%1n@)KXu47hr%ZETz+FMtgWYnZc%PDIBvc^q#Qo|}_ z?09@l{zGn5epa|=_dGHAHec7hllyuiUU03bqIWA+oLSL*rxo_&Nd{87(g+V5`yeU8v)6rS44)J!6Q40q;w z@?*W8gZXeF%B1zDUR9~SyTo&%(sfRRoK~fbxWq3;EmTW3Q%g?o9pX0$1F9g`%kGZo zfi>Fg=5oEocQZdcC(!q9W}t-0gh{)dY-eBO2YOG_kGb7c59~#&+`qu1`;=KsV^3ZZm*=+`xiv|~U{W8dn>c0a z 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 S>pvBOB?u%|Q>C!D+5ZEe6t4FG diff --git a/pc-bios/q35-acpi-dsdt.aml b/pc-bios/q35-acpi-dsdt.aml index e50641cc53416c14133bfc7ae48f35fb14116781..cf7b085762800c82abc612f8a5aed4d7f53449b6 100644 GIT binary patch delta 44 xcmZ2vwa7}@CD Date: Wed, 16 Jan 2013 18:40:29 +0100 Subject: [PATCH 0596/1634] hw: Spelling fix in log message defineition -> definition Signed-off-by: Stefan Weil Reviewed-by: Andreas F=E4rber Signed-off-by: Stefan Hajnoczi --- hw/openrisc_sim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index fb47cdc82d..6c443ba804 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -107,7 +107,7 @@ static void openrisc_sim_init(QEMUMachineInitArgs *args) for (n = 0; n < smp_cpus; n++) { cpu = cpu_openrisc_init(cpu_model); if (cpu == NULL) { - qemu_log("Unable to find CPU defineition!\n"); + qemu_log("Unable to find CPU definition!\n"); exit(1); } qemu_register_reset(main_cpu_reset, cpu); From 5facfb4934221cac2c267e529d7ebab165103bc9 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Thu, 17 Jan 2013 14:53:52 +0400 Subject: [PATCH 0597/1634] acpitable: open the data file in binary mode -acpitable {file|data}=file reads the content of file, but it is in binary form, so the file should be opened usin O_BINARY flag. On *nix it is a no-op, but on windows and other weird platform it is really needed. Signed-off-by: Michael Tokarev Signed-off-by: Stefan Hajnoczi --- hw/acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/acpi.c b/hw/acpi.c index 97617c4ef5..8c9dcc51c4 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -104,7 +104,7 @@ int acpi_table_add(const char *t) /* now read in the data files, reallocating buffer as needed */ for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) { - int fd = open(f, O_RDONLY); + int fd = open(f, O_RDONLY | O_BINARY); if (fd < 0) { fprintf(stderr, "can't open file %s: %s\n", f, strerror(errno)); From acf15c8949f125a4d4f958a5134f8eeece1f99f5 Mon Sep 17 00:00:00 2001 From: Vadim Evard Date: Fri, 18 Jan 2013 17:48:04 +0400 Subject: [PATCH 0598/1634] configure: silence pkg-config's check for curses Signed-off-by: Vadim Evard Signed-off-by: Stefan Hajnoczi --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 4ebb60dedc..6211db9553 100755 --- a/configure +++ b/configure @@ -2039,7 +2039,7 @@ fi if test "$mingw32" = "yes" ; then curses_list="-lpdcurses" else - curses_list="-lncurses:-lcurses:$($pkg_config --libs ncurses)" + curses_list="-lncurses:-lcurses:$($pkg_config --libs ncurses 2>/dev/null)" fi if test "$curses" != "no" ; then From 09a021fb7ceb7255ab106999d7b38ffd92c3bdd6 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 21 Jan 2013 07:49:51 +0100 Subject: [PATCH 0599/1634] hw/tpci200: Fix compiler warning (redefined symbol with MinGW) STATUS_TIMEOUT is defined in winnt.h: CC hw/tpci200.o hw/tpci200.c:34:0: warning: "STATUS_TIMEOUT" redefined [enabled by default] /usr/lib/gcc/x86_64-w64-mingw32/4.6/../../../../x86_64-w64-mingw32/include/winnt.h:1036:0: note: this is the location of the previous definition Use STATUS_TIME instead of STATUS_TIMEOUT as suggested by Alberto Garcia. Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- hw/tpci200.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/tpci200.c b/hw/tpci200.c index e082bca965..a4823fb9f2 100644 --- a/hw/tpci200.c +++ b/hw/tpci200.c @@ -31,7 +31,7 @@ #define IP_INT_SPACE_ADDR_MASK 0x3F #define STATUS_INT(IP, INTNO) BIT((IP) * 2 + (INTNO)) -#define STATUS_TIMEOUT(IP) BIT((IP) + 12) +#define STATUS_TIME(IP) BIT((IP) + 12) #define STATUS_ERR_ANY 0xF00 #define CTRL_CLKRATE BIT(0) @@ -279,9 +279,9 @@ static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val, } } - if (val & STATUS_TIMEOUT(i)) { + if (val & STATUS_TIME(i)) { DPRINTF("Clear IP %c timeout\n", 'A' + i); - s->status &= ~STATUS_TIMEOUT(i); + s->status &= ~STATUS_TIME(i); } } From a42a56c5deeedebe650469640ebe77d80e1eefb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 03:20:58 +0100 Subject: [PATCH 0600/1634] target-cris: Drop unused cpu_cris_close() prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Such a function never existed. Signed-off-by: Andreas Färber Signed-off-by: Edgar E. Iglesias --- target-cris/cpu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 63e6234f11..257cb52be2 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -175,7 +175,6 @@ typedef struct CPUCRISState { CRISCPU *cpu_cris_init(const char *cpu_model); int cpu_cris_exec(CPUCRISState *s); -void cpu_cris_close(CPUCRISState *s); void do_interrupt(CPUCRISState *env); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero From 56a8810dd6686a999e47afa5c1870c66485ef1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 03:26:12 +0100 Subject: [PATCH 0601/1634] target-microblaze: Drop unused cpu_mb_close() prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Such a function never existed. Signed-off-by: Andreas Färber Signed-off-by: Edgar E. Iglesias --- target-microblaze/cpu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 4de22266ef..5621068d82 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -274,7 +274,6 @@ struct CPUMBState { MicroBlazeCPU *cpu_mb_init(const char *cpu_model); int cpu_mb_exec(CPUMBState *s); -void cpu_mb_close(CPUMBState *s); void do_interrupt(CPUMBState *env); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero From 1395af6f76e9f0e145a235a71e3578385d82ece5 Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Tue, 15 Jan 2013 00:08:00 +0100 Subject: [PATCH 0602/1634] qdev: add a maximum device allowed field for the bus. Add a max_dev field to BusClass to specify the maximum amount of devices allowed on the bus (has no effect if max_dev=0) Signed-off-by: KONRAD Frederic Reviewed-by: Peter Maydell Signed-off-by: Anthony Liguori --- hw/qdev-core.h | 2 ++ hw/qdev-monitor.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/hw/qdev-core.h b/hw/qdev-core.h index 731aadd677..d1b8e37d80 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -145,6 +145,8 @@ struct BusClass { */ char *(*get_fw_dev_path)(DeviceState *dev); int (*reset)(BusState *bus); + /* maximum devices allowed on the bus, 0: no limit. */ + int max_dev; }; typedef struct BusChild { diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index 1db5ee0f18..4e2a92b9dd 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -283,6 +283,7 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem) static BusState *qbus_find_recursive(BusState *bus, const char *name, const char *bus_typename) { + BusClass *bus_class = BUS_GET_CLASS(bus); BusChild *kid; BusState *child, *ret; int match = 1; @@ -293,6 +294,17 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name, if (bus_typename && !object_dynamic_cast(OBJECT(bus), bus_typename)) { match = 0; } + if ((bus_class->max_dev != 0) && (bus_class->max_dev <= bus->max_index)) { + if (name != NULL) { + /* bus was explicitly specified: return an error. */ + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Bus '%s' is full", + bus->name); + return NULL; + } else { + /* bus was not specified: try to find another one. */ + match = 0; + } + } if (match) { return bus; } From ff8eca5536edd3f84bc87277e158e4db11dadf82 Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Tue, 15 Jan 2013 00:08:01 +0100 Subject: [PATCH 0603/1634] virtio-bus: introduce virtio-bus Introduce virtio-bus. Refactored transport device will create a bus which extends virtio-bus. Signed-off-by: KONRAD Frederic Reviewed-by: Peter Maydell Signed-off-by: Anthony Liguori --- hw/Makefile.objs | 1 + hw/virtio-bus.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio-bus.h | 87 ++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 hw/virtio-bus.c create mode 100644 hw/virtio-bus.h diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 74b07a7e7e..23ac24977e 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -8,6 +8,7 @@ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o common-obj-$(CONFIG_VIRTIO) += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o +common-obj-$(CONFIG_VIRTIO) += virtio-bus.o common-obj-y += fw_cfg.o common-obj-$(CONFIG_PCI) += pci_bridge_dev.o common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o diff --git a/hw/virtio-bus.c b/hw/virtio-bus.c new file mode 100644 index 0000000000..b8f656e4ef --- /dev/null +++ b/hw/virtio-bus.c @@ -0,0 +1,129 @@ +/* + * VirtioBus + * + * Copyright (C) 2012 : GreenSocs Ltd + * http://www.greensocs.com/ , email: info@greensocs.com + * + * Developed by : + * Frederic Konrad + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#include "hw.h" +#include "qemu/error-report.h" +#include "qdev.h" +#include "virtio-bus.h" +#include "virtio.h" + +/* #define DEBUG_VIRTIO_BUS */ + +#ifdef DEBUG_VIRTIO_BUS +#define DPRINTF(fmt, ...) \ +do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) do { } while (0) +#endif + +/* Plug the VirtIODevice */ +int virtio_bus_plug_device(VirtIODevice *vdev) +{ + DeviceState *qdev = DEVICE(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(qdev)); + VirtioBusState *bus = VIRTIO_BUS(qbus); + VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); + DPRINTF("%s: plug device.\n", qbus->name); + + bus->vdev = vdev; + + /* + * The lines below will disappear when we drop VirtIOBindings, at the end + * of the series. + */ + bus->bindings.notify = klass->notify; + bus->bindings.save_config = klass->save_config; + bus->bindings.save_queue = klass->save_queue; + bus->bindings.load_config = klass->load_config; + bus->bindings.load_queue = klass->load_queue; + bus->bindings.load_done = klass->load_done; + bus->bindings.get_features = klass->get_features; + bus->bindings.query_guest_notifiers = klass->query_guest_notifiers; + bus->bindings.set_guest_notifiers = klass->set_guest_notifiers; + bus->bindings.set_host_notifier = klass->set_host_notifier; + bus->bindings.vmstate_change = klass->vmstate_change; + virtio_bind_device(bus->vdev, &bus->bindings, qbus->parent); + + if (klass->device_plugged != NULL) { + klass->device_plugged(qbus->parent); + } + + return 0; +} + +/* Reset the virtio_bus */ +void virtio_bus_reset(VirtioBusState *bus) +{ + DPRINTF("%s: reset device.\n", qbus->name); + if (bus->vdev != NULL) { + virtio_reset(bus->vdev); + } +} + +/* Destroy the VirtIODevice */ +void virtio_bus_destroy_device(VirtioBusState *bus) +{ + DeviceState *qdev; + BusState *qbus = BUS(bus); + VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); + DPRINTF("%s: remove device.\n", qbus->name); + + if (bus->vdev != NULL) { + if (klass->device_unplug != NULL) { + klass->device_unplug(qbus->parent); + } + qdev = DEVICE(bus->vdev); + qdev_free(qdev); + bus->vdev = NULL; + } +} + +/* Get the device id of the plugged device. */ +uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus) +{ + assert(bus->vdev != NULL); + return bus->vdev->device_id; +} + +/* Get the config_len field of the plugged device. */ +size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus) +{ + assert(bus->vdev != NULL); + return bus->vdev->config_len; +} + +static const TypeInfo virtio_bus_info = { + .name = TYPE_VIRTIO_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(VirtioBusState), + .abstract = true, + .class_size = sizeof(VirtioBusClass), +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_bus_info); +} + +type_init(virtio_register_types) diff --git a/hw/virtio-bus.h b/hw/virtio-bus.h new file mode 100644 index 0000000000..f3788970b2 --- /dev/null +++ b/hw/virtio-bus.h @@ -0,0 +1,87 @@ +/* + * VirtioBus + * + * Copyright (C) 2012 : GreenSocs Ltd + * http://www.greensocs.com/ , email: info@greensocs.com + * + * Developed by : + * Frederic Konrad + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#ifndef VIRTIO_BUS_H +#define VIRTIO_BUS_H + +#include "qdev.h" +#include "sysemu/sysemu.h" +#include "virtio.h" + +#define TYPE_VIRTIO_BUS "virtio-bus" +#define VIRTIO_BUS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtioBusClass, obj, TYPE_VIRTIO_BUS) +#define VIRTIO_BUS_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioBusClass, klass, TYPE_VIRTIO_BUS) +#define VIRTIO_BUS(obj) OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_BUS) + +typedef struct VirtioBusState VirtioBusState; + +typedef struct VirtioBusClass { + /* This is what a VirtioBus must implement */ + BusClass parent; + void (*notify)(DeviceState *d, uint16_t vector); + void (*save_config)(DeviceState *d, QEMUFile *f); + void (*save_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_config)(DeviceState *d, QEMUFile *f); + int (*load_queue)(DeviceState *d, int n, QEMUFile *f); + int (*load_done)(DeviceState *d, QEMUFile *f); + unsigned (*get_features)(DeviceState *d); + bool (*query_guest_notifiers)(DeviceState *d); + int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign); + int (*set_host_notifier)(DeviceState *d, int n, bool assigned); + void (*vmstate_change)(DeviceState *d, bool running); + /* + * transport independent init function. + * This is called by virtio-bus just after the device is plugged. + */ + void (*device_plugged)(DeviceState *d); + /* + * transport independent exit function. + * This is called by virtio-bus just before the device is unplugged. + */ + void (*device_unplug)(DeviceState *d); +} VirtioBusClass; + +struct VirtioBusState { + BusState parent_obj; + /* + * Only one VirtIODevice can be plugged on the bus. + */ + VirtIODevice *vdev; + /* + * This will be removed at the end of the series. + */ + VirtIOBindings bindings; +}; + +int virtio_bus_plug_device(VirtIODevice *vdev); +void virtio_bus_reset(VirtioBusState *bus); +void virtio_bus_destroy_device(VirtioBusState *bus); +/* Get the device id of the plugged device. */ +uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus); +/* Get the config_len field of the plugged device. */ +size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus); + +#endif /* VIRTIO_BUS_H */ From 8e05db9234050cb3f0ffb765608dd8b176334ae1 Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Tue, 15 Jan 2013 00:08:02 +0100 Subject: [PATCH 0604/1634] virtio-device: refactor virtio-device. Create the virtio-device which is abstract. All the virtio-device can extend this class. It also add some functions to virtio-bus. Signed-off-by: KONRAD Frederic Signed-off-by: Anthony Liguori --- hw/virtio-bus.c | 35 +++++++++++++++++++++++++ hw/virtio-bus.h | 7 +++++ hw/virtio.c | 70 ++++++++++++++++++++++++++++++++++++++++--------- hw/virtio.h | 30 +++++++++++++++++++++ 4 files changed, 130 insertions(+), 12 deletions(-) diff --git a/hw/virtio-bus.c b/hw/virtio-bus.c index b8f656e4ef..6045d8ad86 100644 --- a/hw/virtio-bus.c +++ b/hw/virtio-bus.c @@ -113,6 +113,41 @@ size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus) return bus->vdev->config_len; } +/* Get the features of the plugged device. */ +uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus, + uint32_t requested_features) +{ + VirtioDeviceClass *k; + assert(bus->vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + assert(k->get_features != NULL); + return k->get_features(bus->vdev, requested_features); +} + +/* Get bad features of the plugged device. */ +uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus) +{ + VirtioDeviceClass *k; + assert(bus->vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + if (k->bad_features != NULL) { + return k->bad_features(bus->vdev); + } else { + return 0; + } +} + +/* Get config of the plugged device. */ +void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config) +{ + VirtioDeviceClass *k; + assert(bus->vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + if (k->get_config != NULL) { + k->get_config(bus->vdev, config); + } +} + static const TypeInfo virtio_bus_info = { .name = TYPE_VIRTIO_BUS, .parent = TYPE_BUS, diff --git a/hw/virtio-bus.h b/hw/virtio-bus.h index f3788970b2..7584a0e6ae 100644 --- a/hw/virtio-bus.h +++ b/hw/virtio-bus.h @@ -83,5 +83,12 @@ void virtio_bus_destroy_device(VirtioBusState *bus); uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus); /* Get the config_len field of the plugged device. */ size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus); +/* Get the features of the plugged device. */ +uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus, + uint32_t requested_features); +/* Get bad features of the plugged device. */ +uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus); +/* Get config of the plugged device. */ +void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config); #endif /* VIRTIO_BUS_H */ diff --git a/hw/virtio.c b/hw/virtio.c index 77b53a9c21..ca170c319e 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -17,6 +17,7 @@ #include "qemu/error-report.h" #include "virtio.h" #include "qemu/atomic.h" +#include "virtio-bus.h" /* The alignment to use between consumer and producer parts of vring. * x86 pagesize again. */ @@ -875,11 +876,16 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) return 0; } -void virtio_cleanup(VirtIODevice *vdev) +void virtio_common_cleanup(VirtIODevice *vdev) { qemu_del_vm_change_state_handler(vdev->vmstate); g_free(vdev->config); g_free(vdev->vq); +} + +void virtio_cleanup(VirtIODevice *vdev) +{ + virtio_common_cleanup(vdev); g_free(vdev); } @@ -902,14 +908,10 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state) } } -VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, - size_t config_size, size_t struct_size) +void virtio_init(VirtIODevice *vdev, const char *name, + uint16_t device_id, size_t config_size) { - VirtIODevice *vdev; int i; - - vdev = g_malloc0(struct_size); - vdev->device_id = device_id; vdev->status = 0; vdev->isr = 0; @@ -917,20 +919,28 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, vdev->config_vector = VIRTIO_NO_VECTOR; vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX); vdev->vm_running = runstate_is_running(); - for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { + for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { vdev->vq[i].vector = VIRTIO_NO_VECTOR; vdev->vq[i].vdev = vdev; } vdev->name = name; vdev->config_len = config_size; - if (vdev->config_len) + if (vdev->config_len) { vdev->config = g_malloc0(config_size); - else + } else { vdev->config = NULL; + } + vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, + vdev); +} - vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, vdev); - +VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, + size_t config_size, size_t struct_size) +{ + VirtIODevice *vdev; + vdev = g_malloc0(struct_size); + virtio_init(vdev, name, device_id, config_size); return vdev; } @@ -1056,3 +1066,39 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) { return &vq->host_notifier; } + +static int virtio_device_init(DeviceState *qdev) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev); + assert(k->init != NULL); + if (k->init(vdev) < 0) { + return -1; + } + virtio_bus_plug_device(vdev); + return 0; +} + +static void virtio_device_class_init(ObjectClass *klass, void *data) +{ + /* Set the default value here. */ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = virtio_device_init; + dc->bus_type = TYPE_VIRTIO_BUS; +} + +static const TypeInfo virtio_device_info = { + .name = TYPE_VIRTIO_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtIODevice), + .class_init = virtio_device_class_init, + .abstract = true, + .class_size = sizeof(VirtioDeviceClass), +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_device_info); +} + +type_init(virtio_register_types) diff --git a/hw/virtio.h b/hw/virtio.h index b9f1873fd6..9cc7b85671 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -108,8 +108,17 @@ typedef struct { #define VIRTIO_NO_VECTOR 0xffff +#define TYPE_VIRTIO_DEVICE "virtio-device" +#define VIRTIO_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtioDeviceClass, obj, TYPE_VIRTIO_DEVICE) +#define VIRTIO_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, TYPE_VIRTIO_DEVICE) +#define VIRTIO_DEVICE(obj) \ + OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE) + struct VirtIODevice { + DeviceState parent_obj; const char *name; uint8_t status; uint8_t isr; @@ -119,6 +128,10 @@ struct VirtIODevice void *config; uint16_t config_vector; int nvectors; + /* + * Function pointers will be removed at the end of the series as they are in + * VirtioDeviceClass. + */ uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features); uint32_t (*bad_features)(VirtIODevice *vdev); void (*set_features)(VirtIODevice *vdev, uint32_t val); @@ -147,6 +160,23 @@ struct VirtIODevice VMChangeStateEntry *vmstate; }; +typedef struct VirtioDeviceClass { + /* This is what a VirtioDevice must implement */ + DeviceClass parent; + int (*init)(VirtIODevice *vdev); + uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features); + uint32_t (*bad_features)(VirtIODevice *vdev); + void (*set_features)(VirtIODevice *vdev, uint32_t val); + void (*get_config)(VirtIODevice *vdev, uint8_t *config); + void (*set_config)(VirtIODevice *vdev, const uint8_t *config); + void (*reset)(VirtIODevice *vdev); + void (*set_status)(VirtIODevice *vdev, uint8_t val); +} VirtioDeviceClass; + +void virtio_init(VirtIODevice *vdev, const char *name, + uint16_t device_id, size_t config_size); +void virtio_common_cleanup(VirtIODevice *vdev); + VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, void (*handle_output)(VirtIODevice *, VirtQueue *)); From 0a2acf5eb3237350e84693b9b37eced5080a1fef Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Tue, 15 Jan 2013 00:08:03 +0100 Subject: [PATCH 0605/1634] virtio-pci-bus: introduce virtio-pci-bus. Introduce virtio-pci-bus, which extends virtio-bus. It is used with virtio-pci transport device. Signed-off-by: KONRAD Frederic Signed-off-by: Anthony Liguori --- hw/virtio-pci.c | 37 +++++++++++++++++++++++++++++++++++++ hw/virtio-pci.h | 15 +++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 212acd8418..904a7e1e90 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -31,6 +31,7 @@ #include "sysemu/blockdev.h" #include "virtio-pci.h" #include "qemu/range.h" +#include "virtio-bus.h" /* from Linux's linux/virtio_pci.h */ @@ -1311,6 +1312,41 @@ static const TypeInfo virtio_scsi_info = { .class_init = virtio_scsi_class_init, }; +/* virtio-pci-bus */ + +void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev) +{ + DeviceState *qdev = DEVICE(dev); + BusState *qbus; + qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_PCI_BUS, qdev, NULL); + qbus = BUS(bus); + qbus->allow_hotplug = 0; +} + +static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *bus_class = BUS_CLASS(klass); + VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); + bus_class->max_dev = 1; + k->notify = virtio_pci_notify; + k->save_config = virtio_pci_save_config; + k->load_config = virtio_pci_load_config; + k->save_queue = virtio_pci_save_queue; + k->load_queue = virtio_pci_load_queue; + k->get_features = virtio_pci_get_features; + k->query_guest_notifiers = virtio_pci_query_guest_notifiers; + k->set_host_notifier = virtio_pci_set_host_notifier; + k->set_guest_notifiers = virtio_pci_set_guest_notifiers; + k->vmstate_change = virtio_pci_vmstate_change; +} + +static const TypeInfo virtio_pci_bus_info = { + .name = TYPE_VIRTIO_PCI_BUS, + .parent = TYPE_VIRTIO_BUS, + .instance_size = sizeof(VirtioPCIBusState), + .class_init = virtio_pci_bus_class_init, +}; + static void virtio_pci_register_types(void) { type_register_static(&virtio_blk_info); @@ -1319,6 +1355,7 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_balloon_info); type_register_static(&virtio_scsi_info); type_register_static(&virtio_rng_info); + type_register_static(&virtio_pci_bus_info); } type_init(virtio_pci_register_types) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index 917b465874..d11e6225de 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -21,6 +21,20 @@ #include "virtio-rng.h" #include "virtio-serial.h" #include "virtio-scsi.h" +#include "virtio-bus.h" + +/* virtio-pci-bus */ + +typedef struct VirtioBusState VirtioPCIBusState; +typedef struct VirtioBusClass VirtioPCIBusClass; + +#define TYPE_VIRTIO_PCI_BUS "virtio-pci-bus" +#define VIRTIO_PCI_BUS(obj) \ + OBJECT_CHECK(VirtioPCIBusState, (obj), TYPE_VIRTIO_PCI_BUS) +#define VIRTIO_PCI_BUS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtioPCIBusClass, obj, TYPE_VIRTIO_PCI_BUS) +#define VIRTIO_PCI_BUS_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioPCIBusClass, klass, TYPE_VIRTIO_PCI_BUS) /* Performance improves when virtqueue kick processing is decoupled from the * vcpu thread using ioeventfd for some devices. */ @@ -58,6 +72,7 @@ typedef struct { void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev); void virtio_pci_reset(DeviceState *d); +void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev); /* Virtio ABI version, if we increment this, we break the guest driver. */ #define VIRTIO_PCI_ABI_VERSION 0 From 085bccb72c280f36f651556ef5169f5faca31d87 Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Tue, 15 Jan 2013 00:08:04 +0100 Subject: [PATCH 0606/1634] virtio-pci: refactor virtio-pci device. Create the virtio-pci device which is abstract. This transport device will create a virtio-pci-bus, so one VirtIODevice can be connected. Signed-off-by: KONRAD Frederic Signed-off-by: Anthony Liguori --- hw/virtio-pci.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/virtio-pci.h | 23 +++++++++- 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 904a7e1e90..9abbcdfc7c 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -1312,6 +1312,121 @@ static const TypeInfo virtio_scsi_info = { .class_init = virtio_scsi_class_init, }; +/* + * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. + */ + +/* This is called by virtio-bus just after the device is plugged. */ +static void virtio_pci_device_plugged(DeviceState *d) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + VirtioBusState *bus = &proxy->bus; + uint8_t *config; + uint32_t size; + + proxy->vdev = bus->vdev; + + config = proxy->pci_dev.config; + if (proxy->class_code) { + pci_config_set_class(config, proxy->class_code); + } + pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID, + pci_get_word(config + PCI_VENDOR_ID)); + pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus)); + config[PCI_INTERRUPT_PIN] = 1; + + if (proxy->nvectors && + msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) { + proxy->nvectors = 0; + } + + proxy->pci_dev.config_write = virtio_write_config; + + size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + + virtio_bus_get_vdev_config_len(bus); + if (size & (size - 1)) { + size = 1 << qemu_fls(size); + } + + memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy, + "virtio-pci", size); + pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, + &proxy->bar); + + if (!kvm_has_many_ioeventfds()) { + proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; + } + + proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; + proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE; + proxy->host_features = virtio_bus_get_vdev_features(bus, + proxy->host_features); +} + +/* This is called by virtio-bus just before the device is unplugged. */ +static void virtio_pci_device_unplug(DeviceState *d) +{ + VirtIOPCIProxy *dev = VIRTIO_PCI(d); + virtio_pci_stop_ioeventfd(dev); +} + +static int virtio_pci_init(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev); + VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev); + virtio_pci_bus_new(&dev->bus, dev); + if (k->init != NULL) { + return k->init(dev); + } + return 0; +} + +static void virtio_pci_exit(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); + VirtioBusState *bus = VIRTIO_BUS(&proxy->bus); + BusState *qbus = BUS(&proxy->bus); + virtio_bus_destroy_device(bus); + qbus_free(qbus); + virtio_exit_pci(pci_dev); +} + +/* + * This will be renamed virtio_pci_reset at the end of the series. + * virtio_pci_reset is still in use at this moment. + */ +static void virtio_pci_rst(DeviceState *qdev) +{ + VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev); + VirtioBusState *bus = VIRTIO_BUS(&proxy->bus); + virtio_pci_stop_ioeventfd(proxy); + virtio_bus_reset(bus); + msix_unuse_all_vectors(&proxy->pci_dev); + proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG; +} + +static void virtio_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_pci_init; + k->exit = virtio_pci_exit; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_OTHERS; + dc->reset = virtio_pci_rst; +} + +static const TypeInfo virtio_pci_info = { + .name = TYPE_VIRTIO_PCI, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_pci_class_init, + .class_size = sizeof(VirtioPCIClass), + .abstract = true, +}; + /* virtio-pci-bus */ void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev) @@ -1338,6 +1453,8 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->set_host_notifier = virtio_pci_set_host_notifier; k->set_guest_notifiers = virtio_pci_set_guest_notifiers; k->vmstate_change = virtio_pci_vmstate_change; + k->device_plugged = virtio_pci_device_plugged; + k->device_unplug = virtio_pci_device_unplug; } static const TypeInfo virtio_pci_bus_info = { @@ -1356,6 +1473,7 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_scsi_info); type_register_static(&virtio_rng_info); type_register_static(&virtio_pci_bus_info); + type_register_static(&virtio_pci_info); } type_init(virtio_pci_register_types) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index d11e6225de..d24957cc25 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -23,6 +23,8 @@ #include "virtio-scsi.h" #include "virtio-bus.h" +typedef struct VirtIOPCIProxy VirtIOPCIProxy; + /* virtio-pci-bus */ typedef struct VirtioBusState VirtioPCIBusState; @@ -47,7 +49,23 @@ typedef struct { unsigned int users; } VirtIOIRQFD; -typedef struct { +/* + * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. + */ +#define TYPE_VIRTIO_PCI "virtio-pci" +#define VIRTIO_PCI_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtioPCIClass, obj, TYPE_VIRTIO_PCI) +#define VIRTIO_PCI_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioPCIClass, klass, TYPE_VIRTIO_PCI) +#define VIRTIO_PCI(obj) \ + OBJECT_CHECK(VirtIOPCIProxy, (obj), TYPE_VIRTIO_PCI) + +typedef struct VirtioPCIClass { + PCIDeviceClass parent_class; + int (*init)(VirtIOPCIProxy *vpci_dev); +} VirtioPCIClass; + +struct VirtIOPCIProxy { PCIDevice pci_dev; VirtIODevice *vdev; MemoryRegion bar; @@ -68,7 +86,8 @@ typedef struct { bool ioeventfd_started; VirtIOIRQFD *vector_irqfd; int nvqs_with_notifiers; -} VirtIOPCIProxy; + VirtioBusState bus; +}; void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev); void virtio_pci_reset(DeviceState *d); From ea35d4f1e9781a4b489d550e4bbc4568704f34bf Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Tue, 15 Jan 2013 00:08:05 +0100 Subject: [PATCH 0607/1634] virtio-s390-bus: add virtio-s390-bus. This add the virtio-s390-bus which extends virtio-bus. So one VirtIODevice can be connected on this bus. Signed-off-by: KONRAD Frederic Signed-off-by: Anthony Liguori --- hw/s390-virtio-bus.c | 29 +++++++++++++++++++++++++++++ hw/s390-virtio-bus.h | 17 +++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index bcb09f202e..f78725fa91 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -32,6 +32,7 @@ #include "sysemu/kvm.h" #include "hw/s390-virtio-bus.h" +#include "hw/virtio-bus.h" /* #define DEBUG_S390 */ @@ -569,8 +570,36 @@ static const TypeInfo s390_virtio_bridge_info = { .class_init = s390_virtio_bridge_class_init, }; +/* virtio-s390-bus */ + +void virtio_s390_bus_new(VirtioBusState *bus, VirtIOS390Device *dev) +{ + DeviceState *qdev = DEVICE(dev); + BusState *qbus; + qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_S390_BUS, qdev, NULL); + qbus = BUS(bus); + qbus->allow_hotplug = 0; +} + +static void virtio_s390_bus_class_init(ObjectClass *klass, void *data) +{ + VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); + BusClass *bus_class = BUS_CLASS(klass); + bus_class->max_dev = 1; + k->notify = virtio_s390_notify; + k->get_features = virtio_s390_get_features; +} + +static const TypeInfo virtio_s390_bus_info = { + .name = TYPE_VIRTIO_S390_BUS, + .parent = TYPE_VIRTIO_BUS, + .instance_size = sizeof(VirtioS390BusState), + .class_init = virtio_s390_bus_class_init, +}; + static void s390_virtio_register_types(void) { + type_register_static(&virtio_s390_bus_info); type_register_static(&s390_virtio_bus_info); type_register_static(&virtio_s390_device_info); type_register_static(&s390_virtio_serial); diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index 23fedd5be8..ffc6f88a89 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -24,6 +24,7 @@ #include "virtio-rng.h" #include "virtio-serial.h" #include "virtio-scsi.h" +#include "virtio-bus.h" #define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */ #define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */ @@ -59,8 +60,24 @@ #define S390_VIRTIO_BUS(obj) \ OBJECT_CHECK(VirtIOS390Bus, (obj), TYPE_S390_VIRTIO_BUS) +/* virtio-s390-bus */ + +typedef struct VirtioBusState VirtioS390BusState; +typedef struct VirtioBusClass VirtioS390BusClass; + +#define TYPE_VIRTIO_S390_BUS "virtio-s390-bus" +#define VIRTIO_S390_BUS(obj) \ + OBJECT_CHECK(VirtioS390BusState, (obj), TYPE_VIRTIO_S390_BUS) +#define VIRTIO_S390_BUS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtioS390BusClass, obj, TYPE_VIRTIO_S390_BUS) +#define VIRTIO_S390_BUS_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioS390BusClass, klass, TYPE_VIRTIO_S390_BUS) + + typedef struct VirtIOS390Device VirtIOS390Device; +void virtio_s390_bus_new(VirtioBusState *bus, VirtIOS390Device *dev); + typedef struct VirtIOS390DeviceClass { DeviceClass qdev; int (*init)(VirtIOS390Device *dev); From 11e9235b1a88a98124fe005c93ade019d6a09c0b Mon Sep 17 00:00:00 2001 From: KONRAD Frederic Date: Tue, 15 Jan 2013 00:08:06 +0100 Subject: [PATCH 0608/1634] virtio-s390-device: create a virtio-s390-bus during init. A virtio-s390-bus is created during the init. So one VirtIODevice can be connected on the virtio-s390-device through this bus. Signed-off-by: KONRAD Frederic Signed-off-by: Anthony Liguori --- hw/s390-virtio-bus.c | 2 ++ hw/s390-virtio-bus.h | 1 + 2 files changed, 3 insertions(+) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index f78725fa91..b5d1f2be16 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -503,6 +503,8 @@ static int s390_virtio_busdev_init(DeviceState *dev) VirtIOS390Device *_dev = (VirtIOS390Device *)dev; VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev); + virtio_s390_bus_new(&_dev->bus, _dev); + return _info->init(_dev); } diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index ffc6f88a89..438b37fd82 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -96,6 +96,7 @@ struct VirtIOS390Device { virtio_net_conf net; VirtIOSCSIConf scsi; VirtIORNGConf rng; + VirtioBusState bus; }; typedef struct VirtIOS390Bus { From 32ed26808d4e59efb4a03290a4a85f5f8335f268 Mon Sep 17 00:00:00 2001 From: Tim Hardeck Date: Mon, 21 Jan 2013 11:04:43 +0100 Subject: [PATCH 0609/1634] vnc: added buffer_advance function Following Anthony Liguori's Websocket implementation I have added the buffer_advance function to VNC and replaced all related buffer memmove operations with it. Signed-off-by: Tim Hardeck Reviewed-by: Anthony Liguori Signed-off-by: Anthony Liguori --- ui/vnc.c | 13 +++++++++---- ui/vnc.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 8912b78945..ddf01f1055 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -510,6 +510,13 @@ void buffer_append(Buffer *buffer, const void *data, size_t len) buffer->offset += len; } +void buffer_advance(Buffer *buf, size_t len) +{ + memmove(buf->buffer, buf->buffer + len, + (buf->offset - len)); + buf->offset -= len; +} + static void vnc_desktop_resize(VncState *vs) { DisplayState *ds = vs->ds; @@ -1166,8 +1173,7 @@ static long vnc_client_write_plain(VncState *vs) if (!ret) return 0; - memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret)); - vs->output.offset -= ret; + buffer_advance(&vs->output, ret); if (vs->output.offset == 0) { qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); @@ -1313,8 +1319,7 @@ void vnc_client_read(void *opaque) } if (!ret) { - memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len)); - vs->input.offset -= len; + buffer_advance(&vs->input, len); } else { vs->read_handler_expect = ret; } diff --git a/ui/vnc.h b/ui/vnc.h index 8b40f09117..5059cbe3b8 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -510,6 +510,7 @@ void buffer_reserve(Buffer *buffer, size_t len); void buffer_reset(Buffer *buffer); void buffer_free(Buffer *buffer); void buffer_append(Buffer *buffer, const void *data, size_t len); +void buffer_advance(Buffer *buf, size_t len); /* Misc helpers */ From 7536ee4bc3da7e9b7fdadba5ba6ade63eaace430 Mon Sep 17 00:00:00 2001 From: Tim Hardeck Date: Mon, 21 Jan 2013 11:04:44 +0100 Subject: [PATCH 0610/1634] vnc: added initial websocket protocol support This patch adds basic Websocket Protocol version 13 - RFC 6455 - support to QEMU VNC. Binary encoding support on the client side is mandatory. Because of the GnuTLS requirement the Websockets implementation is optional (--enable-vnc-ws). To activate Websocket support the VNC option "websocket"is used, for example "-vnc :0,websocket". The listen port for Websocket connections is (5700 + display) so if QEMU VNC is started with :0 the Websocket port would be 5700. As an alternative the Websocket port could be manually specified by using ",websocket=" instead. Parts of the implementation base on Anthony Liguori's QEMU Websocket patch from 2010 and on Joel Martin's LibVNC Websocket implementation. Signed-off-by: Tim Hardeck Signed-off-by: Anthony Liguori --- configure | 27 ++++- qemu-options.hx | 8 ++ ui/Makefile.objs | 1 + ui/vnc-ws.c | 284 +++++++++++++++++++++++++++++++++++++++++++++++ ui/vnc-ws.h | 86 ++++++++++++++ ui/vnc.c | 187 ++++++++++++++++++++++++++++--- ui/vnc.h | 19 ++++ 7 files changed, 591 insertions(+), 21 deletions(-) create mode 100644 ui/vnc-ws.c create mode 100644 ui/vnc-ws.h diff --git a/configure b/configure index 6211db9553..c6172ef88e 100755 --- a/configure +++ b/configure @@ -158,6 +158,7 @@ vnc_tls="" vnc_sasl="" vnc_jpeg="" vnc_png="" +vnc_ws="" xen="" xen_ctrl_version="" xen_pci_passthrough="" @@ -724,6 +725,10 @@ for opt do ;; --enable-vnc-png) vnc_png="yes" ;; + --disable-vnc-ws) vnc_ws="no" + ;; + --enable-vnc-ws) vnc_ws="yes" + ;; --disable-slirp) slirp="no" ;; --disable-uuid) uuid="no" @@ -1069,6 +1074,8 @@ echo " --disable-vnc-jpeg disable JPEG lossy compression for VNC server" echo " --enable-vnc-jpeg enable JPEG lossy compression for VNC server" echo " --disable-vnc-png disable PNG compression for VNC server (default)" echo " --enable-vnc-png enable PNG compression for VNC server" +echo " --disable-vnc-ws disable Websockets support for VNC server" +echo " --enable-vnc-ws enable Websockets support for VNC server" echo " --disable-curses disable curses output" echo " --enable-curses enable curses output" echo " --disable-curl disable curl connectivity" @@ -1712,8 +1719,8 @@ EOF fi ########################################## -# VNC TLS detection -if test "$vnc" = "yes" -a "$vnc_tls" != "no" ; then +# VNC TLS/WS detection +if test "$vnc" = "yes" -a \( "$vnc_tls" != "no" -o "$vnc_ws" != "no" \) ; then cat > $TMPC < int main(void) { gnutls_session_t s; gnutls_init(&s, GNUTLS_SERVER); return 0; } @@ -1721,14 +1728,23 @@ EOF vnc_tls_cflags=`$pkg_config --cflags gnutls 2> /dev/null` vnc_tls_libs=`$pkg_config --libs gnutls 2> /dev/null` if compile_prog "$vnc_tls_cflags" "$vnc_tls_libs" ; then - vnc_tls=yes + if test "$vnc_tls" != "no" ; then + vnc_tls=yes + fi + if test "$vnc_ws" != "no" ; then + vnc_ws=yes + fi libs_softmmu="$vnc_tls_libs $libs_softmmu" QEMU_CFLAGS="$QEMU_CFLAGS $vnc_tls_cflags" else if test "$vnc_tls" = "yes" ; then feature_not_found "vnc-tls" fi + if test "$vnc_ws" = "yes" ; then + feature_not_found "vnc-ws" + fi vnc_tls=no + vnc_ws=no fi fi @@ -3283,6 +3299,7 @@ if test "$vnc" = "yes" ; then echo "VNC SASL support $vnc_sasl" echo "VNC JPEG support $vnc_jpeg" echo "VNC PNG support $vnc_png" + echo "VNC WS support $vnc_ws" fi if test -n "$sparc_cpu"; then echo "Target Sparc Arch $sparc_cpu" @@ -3461,6 +3478,10 @@ fi if test "$vnc_png" = "yes" ; then echo "CONFIG_VNC_PNG=y" >> $config_host_mak fi +if test "$vnc_ws" = "yes" ; then + echo "CONFIG_VNC_WS=y" >> $config_host_mak + echo "VNC_WS_CFLAGS=$vnc_ws_cflags" >> $config_host_mak +fi if test "$fnmatch" = "yes" ; then echo "CONFIG_FNMATCH=y" >> $config_host_mak fi diff --git a/qemu-options.hx b/qemu-options.hx index 40cd68399d..4e2b4994a2 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1096,6 +1096,14 @@ client is specified by the @var{display}. For reverse network connections (@var{host}:@var{d},@code{reverse}), the @var{d} argument is a TCP port number, not a display number. +@item websocket + +Opens an additional TCP listening port dedicated to VNC Websocket connections. +By defintion the Websocket port is 5700+@var{display}. If @var{host} is +specified connections will only be allowed from this host. +As an alternative the Websocket port could be specified by using +@code{websocket}=@var{port}. + @item password Require that password based authentication is used for client connections. diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 6768bb7f7e..d9db073584 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -4,6 +4,7 @@ vnc-obj-y += vnc-enc-tight.o vnc-palette.o vnc-obj-y += vnc-enc-zrle.o vnc-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o +vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o vnc-obj-y += vnc-jobs.o common-obj-y += keymaps.o console.o cursor.o input.o qemu-pixman.o diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c new file mode 100644 index 0000000000..9ccdc1971c --- /dev/null +++ b/ui/vnc-ws.c @@ -0,0 +1,284 @@ +/* + * QEMU VNC display driver: Websockets support + * + * Copyright (C) 2010 Joel Martin + * Copyright (C) 2012 Tim Hardeck + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, see . + */ + +#include "vnc.h" + +void vncws_handshake_read(void *opaque) +{ + VncState *vs = opaque; + uint8_t *handshake_end; + long ret; + buffer_reserve(&vs->ws_input, 4096); + ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); + + if (!ret) { + if (vs->csock == -1) { + vnc_disconnect_finish(vs); + } + return; + } + vs->ws_input.offset += ret; + + handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer, + vs->ws_input.offset, WS_HANDSHAKE_END); + if (handshake_end) { + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset); + buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer + + strlen(WS_HANDSHAKE_END)); + } +} + + +long vnc_client_read_ws(VncState *vs) +{ + int ret, err; + uint8_t *payload; + size_t payload_size, frame_size; + VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer, + vs->ws_input.capacity, vs->ws_input.offset); + buffer_reserve(&vs->ws_input, 4096); + ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096); + if (!ret) { + return 0; + } + vs->ws_input.offset += ret; + + /* make sure that nothing is left in the ws_input buffer */ + do { + err = vncws_decode_frame(&vs->ws_input, &payload, + &payload_size, &frame_size); + if (err <= 0) { + return err; + } + + buffer_reserve(&vs->input, payload_size); + buffer_append(&vs->input, payload, payload_size); + + buffer_advance(&vs->ws_input, frame_size); + } while (vs->ws_input.offset > 0); + + return ret; +} + +long vnc_client_write_ws(VncState *vs) +{ + long ret; + VNC_DEBUG("Write WS: Pending output %p size %zd offset %zd\n", + vs->output.buffer, vs->output.capacity, vs->output.offset); + vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset); + buffer_reset(&vs->output); + ret = vnc_client_write_buf(vs, vs->ws_output.buffer, vs->ws_output.offset); + if (!ret) { + return 0; + } + + buffer_advance(&vs->ws_output, ret); + + if (vs->ws_output.offset == 0) { + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + } + + return ret; +} + +static char *vncws_extract_handshake_entry(const char *handshake, + size_t handshake_len, const char *name) +{ + char *begin, *end, *ret = NULL; + char *line = g_strdup_printf("%s%s: ", WS_HANDSHAKE_DELIM, name); + begin = g_strstr_len(handshake, handshake_len, line); + if (begin != NULL) { + begin += strlen(line); + end = g_strstr_len(begin, handshake_len - (begin - handshake), + WS_HANDSHAKE_DELIM); + if (end != NULL) { + ret = g_strndup(begin, end - begin); + } + } + g_free(line); + return ret; +} + +static void vncws_send_handshake_response(VncState *vs, const char* key) +{ + char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1]; + char hash[SHA1_DIGEST_LEN]; + size_t hash_size = SHA1_DIGEST_LEN; + char *accept = NULL, *response = NULL; + gnutls_datum_t in; + + g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1); + g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1); + + /* hash and encode it */ + in.data = (void *)combined_key; + in.size = WS_CLIENT_KEY_LEN + WS_GUID_LEN; + if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &in, hash, &hash_size) + == GNUTLS_E_SUCCESS) { + accept = g_base64_encode((guchar *)hash, SHA1_DIGEST_LEN); + } + if (accept == NULL) { + VNC_DEBUG("Hashing Websocket combined key failed\n"); + vnc_client_error(vs); + return; + } + + response = g_strdup_printf(WS_HANDSHAKE, accept); + vnc_write(vs, response, strlen(response)); + vnc_flush(vs); + + g_free(accept); + g_free(response); + + vs->encode_ws = 1; + vnc_init_state(vs); +} + +void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size) +{ + char *protocols = vncws_extract_handshake_entry((const char *)line, size, + "Sec-WebSocket-Protocol"); + char *version = vncws_extract_handshake_entry((const char *)line, size, + "Sec-WebSocket-Version"); + char *key = vncws_extract_handshake_entry((const char *)line, size, + "Sec-WebSocket-Key"); + + if (protocols && version && key + && g_strrstr(protocols, "binary") + && !strcmp(version, WS_SUPPORTED_VERSION) + && strlen(key) == WS_CLIENT_KEY_LEN) { + vncws_send_handshake_response(vs, key); + } else { + VNC_DEBUG("Defective Websockets header or unsupported protocol\n"); + vnc_client_error(vs); + } + + g_free(protocols); + g_free(version); + g_free(key); +} + +void vncws_encode_frame(Buffer *output, const void *payload, + const size_t payload_size) +{ + size_t header_size = 0; + unsigned char opcode = WS_OPCODE_BINARY_FRAME; + union { + char buf[WS_HEAD_MAX_LEN]; + WsHeader ws; + } header; + + if (!payload_size) { + return; + } + + header.ws.b0 = 0x80 | (opcode & 0x0f); + if (payload_size <= 125) { + header.ws.b1 = (uint8_t)payload_size; + header_size = 2; + } else if (payload_size < 65536) { + header.ws.b1 = 0x7e; + header.ws.u.s16.l16 = cpu_to_be16((uint16_t)payload_size); + header_size = 4; + } else { + header.ws.b1 = 0x7f; + header.ws.u.s64.l64 = cpu_to_be64(payload_size); + header_size = 10; + } + + buffer_reserve(output, header_size + payload_size); + buffer_append(output, header.buf, header_size); + buffer_append(output, payload, payload_size); +} + +int vncws_decode_frame(Buffer *input, uint8_t **payload, + size_t *payload_size, size_t *frame_size) +{ + unsigned char opcode = 0, fin = 0, has_mask = 0; + size_t header_size = 0; + uint32_t *payload32; + WsHeader *header = (WsHeader *)input->buffer; + WsMask mask; + int i; + + if (input->offset < WS_HEAD_MIN_LEN + 4) { + /* header not complete */ + return 0; + } + + fin = (header->b0 & 0x80) >> 7; + opcode = header->b0 & 0x0f; + has_mask = (header->b1 & 0x80) >> 7; + *payload_size = header->b1 & 0x7f; + + if (opcode == WS_OPCODE_CLOSE) { + /* disconnect */ + return -1; + } + + /* Websocket frame sanity check: + * * Websocket fragmentation is not supported. + * * All websockets frames sent by a client have to be masked. + * * Only binary encoding is supported. + */ + if (!fin || !has_mask || opcode != WS_OPCODE_BINARY_FRAME) { + VNC_DEBUG("Received faulty/unsupported Websocket frame\n"); + return -2; + } + + if (*payload_size < 126) { + header_size = 6; + mask = header->u.m; + } else if (*payload_size == 126 && input->offset >= 8) { + *payload_size = be16_to_cpu(header->u.s16.l16); + header_size = 8; + mask = header->u.s16.m16; + } else if (*payload_size == 127 && input->offset >= 14) { + *payload_size = be64_to_cpu(header->u.s64.l64); + header_size = 14; + mask = header->u.s64.m64; + } else { + /* header not complete */ + return 0; + } + + *frame_size = header_size + *payload_size; + + if (input->offset < *frame_size) { + /* frame not complete */ + return 0; + } + + *payload = input->buffer + header_size; + + /* unmask frame */ + /* process 1 frame (32 bit op) */ + payload32 = (uint32_t *)(*payload); + for (i = 0; i < *payload_size / 4; i++) { + payload32[i] ^= mask.u; + } + /* process the remaining bytes (if any) */ + for (i *= 4; i < *payload_size; i++) { + (*payload)[i] ^= mask.c[i % 4]; + } + + return 1; +} diff --git a/ui/vnc-ws.h b/ui/vnc-ws.h new file mode 100644 index 0000000000..039a58765c --- /dev/null +++ b/ui/vnc-ws.h @@ -0,0 +1,86 @@ +/* + * QEMU VNC display driver: Websockets support + * + * Copyright (C) 2010 Joel Martin + * Copyright (C) 2012 Tim Hardeck + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, see . + */ + +#ifndef __QEMU_UI_VNC_WS_H +#define __QEMU_UI_VNC_WS_H + +#include + +#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) +#define SHA1_DIGEST_LEN 20 + +#define WS_ACCEPT_LEN (B64LEN(SHA1_DIGEST_LEN) + 1) +#define WS_CLIENT_KEY_LEN 24 +#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" +#define WS_GUID_LEN strlen(WS_GUID) + +#define WS_HANDSHAKE "HTTP/1.1 101 Switching Protocols\r\n\ +Upgrade: websocket\r\n\ +Connection: Upgrade\r\n\ +Sec-WebSocket-Accept: %s\r\n\ +Sec-WebSocket-Protocol: binary\r\n\ +\r\n" +#define WS_HANDSHAKE_DELIM "\r\n" +#define WS_HANDSHAKE_END "\r\n\r\n" +#define WS_SUPPORTED_VERSION "13" + +#define WS_HEAD_MIN_LEN sizeof(uint16_t) +#define WS_HEAD_MAX_LEN (WS_HEAD_MIN_LEN + sizeof(uint64_t) + sizeof(uint32_t)) + +typedef union WsMask { + char c[4]; + uint32_t u; +} WsMask; + +typedef struct QEMU_PACKED WsHeader { + unsigned char b0; + unsigned char b1; + union { + struct QEMU_PACKED { + uint16_t l16; + WsMask m16; + } s16; + struct QEMU_PACKED { + uint64_t l64; + WsMask m64; + } s64; + WsMask m; + } u; +} WsHeader; + +enum { + WS_OPCODE_CONTINUATION = 0x0, + WS_OPCODE_TEXT_FRAME = 0x1, + WS_OPCODE_BINARY_FRAME = 0x2, + WS_OPCODE_CLOSE = 0x8, + WS_OPCODE_PING = 0x9, + WS_OPCODE_PONG = 0xA +}; + +void vncws_handshake_read(void *opaque); +long vnc_client_write_ws(VncState *vs); +long vnc_client_read_ws(VncState *vs); +void vncws_process_handshake(VncState *vs, uint8_t *line, size_t size); +void vncws_encode_frame(Buffer *output, const void *payload, + const size_t payload_size); +int vncws_decode_frame(Buffer *input, uint8_t **payload, + size_t *payload_size, size_t *frame_size); + +#endif /* __QEMU_UI_VNC_WS_H */ diff --git a/ui/vnc.c b/ui/vnc.c index ddf01f1055..ee08894f7f 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -420,7 +420,6 @@ out_error: static int vnc_update_client(VncState *vs, int has_dirty); static int vnc_update_client_sync(VncState *vs, int has_dirty); static void vnc_disconnect_start(VncState *vs); -static void vnc_disconnect_finish(VncState *vs); static void vnc_init_timer(VncDisplay *vd); static void vnc_remove_timer(VncDisplay *vd); @@ -486,7 +485,7 @@ static int buffer_empty(Buffer *buffer) return buffer->offset == 0; } -static uint8_t *buffer_end(Buffer *buffer) +uint8_t *buffer_end(Buffer *buffer) { return buffer->buffer + buffer->offset; } @@ -1023,7 +1022,7 @@ static void vnc_disconnect_start(VncState *vs) vs->csock = -1; } -static void vnc_disconnect_finish(VncState *vs) +void vnc_disconnect_finish(VncState *vs) { int i; @@ -1034,6 +1033,10 @@ static void vnc_disconnect_finish(VncState *vs) buffer_free(&vs->input); buffer_free(&vs->output); +#ifdef CONFIG_VNC_WS + buffer_free(&vs->ws_input); + buffer_free(&vs->ws_output); +#endif /* CONFIG_VNC_WS */ qobject_decref(vs->info); @@ -1199,7 +1202,16 @@ static void vnc_client_write_locked(void *opaque) vnc_client_write_sasl(vs); } else #endif /* CONFIG_VNC_SASL */ - vnc_client_write_plain(vs); + { +#ifdef CONFIG_VNC_WS + if (vs->encode_ws) { + vnc_client_write_ws(vs); + } else +#endif /* CONFIG_VNC_WS */ + { + vnc_client_write_plain(vs); + } + } } void vnc_client_write(void *opaque) @@ -1207,7 +1219,11 @@ void vnc_client_write(void *opaque) VncState *vs = opaque; vnc_lock_output(vs); - if (vs->output.offset) { + if (vs->output.offset +#ifdef CONFIG_VNC_WS + || vs->ws_output.offset +#endif + ) { vnc_client_write_locked(opaque); } else if (vs->csock != -1) { qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); @@ -1301,7 +1317,21 @@ void vnc_client_read(void *opaque) ret = vnc_client_read_sasl(vs); else #endif /* CONFIG_VNC_SASL */ +#ifdef CONFIG_VNC_WS + if (vs->encode_ws) { + ret = vnc_client_read_ws(vs); + if (ret == -1) { + vnc_disconnect_start(vs); + return; + } else if (ret == -2) { + vnc_client_error(vs); + return; + } + } else +#endif /* CONFIG_VNC_WS */ + { ret = vnc_client_read_plain(vs); + } if (!ret) { if (vs->csock == -1) vnc_disconnect_finish(vs); @@ -1372,7 +1402,11 @@ void vnc_write_u8(VncState *vs, uint8_t value) void vnc_flush(VncState *vs) { vnc_lock_output(vs); - if (vs->csock != -1 && vs->output.offset) { + if (vs->csock != -1 && (vs->output.offset +#ifdef CONFIG_VNC_WS + || vs->ws_output.offset +#endif + )) { vnc_client_write_locked(vs); } vnc_unlock_output(vs); @@ -2662,7 +2696,7 @@ static void vnc_remove_timer(VncDisplay *vd) } } -static void vnc_connect(VncDisplay *vd, int csock, int skipauth) +static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket) { VncState *vs = g_malloc0(sizeof(VncState)); int i; @@ -2689,13 +2723,34 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth) VNC_DEBUG("New client on socket %d\n", csock); dcl->idle = 0; socket_set_nonblock(vs->csock); - qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); +#ifdef CONFIG_VNC_WS + if (websocket) { + vs->websocket = 1; + qemu_set_fd_handler2(vs->csock, NULL, vncws_handshake_read, NULL, vs); + } else +#endif /* CONFIG_VNC_WS */ + { + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); + } vnc_client_cache_addr(vs); vnc_qmp_event(vs, QEVENT_VNC_CONNECTED); vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING); vs->vd = vd; + +#ifdef CONFIG_VNC_WS + if (!vs->websocket) +#endif + { + vnc_init_state(vs); + } +} + +void vnc_init_state(VncState *vs) +{ + VncDisplay *vd = vs->vd; + vs->ds = vd->ds; vs->last_x = -1; vs->last_y = -1; @@ -2727,21 +2782,41 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth) /* vs might be free()ed here */ } -static void vnc_listen_read(void *opaque) +static void vnc_listen_read(void *opaque, bool websocket) { VncDisplay *vs = opaque; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); + int csock; /* Catch-up */ vga_hw_update(); +#ifdef CONFIG_VNC_WS + if (websocket) { + csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen); + } else +#endif /* CONFIG_VNC_WS */ + { + csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); + } - int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (csock != -1) { - vnc_connect(vs, csock, 0); + vnc_connect(vs, csock, 0, websocket); } } +static void vnc_listen_regular_read(void *opaque) +{ + vnc_listen_read(opaque, 0); +} + +#ifdef CONFIG_VNC_WS +static void vnc_listen_websocket_read(void *opaque) +{ + vnc_listen_read(opaque, 1); +} +#endif /* CONFIG_VNC_WS */ + void vnc_display_init(DisplayState *ds) { VncDisplay *vs = g_malloc0(sizeof(*vs)); @@ -2753,6 +2828,9 @@ void vnc_display_init(DisplayState *ds) vnc_display = vs; vs->lsock = -1; +#ifdef CONFIG_VNC_WS + vs->lwebsock = -1; +#endif vs->ds = ds; QTAILQ_INIT(&vs->clients); @@ -2794,6 +2872,15 @@ static void vnc_display_close(DisplayState *ds) close(vs->lsock); vs->lsock = -1; } +#ifdef CONFIG_VNC_WS + g_free(vs->ws_display); + vs->ws_display = NULL; + if (vs->lwebsock != -1) { + qemu_set_fd_handler2(vs->lwebsock, NULL, NULL, NULL, NULL); + close(vs->lwebsock); + vs->lwebsock = -1; + } +#endif /* CONFIG_VNC_WS */ vs->auth = VNC_AUTH_INVALID; #ifdef CONFIG_VNC_TLS vs->subauth = VNC_AUTH_INVALID; @@ -2915,6 +3002,36 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) } else if (strncmp(options, "sasl", 4) == 0) { sasl = 1; /* Require SASL auth */ #endif +#ifdef CONFIG_VNC_WS + } else if (strncmp(options, "websocket", 9) == 0) { + char *start, *end; + vs->websocket = 1; + + /* Check for 'websocket=' */ + start = strchr(options, '='); + end = strchr(options, ','); + if (start && (!end || (start < end))) { + int len = end ? end-(start+1) : strlen(start+1); + if (len < 6) { + /* extract the host specification from display */ + char *host = NULL, *port = NULL, *host_end = NULL; + port = g_strndup(start + 1, len); + + /* ipv6 hosts have colons */ + end = strchr(display, ','); + host_end = g_strrstr_len(display, end - display, ":"); + + if (host_end) { + host = g_strndup(display, host_end - display + 1); + } else { + host = g_strndup(":", 1); + } + vs->ws_display = g_strconcat(host, port, NULL); + g_free(host); + g_free(port); + } + } +#endif /* CONFIG_VNC_WS */ #ifdef CONFIG_VNC_TLS } else if (strncmp(options, "tls", 3) == 0) { tls = 1; /* Require TLS */ @@ -3073,6 +3190,9 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) /* connect to viewer */ int csock; vs->lsock = -1; +#ifdef CONFIG_VNC_WS + vs->lwebsock = -1; +#endif if (strncmp(display, "unix:", 5) == 0) { csock = unix_connect(display+5, errp); } else { @@ -3081,7 +3201,7 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) if (csock < 0) { goto fail; } - vnc_connect(vs, csock, 0); + vnc_connect(vs, csock, 0, 0); } else { /* listen for connects */ char *dpy; @@ -3092,25 +3212,56 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) } else { vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900, errp); - } - if (vs->lsock < 0) { - g_free(dpy); - goto fail; + if (vs->lsock < 0) { + g_free(dpy); + goto fail; + } +#ifdef CONFIG_VNC_WS + if (vs->websocket) { + if (vs->ws_display) { + vs->lwebsock = inet_listen(vs->ws_display, NULL, 256, + SOCK_STREAM, 0, errp); + } else { + vs->lwebsock = inet_listen(vs->display, NULL, 256, + SOCK_STREAM, 5700, errp); + } + + if (vs->lwebsock < 0) { + if (vs->lsock) { + close(vs->lsock); + vs->lsock = -1; + } + g_free(dpy); + goto fail; + } + } +#endif /* CONFIG_VNC_WS */ } g_free(vs->display); vs->display = dpy; - qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs); + qemu_set_fd_handler2(vs->lsock, NULL, + vnc_listen_regular_read, NULL, vs); +#ifdef CONFIG_VNC_WS + if (vs->websocket) { + qemu_set_fd_handler2(vs->lwebsock, NULL, + vnc_listen_websocket_read, NULL, vs); + } +#endif /* CONFIG_VNC_WS */ } return; fail: g_free(vs->display); vs->display = NULL; +#ifdef CONFIG_VNC_WS + g_free(vs->ws_display); + vs->ws_display = NULL; +#endif /* CONFIG_VNC_WS */ } void vnc_display_add_client(DisplayState *ds, int csock, int skipauth) { VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; - vnc_connect(vs, csock, skipauth); + vnc_connect(vs, csock, skipauth, 0); } diff --git a/ui/vnc.h b/ui/vnc.h index 5059cbe3b8..f93c89a2f7 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -99,6 +99,9 @@ typedef struct VncDisplay VncDisplay; #ifdef CONFIG_VNC_SASL #include "vnc-auth-sasl.h" #endif +#ifdef CONFIG_VNC_WS +#include "vnc-ws.h" +#endif struct VncRectStat { @@ -142,6 +145,11 @@ struct VncDisplay QEMUTimer *timer; int timer_interval; int lsock; +#ifdef CONFIG_VNC_WS + int lwebsock; + bool websocket; + char *ws_display; +#endif DisplayState *ds; kbd_layout_t *kbd_layout; int lock_key_sync; @@ -269,11 +277,19 @@ struct VncState #ifdef CONFIG_VNC_SASL VncStateSASL sasl; #endif +#ifdef CONFIG_VNC_WS + bool encode_ws; + bool websocket; +#endif QObject *info; Buffer output; Buffer input; +#ifdef CONFIG_VNC_WS + Buffer ws_input; + Buffer ws_output; +#endif /* current output mode information */ VncWritePixels *write_pixels; PixelFormat client_pf; @@ -493,6 +509,8 @@ void vnc_write_u16(VncState *vs, uint16_t value); void vnc_write_u8(VncState *vs, uint8_t value); void vnc_flush(VncState *vs); void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting); +void vnc_disconnect_finish(VncState *vs); +void vnc_init_state(VncState *vs); /* Buffer I/O functions */ @@ -511,6 +529,7 @@ void buffer_reset(Buffer *buffer); void buffer_free(Buffer *buffer); void buffer_append(Buffer *buffer, const void *data, size_t len); void buffer_advance(Buffer *buf, size_t len); +uint8_t *buffer_end(Buffer *buffer); /* Misc helpers */ From 6fd8e79af031d8cfc0eb02d40d03281917fcb27b Mon Sep 17 00:00:00 2001 From: Tim Hardeck Date: Mon, 21 Jan 2013 11:04:45 +0100 Subject: [PATCH 0611/1634] vnc: fix possible uninitialized removals Some VncState values are not initialized before the Websocket handshake. If it fails QEMU segfaults during the cleanup. To prevent this behavior intialization checks are added. Signed-off-by: Tim Hardeck Signed-off-by: Anthony Liguori --- ui/vnc.c | 11 ++++++++--- ui/vnc.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index ee08894f7f..ff4e2ae586 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1053,20 +1053,24 @@ void vnc_disconnect_finish(VncState *vs) audio_del(vs); vnc_release_modifiers(vs); - QTAILQ_REMOVE(&vs->vd->clients, vs, next); + if (vs->initialized) { + QTAILQ_REMOVE(&vs->vd->clients, vs, next); + qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier); + } if (QTAILQ_EMPTY(&vs->vd->clients)) { dcl->idle = 1; } - qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier); vnc_remove_timer(vs->vd); if (vs->vd->lock_key_sync) qemu_remove_led_event_handler(vs->led); vnc_unlock_output(vs); qemu_mutex_destroy(&vs->output_mutex); - qemu_bh_delete(vs->bh); + if (vs->bh != NULL) { + qemu_bh_delete(vs->bh); + } buffer_free(&vs->jobs_buffer); for (i = 0; i < VNC_STAT_ROWS; ++i) { @@ -2749,6 +2753,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket) void vnc_init_state(VncState *vs) { + vs->initialized = true; VncDisplay *vd = vs->vd; vs->ds = vd->ds; diff --git a/ui/vnc.h b/ui/vnc.h index f93c89a2f7..45d7686843 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -306,6 +306,7 @@ struct VncState QEMUPutLEDEntry *led; bool abort; + bool initialized; QemuMutex output_mutex; QEMUBH *bh; Buffer jobs_buffer; From 1356b98d3e95a85071e6bf9a99e8799e1ae1bbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 02:47:33 +0100 Subject: [PATCH 0612/1634] sysbus: Drop sysbus_from_qdev() cast macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace by SYS_BUS_DEVICE() QOM cast macro using a scripted conversion. Avoids the old macro creeping into new code. Resolve a Coding Style warning in openpic code. Signed-off-by: Andreas Färber Cc: Anthony Liguori Signed-off-by: Anthony Liguori --- hw/a15mpcore.c | 2 +- hw/a9mpcore.c | 6 ++--- hw/apb_pci.c | 2 +- hw/arm11mpcore.c | 8 +++--- hw/arm_gic_common.c | 2 +- hw/arm_mptimer.c | 2 +- hw/arm_sysctl.c | 2 +- hw/armv7m.c | 6 ++--- hw/axis_dev88.c | 2 +- hw/cadence_gem.c | 2 +- hw/empty_slot.c | 2 +- hw/escc.c | 4 +-- hw/esp.c | 2 +- hw/etraxfs.h | 2 +- hw/exynos4210.c | 14 +++++----- hw/exynos4210_gic.c | 2 +- hw/exynos4210_uart.c | 2 +- hw/exynos4_boards.c | 2 +- hw/fw_cfg.c | 2 +- hw/grlib.h | 10 ++++---- hw/grlib_irqmp.c | 4 +-- hw/highbank.c | 26 +++++++++---------- hw/hpet.c | 4 +-- hw/imx_serial.c | 2 +- hw/lan9118.c | 4 +-- hw/lm32.h | 2 +- hw/m48t59.c | 2 +- hw/marvell_88w8618_audio.c | 2 +- hw/milkymist-hw.h | 52 +++++++++++++++++++------------------- hw/mips_jazz.c | 4 +-- hw/mips_mipssim.c | 2 +- hw/mpc8544_guts.c | 2 +- hw/musicpal.c | 14 +++++----- hw/nand.c | 2 +- hw/nseries.c | 6 ++--- hw/omap1.c | 10 ++++---- hw/omap2.c | 8 +++--- hw/omap_gpio.c | 4 +-- hw/omap_i2c.c | 4 +-- hw/omap_intc.c | 2 +- hw/onenand.c | 4 +-- hw/openpic.c | 2 +- hw/openrisc_sim.c | 2 +- hw/pc.c | 4 +-- hw/petalogix_ml605_mmu.c | 2 +- hw/pflash_cfi01.c | 2 +- hw/pflash_cfi02.c | 2 +- hw/ppc/e500.c | 4 +-- hw/ppc_newworld.c | 2 +- hw/ppce500_spin.c | 2 +- hw/pxa2xx.c | 2 +- hw/pxa2xx_dma.c | 8 +++--- hw/pxa2xx_gpio.c | 10 ++++---- hw/pxa2xx_pic.c | 6 ++--- hw/r2d.c | 2 +- hw/realview.c | 10 ++++---- hw/realview_gic.c | 2 +- hw/slavio_intctl.c | 4 +-- hw/sm501.c | 4 +-- hw/smc91c111.c | 4 +-- hw/spapr_pci.c | 2 +- hw/spitz.c | 4 +-- hw/stellaris.c | 4 +-- hw/strongarm.c | 8 +++--- hw/sun4m.c | 30 +++++++++++----------- hw/sun4u.c | 4 +-- hw/sysbus.c | 8 +++--- hw/sysbus.h | 1 - hw/tusb6010.c | 2 +- hw/versatilepb.c | 10 ++++---- hw/vexpress.c | 10 ++++---- hw/xilinx.h | 22 ++++++++-------- hw/xilinx_zynq.c | 8 +++--- hw/xtensa_lx60.c | 2 +- hw/zynq_slcr.c | 2 +- target-i386/cpu.c | 2 +- 76 files changed, 214 insertions(+), 215 deletions(-) diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index 30983efc03..fe6c34ca53 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -46,7 +46,7 @@ static int a15mp_priv_init(SysBusDevice *dev) qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq); qdev_prop_set_uint32(s->gic, "revision", 2); qdev_init_nofail(s->gic); - busdev = sysbus_from_qdev(s->gic); + busdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ sysbus_pass_irq(dev, busdev); diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 184734f9b1..673bbd8c42 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -112,7 +112,7 @@ static const MemoryRegionOps a9_scu_ops = { static void a9mp_priv_reset(DeviceState *dev) { - a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, sysbus_from_qdev(dev)); + a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, SYS_BUS_DEVICE(dev)); int i; s->scu_control = 0; for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) { @@ -136,7 +136,7 @@ static int a9mp_priv_init(SysBusDevice *dev) qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq); qdev_init_nofail(s->gic); - gicbusdev = sysbus_from_qdev(s->gic); + gicbusdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ sysbus_pass_irq(dev, gicbusdev); @@ -147,7 +147,7 @@ static int a9mp_priv_init(SysBusDevice *dev) s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); qdev_init_nofail(s->mptimer); - busdev = sysbus_from_qdev(s->mptimer); + busdev = SYS_BUS_DEVICE(s->mptimer); /* Memory map (addresses are offsets from PERIPHBASE): * 0x0000-0x00ff -- Snoop Control Unit diff --git a/hw/apb_pci.c b/hw/apb_pci.c index b9a7ee6a31..7eb0c2bbcb 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -365,7 +365,7 @@ PCIBus *pci_apb_init(hwaddr special_base, /* Ultrasparc PBM main bus */ dev = qdev_create(NULL, "pbm"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); /* apb_config */ sysbus_mmio_map(s, 0, special_base); /* PCI configuration space */ diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index 469f6bfdee..324e503dd9 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -83,8 +83,8 @@ static void mpcore_priv_set_irq(void *opaque, int irq, int level) static void mpcore_priv_map_setup(mpcore_priv_state *s) { int i; - SysBusDevice *gicbusdev = sysbus_from_qdev(s->gic); - SysBusDevice *busdev = sysbus_from_qdev(s->mptimer); + SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic); + SysBusDevice *busdev = SYS_BUS_DEVICE(s->mptimer); memory_region_init(&s->container, "mpcode-priv-container", 0x2000); memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100); memory_region_add_subregion(&s->container, 0, &s->iomem); @@ -131,7 +131,7 @@ static int mpcore_priv_init(SysBusDevice *dev) qdev_init_nofail(s->gic); /* Pass through outbound IRQ lines from the GIC */ - sysbus_pass_irq(dev, sysbus_from_qdev(s->gic)); + sysbus_pass_irq(dev, SYS_BUS_DEVICE(s->gic)); /* Pass through inbound GPIO lines to the GIC */ qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32); @@ -190,7 +190,7 @@ static int realview_mpcore_init(SysBusDevice *dev) priv = qdev_create(NULL, "arm11mpcore_priv"); qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu); qdev_init_nofail(priv); - s->priv = sysbus_from_qdev(priv); + s->priv = SYS_BUS_DEVICE(priv); sysbus_pass_irq(dev, s->priv); for (i = 0; i < 32; i++) { s->cpuic[i] = qdev_get_gpio_in(priv, i); diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 41799ad765..40e8dd7045 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -123,7 +123,7 @@ static int arm_gic_common_init(SysBusDevice *dev) static void arm_gic_common_reset(DeviceState *dev) { - GICState *s = FROM_SYSBUS(GICState, sysbus_from_qdev(dev)); + GICState *s = FROM_SYSBUS(GICState, SYS_BUS_DEVICE(dev)); int i; memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < s->num_cpu; i++) { diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index cdfd62363e..32817d3814 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -238,7 +238,7 @@ static void timerblock_reset(timerblock *tb) static void arm_mptimer_reset(DeviceState *dev) { arm_mptimer_state *s = - FROM_SYSBUS(arm_mptimer_state, sysbus_from_qdev(dev)); + FROM_SYSBUS(arm_mptimer_state, SYS_BUS_DEVICE(dev)); int i; /* We reset every timer in the array, not just the ones we're using, * because vmsave will look at every array element. diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index a196fcc4aa..755a5df2c9 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -75,7 +75,7 @@ static int board_id(arm_sysctl_state *s) static void arm_sysctl_reset(DeviceState *d) { - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sysbus_from_qdev(d)); + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); s->leds = 0; s->lockval = 0; diff --git a/hw/armv7m.c b/hw/armv7m.c index 98fe483c25..904696ca7f 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -137,12 +137,12 @@ static void armv7m_bitband_init(void) dev = qdev_create(NULL, "ARM,bitband-memory"); qdev_prop_set_uint32(dev, "base", 0x20000000); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x22000000); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x22000000); dev = qdev_create(NULL, "ARM,bitband-memory"); qdev_prop_set_uint32(dev, "base", 0x40000000); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0x42000000); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x42000000); } /* Board init. */ @@ -216,7 +216,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, env->nvic = nvic; qdev_init_nofail(nvic); cpu_pic = arm_pic_init_cpu(cpu); - sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); + sysbus_connect_irq(SYS_BUS_DEVICE(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); for (i = 0; i < 64; i++) { pic[i] = qdev_get_gpio_in(nvic, i); } diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index 941898158c..dd37fa13e2 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -300,7 +300,7 @@ void axisdev88_init(QEMUMachineInitArgs *args) /* FIXME: Is there a proper way to signal vectors to the CPU core? */ qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, 0x3001c000); sysbus_connect_irq(s, 0, cpu_irq[0]); sysbus_connect_irq(s, 1, cpu_irq[1]); diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 2beee6268e..0d834422df 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -959,7 +959,7 @@ static void gem_phy_reset(GemState *s) static void gem_reset(DeviceState *d) { - GemState *s = FROM_SYSBUS(GemState, sysbus_from_qdev(d)); + GemState *s = FROM_SYSBUS(GemState, SYS_BUS_DEVICE(d)); DB_PRINT("\n"); diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 3cb6ccb27d..d7b54973a4 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -56,7 +56,7 @@ void empty_slot_init(hwaddr addr, uint64_t slot_size) EmptySlot *e; dev = qdev_create(NULL, "empty_slot"); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); e = FROM_SYSBUS(EmptySlot, s); e->size = slot_size; diff --git a/hw/escc.c b/hw/escc.c index c81088b22f..18c02921e3 100644 --- a/hw/escc.c +++ b/hw/escc.c @@ -700,7 +700,7 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, qdev_prop_set_uint32(dev, "chnBtype", ser); qdev_prop_set_uint32(dev, "chnAtype", ser); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irqB); sysbus_connect_irq(s, 1, irqA); if (base) { @@ -861,7 +861,7 @@ void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, qdev_prop_set_uint32(dev, "chnBtype", mouse); qdev_prop_set_uint32(dev, "chnAtype", kbd); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); sysbus_connect_irq(s, 1, irq); sysbus_mmio_map(s, 0, base); diff --git a/hw/esp.c b/hw/esp.c index 0e4e430880..2af48aac4b 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -633,7 +633,7 @@ void esp_init(hwaddr espaddr, int it_shift, /* XXX for now until rc4030 has been changed to use DMA enable signal */ esp->dma_enabled = 1; qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); sysbus_mmio_map(s, 0, espaddr); *reset = qdev_get_gpio_in(dev, 0); diff --git a/hw/etraxfs.h b/hw/etraxfs.h index cc1d7a17a0..180de5a088 100644 --- a/hw/etraxfs.h +++ b/hw/etraxfs.h @@ -44,7 +44,7 @@ etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr, qdev_prop_set_ptr(dev, "dma_out", dma_out); qdev_prop_set_ptr(dev, "dma_in", dma_in); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; } diff --git a/hw/exynos4210.c b/hw/exynos4210.c index 246a0fc1c3..fa54e42a47 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -154,7 +154,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { gate_irq[i][n] = qdev_get_gpio_in(dev, n); } - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); /* Connect IRQ Gate output to cpu_irq */ sysbus_connect_irq(busdev, 0, cpu_irq[i]); @@ -164,7 +164,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, dev = qdev_create(NULL, "a9mpcore_priv"); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); for (n = 0; n < EXYNOS4210_NCPUS; n++) { sysbus_connect_irq(busdev, n, gate_irq[n][0]); @@ -180,7 +180,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, dev = qdev_create(NULL, "exynos4210.gic"); qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); /* Map CPU interface */ sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); /* Map Distributer interface */ @@ -195,7 +195,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, /* Internal Interrupt Combiner */ dev = qdev_create(NULL, "exynos4210.combiner"); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); } @@ -206,7 +206,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, dev = qdev_create(NULL, "exynos4210.combiner"); qdev_prop_set_uint32(dev, "external", 1); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); } @@ -285,7 +285,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, /* Multi Core Timer */ dev = qdev_create(NULL, "exynos4210.mct"); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); for (n = 0; n < 4; n++) { /* Connect global timer interrupts to Combiner gpio_in */ sysbus_connect_irq(busdev, n, @@ -311,7 +311,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem, dev = qdev_create(NULL, "exynos4210.i2c"); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, i2c_irq); sysbus_mmio_map(busdev, 0, addr); s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c"); diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index f67906e42f..94b138fa46 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -290,7 +290,7 @@ static int exynos4210_gic_init(SysBusDevice *dev) qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); qdev_init_nofail(s->gic); - busdev = sysbus_from_qdev(s->gic); + busdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ sysbus_pass_irq(dev, busdev); diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index adaab242fe..bdf797a029 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -615,7 +615,7 @@ DeviceState *exynos4210_uart_create(hwaddr addr, qdev_prop_set_uint32(dev, "rx-size", fifo_size); qdev_prop_set_uint32(dev, "tx-size", fifo_size); - bus = sysbus_from_qdev(dev); + bus = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); if (addr != (hwaddr)-1) { sysbus_mmio_map(bus, 0, addr); diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index 968bcc3c32..b59e6aabf3 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -87,7 +87,7 @@ static void lan9215_init(uint32_t base, qemu_irq irq) qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint32(dev, "mode_16bit", 1); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 3b31d77f3f..e4dc7c3c31 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -489,7 +489,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port); qdev_prop_set_uint32(dev, "data_iobase", data_port); qdev_init_nofail(dev); - d = sysbus_from_qdev(dev); + d = SYS_BUS_DEVICE(dev); s = DO_UPCAST(FWCfgState, busdev.qdev, dev); diff --git a/hw/grlib.h b/hw/grlib.h index 35c22f5994..afd53892b0 100644 --- a/hw/grlib.h +++ b/hw/grlib.h @@ -61,7 +61,7 @@ DeviceState *grlib_irqmp_create(hwaddr base, env->irq_manager = dev; - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq, dev, @@ -91,10 +91,10 @@ DeviceState *grlib_gptimer_create(hwaddr base, return NULL; } - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < nr_timers; i++) { - sysbus_connect_irq(sysbus_from_qdev(dev), i, cpu_irqs[base_irq + i]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, cpu_irqs[base_irq + i]); } return dev; @@ -116,9 +116,9 @@ DeviceState *grlib_apbuart_create(hwaddr base, return NULL; } - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index b5427c8039..ef8dd95ac9 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -109,7 +109,7 @@ void grlib_irqmp_ack(DeviceState *dev, int intno) assert(dev != NULL); - sdev = sysbus_from_qdev(dev); + sdev = SYS_BUS_DEVICE(dev); assert(sdev != NULL); irqmp = FROM_SYSBUS(typeof(*irqmp), sdev); @@ -138,7 +138,7 @@ void grlib_irqmp_set_irq(void *opaque, int irq, int level) assert(opaque != NULL); - irqmp = FROM_SYSBUS(typeof(*irqmp), sysbus_from_qdev(opaque)); + irqmp = FROM_SYSBUS(typeof(*irqmp), SYS_BUS_DEVICE(opaque)); assert(irqmp != NULL); s = irqmp->state; diff --git a/hw/highbank.c b/hw/highbank.c index 7bc6b444cc..defcc092b4 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -136,7 +136,7 @@ static VMStateDescription vmstate_highbank_regs = { static void highbank_regs_reset(DeviceState *dev) { - SysBusDevice *sys_dev = sysbus_from_qdev(dev); + SysBusDevice *sys_dev = SYS_BUS_DEVICE(dev); HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev); s->regs[0x40] = 0x05F20121; @@ -251,7 +251,7 @@ static void highbank_init(QEMUMachineInitArgs *args) qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR); for (n = 0; n < smp_cpus; n++) { sysbus_connect_irq(busdev, n, cpu_irq[n]); @@ -263,21 +263,21 @@ static void highbank_init(QEMUMachineInitArgs *args) dev = qdev_create(NULL, "l2x0"); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff12000); dev = qdev_create(NULL, "sp804"); qdev_prop_set_uint32(dev, "freq0", 150000000); qdev_prop_set_uint32(dev, "freq1", 150000000); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff34000); sysbus_connect_irq(busdev, 0, pic[18]); sysbus_create_simple("pl011", 0xfff36000, pic[20]); dev = qdev_create(NULL, "highbank-regs"); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff3c000); sysbus_create_simple("pl061", 0xfff30000, pic[14]); @@ -294,19 +294,19 @@ static void highbank_init(QEMUMachineInitArgs *args) dev = qdev_create(NULL, "xgmac"); qdev_set_nic_properties(dev, &nd_table[0]); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff50000); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[77]); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[78]); - sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[79]); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff50000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[77]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[78]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[79]); qemu_check_nic_model(&nd_table[1], "xgmac"); dev = qdev_create(NULL, "xgmac"); qdev_set_nic_properties(dev, &nd_table[1]); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff51000); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[80]); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[81]); - sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[82]); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xfff51000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[80]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, pic[81]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, pic[82]); } highbank_binfo.ram_size = ram_size; diff --git a/hw/hpet.c b/hw/hpet.c index 6efae55eee..97eaa2f700 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -634,7 +634,7 @@ static const MemoryRegionOps hpet_ram_ops = { static void hpet_reset(DeviceState *d) { - HPETState *s = FROM_SYSBUS(HPETState, sysbus_from_qdev(d)); + HPETState *s = FROM_SYSBUS(HPETState, SYS_BUS_DEVICE(d)); int i; for (i = 0; i < s->num_timers; i++) { @@ -657,7 +657,7 @@ static void hpet_reset(DeviceState *d) s->hpet_offset = 0ULL; s->config = 0ULL; hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability; - hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr; + hpet_cfg.hpet[s->hpet_id].address = SYS_BUS_DEVICE(d)->mmio[0].addr; /* to document that the RTC lowers its output on reset as well */ s->rtc_irq_level = 0; diff --git a/hw/imx_serial.c b/hw/imx_serial.c index 77ed693a0c..2d8253e0ee 100644 --- a/hw/imx_serial.c +++ b/hw/imx_serial.c @@ -425,7 +425,7 @@ void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq) } qdev_prop_set_chr(dev, "chardev", chr); - bus = sysbus_from_qdev(dev); + bus = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); if (addr != (hwaddr)-1) { sysbus_mmio_map(bus, 0, addr); diff --git a/hw/lan9118.c b/hw/lan9118.c index 969b634d47..6596979d8b 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -401,7 +401,7 @@ static void phy_reset(lan9118_state *s) static void lan9118_reset(DeviceState *d) { - lan9118_state *s = FROM_SYSBUS(lan9118_state, sysbus_from_qdev(d)); + lan9118_state *s = FROM_SYSBUS(lan9118_state, SYS_BUS_DEVICE(d)); s->irq_cfg &= (IRQ_TYPE | IRQ_POL); s->int_sts = 0; s->int_en = 0; @@ -1391,7 +1391,7 @@ void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq) dev = qdev_create(NULL, "lan9118"); qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } diff --git a/hw/lm32.h b/hw/lm32.h index 4194c9a813..236686ef2b 100644 --- a/hw/lm32.h +++ b/hw/lm32.h @@ -11,7 +11,7 @@ static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) dev = qdev_create(NULL, "lm32-pic"); qdev_init_nofail(dev); - d = sysbus_from_qdev(dev); + d = SYS_BUS_DEVICE(dev); sysbus_connect_irq(d, 0, cpu_irq); return dev; diff --git a/hw/m48t59.c b/hw/m48t59.c index 8f1ca3cccd..427d95b5a6 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -646,7 +646,7 @@ M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base, qdev_prop_set_uint32(dev, "size", size); qdev_prop_set_uint32(dev, "io_base", io_base); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); d = FROM_SYSBUS(M48t59SysBusState, s); state = &d->state; sysbus_connect_irq(s, 0, IRQ); diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index 511004b94e..c792caf271 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -222,7 +222,7 @@ static void mv88w8618_audio_write(void *opaque, hwaddr offset, static void mv88w8618_audio_reset(DeviceState *d) { mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, - sysbus_from_qdev(d)); + SYS_BUS_DEVICE(d)); s->playback_mode = 0; s->status = 0; diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h index 812ddd2bd1..c8bd7e93dd 100644 --- a/hw/milkymist-hw.h +++ b/hw/milkymist-hw.h @@ -12,8 +12,8 @@ static inline DeviceState *milkymist_uart_create(hwaddr base, dev = qdev_create(NULL, "milkymist-uart"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } @@ -24,7 +24,7 @@ static inline DeviceState *milkymist_hpdmc_create(hwaddr base) dev = qdev_create(NULL, "milkymist-hpdmc"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; } @@ -35,7 +35,7 @@ static inline DeviceState *milkymist_memcard_create(hwaddr base) dev = qdev_create(NULL, "milkymist-memcard"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; } @@ -49,7 +49,7 @@ static inline DeviceState *milkymist_vgafb_create(hwaddr base, qdev_prop_set_uint32(dev, "fb_offset", fb_offset); qdev_prop_set_uint32(dev, "fb_mask", fb_mask); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); return dev; } @@ -67,10 +67,10 @@ static inline DeviceState *milkymist_sysctl_create(hwaddr base, qdev_prop_set_uint32(dev, "capabilities", capabilities); qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, gpio_irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, timer0_irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 2, timer1_irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq); return dev; } @@ -82,8 +82,8 @@ static inline DeviceState *milkymist_pfpu_create(hwaddr base, dev = qdev_create(NULL, "milkymist-pfpu"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } @@ -144,8 +144,8 @@ static inline DeviceState *milkymist_tmu2_create(hwaddr base, dev = qdev_create(NULL, "milkymist-tmu2"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; #else @@ -161,11 +161,11 @@ static inline DeviceState *milkymist_ac97_create(hwaddr base, dev = qdev_create(NULL, "milkymist-ac97"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, crrequest_irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, crreply_irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 2, dmar_irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 3, dmaw_irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq); return dev; } @@ -179,9 +179,9 @@ static inline DeviceState *milkymist_minimac_create(hwaddr base, dev = qdev_create(NULL, "milkymist-minimac"); qdev_set_nic_properties(dev, &nd_table[0]); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq); return dev; } @@ -196,9 +196,9 @@ static inline DeviceState *milkymist_minimac2_create(hwaddr base, qdev_prop_set_taddr(dev, "buffers_base", buffers_base); qdev_set_nic_properties(dev, &nd_table[0]); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq); return dev; } @@ -215,8 +215,8 @@ static inline DeviceState *milkymist_softusb_create(hwaddr base, qdev_prop_set_uint32(dev, "dmem_base", dmem_base); qdev_prop_set_uint32(dev, "dmem_size", dmem_size); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 72f70cae52..17fbdde063 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -209,7 +209,7 @@ static void mips_jazz_init(MemoryRegion *address_space, case JAZZ_MAGNUM: dev = qdev_create(NULL, "sysbus-g364"); qdev_init_nofail(dev); - sysbus = sysbus_from_qdev(dev); + sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x60080000); sysbus_mmio_map(sysbus, 1, 0x40000000); sysbus_connect_irq(sysbus, 0, rc4030[3]); @@ -295,7 +295,7 @@ static void mips_jazz_init(MemoryRegion *address_space, /* NVRAM */ dev = qdev_create(NULL, "ds1225y"); qdev_init_nofail(dev); - sysbus = sysbus_from_qdev(dev); + sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x80009000); /* LED indicator */ diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index 8fd6692e82..b0ab8f69e2 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -123,7 +123,7 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd) qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); memory_region_add_subregion(get_system_io(), base, diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c index 9c57d7665f..728723c946 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -112,7 +112,7 @@ static int mpc8544_guts_initfn(SysBusDevice *dev) { GutsState *s; - s = FROM_SYSBUS(GutsState, sysbus_from_qdev(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); diff --git a/hw/musicpal.c b/hw/musicpal.c index 035865f058..7ac0a918fb 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -716,7 +716,7 @@ static void mv88w8618_pic_write(void *opaque, hwaddr offset, static void mv88w8618_pic_reset(DeviceState *d) { mv88w8618_pic_state *s = FROM_SYSBUS(mv88w8618_pic_state, - sysbus_from_qdev(d)); + SYS_BUS_DEVICE(d)); s->level = 0; s->enabled = 0; @@ -873,7 +873,7 @@ static void mv88w8618_pit_write(void *opaque, hwaddr offset, static void mv88w8618_pit_reset(DeviceState *d) { mv88w8618_pit_state *s = FROM_SYSBUS(mv88w8618_pit_state, - sysbus_from_qdev(d)); + SYS_BUS_DEVICE(d)); int i; for (i = 0; i < 4; i++) { @@ -1288,7 +1288,7 @@ static const MemoryRegionOps musicpal_gpio_ops = { static void musicpal_gpio_reset(DeviceState *d) { musicpal_gpio_state *s = FROM_SYSBUS(musicpal_gpio_state, - sysbus_from_qdev(d)); + SYS_BUS_DEVICE(d)); s->lcd_brightness = 0; s->out_state = 0; @@ -1607,12 +1607,12 @@ static void musicpal_init(QEMUMachineInitArgs *args) dev = qdev_create(NULL, "mv88w8618_eth"); qdev_set_nic_properties(dev, &nd_table[0]); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, MP_ETH_BASE); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[MP_ETH_IRQ]); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, MP_ETH_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[MP_ETH_IRQ]); sysbus_create_simple("mv88w8618_wlan", MP_WLAN_BASE, NULL); - musicpal_misc_init(sysbus_from_qdev(dev)); + musicpal_misc_init(SYS_BUS_DEVICE(dev)); dev = sysbus_create_simple("musicpal_gpio", MP_GPIO_BASE, pic[MP_GPIO_IRQ]); i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL); @@ -1641,7 +1641,7 @@ static void musicpal_init(QEMUMachineInitArgs *args) wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR); dev = qdev_create(NULL, "mv88w8618_audio"); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); qdev_prop_set_ptr(dev, "wm8750", wm8750_dev); qdev_init_nofail(dev); sysbus_mmio_map(s, 0, MP_AUDIO_BASE); diff --git a/hw/nand.c b/hw/nand.c index 6054f46581..4a71265ed3 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -224,7 +224,7 @@ static const struct { static void nand_reset(DeviceState *dev) { - NANDFlashState *s = FROM_SYSBUS(NANDFlashState, sysbus_from_qdev(dev)); + NANDFlashState *s = FROM_SYSBUS(NANDFlashState, SYS_BUS_DEVICE(dev)); s->cmd = NAND_CMD_READ0; s->addr = 0; s->addrlen = 0; diff --git a/hw/nseries.c b/hw/nseries.c index 6b717cfe1e..99d353aaa9 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -178,10 +178,10 @@ static void n8x0_nand_setup(struct n800_s *s) qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv); } qdev_init_nofail(s->nand); - sysbus_connect_irq(sysbus_from_qdev(s->nand), 0, + sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0, qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO)); omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS, - sysbus_mmio_get_region(sysbus_from_qdev(s->nand), 0)); + sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0)); otp_region = onenand_raw_otp(s->nand); memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac)); @@ -783,7 +783,7 @@ static void n8x0_usb_setup(struct n800_s *s) { SysBusDevice *dev; s->usb = qdev_create(NULL, "tusb6010"); - dev = sysbus_from_qdev(s->usb); + dev = SYS_BUS_DEVICE(s->usb); qdev_init_nofail(s->usb); sysbus_connect_irq(dev, 0, qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO)); diff --git a/hw/omap1.c b/hw/omap1.c index e85f2e2423..1870f4dfed 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -3859,7 +3859,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, qdev_prop_set_uint32(s->ih[0], "size", 0x100); qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck")); qdev_init_nofail(s->ih[0]); - busdev = sysbus_from_qdev(s->ih[0]); + busdev = SYS_BUS_DEVICE(s->ih[0]); sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); sysbus_mmio_map(busdev, 0, 0xfffecb00); @@ -3867,7 +3867,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, qdev_prop_set_uint32(s->ih[1], "size", 0x800); qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck")); qdev_init_nofail(s->ih[1]); - busdev = sysbus_from_qdev(s->ih[1]); + busdev = SYS_BUS_DEVICE(s->ih[1]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ)); /* The second interrupt controller's FIQ output is not wired up */ @@ -3980,9 +3980,9 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck")); qdev_init_nofail(s->gpio); - sysbus_connect_irq(sysbus_from_qdev(s->gpio), 0, + sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1)); - sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000); + sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000); s->microwire = omap_uwire_init(system_memory, 0xfffb3000, qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX), @@ -3998,7 +3998,7 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, qdev_prop_set_uint8(s->i2c[0], "revision", 0x11); qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck")); qdev_init_nofail(s->i2c[0]); - busdev = sysbus_from_qdev(s->i2c[0]); + busdev = SYS_BUS_DEVICE(s->i2c[0]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C)); sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]); sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]); diff --git a/hw/omap2.c b/hw/omap2.c index c8358500bc..038a82a517 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -2283,7 +2283,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, qdev_prop_set_ptr(s->ih[0], "fclk", omap_findclk(s, "mpu_intc_fclk")); qdev_prop_set_ptr(s->ih[0], "iclk", omap_findclk(s, "mpu_intc_iclk")); qdev_init_nofail(s->ih[0]); - busdev = sysbus_from_qdev(s->ih[0]); + busdev = SYS_BUS_DEVICE(s->ih[0]); sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]); sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]); sysbus_mmio_map(busdev, 0, 0x480fe000); @@ -2398,7 +2398,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk")); qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk")); qdev_init_nofail(s->i2c[0]); - busdev = sysbus_from_qdev(s->i2c[0]); + busdev = SYS_BUS_DEVICE(s->i2c[0]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ)); sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]); @@ -2410,7 +2410,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk")); qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk")); qdev_init_nofail(s->i2c[1]); - busdev = sysbus_from_qdev(s->i2c[1]); + busdev = SYS_BUS_DEVICE(s->i2c[1]); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ)); sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]); @@ -2428,7 +2428,7 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk")); } qdev_init_nofail(s->gpio); - busdev = sysbus_from_qdev(s->gpio); + busdev = SYS_BUS_DEVICE(s->gpio); sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1)); sysbus_connect_irq(busdev, 3, diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index 15bdd629bf..aadf1cc59f 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -588,7 +588,7 @@ static const MemoryRegionOps omap2_gpio_module_ops = { static void omap_gpif_reset(DeviceState *dev) { struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, - sysbus_from_qdev(dev)); + SYS_BUS_DEVICE(dev)); omap_gpio_reset(&s->omap1); } @@ -596,7 +596,7 @@ static void omap2_gpif_reset(DeviceState *dev) { int i; struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, - sysbus_from_qdev(dev)); + SYS_BUS_DEVICE(dev)); for (i = 0; i < s->modulecount; i++) { omap2_gpio_module_reset(&s->modules[i]); } diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index e0a5087f37..143b198f1d 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -131,7 +131,7 @@ static void omap_i2c_fifo_run(OMAPI2CState *s) static void omap_i2c_reset(DeviceState *dev) { OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, - sysbus_from_qdev(dev)); + SYS_BUS_DEVICE(dev)); s->mask = 0; s->stat = 0; s->dma = 0; @@ -485,7 +485,7 @@ static void omap_i2c_register_types(void) i2c_bus *omap_i2c_bus(DeviceState *omap_i2c) { - OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, sysbus_from_qdev(omap_i2c)); + OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, SYS_BUS_DEVICE(omap_i2c)); return s->bus; } diff --git a/hw/omap_intc.c b/hw/omap_intc.c index 113725ef98..4b0acd0f33 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -329,7 +329,7 @@ static const MemoryRegionOps omap_inth_mem_ops = { static void omap_inth_reset(DeviceState *dev) { struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s, - sysbus_from_qdev(dev)); + SYS_BUS_DEVICE(dev)); int i; for (i = 0; i < s->nbanks; ++i){ diff --git a/hw/onenand.c b/hw/onenand.c index b82bf7d333..00a8738caf 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -224,7 +224,7 @@ static void onenand_reset(OneNANDState *s, int cold) static void onenand_system_reset(DeviceState *dev) { - onenand_reset(FROM_SYSBUS(OneNANDState, sysbus_from_qdev(dev)), 1); + onenand_reset(FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(dev)), 1); } static inline int onenand_load_main(OneNANDState *s, int sec, int secn, @@ -835,7 +835,7 @@ static void onenand_register_types(void) void *onenand_raw_otp(DeviceState *onenand_device) { - return FROM_SYSBUS(OneNANDState, sysbus_from_qdev(onenand_device))->otp; + return FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(onenand_device))->otp; } type_init(onenand_register_types) diff --git a/hw/openpic.c b/hw/openpic.c index cc8ec35b5d..d414f47b7d 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -506,7 +506,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), sysbus_from_qdev(d)); + OpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d)); int i; opp->gcr = GCR_RESET; diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index 6c443ba804..30947dee6e 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -50,7 +50,7 @@ static void openrisc_sim_net_init(MemoryRegion *address_space, qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); memory_region_add_subregion(address_space, base, sysbus_mmio_get_region(s, 0)); diff --git a/hw/pc.c b/hw/pc.c index 8fc69dbe0a..780b1e4743 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1019,7 +1019,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, if (hpet) { for (i = 0; i < GSI_NUM_PINS; i++) { - sysbus_connect_irq(sysbus_from_qdev(hpet), i, gsi[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]); } pit_isa_irq = -1; pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT); @@ -1122,7 +1122,7 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name) "ioapic", OBJECT(dev), NULL); } qdev_init_nofail(dev); - d = sysbus_from_qdev(dev); + d = SYS_BUS_DEVICE(dev); sysbus_mmio_map(d, 0, 0xfec00000); for (i = 0; i < IOAPIC_NUM_PINS; i++) { diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index 9cad07476e..bdfc6ce365 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -147,7 +147,7 @@ petalogix_ml605_init(QEMUMachineInitArgs *args) dev = qdev_create(NULL, "xlnx.xps-spi"); qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0x40a00000); sysbus_connect_irq(busdev, 0, irq[4]); diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index aadedefb25..9e6ff52336 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -729,7 +729,7 @@ pflash_t *pflash_cfi01_register(hwaddr base, uint16_t id2, uint16_t id3, int be) { DeviceState *dev = qdev_create(NULL, "cfi.pflash01"); - SysBusDevice *busdev = sysbus_from_qdev(dev); + SysBusDevice *busdev = SYS_BUS_DEVICE(dev); pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev), "cfi.pflash01"); diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index cfb91cb143..b4220c1896 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -760,7 +760,7 @@ pflash_t *pflash_cfi02_register(hwaddr base, int be) { DeviceState *dev = qdev_create(NULL, "cfi.pflash02"); - SysBusDevice *busdev = sysbus_from_qdev(dev); + SysBusDevice *busdev = SYS_BUS_DEVICE(dev); pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev), "cfi.pflash02"); diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index c36821a99f..9ccf4d1840 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -547,7 +547,7 @@ void ppce500_init(PPCE500Params *params) qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_FSL_MPIC_20); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); k = 0; for (i = 0; i < smp_cpus; i++) { @@ -599,7 +599,7 @@ void ppce500_init(PPCE500Params *params) if (!pci_bus) printf("couldn't create PCI controller!\n"); - sysbus_mmio_map(sysbus_from_qdev(dev), 1, MPC8544_PCI_IO); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO); if (pci_bus) { /* Register network interfaces. */ diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index 7a465a7ebb..b1973f18ff 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -329,7 +329,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) dev = qdev_create(NULL, "openpic"); qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); pic_mem = s->mmio[0].memory; k = 0; for (i = 0; i < smp_cpus; i++) { diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 4c206e2834..7e90fb9824 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -196,7 +196,7 @@ static int ppce500_spin_initfn(SysBusDevice *dev) { SpinState *s; - s = FROM_SYSBUS(SpinState, sysbus_from_qdev(dev)); + s = FROM_SYSBUS(SpinState, SYS_BUS_DEVICE(dev)); memory_region_init_io(&s->iomem, &spin_rw_ops, s, "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS); diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 492805f2fa..2367c6a4a4 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1456,7 +1456,7 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, SysBusDevice *i2c_dev; PXA2xxI2CState *s; - i2c_dev = sysbus_from_qdev(qdev_create(NULL, "pxa2xx_i2c")); + i2c_dev = SYS_BUS_DEVICE(qdev_create(NULL, "pxa2xx_i2c")); qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1); qdev_prop_set_uint32(&i2c_dev->qdev, "offset", base & region_size); diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 693b1c23d9..c0dba45752 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -481,8 +481,8 @@ DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq) qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } @@ -495,8 +495,8 @@ DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq) qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index eec2ea3f1c..05d2ad2add 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -260,12 +260,12 @@ DeviceState *pxa2xx_gpio_init(hwaddr base, qdev_prop_set_int32(dev, "ncpu", cs->cpu_index); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0)); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1)); - sysbus_connect_irq(sysbus_from_qdev(dev), 2, + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X)); return dev; @@ -297,7 +297,7 @@ static int pxa2xx_gpio_initfn(SysBusDevice *dev) */ void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler) { - PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, sysbus_from_qdev(dev)); + PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, SYS_BUS_DEVICE(dev)); s->read_notify = handler; } diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index 138245b0f9..90b8fef3f9 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -261,7 +261,7 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) { CPUARMState *env = &cpu->env; DeviceState *dev = qdev_create(NULL, "pxa2xx_pic"); - PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, sysbus_from_qdev(dev)); + PXA2xxPICState *s = FROM_SYSBUS(PXA2xxPICState, SYS_BUS_DEVICE(dev)); s->cpu = cpu; @@ -279,8 +279,8 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) /* Enable IC memory-mapped registers access. */ memory_region_init_io(&s->iomem, &pxa2xx_pic_ops, s, "pxa2xx-pic", 0x00100000); - sysbus_init_mmio(sysbus_from_qdev(dev), &s->iomem); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); /* Enable IC coprocessor access. */ define_arm_cp_regs_with_opaque(arm_env_get_cpu(env), pxa_pic_cp_reginfo, s); diff --git a/hw/r2d.c b/hw/r2d.c index 72b593f597..a2e3b6fe1c 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -262,7 +262,7 @@ static void r2d_init(QEMUMachineInitArgs *args) irq = r2d_fpga_init(address_space_mem, 0x04000000, sh7750_irl(s)); dev = qdev_create(NULL, "sh_pci"); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000)); sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000)); diff --git a/hw/realview.c b/hw/realview.c index cecb67e4d5..78da7676c4 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -140,14 +140,14 @@ static void realview_init(QEMUMachineInitArgs *args, qdev_prop_set_uint32(sysctl, "sys_id", sys_id); qdev_prop_set_uint32(sysctl, "proc_id", proc_id); qdev_init_nofail(sysctl); - sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); + sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); if (is_mpcore) { hwaddr periphbase; dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); if (is_pb) { periphbase = 0x1f000000; } else { @@ -172,8 +172,8 @@ static void realview_init(QEMUMachineInitArgs *args, pl041 = qdev_create(NULL, "pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); qdev_init_nofail(pl041); - sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000); - sysbus_connect_irq(sysbus_from_qdev(pl041), 0, pic[19]); + sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); + sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[19]); sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]); @@ -215,7 +215,7 @@ static void realview_init(QEMUMachineInitArgs *args, if (!is_pb) { dev = qdev_create(NULL, "realview_pci"); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); sysbus_mmio_map(busdev, 0, 0x61000000); /* PCI self-config */ sysbus_mmio_map(busdev, 1, 0x62000000); /* PCI config */ diff --git a/hw/realview_gic.c b/hw/realview_gic.c index b1b74d8e9c..8f2a7e2f34 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -35,7 +35,7 @@ static int realview_gic_init(SysBusDevice *dev) qdev_prop_set_uint32(s->gic, "num-cpu", 1); qdev_prop_set_uint32(s->gic, "num-irq", numirq); qdev_init_nofail(s->gic); - busdev = sysbus_from_qdev(s->gic); + busdev = SYS_BUS_DEVICE(s->gic); /* Pass through outbound IRQ lines from the GIC */ sysbus_pass_irq(dev, busdev); diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index d67c8ccc9f..136ceebc80 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -210,7 +210,7 @@ void slavio_pic_info(Monitor *mon, DeviceState *dev) SLAVIO_INTCTLState *s; int i; - sd = sysbus_from_qdev(dev); + sd = SYS_BUS_DEVICE(dev); s = FROM_SYSBUS(SLAVIO_INTCTLState, sd); for (i = 0; i < MAX_CPUS; i++) { monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, @@ -230,7 +230,7 @@ void slavio_irq_info(Monitor *mon, DeviceState *dev) int i; int64_t count; - sd = sysbus_from_qdev(dev); + sd = SYS_BUS_DEVICE(dev); s = FROM_SYSBUS(SLAVIO_INTCTLState, sd); monitor_printf(mon, "IRQ statistics:\n"); for (i = 0; i < 32; i++) { diff --git a/hw/sm501.c b/hw/sm501.c index dd186aa7f2..b7ac7f9bff 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -1428,9 +1428,9 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, qdev_prop_set_uint32(dev, "num-ports", 2); qdev_prop_set_taddr(dev, "dma-offset", base); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base + MMIO_BASE_OFFSET + SM501_USB_HOST); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); /* bridge to serial emulation module */ if (chr) { diff --git a/hw/smc91c111.c b/hw/smc91c111.c index a34698f9e3..36cb4ed74f 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -254,7 +254,7 @@ static void smc91c111_queue_tx(smc91c111_state *s, int packet) static void smc91c111_reset(DeviceState *dev) { - smc91c111_state *s = FROM_SYSBUS(smc91c111_state, sysbus_from_qdev(dev)); + smc91c111_state *s = FROM_SYSBUS(smc91c111_state, SYS_BUS_DEVICE(dev)); s->bank = 0; s->tx_fifo_len = 0; s->tx_fifo_done_len = 0; @@ -797,7 +797,7 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) dev = qdev_create(NULL, "smc91c111"); qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 27b3ad3d60..bbcc9fc968 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -597,7 +597,7 @@ static int spapr_phb_init(SysBusDevice *s) static void spapr_phb_reset(DeviceState *qdev) { - SysBusDevice *s = sysbus_from_qdev(qdev); + SysBusDevice *s = SYS_BUS_DEVICE(qdev); sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); /* Reset the IOMMU state */ diff --git a/hw/spitz.c b/hw/spitz.c index ab7ca80f6c..5bc49fcd27 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -156,7 +156,7 @@ static void sl_flash_register(PXA2xxState *cpu, int size) qdev_prop_set_uint8(dev, "chip_id", 0xf1); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, FLASH_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); } static int sl_nand_init(SysBusDevice *dev) { @@ -459,7 +459,7 @@ static void spitz_keyboard_register(PXA2xxState *cpu) SpitzKeyboardState *s; dev = sysbus_create_simple("spitz-keyboard", -1, NULL); - s = FROM_SYSBUS(SpitzKeyboardState, sysbus_from_qdev(dev)); + s = FROM_SYSBUS(SpitzKeyboardState, SYS_BUS_DEVICE(dev)); for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i])); diff --git a/hw/stellaris.c b/hw/stellaris.c index b5e78ffb68..9b8f2034f1 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1286,8 +1286,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, enet = qdev_create(NULL, "stellaris_enet"); qdev_set_nic_properties(enet, &nd_table[0]); qdev_init_nofail(enet); - sysbus_mmio_map(sysbus_from_qdev(enet), 0, 0x40048000); - sysbus_connect_irq(sysbus_from_qdev(enet), 0, pic[42]); + sysbus_mmio_map(SYS_BUS_DEVICE(enet), 0, 0x40048000); + sysbus_connect_irq(SYS_BUS_DEVICE(enet), 0, pic[42]); } if (board->peripherals & BP_GAMEPAD) { qemu_irq gpad_irq[5]; diff --git a/hw/strongarm.c b/hw/strongarm.c index af688ac4ca..ab736e300e 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -619,9 +619,9 @@ static DeviceState *strongarm_gpio_init(hwaddr base, dev = qdev_create(NULL, "strongarm-gpio"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); for (i = 0; i < 12; i++) - sysbus_connect_irq(sysbus_from_qdev(dev), i, + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i)); return dev; @@ -1597,9 +1597,9 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, DeviceState *dev = qdev_create(NULL, "strongarm-uart"); qdev_prop_set_chr(dev, "chardev", serial_hds[i]); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, sa_serial[i].io_base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(s->pic, sa_serial[i].irq)); } diff --git a/hw/sun4m.c b/hw/sun4m.c index 41730bc7a8..035a011768 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -381,7 +381,7 @@ static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) dev = qdev_create(NULL, "iommu"); qdev_prop_set_uint32(dev, "version", version); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); sysbus_mmio_map(s, 0, addr); @@ -398,7 +398,7 @@ static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, qdev_prop_set_ptr(dev, "iommu_opaque", iommu); qdev_prop_set_uint32(dev, "is_ledma", is_ledma); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, parent_irq); *dev_irq = qdev_get_gpio_in(dev, 0); sysbus_mmio_map(s, 0, daddr); @@ -419,7 +419,7 @@ static void lance_init(NICInfo *nd, hwaddr leaddr, qdev_set_nic_properties(dev, nd); qdev_prop_set_ptr(dev, "dma", dma_opaque); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, leaddr); sysbus_connect_irq(s, 0, irq); reset = qdev_get_gpio_in(dev, 0); @@ -437,7 +437,7 @@ static DeviceState *slavio_intctl_init(hwaddr addr, dev = qdev_create(NULL, "slavio_intctl"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); for (i = 0; i < MAX_CPUS; i++) { for (j = 0; j < MAX_PILS; j++) { @@ -465,7 +465,7 @@ static void slavio_timer_init_all(hwaddr addr, qemu_irq master_irq, dev = qdev_create(NULL, "slavio_timer"); qdev_prop_set_uint32(dev, "num_cpus", num_cpus); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, master_irq); sysbus_mmio_map(s, 0, addr + SYS_TIMER_OFFSET); @@ -502,7 +502,7 @@ static void slavio_misc_init(hwaddr base, dev = qdev_create(NULL, "slavio_misc"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); if (base) { /* 8 bit registers */ /* Slavio control */ @@ -540,7 +540,7 @@ static void ecc_init(hwaddr base, qemu_irq irq, uint32_t version) dev = qdev_create(NULL, "eccmemctl"); qdev_prop_set_uint32(dev, "version", version); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); sysbus_mmio_map(s, 0, base); if (version == 0) { // SS-600MP only @@ -555,7 +555,7 @@ static void apc_init(hwaddr power_base, qemu_irq cpu_halt) dev = qdev_create(NULL, "apc"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); /* Power management (APC) XXX: not a Slavio device */ sysbus_mmio_map(s, 0, power_base); sysbus_connect_irq(s, 0, cpu_halt); @@ -574,7 +574,7 @@ static void tcx_init(hwaddr addr, int vram_size, int width, qdev_prop_set_uint16(dev, "height", height); qdev_prop_set_uint16(dev, "depth", depth); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); /* 8-bit plane */ sysbus_mmio_map(s, 0, addr + 0x00800000ULL); /* DAC */ @@ -604,7 +604,7 @@ static void idreg_init(hwaddr addr) dev = qdev_create(NULL, "macio_idreg"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); cpu_physical_memory_write_rom(addr, idreg_data, sizeof(idreg_data)); @@ -653,7 +653,7 @@ static void afx_init(hwaddr addr) dev = qdev_create(NULL, "tcx_afx"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); } @@ -703,7 +703,7 @@ static void prom_init(hwaddr addr, const char *bios_name) dev = qdev_create(NULL, "openprom"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); @@ -793,7 +793,7 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size, exit(1); } dev = qdev_create(NULL, "memory"); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); d = FROM_SYSBUS(RamDevice, s); d->size = RAM_size; @@ -1560,7 +1560,7 @@ static DeviceState *sbi_init(hwaddr addr, qemu_irq **parent_irq) dev = qdev_create(NULL, "sbi"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); for (i = 0; i < MAX_CPUS; i++) { sysbus_connect_irq(s, i, *parent_irq[i]); @@ -1761,7 +1761,7 @@ static DeviceState *sun4c_intctl_init(hwaddr addr, dev = qdev_create(NULL, "sun4c_intctl"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); for (i = 0; i < MAX_PILS; i++) { sysbus_connect_irq(s, i, parent_irq[i]); diff --git a/hw/sun4u.c b/hw/sun4u.c index d36acde545..b891b84c9c 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -646,7 +646,7 @@ static void prom_init(hwaddr addr, const char *bios_name) dev = qdev_create(NULL, "openprom"); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, addr); @@ -729,7 +729,7 @@ static void ram_init(hwaddr addr, ram_addr_t RAM_size) /* allocate RAM */ dev = qdev_create(NULL, "memory"); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); d = FROM_SYSBUS(RamDevice, s); d->size = RAM_size; diff --git a/hw/sysbus.c b/hw/sysbus.c index f0ab8a859a..6d9d1df419 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -131,7 +131,7 @@ DeviceState *sysbus_create_varargs(const char *name, int n; dev = qdev_create(NULL, name); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); if (addr != (hwaddr)-1) { sysbus_mmio_map(s, 0, addr); @@ -163,7 +163,7 @@ DeviceState *sysbus_try_create_varargs(const char *name, if (!dev) { return NULL; } - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); if (addr != (hwaddr)-1) { sysbus_mmio_map(s, 0, addr); @@ -184,7 +184,7 @@ DeviceState *sysbus_try_create_varargs(const char *name, static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) { - SysBusDevice *s = sysbus_from_qdev(dev); + SysBusDevice *s = SYS_BUS_DEVICE(dev); hwaddr size; int i; @@ -198,7 +198,7 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) static char *sysbus_get_fw_dev_path(DeviceState *dev) { - SysBusDevice *s = sysbus_from_qdev(dev); + SysBusDevice *s = SYS_BUS_DEVICE(dev); char path[40]; int off; diff --git a/hw/sysbus.h b/hw/sysbus.h index 669cf87ae9..a7fcded6e7 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -44,7 +44,6 @@ struct SysBusDevice { }; /* Macros to compensate for lack of type inheritance in C. */ -#define sysbus_from_qdev(dev) ((SysBusDevice *)(dev)) #define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev) void *sysbus_new(void); diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 7d05b31024..2c7d033651 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -740,7 +740,7 @@ static void tusb6010_irq(void *opaque, int source, int level) static void tusb6010_reset(DeviceState *dev) { - TUSBState *s = FROM_SYSBUS(TUSBState, sysbus_from_qdev(dev)); + TUSBState *s = FROM_SYSBUS(TUSBState, SYS_BUS_DEVICE(dev)); int i; s->test_reset = TUSB_PROD_TEST_RESET_VAL; diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 7a1b20b36c..e0a28f08d3 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -203,7 +203,7 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004); qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000); qdev_init_nofail(sysctl); - sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000); + sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); cpu_pic = arm_pic_init_cpu(cpu); dev = sysbus_create_varargs("pl190", 0x10140000, @@ -214,7 +214,7 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) } dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL); for (n = 0; n < 32; n++) { - sysbus_connect_irq(sysbus_from_qdev(dev), n, pic[n]); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]); sic[n] = qdev_get_gpio_in(dev, n); } @@ -222,7 +222,7 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]); dev = qdev_create(NULL, "versatile_pci"); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); qdev_init_nofail(dev); sysbus_mmio_map(busdev, 0, 0x41000000); /* PCI self-config */ sysbus_mmio_map(busdev, 1, 0x42000000); /* PCI config */ @@ -287,8 +287,8 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id) pl041 = qdev_create(NULL, "pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); qdev_init_nofail(pl041); - sysbus_mmio_map(sysbus_from_qdev(pl041), 0, 0x10004000); - sysbus_connect_irq(sysbus_from_qdev(pl041), 0, sic[24]); + sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000); + sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]); /* Memory map for Versatile/PB: */ /* 0x10000000 System registers. */ diff --git a/hw/vexpress.c b/hw/vexpress.c index 6bbe8c38f9..7f0897c773 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -211,7 +211,7 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, dev = qdev_create(NULL, "a9mpcore_priv"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0x1e000000); for (n = 0; n < smp_cpus; n++) { sysbus_connect_irq(busdev, n, cpu_irq[n]); @@ -307,7 +307,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, dev = qdev_create(NULL, "a15mpcore_priv"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0x2c000000); for (n = 0; n < smp_cpus; n++) { sysbus_connect_irq(busdev, n, cpu_irq[n]); @@ -374,7 +374,7 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, qdev_prop_set_uint32(sysctl, "sys_id", sys_id); qdev_prop_set_uint32(sysctl, "proc_id", proc_id); qdev_init_nofail(sysctl); - sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, map[VE_SYSREGS]); + sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); /* VE_SP810: not modelled */ /* VE_SERIALPCI: not modelled */ @@ -382,8 +382,8 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, pl041 = qdev_create(NULL, "pl041"); qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); qdev_init_nofail(pl041); - sysbus_mmio_map(sysbus_from_qdev(pl041), 0, map[VE_PL041]); - sysbus_connect_irq(sysbus_from_qdev(pl041), 0, pic[11]); + sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); + sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL); /* Wire up MMC card detect and read-only signals */ diff --git a/hw/xilinx.h b/hw/xilinx.h index a12eccbe3c..725f2f4898 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -14,8 +14,8 @@ xilinx_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr) dev = qdev_create(NULL, "xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", kind_of_intr); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } @@ -29,8 +29,8 @@ xilinx_timer_create(hwaddr base, qemu_irq irq, int oto, int freq) qdev_prop_set_uint32(dev, "one-timer-only", oto); qdev_prop_set_uint32(dev, "clock-frequency", freq); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } @@ -48,8 +48,8 @@ xilinx_ethlite_create(NICInfo *nd, hwaddr base, qemu_irq irq, qdev_prop_set_uint32(dev, "tx-ping-pong", txpingpong); qdev_prop_set_uint32(dev, "rx-ping-pong", rxpingpong); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } @@ -71,8 +71,8 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, &errp); assert_no_error(errp); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); return dev; } @@ -90,9 +90,9 @@ xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer, assert_no_error(errp); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); - sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); - sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, irq2); } #endif diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 8dede9fe89..0ac33b5dab 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -46,7 +46,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) dev = qdev_create(NULL, "cadence_gem"); qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, base); sysbus_connect_irq(s, 0, irq); } @@ -67,7 +67,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, qdev_prop_set_uint8(dev, "num-ss-bits", num_ss); qdev_prop_set_uint8(dev, "num-busses", num_busses); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, base_addr); if (is_qspi) { sysbus_mmio_map(busdev, 1, 0xFC000000); @@ -150,12 +150,12 @@ static void zynq_init(QEMUMachineInitArgs *args) dev = qdev_create(NULL, "xilinx,zynq_slcr"); qdev_init_nofail(dev); - sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xF8000000); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); dev = qdev_create(NULL, "a9mpcore_priv"); qdev_prop_set_uint32(dev, "num-cpu", 1); qdev_init_nofail(dev); - busdev = sysbus_from_qdev(dev); + busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xF8F00000); sysbus_connect_irq(busdev, 0, cpu_irq); diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index a85fe9b738..a810b9eae0 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -131,7 +131,7 @@ static void lx60_net_init(MemoryRegion *address_space, qdev_set_nic_properties(dev, nd); qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); + s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, irq); memory_region_add_subregion(address_space, base, sysbus_mmio_get_region(s, 0)); diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 4d6f8d9001..27b00f07d4 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -160,7 +160,7 @@ static void zynq_slcr_reset(DeviceState *d) { int i; ZynqSLCRState *s = - FROM_SYSBUS(ZynqSLCRState, sysbus_from_qdev(d)); + FROM_SYSBUS(ZynqSLCRState, SYS_BUS_DEVICE(d)); DB_PRINT("RESET\n"); diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 333745b456..376d4c8737 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2134,7 +2134,7 @@ static void x86_cpu_apic_init(X86CPU *cpu, Error **errp) /* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ /* XXX: what if the base changes? */ - sysbus_mmio_map(sysbus_from_qdev(env->apic_state), 0, MSI_ADDR_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(env->apic_state), 0, MSI_ADDR_BASE); apic_mapped = 1; } } From f9e90c798dc84be2b0b988517e86b49faf79d5dc Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Thu, 10 Jan 2013 23:02:48 -0200 Subject: [PATCH 0613/1634] vmxcap: bit 9 of VMX_PROCBASED_CTLS2 is 'virtual interrupt delivery' Bit 9 of MSR_IA32_VMX_PROCBASED_CTLS2 is virtual interrupt delivery. Signed-off-by: Marcelo Tosatti --- scripts/kvm/vmxcap | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index cbe6440ba3..0b23f7795a 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -147,6 +147,7 @@ controls = [ 5: 'Enable VPID', 6: 'WBINVD exiting', 7: 'Unrestricted guest', + 9: 'Virtual interrupt delivery', 10: 'PAUSE-loop exiting', 11: 'RDRAND exiting', 12: 'Enable INVPCID', From e0ac6097b6cc24694e83ae61e80040177bb5a584 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Mon, 21 Jan 2013 14:48:06 +0200 Subject: [PATCH 0614/1634] qxl: stop using non revision 4 rom fields for revision < 4 Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 11 +++++++++++ trace-events | 2 ++ 2 files changed, 13 insertions(+) diff --git a/hw/qxl.c b/hw/qxl.c index 9dc44b9b88..0d81816944 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -945,6 +945,12 @@ static void interface_set_client_capabilities(QXLInstance *sin, { PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + if (qxl->revision < 4) { + trace_qxl_set_client_capabilities_unsupported_by_revision(qxl->id, + qxl->revision); + return; + } + if (runstate_check(RUN_STATE_INMIGRATE) || runstate_check(RUN_STATE_POSTMIGRATE)) { return; @@ -979,6 +985,11 @@ static int interface_client_monitors_config(QXLInstance *sin, QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); int i; + if (qxl->revision < 4) { + trace_qxl_client_monitors_config_unsupported_by_device(qxl->id, + qxl->revision); + return 0; + } /* * Older windows drivers set int_mask to 0 when their ISR is called, * then later set it to ~0. So it doesn't relate to the actual interrupts diff --git a/trace-events b/trace-events index 7de9106664..09091e6d17 100644 --- a/trace-events +++ b/trace-events @@ -1029,8 +1029,10 @@ qxl_send_events_vm_stopped(int qid, uint32_t events) "%d %d" qxl_set_guest_bug(int qid) "%d" qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" +qxl_client_monitors_config_unsupported_by_device(int qid, int revision) "%d revision=%d" qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d" qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u" +qxl_set_client_capabilities_unsupported_by_revision(int qid, int revision) "%d revision=%d" # hw/qxl-render.c qxl_render_blit_guest_primary_initialized(void) "" From f4c0e5011b96d67b87db407854ee948da708a0d9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 21 Jan 2013 11:18:47 +0100 Subject: [PATCH 0615/1634] Revert "usb-storage: Drop useless null test in usb_msd_handle_data()" This reverts commit a1cbfd554e11bb8af38c2f3e1f1574bf4c563cd2. Test isn't useless. scsi_req_enqueue() may finish the request (will actually happen for requests which don't trigger any I/O such as INQUIRY), then call usb_msd_command_complete() which in turn will set s->req to NULL after unref'ing it. Signed-off-by: Gerd Hoffmann --- hw/usb/dev-storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index b839798eaf..1b87352db0 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -427,7 +427,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) scsi_req_print(s->req); #endif scsi_req_enqueue(s->req); - if (s->req->cmd.xfer != SCSI_XFER_NONE) { + if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { scsi_req_continue(s->req); } break; From 038c1879a00153b14bce113315b693e8c2944fa9 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Mon, 21 Jan 2013 14:48:07 +0200 Subject: [PATCH 0616/1634] qxl: change rom size to 8192 This is a simpler solution to 869981, where migration breaks since qxl's rom bar size has changed. Instead of ignoring fields in QXLRom, which is what has actually changed, we remove some of the modes, a mechanism already accounted for by the guest. The modes left allow for portrait and landscape only modes, corresponding to orientations 0 and 1. Orientations 2 and 3 are dropped. Added assert so that rom size will fit the future QXLRom increases via spice-protocol changes. This patch has been tested with 6.1.0.10015. With the newer 6.1.0.10016 there are problems with both "(flipped)" modes prior to the patch, and the patch loses the ability to set "Portrait" modes. But this is a separate bug to be fixed in the driver, and besides the patch doesn't affect the new arbitrary mode setting functionality. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index 0d81816944..a125e294aa 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -80,9 +80,7 @@ #define QXL_MODE_EX(x_res, y_res) \ QXL_MODE_16_32(x_res, y_res, 0), \ - QXL_MODE_16_32(y_res, x_res, 1), \ - QXL_MODE_16_32(x_res, y_res, 2), \ - QXL_MODE_16_32(y_res, x_res, 3) + QXL_MODE_16_32(x_res, y_res, 1) static QXLMode qxl_modes[] = { QXL_MODE_EX(640, 480), @@ -306,10 +304,13 @@ static inline uint32_t msb_mask(uint32_t val) static ram_addr_t qxl_rom_size(void) { - uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes); + uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) + + sizeof(qxl_modes); + uint32_t rom_size = 8192; /* two pages */ - rom_size = MAX(rom_size, TARGET_PAGE_SIZE); - rom_size = msb_mask(rom_size * 2 - 1); + required_rom_size = MAX(required_rom_size, TARGET_PAGE_SIZE); + required_rom_size = msb_mask(required_rom_size * 2 - 1); + assert(required_rom_size <= rom_size); return rom_size; } From 7fa96d73893728752ec7b832a62a48c434748497 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 21 Jan 2013 14:53:01 +0100 Subject: [PATCH 0617/1634] ohci: add missing break Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ohci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 6a2f5f8c5d..dd9967b13d 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1736,6 +1736,7 @@ static void ohci_mem_write(void *opaque, /* PXA27x specific registers */ case 24: /* HcStatus */ ohci->hstatus &= ~(val & ohci->hmask); + break; case 25: /* HcHReset */ ohci->hreset = val & ~OHCI_HRESET_FSBIR; From 347073336d393a819928de0d4fd56563134c0e1a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 14 Jan 2013 15:29:44 +0100 Subject: [PATCH 0618/1634] usb: add usb-bot device (scsi bulk-only transport). Basically the same as usb-storage, but without automatic scsi device setup. Also features support for up to 16 LUNs. Signed-off-by: Gerd Hoffmann --- docs/usb-storage.txt | 11 ++++- hw/usb/dev-storage.c | 96 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 90 insertions(+), 17 deletions(-) diff --git a/docs/usb-storage.txt b/docs/usb-storage.txt index e58e849d4d..fa93111cf6 100644 --- a/docs/usb-storage.txt +++ b/docs/usb-storage.txt @@ -2,7 +2,7 @@ qemu usb storage emulation -------------------------- -QEMU has two emulations for usb storage devices. +QEMU has three devices for usb storage emulation. Number one emulates the classic bulk-only transport protocol which is used by 99% of the usb sticks on the marked today and is called @@ -31,6 +31,15 @@ with tree logical units: -device scsi-cd,bus=uas.0,scsi-id=0,lun=5,drive=uas-cdrom +Number three emulates the classic bulk-only transport protocol too. +It's called "usb-bot". It shares most code with "usb-storage", and +the guest will not be able to see the difference. The qemu command +line interface is simliar to usb-uas though, i.e. no automatic scsi +disk creation. It also features support for up to 16 LUNs. The LUN +numbers must be continous, i.e. for three devices you must use 0+1+2. +The 0+1+5 numbering from the "usb-uas" example isn't going to work +with "usb-bot". + enjoy, Gerd diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 1b87352db0..b89d00f7cf 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -54,12 +54,12 @@ typedef struct { struct usb_msd_csw csw; SCSIRequest *req; SCSIBus bus; - BlockConf conf; - char *serial; - SCSIDevice *scsi_dev; - uint32_t removable; /* For async completion. */ USBPacket *packet; + /* usb-storage only */ + BlockConf conf; + char *serial; + uint32_t removable; } MSDState; struct usb_msd_cbw { @@ -343,7 +343,8 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { MSDState *s = (MSDState *)dev; - int ret; + SCSIDevice *scsi_dev; + int ret, maxlun; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { @@ -359,7 +360,19 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, s->mode = USB_MSDM_CBW; break; case ClassInterfaceRequest | GetMaxLun: - data[0] = 0; + maxlun = 0; + for (;;) { + scsi_dev = scsi_device_find(&s->bus, 0, 0, maxlun+1); + if (scsi_dev == NULL) { + break; + } + if (scsi_dev->lun != maxlun+1) { + break; + } + maxlun++; + } + DPRINTF("MaxLun %d\n", maxlun); + data[0] = maxlun; p->actual_length = 1; break; default: @@ -386,6 +399,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) uint32_t tag; struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; + SCSIDevice *scsi_dev; switch (p->pid) { case USB_TOKEN_OUT: @@ -405,7 +419,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) goto fail; } DPRINTF("Command on LUN %d\n", cbw.lun); - if (cbw.lun != 0) { + scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun); + if (scsi_dev == NULL) { fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); goto fail; } @@ -422,7 +437,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) tag, cbw.flags, cbw.cmd_len, s->data_len); assert(le32_to_cpu(s->csw.residue) == 0); s->scsi_len = 0; - s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL); + s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL); #ifdef DEBUG_MSD scsi_req_print(s->req); #endif @@ -553,7 +568,7 @@ static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req) return NULL; } -static const struct SCSIBusInfo usb_msd_scsi_info = { +static const struct SCSIBusInfo usb_msd_scsi_info_storage = { .tcq = false, .max_target = 0, .max_lun = 0, @@ -564,10 +579,22 @@ static const struct SCSIBusInfo usb_msd_scsi_info = { .load_request = usb_msd_load_request, }; -static int usb_msd_initfn(USBDevice *dev) +static const struct SCSIBusInfo usb_msd_scsi_info_bot = { + .tcq = false, + .max_target = 0, + .max_lun = 15, + + .transfer_data = usb_msd_transfer_data, + .complete = usb_msd_command_complete, + .cancel = usb_msd_request_cancelled, + .load_request = usb_msd_load_request, +}; + +static int usb_msd_initfn_storage(USBDevice *dev) { MSDState *s = DO_UPCAST(MSDState, dev, dev); BlockDriverState *bs = s->conf.bs; + SCSIDevice *scsi_dev; if (!bs) { error_report("drive property not set"); @@ -595,10 +622,10 @@ static int usb_msd_initfn(USBDevice *dev) } usb_desc_init(dev); - scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info); - s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, + scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage); + scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, s->conf.bootindex); - if (!s->scsi_dev) { + if (!scsi_dev) { return -1; } s->bus.qbus.allow_hotplug = 0; @@ -616,6 +643,19 @@ static int usb_msd_initfn(USBDevice *dev) return 0; } +static int usb_msd_initfn_bot(USBDevice *dev) +{ + MSDState *s = DO_UPCAST(MSDState, dev, dev); + + usb_desc_create_serial(dev); + usb_desc_init(dev); + scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_bot); + s->bus.qbus.allow_hotplug = 0; + usb_msd_handle_reset(dev); + + return 0; +} + static USBDevice *usb_msd_init(USBBus *bus, const char *filename) { static int nr=0; @@ -698,12 +738,11 @@ static Property msd_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void usb_msd_class_initfn(ObjectClass *klass, void *data) +static void usb_msd_class_initfn_common(ObjectClass *klass) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_msd_initfn; uc->product_desc = "QEMU USB MSD"; uc->usb_desc = &desc; uc->cancel_packet = usb_msd_cancel_io; @@ -713,19 +752,44 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_msd_handle_data; dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_msd; +} + +static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_msd_initfn_storage; dc->props = msd_properties; + usb_msd_class_initfn_common(klass); +} + +static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data) +{ + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_msd_initfn_bot; + usb_msd_class_initfn_common(klass); } static const TypeInfo msd_info = { .name = "usb-storage", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(MSDState), - .class_init = usb_msd_class_initfn, + .class_init = usb_msd_class_initfn_storage, +}; + +static const TypeInfo bot_info = { + .name = "usb-bot", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(MSDState), + .class_init = usb_msd_class_initfn_bot, }; static void usb_msd_register_types(void) { type_register_static(&msd_info); + type_register_static(&bot_info); usb_legacy_register("usb-storage", "disk", usb_msd_init); } From de8864e5ae645fc22aa4ecf1999705c2dd5cf93c Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Sat, 17 Nov 2012 16:13:24 +0100 Subject: [PATCH 0619/1634] iscsi: add iscsi_create support This patch adds support for bdrv_create. This allows e.g. to use qemu-img to convert from any supported device to an iscsi backed storage as destination. Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini --- block/iscsi.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 041ee07de3..d8382fdd5d 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -957,6 +957,56 @@ static int iscsi_has_zero_init(BlockDriverState *bs) return 0; } +static int iscsi_create(const char *filename, QEMUOptionParameter *options) +{ + int ret = 0; + int64_t total_size = 0; + BlockDriverState bs; + IscsiLun *iscsilun = NULL; + + memset(&bs, 0, sizeof(BlockDriverState)); + + /* Read out options */ + while (options && options->name) { + if (!strcmp(options->name, "size")) { + total_size = options->value.n / BDRV_SECTOR_SIZE; + } + options++; + } + + bs.opaque = g_malloc0(sizeof(struct IscsiLun)); + iscsilun = bs.opaque; + + ret = iscsi_open(&bs, filename, 0); + if (ret != 0) { + goto out; + } + if (iscsilun->type != TYPE_DISK) { + ret = -ENODEV; + goto out; + } + if (bs.total_sectors < total_size) { + ret = -ENOSPC; + } + + ret = 0; +out: + if (iscsilun->iscsi != NULL) { + iscsi_destroy_context(iscsilun->iscsi); + } + g_free(bs.opaque); + return ret; +} + +static QEMUOptionParameter iscsi_create_options[] = { + { + .name = BLOCK_OPT_SIZE, + .type = OPT_SIZE, + .help = "Virtual disk size" + }, + { NULL } +}; + static BlockDriver bdrv_iscsi = { .format_name = "iscsi", .protocol_name = "iscsi", @@ -964,6 +1014,8 @@ static BlockDriver bdrv_iscsi = { .instance_size = sizeof(IscsiLun), .bdrv_file_open = iscsi_open, .bdrv_close = iscsi_close, + .bdrv_create = iscsi_create, + .create_options = iscsi_create_options, .bdrv_getlength = iscsi_getlength, From 4cc841b57c1dc91d71bafc25b53ffab4eff7959b Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Mon, 19 Nov 2012 15:58:31 +0100 Subject: [PATCH 0620/1634] iscsi: partly avoid iovec linearization in iscsi_aio_writev libiscsi expects all write16 data in a linear buffer. If the iovec only contains one buffer we can skip the linearization step as well as the additional malloc/free and pass the buffer directly. Reported-by: Ronnie Sahlberg Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini --- block/iscsi.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index d8382fdd5d..259192f535 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -241,8 +241,17 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, /* XXX we should pass the iovec to write16 to avoid the extra copy */ /* this will allow us to get rid of 'buf' completely */ size = nb_sectors * BDRV_SECTOR_SIZE; - acb->buf = g_malloc(size); - qemu_iovec_to_buf(acb->qiov, 0, acb->buf, size); + data.size = MIN(size, acb->qiov->size); + + /* if the iovec only contains one buffer we can pass it directly */ + if (acb->qiov->niov == 1) { + acb->buf = NULL; + data.data = acb->qiov->iov[0].iov_base; + } else { + acb->buf = g_malloc(data.size); + qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size); + data.data = acb->buf; + } acb->task = malloc(sizeof(struct scsi_task)); if (acb->task == NULL) { @@ -263,9 +272,6 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors); acb->task->expxferlen = size; - data.data = acb->buf; - data.size = size; - if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, iscsi_aio_write16_cb, &data, From 5b5d34ec9882b29b757f6808693308e52a8e8ba7 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 6 Dec 2012 10:46:47 +0100 Subject: [PATCH 0621/1634] iscsi: add support for iSCSI NOPs [v2] This patch will send NOP-Out PDUs every 5 seconds to the iSCSI target. If a consecutive number of NOP-In replies fail a reconnect is initiated. iSCSI NOPs help to ensure that the connection to the target is still operational. This should not, but in reality may be the case even if the TCP connection is still alive if there are bugs in either the target or the initiator implementation. v2: - track the NOPs inside libiscsi so libiscsi can reset the counter in case it initiates a reconnect. Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini --- block/iscsi.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 259192f535..249778986d 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -48,6 +48,7 @@ typedef struct IscsiLun { int block_size; uint64_t num_blocks; int events; + QEMUTimer *nop_timer; } IscsiLun; typedef struct IscsiAIOCB { @@ -66,6 +67,9 @@ typedef struct IscsiAIOCB { #endif } IscsiAIOCB; +#define NOP_INTERVAL 5000 +#define MAX_NOP_FAILURES 3 + static void iscsi_bh_cb(void *p) { @@ -768,6 +772,26 @@ static char *parse_initiator_name(const char *target) } } +#if defined(LIBISCSI_FEATURE_NOP_COUNTER) +static void iscsi_nop_timed_event(void *opaque) +{ + IscsiLun *iscsilun = opaque; + + if (iscsi_get_nops_in_flight(iscsilun->iscsi) > MAX_NOP_FAILURES) { + error_report("iSCSI: NOP timeout. Reconnecting..."); + iscsi_reconnect(iscsilun->iscsi); + } + + if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) { + error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages."); + return; + } + + qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL); + iscsi_set_events(iscsilun); +} +#endif + /* * We support iscsi url's on the form * iscsi://[%@][:]// @@ -928,6 +952,12 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) ret = 0; +#if defined(LIBISCSI_FEATURE_NOP_COUNTER) + /* Set up a timer for sending out iSCSI NOPs */ + iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event, iscsilun); + qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL); +#endif + out: if (initiator_name != NULL) { g_free(initiator_name); @@ -953,6 +983,10 @@ static void iscsi_close(BlockDriverState *bs) IscsiLun *iscsilun = bs->opaque; struct iscsi_context *iscsi = iscsilun->iscsi; + if (iscsilun->nop_timer) { + qemu_del_timer(iscsilun->nop_timer); + qemu_free_timer(iscsilun->nop_timer); + } qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL); iscsi_destroy_context(iscsi); memset(iscsilun, 0, sizeof(IscsiLun)); @@ -987,6 +1021,10 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options) if (ret != 0) { goto out; } + if (iscsilun->nop_timer) { + qemu_del_timer(iscsilun->nop_timer); + qemu_free_timer(iscsilun->nop_timer); + } if (iscsilun->type != TYPE_DISK) { ret = -ENODEV; goto out; From 0369f06f7464e7fb023f103aff889d28e99c43c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Jan 2013 15:08:05 +0100 Subject: [PATCH 0622/1634] scsi: fix segfault with 0-byte disk When a 0-sized disk is found, READ CAPACITY will return a LUN NOT READY error. However, because it returns -1 instead of zero, the HBA will call scsi_req_continue. This will typically cause a segmentation fault or an assertion failure. Signed-off-by: Paolo Bonzini --- hw/scsi-disk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index f8d7ef3374..658e315660 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1682,7 +1682,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); if (!nb_sectors) { scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); - return -1; + return 0; } if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) { goto illegal_request; @@ -1751,7 +1751,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); if (!nb_sectors) { scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); - return -1; + return 0; } if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) { goto illegal_request; From 032f0101aa6e009efda3a419379837ebceaeade1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Dec 2012 11:23:25 +0100 Subject: [PATCH 0623/1634] lsi: use qbus_reset_all to reset SCSI bus Signed-off-by: Paolo Bonzini --- hw/lsi53c895a.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 89c657fb00..860df328e5 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1670,12 +1670,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) } if (val & LSI_SCNTL1_RST) { if (!(s->sstat0 & LSI_SSTAT0_RST)) { - BusChild *kid; - - QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { - DeviceState *dev = kid->child; - device_reset(dev); - } + qbus_reset_all(&s->bus.qbus); s->sstat0 |= LSI_SSTAT0_RST; lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); } From 0bf8264e2d2bd19c1eecf9bde0e59284ef47eabb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 17 Jan 2013 13:07:47 +0100 Subject: [PATCH 0624/1634] scsi: Drop useless null test in scsi_unit_attention() req was created by scsi_req_alloc(), which initializes req->dev to a value it dereferences. req->dev isn't changed anywhere else. Therefore, req->dev can't be null. Drop the useless null test; it spooks Coverity. Signed-off-by: Markus Armbruster --- hw/scsi-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 267a942f76..a97f1cdc1c 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -282,7 +282,7 @@ static const struct SCSIReqOps reqops_invalid_opcode = { static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf) { - if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) { + if (req->dev->unit_attention.key == UNIT_ATTENTION) { scsi_req_build_sense(req, req->dev->unit_attention); } else if (req->bus->unit_attention.key == UNIT_ATTENTION) { scsi_req_build_sense(req, req->bus->unit_attention); From 9fc7577af56153a4f75709ce526d64bf6845d002 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 23 Jan 2013 16:15:25 +0000 Subject: [PATCH 0625/1634] trivial: etraxfs_eth: Eliminate checkpatch errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a trivial patch to harmonize the coding style on hw/etraxfs_eth.c. This is in preparation to split off the bitbang mdio code into a separate file. Cc: Peter Maydell Cc: Paul Brook Cc: Edgar E. Iglesias Cc: Anthony Liguori Cc: Andreas Färber Signed-off-by: Grant Likely Signed-off-by: Edgar E. Iglesias --- hw/etraxfs_eth.c | 848 ++++++++++++++++++++++++----------------------- 1 file changed, 429 insertions(+), 419 deletions(-) diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index ec23fa6edf..0b474c0843 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -35,582 +35,592 @@ #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ -/* - * The MDIO extensions in the TDK PHY model were reversed engineered from the +/* + * The MDIO extensions in the TDK PHY model were reversed engineered from the * linux driver (PHYID and Diagnostics reg). * TODO: Add friendly names for the register nums. */ struct qemu_phy { - uint32_t regs[32]; + uint32_t regs[32]; - int link; + int link; - unsigned int (*read)(struct qemu_phy *phy, unsigned int req); - void (*write)(struct qemu_phy *phy, unsigned int req, - unsigned int data); + unsigned int (*read)(struct qemu_phy *phy, unsigned int req); + void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data); }; static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) { - int regnum; - unsigned r = 0; + int regnum; + unsigned r = 0; - regnum = req & 0x1f; + regnum = req & 0x1f; - switch (regnum) { - case 1: - if (!phy->link) - break; - /* MR1. */ - /* Speeds and modes. */ - r |= (1 << 13) | (1 << 14); - r |= (1 << 11) | (1 << 12); - r |= (1 << 5); /* Autoneg complete. */ - r |= (1 << 3); /* Autoneg able. */ - r |= (1 << 2); /* link. */ - break; - case 5: - /* Link partner ability. - We are kind; always agree with whatever best mode - the guest advertises. */ - r = 1 << 14; /* Success. */ - /* Copy advertised modes. */ - r |= phy->regs[4] & (15 << 5); - /* Autoneg support. */ - r |= 1; - break; - case 18: - { - /* Diagnostics reg. */ - int duplex = 0; - int speed_100 = 0; + switch (regnum) { + case 1: + if (!phy->link) { + break; + } + /* MR1. */ + /* Speeds and modes. */ + r |= (1 << 13) | (1 << 14); + r |= (1 << 11) | (1 << 12); + r |= (1 << 5); /* Autoneg complete. */ + r |= (1 << 3); /* Autoneg able. */ + r |= (1 << 2); /* link. */ + break; + case 5: + /* Link partner ability. + We are kind; always agree with whatever best mode + the guest advertises. */ + r = 1 << 14; /* Success. */ + /* Copy advertised modes. */ + r |= phy->regs[4] & (15 << 5); + /* Autoneg support. */ + r |= 1; + break; + case 18: + { + /* Diagnostics reg. */ + int duplex = 0; + int speed_100 = 0; - if (!phy->link) - break; + if (!phy->link) { + break; + } - /* Are we advertising 100 half or 100 duplex ? */ - speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); - speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); + /* Are we advertising 100 half or 100 duplex ? */ + speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); + speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); - /* Are we advertising 10 duplex or 100 duplex ? */ - duplex = !!(phy->regs[4] & ADVERTISE_100FULL); - duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); - r = (speed_100 << 10) | (duplex << 11); - } - break; + /* Are we advertising 10 duplex or 100 duplex ? */ + duplex = !!(phy->regs[4] & ADVERTISE_100FULL); + duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); + r = (speed_100 << 10) | (duplex << 11); + } + break; - default: - r = phy->regs[regnum]; - break; - } - D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); - return r; + default: + r = phy->regs[regnum]; + break; + } + D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); + return r; } -static void +static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) { - int regnum; + int regnum; - regnum = req & 0x1f; - D(printf("%s reg[%d] = %x\n", __func__, regnum, data)); - switch (regnum) { - default: - phy->regs[regnum] = data; - break; - } + regnum = req & 0x1f; + D(printf("%s reg[%d] = %x\n", __func__, regnum, data)); + switch (regnum) { + default: + phy->regs[regnum] = data; + break; + } } -static void +static void tdk_init(struct qemu_phy *phy) { - phy->regs[0] = 0x3100; - /* PHY Id. */ - phy->regs[2] = 0x0300; - phy->regs[3] = 0xe400; - /* Autonegotiation advertisement reg. */ - phy->regs[4] = 0x01E1; - phy->link = 1; + phy->regs[0] = 0x3100; + /* PHY Id. */ + phy->regs[2] = 0x0300; + phy->regs[3] = 0xe400; + /* Autonegotiation advertisement reg. */ + phy->regs[4] = 0x01E1; + phy->link = 1; - phy->read = tdk_read; - phy->write = tdk_write; + phy->read = tdk_read; + phy->write = tdk_write; } struct qemu_mdio { - /* bus. */ - int mdc; - int mdio; + /* bus. */ + int mdc; + int mdio; - /* decoder. */ - enum { - PREAMBLE, - SOF, - OPC, - ADDR, - REQ, - TURNAROUND, - DATA - } state; - unsigned int drive; + /* decoder. */ + enum { + PREAMBLE, + SOF, + OPC, + ADDR, + REQ, + TURNAROUND, + DATA + } state; + unsigned int drive; - unsigned int cnt; - unsigned int addr; - unsigned int opc; - unsigned int req; - unsigned int data; + unsigned int cnt; + unsigned int addr; + unsigned int opc; + unsigned int req; + unsigned int data; - struct qemu_phy *devs[32]; + struct qemu_phy *devs[32]; }; -static void +static void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) { - bus->devs[addr & 0x1f] = phy; + bus->devs[addr & 0x1f] = phy; } #ifdef USE_THIS_DEAD_CODE -static void +static void mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) { - bus->devs[addr & 0x1f] = NULL; + bus->devs[addr & 0x1f] = NULL; } #endif static void mdio_read_req(struct qemu_mdio *bus) { - struct qemu_phy *phy; + struct qemu_phy *phy; - phy = bus->devs[bus->addr]; - if (phy && phy->read) - bus->data = phy->read(phy, bus->req); - else - bus->data = 0xffff; + phy = bus->devs[bus->addr]; + if (phy && phy->read) { + bus->data = phy->read(phy, bus->req); + } else { + bus->data = 0xffff; + } } static void mdio_write_req(struct qemu_mdio *bus) { - struct qemu_phy *phy; + struct qemu_phy *phy; - phy = bus->devs[bus->addr]; - if (phy && phy->write) - phy->write(phy, bus->req, bus->data); + phy = bus->devs[bus->addr]; + if (phy && phy->write) { + phy->write(phy, bus->req, bus->data); + } } static void mdio_cycle(struct qemu_mdio *bus) { - bus->cnt++; + bus->cnt++; - D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", - bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); + D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", + bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); #if 0 - if (bus->mdc) - printf("%d", bus->mdio); + if (bus->mdc) { + printf("%d", bus->mdio); + } #endif - switch (bus->state) - { - case PREAMBLE: - if (bus->mdc) { - if (bus->cnt >= (32 * 2) && !bus->mdio) { - bus->cnt = 0; - bus->state = SOF; - bus->data = 0; - } - } - break; - case SOF: - if (bus->mdc) { - if (bus->mdio != 1) - printf("WARNING: no SOF\n"); - if (bus->cnt == 1*2) { - bus->cnt = 0; - bus->opc = 0; - bus->state = OPC; - } - } - break; - case OPC: - if (bus->mdc) { - bus->opc <<= 1; - bus->opc |= bus->mdio & 1; - if (bus->cnt == 2*2) { - bus->cnt = 0; - bus->addr = 0; - bus->state = ADDR; - } - } - break; - case ADDR: - if (bus->mdc) { - bus->addr <<= 1; - bus->addr |= bus->mdio & 1; + switch (bus->state) { + case PREAMBLE: + if (bus->mdc) { + if (bus->cnt >= (32 * 2) && !bus->mdio) { + bus->cnt = 0; + bus->state = SOF; + bus->data = 0; + } + } + break; + case SOF: + if (bus->mdc) { + if (bus->mdio != 1) { + printf("WARNING: no SOF\n"); + } + if (bus->cnt == 1*2) { + bus->cnt = 0; + bus->opc = 0; + bus->state = OPC; + } + } + break; + case OPC: + if (bus->mdc) { + bus->opc <<= 1; + bus->opc |= bus->mdio & 1; + if (bus->cnt == 2*2) { + bus->cnt = 0; + bus->addr = 0; + bus->state = ADDR; + } + } + break; + case ADDR: + if (bus->mdc) { + bus->addr <<= 1; + bus->addr |= bus->mdio & 1; - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->req = 0; - bus->state = REQ; - } - } - break; - case REQ: - if (bus->mdc) { - bus->req <<= 1; - bus->req |= bus->mdio & 1; - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->state = TURNAROUND; - } - } - break; - case TURNAROUND: - if (bus->mdc && bus->cnt == 2*2) { - bus->mdio = 0; - bus->cnt = 0; + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->req = 0; + bus->state = REQ; + } + } + break; + case REQ: + if (bus->mdc) { + bus->req <<= 1; + bus->req |= bus->mdio & 1; + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->state = TURNAROUND; + } + } + break; + case TURNAROUND: + if (bus->mdc && bus->cnt == 2*2) { + bus->mdio = 0; + bus->cnt = 0; - if (bus->opc == 2) { - bus->drive = 1; - mdio_read_req(bus); - bus->mdio = bus->data & 1; - } - bus->state = DATA; - } - break; - case DATA: - if (!bus->mdc) { - if (bus->drive) { - bus->mdio = !!(bus->data & (1 << 15)); - bus->data <<= 1; - } - } else { - if (!bus->drive) { - bus->data <<= 1; - bus->data |= bus->mdio; - } - if (bus->cnt == 16 * 2) { - bus->cnt = 0; - bus->state = PREAMBLE; - if (!bus->drive) - mdio_write_req(bus); - bus->drive = 0; - } - } - break; - default: - break; - } + if (bus->opc == 2) { + bus->drive = 1; + mdio_read_req(bus); + bus->mdio = bus->data & 1; + } + bus->state = DATA; + } + break; + case DATA: + if (!bus->mdc) { + if (bus->drive) { + bus->mdio = !!(bus->data & (1 << 15)); + bus->data <<= 1; + } + } else { + if (!bus->drive) { + bus->data <<= 1; + bus->data |= bus->mdio; + } + if (bus->cnt == 16 * 2) { + bus->cnt = 0; + bus->state = PREAMBLE; + if (!bus->drive) { + mdio_write_req(bus); + } + bus->drive = 0; + } + } + break; + default: + break; + } } /* ETRAX-FS Ethernet MAC block starts here. */ -#define RW_MA0_LO 0x00 -#define RW_MA0_HI 0x01 -#define RW_MA1_LO 0x02 -#define RW_MA1_HI 0x03 -#define RW_GA_LO 0x04 -#define RW_GA_HI 0x05 -#define RW_GEN_CTRL 0x06 -#define RW_REC_CTRL 0x07 -#define RW_TR_CTRL 0x08 -#define RW_CLR_ERR 0x09 -#define RW_MGM_CTRL 0x0a -#define R_STAT 0x0b -#define FS_ETH_MAX_REGS 0x17 +#define RW_MA0_LO 0x00 +#define RW_MA0_HI 0x01 +#define RW_MA1_LO 0x02 +#define RW_MA1_HI 0x03 +#define RW_GA_LO 0x04 +#define RW_GA_HI 0x05 +#define RW_GEN_CTRL 0x06 +#define RW_REC_CTRL 0x07 +#define RW_TR_CTRL 0x08 +#define RW_CLR_ERR 0x09 +#define RW_MGM_CTRL 0x0a +#define R_STAT 0x0b +#define FS_ETH_MAX_REGS 0x17 struct fs_eth { - SysBusDevice busdev; - MemoryRegion mmio; - NICState *nic; - NICConf conf; + SysBusDevice busdev; + MemoryRegion mmio; + NICState *nic; + NICConf conf; - /* Two addrs in the filter. */ - uint8_t macaddr[2][6]; - uint32_t regs[FS_ETH_MAX_REGS]; + /* Two addrs in the filter. */ + uint8_t macaddr[2][6]; + uint32_t regs[FS_ETH_MAX_REGS]; - union { - void *vdma_out; - struct etraxfs_dma_client *dma_out; - }; - union { - void *vdma_in; - struct etraxfs_dma_client *dma_in; - }; + union { + void *vdma_out; + struct etraxfs_dma_client *dma_out; + }; + union { + void *vdma_in; + struct etraxfs_dma_client *dma_in; + }; - /* MDIO bus. */ - struct qemu_mdio mdio_bus; - unsigned int phyaddr; - int duplex_mismatch; + /* MDIO bus. */ + struct qemu_mdio mdio_bus; + unsigned int phyaddr; + int duplex_mismatch; - /* PHY. */ - struct qemu_phy phy; + /* PHY. */ + struct qemu_phy phy; }; static void eth_validate_duplex(struct fs_eth *eth) { - struct qemu_phy *phy; - unsigned int phy_duplex; - unsigned int mac_duplex; - int new_mm = 0; + struct qemu_phy *phy; + unsigned int phy_duplex; + unsigned int mac_duplex; + int new_mm = 0; - phy = eth->mdio_bus.devs[eth->phyaddr]; - phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); - mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); + phy = eth->mdio_bus.devs[eth->phyaddr]; + phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); + mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); - if (mac_duplex != phy_duplex) - new_mm = 1; + if (mac_duplex != phy_duplex) { + new_mm = 1; + } - if (eth->regs[RW_GEN_CTRL] & 1) { - if (new_mm != eth->duplex_mismatch) { - if (new_mm) - printf("HW: WARNING " - "ETH duplex mismatch MAC=%d PHY=%d\n", - mac_duplex, phy_duplex); - else - printf("HW: ETH duplex ok.\n"); - } - eth->duplex_mismatch = new_mm; - } + if (eth->regs[RW_GEN_CTRL] & 1) { + if (new_mm != eth->duplex_mismatch) { + if (new_mm) { + printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n", + mac_duplex, phy_duplex); + } else { + printf("HW: ETH duplex ok.\n"); + } + } + eth->duplex_mismatch = new_mm; + } } static uint64_t eth_read(void *opaque, hwaddr addr, unsigned int size) { - struct fs_eth *eth = opaque; - uint32_t r = 0; + struct fs_eth *eth = opaque; + uint32_t r = 0; - addr >>= 2; + addr >>= 2; - switch (addr) { - case R_STAT: - r = eth->mdio_bus.mdio & 1; - break; - default: - r = eth->regs[addr]; - D(printf ("%s %x\n", __func__, addr * 4)); - break; - } - return r; + switch (addr) { + case R_STAT: + r = eth->mdio_bus.mdio & 1; + break; + default: + r = eth->regs[addr]; + D(printf("%s %x\n", __func__, addr * 4)); + break; + } + return r; } static void eth_update_ma(struct fs_eth *eth, int ma) { - int reg; - int i = 0; + int reg; + int i = 0; - ma &= 1; + ma &= 1; - reg = RW_MA0_LO; - if (ma) - reg = RW_MA1_LO; + reg = RW_MA0_LO; + if (ma) { + reg = RW_MA1_LO; + } - eth->macaddr[ma][i++] = eth->regs[reg]; - eth->macaddr[ma][i++] = eth->regs[reg] >> 8; - eth->macaddr[ma][i++] = eth->regs[reg] >> 16; - eth->macaddr[ma][i++] = eth->regs[reg] >> 24; - eth->macaddr[ma][i++] = eth->regs[reg + 1]; - eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8; + eth->macaddr[ma][i++] = eth->regs[reg]; + eth->macaddr[ma][i++] = eth->regs[reg] >> 8; + eth->macaddr[ma][i++] = eth->regs[reg] >> 16; + eth->macaddr[ma][i++] = eth->regs[reg] >> 24; + eth->macaddr[ma][i++] = eth->regs[reg + 1]; + eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8; - D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, - eth->macaddr[ma][0], eth->macaddr[ma][1], - eth->macaddr[ma][2], eth->macaddr[ma][3], - eth->macaddr[ma][4], eth->macaddr[ma][5])); + D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, + eth->macaddr[ma][0], eth->macaddr[ma][1], + eth->macaddr[ma][2], eth->macaddr[ma][3], + eth->macaddr[ma][4], eth->macaddr[ma][5])); } static void eth_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct fs_eth *eth = opaque; - uint32_t value = val64; + struct fs_eth *eth = opaque; + uint32_t value = val64; - addr >>= 2; - switch (addr) - { - case RW_MA0_LO: - case RW_MA0_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 0); - break; - case RW_MA1_LO: - case RW_MA1_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 1); - break; + addr >>= 2; + switch (addr) { + case RW_MA0_LO: + case RW_MA0_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 0); + break; + case RW_MA1_LO: + case RW_MA1_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 1); + break; - case RW_MGM_CTRL: - /* Attach an MDIO/PHY abstraction. */ - if (value & 2) - eth->mdio_bus.mdio = value & 1; - if (eth->mdio_bus.mdc != (value & 4)) { - mdio_cycle(ð->mdio_bus); - eth_validate_duplex(eth); - } - eth->mdio_bus.mdc = !!(value & 4); - eth->regs[addr] = value; - break; + case RW_MGM_CTRL: + /* Attach an MDIO/PHY abstraction. */ + if (value & 2) { + eth->mdio_bus.mdio = value & 1; + } + if (eth->mdio_bus.mdc != (value & 4)) { + mdio_cycle(ð->mdio_bus); + eth_validate_duplex(eth); + } + eth->mdio_bus.mdc = !!(value & 4); + eth->regs[addr] = value; + break; - case RW_REC_CTRL: - eth->regs[addr] = value; - eth_validate_duplex(eth); - break; + case RW_REC_CTRL: + eth->regs[addr] = value; + eth_validate_duplex(eth); + break; - default: - eth->regs[addr] = value; - D(printf ("%s %x %x\n", - __func__, addr, value)); - break; - } + default: + eth->regs[addr] = value; + D(printf("%s %x %x\n", __func__, addr, value)); + break; + } } /* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom - filter dropping group addresses we have not joined. The filter has 64 - bits (m). The has function is a simple nible xor of the group addr. */ + filter dropping group addresses we have not joined. The filter has 64 + bits (m). The has function is a simple nible xor of the group addr. */ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) { - unsigned int hsh; - int m_individual = eth->regs[RW_REC_CTRL] & 4; - int match; + unsigned int hsh; + int m_individual = eth->regs[RW_REC_CTRL] & 4; + int match; - /* First bit on the wire of a MAC address signals multicast or - physical address. */ - if (!m_individual && !(sa[0] & 1)) - return 0; + /* First bit on the wire of a MAC address signals multicast or + physical address. */ + if (!m_individual && !(sa[0] & 1)) { + return 0; + } - /* Calculate the hash index for the GA registers. */ - hsh = 0; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; - ++sa; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; + /* Calculate the hash index for the GA registers. */ + hsh = 0; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; + ++sa; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; - hsh &= 63; - if (hsh > 31) - match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); - else - match = eth->regs[RW_GA_LO] & (1 << hsh); - D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, - eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); - return match; + hsh &= 63; + if (hsh > 31) { + match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); + } else { + match = eth->regs[RW_GA_LO] & (1 << hsh); + } + D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, + eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); + return match; } static int eth_can_receive(NetClientState *nc) { - return 1; + return 1; } static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - int use_ma0 = eth->regs[RW_REC_CTRL] & 1; - int use_ma1 = eth->regs[RW_REC_CTRL] & 2; - int r_bcast = eth->regs[RW_REC_CTRL] & 8; + unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + int use_ma0 = eth->regs[RW_REC_CTRL] & 1; + int use_ma1 = eth->regs[RW_REC_CTRL] & 2; + int r_bcast = eth->regs[RW_REC_CTRL] & 8; - if (size < 12) - return -1; + if (size < 12) { + return -1; + } - D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - use_ma0, use_ma1, r_bcast)); - - /* Does the frame get through the address filters? */ - if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) - && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) - && (!r_bcast || memcmp(buf, sa_bcast, 6)) - && !eth_match_groupaddr(eth, buf)) - return size; + D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + use_ma0, use_ma1, r_bcast)); - /* FIXME: Find another way to pass on the fake csum. */ - etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); + /* Does the frame get through the address filters? */ + if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) + && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) + && (!r_bcast || memcmp(buf, sa_bcast, 6)) + && !eth_match_groupaddr(eth, buf)) { + return size; + } + + /* FIXME: Find another way to pass on the fake csum. */ + etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); return size; } static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) { - struct fs_eth *eth = opaque; + struct fs_eth *eth = opaque; - D(printf("%s buf=%p len=%d\n", __func__, buf, len)); - qemu_send_packet(ð->nic->nc, buf, len); - return len; + D(printf("%s buf=%p len=%d\n", __func__, buf, len)); + qemu_send_packet(ð->nic->nc, buf, len); + return len; } static void eth_set_link(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - D(printf("%s %d\n", __func__, nc->link_down)); - eth->phy.link = !nc->link_down; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + D(printf("%s %d\n", __func__, nc->link_down)); + eth->phy.link = !nc->link_down; } static const MemoryRegionOps eth_ops = { - .read = eth_read, - .write = eth_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } + .read = eth_read, + .write = eth_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } }; static void eth_cleanup(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - /* Disconnect the client. */ - eth->dma_out->client.push = NULL; - eth->dma_out->client.opaque = NULL; - eth->dma_in->client.opaque = NULL; - eth->dma_in->client.pull = NULL; + /* Disconnect the client. */ + eth->dma_out->client.push = NULL; + eth->dma_out->client.opaque = NULL; + eth->dma_in->client.opaque = NULL; + eth->dma_in->client.pull = NULL; g_free(eth); } static NetClientInfo net_etraxfs_info = { - .type = NET_CLIENT_OPTIONS_KIND_NIC, - .size = sizeof(NICState), - .can_receive = eth_can_receive, - .receive = eth_receive, - .cleanup = eth_cleanup, - .link_status_changed = eth_set_link, + .type = NET_CLIENT_OPTIONS_KIND_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_receive, + .receive = eth_receive, + .cleanup = eth_cleanup, + .link_status_changed = eth_set_link, }; static int fs_eth_init(SysBusDevice *dev) { - struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev); + struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev); - if (!s->dma_out || !s->dma_in) { - hw_error("Unconnected ETRAX-FS Ethernet MAC.\n"); - } + if (!s->dma_out || !s->dma_in) { + hw_error("Unconnected ETRAX-FS Ethernet MAC.\n"); + } - s->dma_out->client.push = eth_tx_push; - s->dma_out->client.opaque = s; - s->dma_in->client.opaque = s; - s->dma_in->client.pull = NULL; + s->dma_out->client.push = eth_tx_push; + s->dma_out->client.opaque = s; + s->dma_in->client.opaque = s; + s->dma_in->client.pull = NULL; - memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c); - sysbus_init_mmio(dev, &s->mmio); + memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c); + sysbus_init_mmio(dev, &s->mmio); - qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, - object_get_typename(OBJECT(s)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, + object_get_typename(OBJECT(s)), dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); - tdk_init(&s->phy); - mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); - return 0; + tdk_init(&s->phy); + mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); + return 0; } static Property etraxfs_eth_properties[] = { From 3f668b6c5dc9747d0367837532c3b2ce0520cc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 24 Jan 2013 10:51:47 +0100 Subject: [PATCH 0626/1634] target-cris: Fix typo in D_LOG() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's __VA_ARGS__. Fixes the build with CRIS_[OP_]HELPER_DEBUG defined. Broken since r6338 / 93fcfe39a0383377e647b821c9f165fd927cd4e0 (Convert references to logfile/loglevel to use qemu_log*() macros). Cc: Eduardo Habkost Signed-off-by: Andreas Färber Signed-off-by: Edgar E. Iglesias --- target-cris/helper.c | 2 +- target-cris/op_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target-cris/helper.c b/target-cris/helper.c index 8407a6d880..6e75e9819e 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -28,7 +28,7 @@ #ifdef CRIS_HELPER_DEBUG #define D(x) x -#define D_LOG(...) qemu_log(__VA__ARGS__) +#define D_LOG(...) qemu_log(__VA_ARGS__) #else #define D(x) #define D_LOG(...) do { } while (0) diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index 79bff38663..0f6a1eeb0a 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -28,7 +28,7 @@ #ifdef CRIS_OP_HELPER_DEBUG #define D(x) x -#define D_LOG(...) qemu_log(__VA__ARGS__) +#define D_LOG(...) qemu_log(__VA_ARGS__) #else #define D(x) #define D_LOG(...) do { } while (0) From 4790b03d308f6c7dea7dc6941ddab9867c9530b8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jan 2013 17:34:29 +0100 Subject: [PATCH 0627/1634] iscsi: do not leak acb->buf when commands are aborted acb->buf is freed in the WRITE(16) callback, but this may not get called at all when commands are aborted. Add another free in the ABORT TASK callback, which requires setting acb->buf to NULL everywhere. Signed-off-by: Paolo Bonzini --- block/iscsi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/block/iscsi.c b/block/iscsi.c index fd54a1550e..b647201ec2 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -77,6 +77,9 @@ iscsi_bh_cb(void *p) qemu_bh_delete(acb->bh); + g_free(acb->buf); + acb->buf = NULL; + if (acb->canceled == 0) { acb->common.cb(acb->common.opaque, acb->status); } @@ -198,6 +201,7 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status, trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled); g_free(acb->buf); + acb->buf = NULL; if (acb->canceled != 0) { return; @@ -241,6 +245,7 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; + acb->buf = NULL; /* XXX we should pass the iovec to write16 to avoid the extra copy */ /* this will allow us to get rid of 'buf' completely */ @@ -249,7 +254,6 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, /* if the iovec only contains one buffer we can pass it directly */ if (acb->qiov->niov == 1) { - acb->buf = NULL; data.data = acb->qiov->iov[0].iov_base; } else { acb->buf = g_malloc(data.size); @@ -440,6 +444,7 @@ iscsi_aio_flush(BlockDriverState *bs, acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; + acb->buf = NULL; acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun, 0, 0, 0, 0, @@ -493,6 +498,7 @@ iscsi_aio_discard(BlockDriverState *bs, acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; + acb->buf = NULL; list[0].lba = sector_qemu2lun(sector_num, iscsilun); list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size; From 7371d56fb2759f52106c76692440d0c29731ef9c Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Mon, 3 Dec 2012 20:35:15 +0100 Subject: [PATCH 0628/1634] iscsi: add support for iovectors This patch adds support for directly passing the iovec array from QEMUIOVector if libiscsi supports it (1.8.0 or newer). Signed-off-by: Peter Lieven [Preserve the improvements from commit 4cc841b, iscsi: partly avoid iovec linearization in iscsi_aio_writev, 2012-11-19 - Paolo] Signed-off-by: Paolo Bonzini --- block/iscsi.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index b647201ec2..deb3b68890 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -234,7 +234,10 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, size_t size; uint32_t num_sectors; uint64_t lba; +#if !defined(LIBISCSI_FEATURE_IOVECTOR) struct iscsi_data data; +#endif + int ret; acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb); @@ -247,9 +250,10 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, acb->status = -EINPROGRESS; acb->buf = NULL; - /* XXX we should pass the iovec to write16 to avoid the extra copy */ /* this will allow us to get rid of 'buf' completely */ size = nb_sectors * BDRV_SECTOR_SIZE; + +#if !defined(LIBISCSI_FEATURE_IOVECTOR) data.size = MIN(size, acb->qiov->size); /* if the iovec only contains one buffer we can pass it directly */ @@ -260,6 +264,7 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size); data.data = acb->buf; } +#endif acb->task = malloc(sizeof(struct scsi_task)); if (acb->task == NULL) { @@ -280,16 +285,28 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors); acb->task->expxferlen = size; - if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, - iscsi_aio_write16_cb, - &data, - acb) != 0) { +#if defined(LIBISCSI_FEATURE_IOVECTOR) + ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + iscsi_aio_write16_cb, + NULL, + acb); +#else + ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + iscsi_aio_write16_cb, + &data, + acb); +#endif + if (ret != 0) { scsi_free_scsi_task(acb->task); g_free(acb->buf); qemu_aio_release(acb); return NULL; } +#if defined(LIBISCSI_FEATURE_IOVECTOR) + scsi_task_set_iov_out(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov); +#endif + iscsi_set_events(iscsilun); return &acb->common; @@ -327,7 +344,10 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, struct iscsi_context *iscsi = iscsilun->iscsi; IscsiAIOCB *acb; size_t qemu_read_size; +#if !defined(LIBISCSI_FEATURE_IOVECTOR) int i; +#endif + int ret; uint64_t lba; uint32_t num_sectors; @@ -389,20 +409,25 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, break; } - if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, - iscsi_aio_read16_cb, - NULL, - acb) != 0) { + ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + iscsi_aio_read16_cb, + NULL, + acb); + if (ret != 0) { scsi_free_scsi_task(acb->task); qemu_aio_release(acb); return NULL; } +#if defined(LIBISCSI_FEATURE_IOVECTOR) + scsi_task_set_iov_in(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov); +#else for (i = 0; i < acb->qiov->niov; i++) { scsi_task_add_data_in_buffer(acb->task, acb->qiov->iov[i].iov_len, acb->qiov->iov[i].iov_base); } +#endif iscsi_set_events(iscsilun); From b37a2e4576530597dda880387e3f4da52c42b5b5 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Wed, 19 Sep 2012 12:08:31 +0400 Subject: [PATCH 0629/1634] Revert "serial: fix retry logic" This reverts commit 67c5322d7000fd105a926eec44bc1765b7d70bdd: I'm not sure if the retry logic has ever worked when not using FIFO mode. I found this while writing a test case although code inspection confirms it is definitely broken. The TSR retry logic will never actually happen because it is guarded by an 'if (s->tsr_rety > 0)' but this is the only place that can ever make the variable greater than zero. That effectively makes the retry logic an 'if (0) I believe this is a typo and the intention was >= 0. Once this is fixed thoug I see double transmits with my test case. This is because in the non FIFO case, serial_xmit may get invoked while LSR.THRE is still high because the character was processed but the retransmit timer was still active. We can handle this by simply checking for LSR.THRE and returning early. It's possible that the FIFO paths also need some attention. Cc: Stefano Stabellini Signed-off-by: Anthony Liguori Even if the previous logic was never worked, new logic breaks stuff - namely, qemu -enable-kvm -nographic -kernel /boot/vmlinuz-$(uname -r) -append console=ttyS0 -serial pty the above command will cause the virtual machine to stuck at startup using 100% CPU till one connects to the pty and sends any char to it. Note this is rather typical invocation for various headless virtual machines by libvirt. So revert this change for now, till a better solution will be found. Signed-off-by: Michael Tokarev Signed-off-by: Anthony Liguori --- hw/serial.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index a5b2a0c609..f0ce9b0c15 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -266,8 +266,6 @@ static void serial_xmit(void *opaque) s->tsr = fifo_get(s,XMIT_FIFO); if (!s->xmit_fifo.count) s->lsr |= UART_LSR_THRE; - } else if ((s->lsr & UART_LSR_THRE)) { - return; } else { s->tsr = s->thr; s->lsr |= UART_LSR_THRE; @@ -279,7 +277,7 @@ static void serial_xmit(void *opaque) /* in loopback mode, say that we just received a char */ serial_receive1(s, &s->tsr, 1); } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { - if ((s->tsr_retry >= 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { + if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { s->tsr_retry++; qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); return; From 58513bde833804bc9395d79fd81aae631b97c348 Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Fri, 18 Jan 2013 12:45:35 -0500 Subject: [PATCH 0630/1634] block: Monitor command commit neglects to report some errors The non-live bdrv_commit() function may return one of the following errors: -ENOTSUP, -EBUSY, -EACCES, -EIO. The only error that is checked in the HMP handler is -EBUSY, so the monitor command 'commit' silently fails for all error cases other than 'Device is in use'. Report error using monitor_printf() and strerror(), and convert existing qerror_report() calls in do_commit() to monitor_printf(). Signed-off-by: Jeff Cody Reviewed-by: Markus Armbruster Signed-off-by: Luiz Capitulino --- blockdev.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/blockdev.c b/blockdev.c index 9126587c45..030070b607 100644 --- a/blockdev.c +++ b/blockdev.c @@ -642,21 +642,17 @@ void do_commit(Monitor *mon, const QDict *qdict) if (!strcmp(device, "all")) { ret = bdrv_commit_all(); - if (ret == -EBUSY) { - qerror_report(QERR_DEVICE_IN_USE, device); - return; - } } else { bs = bdrv_find(device); if (!bs) { - qerror_report(QERR_DEVICE_NOT_FOUND, device); + monitor_printf(mon, "Device '%s' not found\n", device); return; } ret = bdrv_commit(bs); - if (ret == -EBUSY) { - qerror_report(QERR_DEVICE_IN_USE, device); - return; - } + } + if (ret < 0) { + monitor_printf(mon, "'commit' error for '%s': %s\n", device, + strerror(-ret)); } } From 01ceb97e7b8b00a1d4779543fe4b958df7e16890 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 3 Dec 2012 15:56:41 -0200 Subject: [PATCH 0631/1634] balloon: drop old stats code & API Next commit will re-enable balloon stats with a different interface, but this old code conflicts with it. Let's drop it. It's important to note that the QMP and HMP interfaces are also dropped by this commit. That shouldn't be a problem though, because: 1. All QMP fields are optional 2. This feature has always been disabled Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake --- hmp.c | 24 +----------------------- hw/virtio-balloon.c | 24 ------------------------ qapi-schema.json | 20 +------------------- qmp-commands.hx | 13 ------------- 4 files changed, 2 insertions(+), 79 deletions(-) diff --git a/hmp.c b/hmp.c index c7b6ba02fc..ae16916da2 100644 --- a/hmp.c +++ b/hmp.c @@ -465,29 +465,7 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict) return; } - monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20); - if (info->has_mem_swapped_in) { - monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in); - } - if (info->has_mem_swapped_out) { - monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out); - } - if (info->has_major_page_faults) { - monitor_printf(mon, " major_page_faults=%" PRId64, - info->major_page_faults); - } - if (info->has_minor_page_faults) { - monitor_printf(mon, " minor_page_faults=%" PRId64, - info->minor_page_faults); - } - if (info->has_free_mem) { - monitor_printf(mon, " free_mem=%" PRId64, info->free_mem); - } - if (info->has_total_mem) { - monitor_printf(mon, " total_mem=%" PRId64, info->total_mem); - } - - monitor_printf(mon, "\n"); + monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20); qapi_free_BalloonInfo(info); } diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 3040bc63ab..2520cba584 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -164,28 +164,6 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f) static void virtio_balloon_stat(void *opaque, BalloonInfo *info) { VirtIOBalloon *dev = opaque; - -#if 0 - /* Disable guest-provided stats for now. For more details please check: - * https://bugzilla.redhat.com/show_bug.cgi?id=623903 - * - * If you do enable it (which is probably not going to happen as we - * need a new command for it), remember that you also need to fill the - * appropriate members of the BalloonInfo structure so that the stats - * are returned to the client. - */ - if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) { - virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset); - virtio_notify(&dev->vdev, dev->svq); - return; - } -#endif - - /* Stats are not supported. Clear out any stale values that might - * have been set by a more featureful guest kernel. - */ - reset_stats(dev); - info->actual = ram_size - ((uint64_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT); } @@ -255,8 +233,6 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev) s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats); - reset_stats(s); - s->qdev = dev; register_savevm(dev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); diff --git a/qapi-schema.json b/qapi-schema.json index 6d7252b9e8..a4c6eca319 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -977,28 +977,10 @@ # # @actual: the number of bytes the balloon currently contains # -# @mem_swapped_in: #optional number of pages swapped in within the guest -# -# @mem_swapped_out: #optional number of pages swapped out within the guest -# -# @major_page_faults: #optional number of major page faults within the guest -# -# @minor_page_faults: #optional number of minor page faults within the guest -# -# @free_mem: #optional amount of memory (in bytes) free in the guest -# -# @total_mem: #optional amount of memory (in bytes) visible to the guest -# # Since: 0.14.0 # -# Notes: all current versions of QEMU do not fill out optional information in -# this structure. ## -{ 'type': 'BalloonInfo', - 'data': {'actual': 'int', '*mem_swapped_in': 'int', - '*mem_swapped_out': 'int', '*major_page_faults': 'int', - '*minor_page_faults': 'int', '*free_mem': 'int', - '*total_mem': 'int'} } +{ 'type': 'BalloonInfo', 'data': {'actual': 'int' } } ## # @query-balloon: diff --git a/qmp-commands.hx b/qmp-commands.hx index cbf12804be..3be5330bb8 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2549,13 +2549,6 @@ Make an asynchronous request for balloon info. When the request completes a json-object will be returned containing the following data: - "actual": current balloon value in bytes (json-int) -- "mem_swapped_in": Amount of memory swapped in bytes (json-int, optional) -- "mem_swapped_out": Amount of memory swapped out in bytes (json-int, optional) -- "major_page_faults": Number of major faults (json-int, optional) -- "minor_page_faults": Number of minor faults (json-int, optional) -- "free_mem": Total amount of free and unused memory in - bytes (json-int, optional) -- "total_mem": Total amount of available memory in bytes (json-int, optional) Example: @@ -2563,12 +2556,6 @@ Example: <- { "return":{ "actual":1073741824, - "mem_swapped_in":0, - "mem_swapped_out":0, - "major_page_faults":142, - "minor_page_faults":239245, - "free_mem":1014185984, - "total_mem":1044668416 } } From 7e6ccd9c159450e79f42d08112ebe263b0466644 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Sat, 1 Dec 2012 00:14:57 -0200 Subject: [PATCH 0632/1634] balloon: re-enable balloon stats The statistics are now available through device properties via a polling mechanism. First a client has to enable polling, then it can query available stats. Polling is enabled by setting an update interval (in seconds) to a property named guest-stats-polling-interval, like this: { "execute": "qom-set", "arguments": { "path": "/machine/peripheral-anon/device[1]", "property": "guest-stats-polling-interval", "value": 4 } } Then the available stats can be retrieved by querying the guest-stats property. The returned object is a dict containing all available stats. Example: { "execute": "qom-get", "arguments": { "path": "/machine/peripheral-anon/device[1]", "property": "guest-stats" } } { "return": { "stats": { "stat-swap-out": 0, "stat-free-memory": 844943360, "stat-minor-faults": 219028, "stat-major-faults": 235, "stat-total-memory": 1044406272, "stat-swap-in": 0 }, "last-update": 1358529861 } } Please, check the next commit for full documentation. Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake --- hw/virtio-balloon.c | 151 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 1 deletion(-) diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 2520cba584..c0a790264c 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -14,6 +14,7 @@ */ #include "qemu/iov.h" +#include "qemu/timer.h" #include "qemu-common.h" #include "virtio.h" #include "pc.h" @@ -22,6 +23,7 @@ #include "virtio-balloon.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" +#include "qapi/visitor.h" #if defined(__linux__) #include @@ -36,6 +38,9 @@ typedef struct VirtIOBalloon uint64_t stats[VIRTIO_BALLOON_S_NR]; VirtQueueElement stats_vq_elem; size_t stats_vq_offset; + QEMUTimer *stats_timer; + int64_t stats_last_update; + int64_t stats_poll_interval; DeviceState *qdev; } VirtIOBalloon; @@ -53,6 +58,16 @@ static void balloon_page(void *addr, int deflate) #endif } +static const char *balloon_stat_names[] = { + [VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in", + [VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out", + [VIRTIO_BALLOON_S_MAJFLT] = "stat-major-faults", + [VIRTIO_BALLOON_S_MINFLT] = "stat-minor-faults", + [VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory", + [VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory", + [VIRTIO_BALLOON_S_NR] = NULL +}; + /* * reset_stats - Mark all items in the stats array as unset * @@ -67,6 +82,118 @@ static inline void reset_stats(VirtIOBalloon *dev) for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1); } +static bool balloon_stats_supported(const VirtIOBalloon *s) +{ + return s->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ); +} + +static bool balloon_stats_enabled(const VirtIOBalloon *s) +{ + return s->stats_poll_interval > 0; +} + +static void balloon_stats_destroy_timer(VirtIOBalloon *s) +{ + if (balloon_stats_enabled(s)) { + qemu_del_timer(s->stats_timer); + qemu_free_timer(s->stats_timer); + s->stats_timer = NULL; + s->stats_poll_interval = 0; + } +} + +static void balloon_stats_change_timer(VirtIOBalloon *s, int secs) +{ + qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000); +} + +static void balloon_stats_poll_cb(void *opaque) +{ + VirtIOBalloon *s = opaque; + + if (!balloon_stats_supported(s)) { + /* re-schedule */ + balloon_stats_change_timer(s, s->stats_poll_interval); + return; + } + + virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset); + virtio_notify(&s->vdev, s->svq); +} + +static void balloon_stats_get_all(Object *obj, struct Visitor *v, + void *opaque, const char *name, Error **errp) +{ + VirtIOBalloon *s = opaque; + int i; + + if (!s->stats_last_update) { + error_setg(errp, "guest hasn't updated any stats yet"); + return; + } + + visit_start_struct(v, NULL, "guest-stats", name, 0, errp); + visit_type_int(v, &s->stats_last_update, "last-update", errp); + + visit_start_struct(v, NULL, NULL, "stats", 0, errp); + for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { + visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i], + errp); + } + visit_end_struct(v, errp); + + visit_end_struct(v, errp); +} + +static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + VirtIOBalloon *s = opaque; + visit_type_int(v, &s->stats_poll_interval, name, errp); +} + +static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + VirtIOBalloon *s = opaque; + int64_t value; + + visit_type_int(v, &value, name, errp); + if (error_is_set(errp)) { + return; + } + + if (value < 0) { + error_setg(errp, "timer value must be greater than zero"); + return; + } + + if (value == s->stats_poll_interval) { + return; + } + + if (value == 0) { + /* timer=0 disables the timer */ + balloon_stats_destroy_timer(s); + return; + } + + if (balloon_stats_enabled(s)) { + /* timer interval change */ + s->stats_poll_interval = value; + balloon_stats_change_timer(s, value); + return; + } + + /* create a new timer */ + g_assert(s->stats_timer == NULL); + s->stats_timer = qemu_new_timer_ms(vm_clock, balloon_stats_poll_cb, s); + s->stats_poll_interval = value; + balloon_stats_change_timer(s, 0); +} + static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = to_virtio_balloon(vdev); @@ -107,9 +234,10 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) VirtQueueElement *elem = &s->stats_vq_elem; VirtIOBalloonStat stat; size_t offset = 0; + qemu_timeval tv; if (!virtqueue_pop(vq, elem)) { - return; + goto out; } /* Initialize the stats to get rid of any stale values. This is only @@ -128,6 +256,18 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) s->stats[tag] = val; } s->stats_vq_offset = offset; + + if (qemu_gettimeofday(&tv) < 0) { + fprintf(stderr, "warning: %s: failed to get time of day\n", __func__); + goto out; + } + + s->stats_last_update = tv.tv_sec; + +out: + if (balloon_stats_enabled(s)) { + balloon_stats_change_timer(s, s->stats_poll_interval); + } } static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) @@ -237,6 +377,14 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev) register_savevm(dev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); + object_property_add(OBJECT(dev), "guest-stats", "guest statistics", + balloon_stats_get_all, NULL, NULL, s, NULL); + + object_property_add(OBJECT(dev), "guest-stats-polling-interval", "int", + balloon_stats_get_poll_interval, + balloon_stats_set_poll_interval, + NULL, s, NULL); + return &s->vdev; } @@ -244,6 +392,7 @@ void virtio_balloon_exit(VirtIODevice *vdev) { VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev); + balloon_stats_destroy_timer(s); qemu_remove_balloon_handler(s); unregister_savevm(s->qdev, "virtio-balloon", s); virtio_cleanup(vdev); From 045a70857ac07de791ddbf313323c4e4f91e056e Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Tue, 4 Dec 2012 12:04:39 -0200 Subject: [PATCH 0633/1634] docs: document virtio-balloon stats Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake --- docs/virtio-balloon-stats.txt | 104 ++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 docs/virtio-balloon-stats.txt diff --git a/docs/virtio-balloon-stats.txt b/docs/virtio-balloon-stats.txt new file mode 100644 index 0000000000..f74612f468 --- /dev/null +++ b/docs/virtio-balloon-stats.txt @@ -0,0 +1,104 @@ +virtio balloon memory statistics +================================ + +The virtio balloon driver supports guest memory statistics reporting. These +statistics are available to QEMU users as QOM (QEMU Object Model) device +properties via a polling mechanism. + +Before querying the available stats, clients first have to enable polling. +This is done by writing a time interval value (in seconds) to the +guest-stats-polling-interval property. This value can be: + + > 0 enables polling in the specified interval. If polling is already + enabled, the polling time interval is changed to the new value + + 0 disables polling. Previous polled statistics are still valid and + can be queried. + +Once polling is enabled, the virtio-balloon device in QEMU will start +polling the guest's balloon driver for new stats in the specified time +interval. + +To retrieve those stats, clients have to query the guest-stats property, +which will return a dictionary containing: + + o A key named 'stats', containing all available stats. If the guest + doesn't support a particular stat, or if it couldn't be retrieved, + its value will be -1. Currently, the following stats are supported: + + - stat-swap-in + - stat-swap-out + - stat-major-faults + - stat-minor-faults + - stat-free-memory + - stat-total-memory + + o A key named last-update, which contains the last stats update + timestamp in seconds. Since this timestamp is generated by the host, + a buggy guest can't influence its value + +It's also important to note the following: + + - Previously polled statistics remain available even if the polling is + later disabled + + - As noted above, if a guest doesn't support a particular stat its value + will always be -1. However, it's also possible that a guest temporarily + couldn't update one or even all stats. If this happens, just wait for + the next update + + - Polling can be enabled even if the guest doesn't have stats support + or the balloon driver wasn't loaded in the guest. If this is the case + and stats are queried, an error will be returned + + - The polling timer is only re-armed when the guest responds to the + statistics request. This means that if a (buggy) guest doesn't ever + respond to the request the timer will never be re-armed, which has + the same effect as disabling polling + +Here are a few examples. QEMU is started with '-balloon virtio', which +generates '/machine/peripheral-anon/device[1]' as the QOM path for the +balloon device. + +Enable polling with 2 seconds interval: + +{ "execute": "qom-set", + "arguments": { "path": "/machine/peripheral-anon/device[1]", + "property": "guest-stats-polling-interval", "value": 2 } } + +{ "return": {} } + +Change polling to 10 seconds: + +{ "execute": "qom-set", + "arguments": { "path": "/machine/peripheral-anon/device[1]", + "property": "guest-stats-polling-interval", "value": 10 } } + +{ "return": {} } + +Get stats: + +{ "execute": "qom-get", + "arguments": { "path": "/machine/peripheral-anon/device[1]", + "property": "guest-stats" } } +{ + "return": { + "stats": { + "stat-swap-out": 0, + "stat-free-memory": 844943360, + "stat-minor-faults": 219028, + "stat-major-faults": 235, + "stat-total-memory": 1044406272, + "stat-swap-in": 0 + }, + "last-update": 1358529861 + } +} + +Disable polling: + +{ "execute": "qom-set", + "arguments": { "path": "/machine/peripheral-anon/device[1]", + "property": "stats-polling-interval", "value": 0 } } + +{ "return": {} } From 51767e7cf2c3abc07d30009ab3d6262bdfd89b8b Mon Sep 17 00:00:00 2001 From: Lei Li Date: Fri, 25 Jan 2013 00:03:19 +0800 Subject: [PATCH 0634/1634] qemu-char: Add new char backend CirMemCharDriver Signed-off-by: Lei Li Signed-off-by: Luiz Capitulino --- qemu-char.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 10 +++++ 2 files changed, 124 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 9ba0573c6a..80458697f2 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -98,6 +98,7 @@ #include "ui/qemu-spice.h" #define READ_BUF_LEN 4096 +#define CBUFF_SIZE 65536 /***********************************************************/ /* character device */ @@ -2643,6 +2644,110 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr) return d->outbuf_size; } +/*********************************************************/ +/*CircularMemory chardev*/ + +typedef struct { + size_t size; + size_t prod; + size_t cons; + uint8_t *cbuf; +} CirMemCharDriver; + +static bool cirmem_chr_is_empty(const CharDriverState *chr) +{ + const CirMemCharDriver *d = chr->opaque; + + return d->cons == d->prod; +} + +static size_t qemu_chr_cirmem_count(const CharDriverState *chr) +{ + const CirMemCharDriver *d = chr->opaque; + + return (d->prod - d->cons); +} + +static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + CirMemCharDriver *d = chr->opaque; + int i; + + if (!buf || (len < 0)) { + return -1; + } + + for (i = 0; i < len; i++ ) { + /* Avoid writing the IAC information to the queue. */ + if ((unsigned char)buf[i] == IAC) { + continue; + } + + d->cbuf[d->prod++ % d->size] = buf[i]; + if ((d->prod - d->cons) > d->size) { + d->cons = d->prod - d->size; + } + } + + return 0; +} + +static int cirmem_chr_read(CharDriverState *chr, uint8_t *buf, int len) +{ + CirMemCharDriver *d = chr->opaque; + int i; + + for (i = 0; i < len && !cirmem_chr_is_empty(chr); i++) { + buf[i] = d->cbuf[d->cons++ % d->size]; + } + + return i; +} + +static void cirmem_chr_close(struct CharDriverState *chr) +{ + CirMemCharDriver *d = chr->opaque; + + g_free(d->cbuf); + g_free(d); + chr->opaque = NULL; +} + +static CharDriverState *qemu_chr_open_cirmemchr(QemuOpts *opts) +{ + CharDriverState *chr; + CirMemCharDriver *d; + + chr = g_malloc0(sizeof(CharDriverState)); + d = g_malloc(sizeof(*d)); + + d->size = qemu_opt_get_number(opts, "maxcapacity", 0); + if (d->size == 0) { + d->size = CBUFF_SIZE; + } + + /* The size must be power of 2 */ + if (d->size & (d->size - 1)) { + fprintf(stderr, "chardev: size of memory device must be power of 2\n"); + goto fail; + } + + d->prod = 0; + d->cons = 0; + d->cbuf = g_malloc0(d->size); + + chr->opaque = d; + chr->chr_write = cirmem_chr_write; + chr->chr_close = cirmem_chr_close; + + return chr; + +fail: + g_free(d); + g_free(chr); + return NULL; +} + QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; @@ -2697,6 +2802,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) qemu_opt_set(opts, "path", filename); return opts; } + if (strstart(filename, "memory", &p)) { + qemu_opt_set(opts, "backend", "memory"); + qemu_opt_set(opts, "maxcapacity", p); + return opts; + } if (strstart(filename, "file:", &p)) { qemu_opt_set(opts, "backend", "file"); qemu_opt_set(opts, "path", p); @@ -2796,6 +2906,7 @@ static const struct { { .name = "udp", .open = qemu_chr_open_udp }, { .name = "msmouse", .open = qemu_chr_open_msmouse }, { .name = "vc", .open = text_console_init }, + { .name = "memory", .open = qemu_chr_open_cirmemchr }, #ifdef _WIN32 { .name = "file", .open = qemu_chr_open_win_file_out }, { .name = "pipe", .open = qemu_chr_open_win_pipe }, @@ -3055,6 +3166,9 @@ QemuOptsList qemu_chardev_opts = { },{ .name = "debug", .type = QEMU_OPT_NUMBER, + },{ + .name = "maxcapacity", + .type = QEMU_OPT_NUMBER, }, { /* end of list */ } }, diff --git a/qemu-options.hx b/qemu-options.hx index 4e2b4994a2..2d44137bf9 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1736,6 +1736,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev msmouse,id=id[,mux=on|off]\n" "-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]\n" " [,mux=on|off]\n" + "-chardev memory,id=id,maxcapacity=maxcapacity\n" "-chardev file,id=id,path=path[,mux=on|off]\n" "-chardev pipe,id=id,path=path[,mux=on|off]\n" #ifdef _WIN32 @@ -1777,6 +1778,7 @@ Backend is one of: @option{udp}, @option{msmouse}, @option{vc}, +@option{memory}, @option{file}, @option{pipe}, @option{console}, @@ -1885,6 +1887,14 @@ the console, in pixels. @option{cols} and @option{rows} specify that the console be sized to fit a text console with the given dimensions. +@item -chardev memory ,id=@var{id} ,maxcapacity=@var{maxcapacity} + +Create a circular buffer with fixed size indicated by optionally @option{maxcapacity} +which will be default 64K if it is not given. + +@option{maxcapacity} specifies the max capacity of the size of circular buffer +to create. Should be power of 2. + @item -chardev file ,id=@var{id} ,path=@var{path} Log all traffic received from the guest to a file. From 1f590cf9455c571799d1bfc0777255fa0796d4da Mon Sep 17 00:00:00 2001 From: Lei Li Date: Fri, 25 Jan 2013 00:03:20 +0800 Subject: [PATCH 0635/1634] QAPI: Introduce memchar-write QMP command Signed-off-by: Lei Li Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 18 ++++++++++++++++++ hmp.c | 13 +++++++++++++ hmp.h | 1 + qapi-schema.json | 38 ++++++++++++++++++++++++++++++++++++++ qemu-char.c | 42 ++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 145 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index 0934b9b915..bcfea11c38 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -837,6 +837,24 @@ STEXI @item nmi @var{cpu} @findex nmi Inject an NMI on the given CPU (x86 only). + +ETEXI + + { + .name = "memchar_write", + .args_type = "device:s,data:s", + .params = "device data", + .help = "Provide writing interface for CirMemCharDriver. Write" + "'data' to it.", + .mhandler.cmd = hmp_memchar_write, + }, + +STEXI +@item memchar_write @var{device} @var{data} +@findex memchar_write +Provide writing interface for CirMemCharDriver. Write @var{data} +to char device 'memory'. + ETEXI { diff --git a/hmp.c b/hmp.c index ae16916da2..cd614e8720 100644 --- a/hmp.c +++ b/hmp.c @@ -662,6 +662,19 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &errp); } +void hmp_memchar_write(Monitor *mon, const QDict *qdict) +{ + uint32_t size; + const char *chardev = qdict_get_str(qdict, "device"); + const char *data = qdict_get_str(qdict, "data"); + Error *errp = NULL; + + size = strlen(data); + qmp_memchar_write(chardev, size, data, false, 0, &errp); + + hmp_handle_error(mon, &errp); +} + static void hmp_cont_cb(void *opaque, int err) { if (!err) { diff --git a/hmp.h b/hmp.h index 44be683fcc..06d6ea23e7 100644 --- a/hmp.h +++ b/hmp.h @@ -43,6 +43,7 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict); void hmp_cpu(Monitor *mon, const QDict *qdict); void hmp_memsave(Monitor *mon, const QDict *qdict); void hmp_pmemsave(Monitor *mon, const QDict *qdict); +void hmp_memchar_write(Monitor *mon, const QDict *qdict); void hmp_cont(Monitor *mon, const QDict *qdict); void hmp_system_wakeup(Monitor *mon, const QDict *qdict); void hmp_inject_nmi(Monitor *mon, const QDict *qdict); diff --git a/qapi-schema.json b/qapi-schema.json index a4c6eca319..d6231e5283 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -324,6 +324,44 @@ ## { 'command': 'query-chardev', 'returns': ['ChardevInfo'] } +## +# @DataFormat: +# +# An enumeration of data format. +# +# @utf8: The data format is 'utf8'. +# +# @base64: The data format is 'base64'. +# +# Since: 1.4 +## +{ 'enum': 'DataFormat' + 'data': [ 'utf8', 'base64' ] } + +## +# @memchar-write: +# +# Provide writing interface for memchardev. Write data to char +# device 'memory'. +# +# @device: the name of the memory char device. +# +# @size: the size to write in bytes. +# +# @data: the source data write to memchar. +# +# @format: #optional the format of the data write to chardev 'memory', +# by default is 'utf8'. +# +# Returns: Nothing on success +# If @device is not a valid char device, DeviceNotFound +# +# Since: 1.4 +## +{ 'command': 'memchar-write', + 'data': {'device': 'str', 'size': 'int', 'data': 'str', + '*format': 'DataFormat'} } + ## # @CommandInfo: # diff --git a/qemu-char.c b/qemu-char.c index 80458697f2..dbd1a7c066 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2748,6 +2748,48 @@ fail: return NULL; } +static bool qemu_is_chr(const CharDriverState *chr, const char *filename) +{ + return strcmp(chr->filename, filename); +} + +void qmp_memchar_write(const char *device, int64_t size, + const char *data, bool has_format, + enum DataFormat format, + Error **errp) +{ + CharDriverState *chr; + guchar *write_data; + int ret; + gsize write_count; + + chr = qemu_chr_find(device); + if (!chr) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; + } + + if (qemu_is_chr(chr, "memory")) { + error_setg(errp,"%s is not memory char device", device); + return; + } + + write_count = (gsize)size; + + if (has_format && (format == DATA_FORMAT_BASE64)) { + write_data = g_base64_decode(data, &write_count); + } else { + write_data = (uint8_t *)data; + } + + ret = cirmem_chr_write(chr, write_data, write_count); + + if (ret < 0) { + error_setg(errp, "Failed to write to device %s", device); + return; + } +} + QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; diff --git a/qmp-commands.hx b/qmp-commands.hx index 3be5330bb8..96de0b8852 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -463,6 +463,39 @@ Example: Note: inject-nmi fails when the guest doesn't support injecting. Currently, only x86 guests do. +EQMP + + { + .name = "memchar-write", + .args_type = "device:s,size:i,data:s,format:s?", + .mhandler.cmd_new = qmp_marshal_input_memchar_write, + }, + +SQMP +memchar-write +------------- + +Provide writing interface for CirMemCharDriver. Write data to memory +char device. + +Arguments: + +- "device": the name of the char device, must be unique (json-string) +- "size": the memory size, in bytes, should be power of 2 (json-int) +- "data": the source data write to memory (json-string) +- "format": the data format write to memory, default is + utf8. (json-string, optional) + - Possible values: "utf8", "base64" + +Example: + +-> { "execute": "memchar-write", + "arguments": { "device": foo, + "size": 8, + "data": "abcdefgh", + "format": "utf8" } } +<- { "return": {} } + EQMP { From 49b6d7220bce42e6c06e0dbb61969a997868491f Mon Sep 17 00:00:00 2001 From: Lei Li Date: Fri, 25 Jan 2013 00:03:21 +0800 Subject: [PATCH 0636/1634] QAPI: Introduce memchar-read QMP command Signed-off-by: Lei Li Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 21 +++++++++++++++++++++ hmp.c | 21 +++++++++++++++++++++ hmp.h | 1 + qapi-schema.json | 36 ++++++++++++++++++++++++++++++++++++ qemu-char.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ qmp-commands.hx | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 159 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index bcfea11c38..bdd48f3469 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -855,6 +855,27 @@ STEXI Provide writing interface for CirMemCharDriver. Write @var{data} to char device 'memory'. +ETEXI + + { + .name = "memchar_read", + .args_type = "device:s,size:i", + .params = "device size", + .help = "Provide read interface for CirMemCharDriver. Read from" + "it and return the data with size.", + .mhandler.cmd = hmp_memchar_read, + }, + +STEXI +@item memchar_read @var{device} +@findex memchar_read +Provide read interface for CirMemCharDriver. Read from char device +'memory' and return the data. + +@var{size} is the size of data want to read from. Refer to unencoded +size of the raw data, would adjust to the init size of the memchar +if the requested size is larger than it. + ETEXI { diff --git a/hmp.c b/hmp.c index cd614e8720..7e259c2b56 100644 --- a/hmp.c +++ b/hmp.c @@ -675,6 +675,27 @@ void hmp_memchar_write(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &errp); } +void hmp_memchar_read(Monitor *mon, const QDict *qdict) +{ + uint32_t size = qdict_get_int(qdict, "size"); + const char *chardev = qdict_get_str(qdict, "device"); + MemCharRead *meminfo; + Error *errp = NULL; + + meminfo = qmp_memchar_read(chardev, size, false, 0, &errp); + if (errp) { + monitor_printf(mon, "%s\n", error_get_pretty(errp)); + error_free(errp); + return; + } + + if (meminfo->count > 0) { + monitor_printf(mon, "%s\n", meminfo->data); + } + + qapi_free_MemCharRead(meminfo); +} + static void hmp_cont_cb(void *opaque, int err) { if (!err) { diff --git a/hmp.h b/hmp.h index 06d6ea23e7..076d8cf378 100644 --- a/hmp.h +++ b/hmp.h @@ -44,6 +44,7 @@ void hmp_cpu(Monitor *mon, const QDict *qdict); void hmp_memsave(Monitor *mon, const QDict *qdict); void hmp_pmemsave(Monitor *mon, const QDict *qdict); void hmp_memchar_write(Monitor *mon, const QDict *qdict); +void hmp_memchar_read(Monitor *mon, const QDict *qdict); void hmp_cont(Monitor *mon, const QDict *qdict); void hmp_system_wakeup(Monitor *mon, const QDict *qdict); void hmp_inject_nmi(Monitor *mon, const QDict *qdict); diff --git a/qapi-schema.json b/qapi-schema.json index d6231e5283..6c29f569b9 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -362,6 +362,42 @@ 'data': {'device': 'str', 'size': 'int', 'data': 'str', '*format': 'DataFormat'} } +## +# @MemCharRead +# +# Result of QMP command memchar-read. +# +# @data: The data read from memchar as string. +# +# @count: The numbers of bytes read from. +# +# Since: 1.4 +## +{ 'type': 'MemCharRead', + 'data': { 'data': 'str', 'count': 'int' } } + +## +# @memchar-read: +# +# Provide read interface for memchardev. Read from the char +# device 'memory' and return the data. +# +# @device: the name of the memory char device. +# +# @size: the size to read in bytes. +# +# @format: #optional the format of the data want to read from +# memchardev, by default is 'utf8'. +# +# Returns: @MemCharRead +# If @device is not a valid memchr device, DeviceNotFound +# +# Since: 1.4 +## +{ 'command': 'memchar-read', + 'data': {'device': 'str', 'size': 'int', '*format': 'DataFormat'}, + 'returns': 'MemCharRead' } + ## # @CommandInfo: # diff --git a/qemu-char.c b/qemu-char.c index dbd1a7c066..1d1c631c98 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2790,6 +2790,53 @@ void qmp_memchar_write(const char *device, int64_t size, } } +MemCharRead *qmp_memchar_read(const char *device, int64_t size, + bool has_format, enum DataFormat format, + Error **errp) +{ + CharDriverState *chr; + guchar *read_data; + MemCharRead *meminfo; + size_t count; + + chr = qemu_chr_find(device); + if (!chr) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return NULL; + } + + if (qemu_is_chr(chr, "memory")) { + error_setg(errp,"%s is not memory char device", device); + return NULL; + } + + if (size <= 0) { + error_setg(errp, "size must be greater than zero"); + return NULL; + } + + meminfo = g_malloc0(sizeof(MemCharRead)); + + count = qemu_chr_cirmem_count(chr); + if (count == 0) { + meminfo->data = g_strdup(""); + return meminfo; + } + + size = size > count ? count : size; + read_data = g_malloc0(size + 1); + + meminfo->count = cirmem_chr_read(chr, read_data, size); + + if (has_format && (format == DATA_FORMAT_BASE64)) { + meminfo->data = g_base64_encode(read_data, (size_t)meminfo->count); + } else { + meminfo->data = (char *)read_data; + } + + return meminfo; +} + QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; diff --git a/qmp-commands.hx b/qmp-commands.hx index 96de0b8852..f0f7d2b395 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -496,6 +496,39 @@ Example: "format": "utf8" } } <- { "return": {} } +EQMP + + { + .name = "memchar-read", + .args_type = "device:s,size:i,format:s?", + .mhandler.cmd_new = qmp_marshal_input_memchar_read, + }, + +SQMP +memchar-read +------------- + +Provide read interface for CirMemCharDriver. Read from the char +device memory and return the data with size. + +Arguments: + +- "device": the name of the char device, must be unique (json-string) +- "size": the memory size wanted to read in bytes (refer to unencoded + size of the raw data), would adjust to the init size of the + memchar if the requested size is larger than it. (json-int) +- "format": the data format write to memchardev, default is + utf8. (json-string, optional) + - Possible values: "utf8", "base64" + +Example: + +-> { "execute": "memchar-read", + "arguments": { "device": foo, + "size": 1000, + "format": "utf8" } } +<- { "return": { "data": "data string...", "count": 1000 } } + EQMP { From e7c033c3fa22a1e42d9ba57fed6ddecfbce3a01c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:40 +0100 Subject: [PATCH 0637/1634] add hierarchical bitmap data type and test cases HBitmaps provides an array of bits. The bits are stored as usual in an array of unsigned longs, but HBitmap is also optimized to provide fast iteration over set bits; going from one bit to the next is O(logB n) worst case, with B = sizeof(long) * CHAR_BIT: the result is low enough that the number of levels is in fact fixed. In order to do this, it stacks multiple bitmaps with progressively coarser granularity; in all levels except the last, bit N is set iff the N-th unsigned long is nonzero in the immediately next level. When iteration completes on the last level it can examine the 2nd-last level to quickly skip entire words, and even do so recursively to skip blocks of 64 words or powers thereof (32 on 32-bit machines). Given an index in the bitmap, it can be split in group of bits like this (for the 64-bit case): bits 0-57 => word in the last bitmap | bits 58-63 => bit in the word bits 0-51 => word in the 2nd-last bitmap | bits 52-57 => bit in the word bits 0-45 => word in the 3rd-last bitmap | bits 46-51 => bit in the word So it is easy to move up simply by shifting the index right by log2(BITS_PER_LONG) bits. To move down, you shift the index left similarly, and add the word index within the group. Iteration uses ffs (find first set bit) to find the next word to examine; this operation can be done in constant time in most current architectures. Setting or clearing a range of m bits on all levels, the work to perform is O(m + m/W + m/W^2 + ...), which is O(m) like on a regular bitmap. When iterating on a bitmap, each bit (on any level) is only visited once. Hence, The total cost of visiting a bitmap with m bits in it is the number of bits that are set in all bitmaps. Unless the bitmap is extremely sparse, this is also O(m + m/W + m/W^2 + ...), so the amortized cost of advancing from one bit to the next is usually constant. Reviewed-by: Laszlo Ersek Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- include/qemu/hbitmap.h | 207 +++++++++++++++++++++ tests/Makefile | 3 + tests/test-hbitmap.c | 408 +++++++++++++++++++++++++++++++++++++++++ trace-events | 5 + util/Makefile.objs | 2 +- util/hbitmap.c | 400 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1024 insertions(+), 1 deletion(-) create mode 100644 include/qemu/hbitmap.h create mode 100644 tests/test-hbitmap.c create mode 100644 util/hbitmap.c diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h new file mode 100644 index 0000000000..7ddfb66808 --- /dev/null +++ b/include/qemu/hbitmap.h @@ -0,0 +1,207 @@ +/* + * Hierarchical Bitmap Data Type + * + * Copyright Red Hat, Inc., 2012 + * + * Author: Paolo Bonzini + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#ifndef HBITMAP_H +#define HBITMAP_H 1 + +#include +#include +#include +#include "bitops.h" + +typedef struct HBitmap HBitmap; +typedef struct HBitmapIter HBitmapIter; + +#define BITS_PER_LEVEL (BITS_PER_LONG == 32 ? 5 : 6) + +/* For 32-bit, the largest that fits in a 4 GiB address space. + * For 64-bit, the number of sectors in 1 PiB. Good luck, in + * either case... :) + */ +#define HBITMAP_LOG_MAX_SIZE (BITS_PER_LONG == 32 ? 34 : 41) + +/* We need to place a sentinel in level 0 to speed up iteration. Thus, + * we do this instead of HBITMAP_LOG_MAX_SIZE / BITS_PER_LEVEL. The + * difference is that it allocates an extra level when HBITMAP_LOG_MAX_SIZE + * is an exact multiple of BITS_PER_LEVEL. + */ +#define HBITMAP_LEVELS ((HBITMAP_LOG_MAX_SIZE / BITS_PER_LEVEL) + 1) + +struct HBitmapIter { + const HBitmap *hb; + + /* Copied from hb for access in the inline functions (hb is opaque). */ + int granularity; + + /* Entry offset into the last-level array of longs. */ + size_t pos; + + /* The currently-active path in the tree. Each item of cur[i] stores + * the bits (i.e. the subtrees) yet to be processed under that node. + */ + unsigned long cur[HBITMAP_LEVELS]; +}; + +/** + * hbitmap_alloc: + * @size: Number of bits in the bitmap. + * @granularity: Granularity of the bitmap. Aligned groups of 2^@granularity + * bits will be represented by a single bit. Each operation on a + * range of bits first rounds the bits to determine which group they land + * in, and then affect the entire set; iteration will only visit the first + * bit of each group. + * + * Allocate a new HBitmap. + */ +HBitmap *hbitmap_alloc(uint64_t size, int granularity); + +/** + * hbitmap_empty: + * @hb: HBitmap to operate on. + * + * Return whether the bitmap is empty. + */ +bool hbitmap_empty(const HBitmap *hb); + +/** + * hbitmap_granularity: + * @hb: HBitmap to operate on. + * + * Return the granularity of the HBitmap. + */ +int hbitmap_granularity(const HBitmap *hb); + +/** + * hbitmap_count: + * @hb: HBitmap to operate on. + * + * Return the number of bits set in the HBitmap. + */ +uint64_t hbitmap_count(const HBitmap *hb); + +/** + * hbitmap_set: + * @hb: HBitmap to operate on. + * @start: First bit to set (0-based). + * @count: Number of bits to set. + * + * Set a consecutive range of bits in an HBitmap. + */ +void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count); + +/** + * hbitmap_reset: + * @hb: HBitmap to operate on. + * @start: First bit to reset (0-based). + * @count: Number of bits to reset. + * + * Reset a consecutive range of bits in an HBitmap. + */ +void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count); + +/** + * hbitmap_get: + * @hb: HBitmap to operate on. + * @item: Bit to query (0-based). + * + * Return whether the @item-th bit in an HBitmap is set. + */ +bool hbitmap_get(const HBitmap *hb, uint64_t item); + +/** + * hbitmap_free: + * @hb: HBitmap to operate on. + * + * Free an HBitmap and all of its associated memory. + */ +void hbitmap_free(HBitmap *hb); + +/** + * hbitmap_iter_init: + * @hbi: HBitmapIter to initialize. + * @hb: HBitmap to iterate on. + * @first: First bit to visit (0-based). + * + * Set up @hbi to iterate on the HBitmap @hb. hbitmap_iter_next will return + * the lowest-numbered bit that is set in @hb, starting at @first. + * + * Concurrent setting of bits is acceptable, and will at worst cause the + * iteration to miss some of those bits. Resetting bits before the current + * position of the iterator is also okay. However, concurrent resetting of + * bits can lead to unexpected behavior if the iterator has not yet reached + * those bits. + */ +void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first); + +/* hbitmap_iter_skip_words: + * @hbi: HBitmapIter to operate on. + * + * Internal function used by hbitmap_iter_next and hbitmap_iter_next_word. + */ +unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi); + +/** + * hbitmap_iter_next: + * @hbi: HBitmapIter to operate on. + * + * Return the next bit that is set in @hbi's associated HBitmap, + * or -1 if all remaining bits are zero. + */ +static inline int64_t hbitmap_iter_next(HBitmapIter *hbi) +{ + unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1]; + int64_t item; + + if (cur == 0) { + cur = hbitmap_iter_skip_words(hbi); + if (cur == 0) { + return -1; + } + } + + /* The next call will resume work from the next bit. */ + hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); + item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ffsl(cur) - 1; + + return item << hbi->granularity; +} + +/** + * hbitmap_iter_next_word: + * @hbi: HBitmapIter to operate on. + * @p_cur: Location where to store the next non-zero word. + * + * Return the index of the next nonzero word that is set in @hbi's + * associated HBitmap, and set *p_cur to the content of that word + * (bits before the index that was passed to hbitmap_iter_init are + * trimmed on the first call). Return -1, and set *p_cur to zero, + * if all remaining words are zero. + */ +static inline size_t hbitmap_iter_next_word(HBitmapIter *hbi, unsigned long *p_cur) +{ + unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1]; + + if (cur == 0) { + cur = hbitmap_iter_skip_words(hbi); + if (cur == 0) { + *p_cur = 0; + return -1; + } + } + + /* The next call will resume work from the next word. */ + hbi->cur[HBITMAP_LEVELS - 1] = 0; + *p_cur = cur; + return hbi->pos; +} + + +#endif diff --git a/tests/Makefile b/tests/Makefile index d86e95a400..b3a6d8697b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -45,6 +45,8 @@ gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c check-unit-y += tests/test-thread-pool$(EXESUF) gcov-files-test-thread-pool-y = thread-pool.c +gcov-files-test-hbitmap-y = util/hbitmap.c +check-unit-y += tests/test-hbitmap$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -86,6 +88,7 @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a +tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c new file mode 100644 index 0000000000..fcc6a00fc3 --- /dev/null +++ b/tests/test-hbitmap.c @@ -0,0 +1,408 @@ +/* + * Hierarchical bitmap unit-tests. + * + * Copyright (C) 2012 Red Hat Inc. + * + * Author: Paolo Bonzini + * + * 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 +#include +#include "qemu/hbitmap.h" + +#define LOG_BITS_PER_LONG (BITS_PER_LONG == 32 ? 5 : 6) + +#define L1 BITS_PER_LONG +#define L2 (BITS_PER_LONG * L1) +#define L3 (BITS_PER_LONG * L2) + +typedef struct TestHBitmapData { + HBitmap *hb; + unsigned long *bits; + size_t size; + int granularity; +} TestHBitmapData; + + +/* Check that the HBitmap and the shadow bitmap contain the same data, + * ignoring the same "first" bits. + */ +static void hbitmap_test_check(TestHBitmapData *data, + uint64_t first) +{ + uint64_t count = 0; + size_t pos; + int bit; + HBitmapIter hbi; + int64_t i, next; + + hbitmap_iter_init(&hbi, data->hb, first); + + i = first; + for (;;) { + next = hbitmap_iter_next(&hbi); + if (next < 0) { + next = data->size; + } + + while (i < next) { + pos = i >> LOG_BITS_PER_LONG; + bit = i & (BITS_PER_LONG - 1); + i++; + g_assert_cmpint(data->bits[pos] & (1UL << bit), ==, 0); + } + + if (next == data->size) { + break; + } + + pos = i >> LOG_BITS_PER_LONG; + bit = i & (BITS_PER_LONG - 1); + i++; + count++; + g_assert_cmpint(data->bits[pos] & (1UL << bit), !=, 0); + } + + if (first == 0) { + g_assert_cmpint(count << data->granularity, ==, hbitmap_count(data->hb)); + } +} + +/* This is provided instead of a test setup function so that the sizes + are kept in the test functions (and not in main()) */ +static void hbitmap_test_init(TestHBitmapData *data, + uint64_t size, int granularity) +{ + size_t n; + data->hb = hbitmap_alloc(size, granularity); + + n = (size + BITS_PER_LONG - 1) / BITS_PER_LONG; + if (n == 0) { + n = 1; + } + data->bits = g_new0(unsigned long, n); + data->size = size; + data->granularity = granularity; + hbitmap_test_check(data, 0); +} + +static void hbitmap_test_teardown(TestHBitmapData *data, + const void *unused) +{ + if (data->hb) { + hbitmap_free(data->hb); + data->hb = NULL; + } + if (data->bits) { + g_free(data->bits); + data->bits = NULL; + } +} + +/* Set a range in the HBitmap and in the shadow "simple" bitmap. + * The two bitmaps are then tested against each other. + */ +static void hbitmap_test_set(TestHBitmapData *data, + uint64_t first, uint64_t count) +{ + hbitmap_set(data->hb, first, count); + while (count-- != 0) { + size_t pos = first >> LOG_BITS_PER_LONG; + int bit = first & (BITS_PER_LONG - 1); + first++; + + data->bits[pos] |= 1UL << bit; + } + + if (data->granularity == 0) { + hbitmap_test_check(data, 0); + } +} + +/* Reset a range in the HBitmap and in the shadow "simple" bitmap. + */ +static void hbitmap_test_reset(TestHBitmapData *data, + uint64_t first, uint64_t count) +{ + hbitmap_reset(data->hb, first, count); + while (count-- != 0) { + size_t pos = first >> LOG_BITS_PER_LONG; + int bit = first & (BITS_PER_LONG - 1); + first++; + + data->bits[pos] &= ~(1UL << bit); + } + + if (data->granularity == 0) { + hbitmap_test_check(data, 0); + } +} + +static void hbitmap_test_check_get(TestHBitmapData *data) +{ + uint64_t count = 0; + uint64_t i; + + for (i = 0; i < data->size; i++) { + size_t pos = i >> LOG_BITS_PER_LONG; + int bit = i & (BITS_PER_LONG - 1); + unsigned long val = data->bits[pos] & (1UL << bit); + count += hbitmap_get(data->hb, i); + g_assert_cmpint(hbitmap_get(data->hb, i), ==, val != 0); + } + g_assert_cmpint(count, ==, hbitmap_count(data->hb)); +} + +static void test_hbitmap_zero(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, 0, 0); +} + +static void test_hbitmap_unaligned(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3 + 23, 0); + hbitmap_test_set(data, 0, 1); + hbitmap_test_set(data, L3 + 22, 1); +} + +static void test_hbitmap_iter_empty(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L1, 0); +} + +static void test_hbitmap_iter_partial(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3, 0); + hbitmap_test_set(data, 0, L3); + hbitmap_test_check(data, 1); + hbitmap_test_check(data, L1 - 1); + hbitmap_test_check(data, L1); + hbitmap_test_check(data, L1 * 2 - 1); + hbitmap_test_check(data, L2 - 1); + hbitmap_test_check(data, L2); + hbitmap_test_check(data, L2 + 1); + hbitmap_test_check(data, L2 + L1); + hbitmap_test_check(data, L2 + L1 * 2 - 1); + hbitmap_test_check(data, L2 * 2 - 1); + hbitmap_test_check(data, L2 * 2); + hbitmap_test_check(data, L2 * 2 + 1); + hbitmap_test_check(data, L2 * 2 + L1); + hbitmap_test_check(data, L2 * 2 + L1 * 2 - 1); + hbitmap_test_check(data, L3 / 2); +} + +static void test_hbitmap_iter_past(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3, 0); + hbitmap_test_set(data, 0, L3); + hbitmap_test_check(data, L3); +} + +static void test_hbitmap_set_all(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3, 0); + hbitmap_test_set(data, 0, L3); +} + +static void test_hbitmap_get_all(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3, 0); + hbitmap_test_set(data, 0, L3); + hbitmap_test_check_get(data); +} + +static void test_hbitmap_get_some(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, 2 * L2, 0); + hbitmap_test_set(data, 10, 1); + hbitmap_test_check_get(data); + hbitmap_test_set(data, L1 - 1, 1); + hbitmap_test_check_get(data); + hbitmap_test_set(data, L1, 1); + hbitmap_test_check_get(data); + hbitmap_test_set(data, L2 - 1, 1); + hbitmap_test_check_get(data); + hbitmap_test_set(data, L2, 1); + hbitmap_test_check_get(data); +} + +static void test_hbitmap_set_one(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, 2 * L2, 0); + hbitmap_test_set(data, 10, 1); + hbitmap_test_set(data, L1 - 1, 1); + hbitmap_test_set(data, L1, 1); + hbitmap_test_set(data, L2 - 1, 1); + hbitmap_test_set(data, L2, 1); +} + +static void test_hbitmap_set_two_elem(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, 2 * L2, 0); + hbitmap_test_set(data, L1 - 1, 2); + hbitmap_test_set(data, L1 * 2 - 1, 4); + hbitmap_test_set(data, L1 * 4, L1 + 1); + hbitmap_test_set(data, L1 * 8 - 1, L1 + 1); + hbitmap_test_set(data, L2 - 1, 2); + hbitmap_test_set(data, L2 + L1 - 1, 8); + hbitmap_test_set(data, L2 + L1 * 4, L1 + 1); + hbitmap_test_set(data, L2 + L1 * 8 - 1, L1 + 1); +} + +static void test_hbitmap_set(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3 * 2, 0); + hbitmap_test_set(data, L1 - 1, L1 + 2); + hbitmap_test_set(data, L1 * 3 - 1, L1 + 2); + hbitmap_test_set(data, L1 * 5, L1 * 2 + 1); + hbitmap_test_set(data, L1 * 8 - 1, L1 * 2 + 1); + hbitmap_test_set(data, L2 - 1, L1 + 2); + hbitmap_test_set(data, L2 + L1 * 2 - 1, L1 + 2); + hbitmap_test_set(data, L2 + L1 * 4, L1 * 2 + 1); + hbitmap_test_set(data, L2 + L1 * 7 - 1, L1 * 2 + 1); + hbitmap_test_set(data, L2 * 2 - 1, L3 * 2 - L2 * 2); +} + +static void test_hbitmap_set_twice(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L1 * 3, 0); + hbitmap_test_set(data, 0, L1 * 3); + hbitmap_test_set(data, L1, 1); +} + +static void test_hbitmap_set_overlap(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3 * 2, 0); + hbitmap_test_set(data, L1 - 1, L1 + 2); + hbitmap_test_set(data, L1 * 2 - 1, L1 * 2 + 2); + hbitmap_test_set(data, 0, L1 * 3); + hbitmap_test_set(data, L1 * 8 - 1, L2); + hbitmap_test_set(data, L2, L1); + hbitmap_test_set(data, L2 - L1 - 1, L1 * 8 + 2); + hbitmap_test_set(data, L2, L3 - L2 + 1); + hbitmap_test_set(data, L3 - L1, L1 * 3); + hbitmap_test_set(data, L3 - 1, 3); + hbitmap_test_set(data, L3 - 1, L2); +} + +static void test_hbitmap_reset_empty(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3, 0); + hbitmap_test_reset(data, 0, L3); +} + +static void test_hbitmap_reset(TestHBitmapData *data, + const void *unused) +{ + hbitmap_test_init(data, L3 * 2, 0); + hbitmap_test_set(data, L1 - 1, L1 + 2); + hbitmap_test_reset(data, L1 * 2 - 1, L1 * 2 + 2); + hbitmap_test_set(data, 0, L1 * 3); + hbitmap_test_reset(data, L1 * 8 - 1, L2); + hbitmap_test_set(data, L2, L1); + hbitmap_test_reset(data, L2 - L1 - 1, L1 * 8 + 2); + hbitmap_test_set(data, L2, L3 - L2 + 1); + hbitmap_test_reset(data, L3 - L1, L1 * 3); + hbitmap_test_set(data, L3 - 1, 3); + hbitmap_test_reset(data, L3 - 1, L2); + hbitmap_test_set(data, 0, L3 * 2); + hbitmap_test_reset(data, 0, L1); + hbitmap_test_reset(data, 0, L2); + hbitmap_test_reset(data, L3, L3); + hbitmap_test_set(data, L3 / 2, L3); +} + +static void test_hbitmap_granularity(TestHBitmapData *data, + const void *unused) +{ + /* Note that hbitmap_test_check has to be invoked manually in this test. */ + hbitmap_test_init(data, L1, 1); + hbitmap_test_set(data, 0, 1); + g_assert_cmpint(hbitmap_count(data->hb), ==, 2); + hbitmap_test_check(data, 0); + hbitmap_test_set(data, 2, 1); + g_assert_cmpint(hbitmap_count(data->hb), ==, 4); + hbitmap_test_check(data, 0); + hbitmap_test_set(data, 0, 3); + g_assert_cmpint(hbitmap_count(data->hb), ==, 4); + hbitmap_test_reset(data, 0, 1); + g_assert_cmpint(hbitmap_count(data->hb), ==, 2); +} + +static void test_hbitmap_iter_granularity(TestHBitmapData *data, + const void *unused) +{ + HBitmapIter hbi; + + /* Note that hbitmap_test_check has to be invoked manually in this test. */ + hbitmap_test_init(data, 131072 << 7, 7); + hbitmap_iter_init(&hbi, data->hb, 0); + g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); + g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_test_set(data, (131072 << 7) - 8, 8); + hbitmap_iter_init(&hbi, data->hb, 0); + g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); + + hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); + g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); +} + +static void hbitmap_test_add(const char *testpath, + void (*test_func)(TestHBitmapData *data, const void *user_data)) +{ + g_test_add(testpath, TestHBitmapData, NULL, NULL, test_func, + hbitmap_test_teardown); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + hbitmap_test_add("/hbitmap/size/0", test_hbitmap_zero); + hbitmap_test_add("/hbitmap/size/unaligned", test_hbitmap_unaligned); + hbitmap_test_add("/hbitmap/iter/empty", test_hbitmap_iter_empty); + hbitmap_test_add("/hbitmap/iter/past", test_hbitmap_iter_past); + hbitmap_test_add("/hbitmap/iter/partial", test_hbitmap_iter_partial); + hbitmap_test_add("/hbitmap/iter/granularity", test_hbitmap_iter_granularity); + hbitmap_test_add("/hbitmap/get/all", test_hbitmap_get_all); + hbitmap_test_add("/hbitmap/get/some", test_hbitmap_get_some); + hbitmap_test_add("/hbitmap/set/all", test_hbitmap_set_all); + hbitmap_test_add("/hbitmap/set/one", test_hbitmap_set_one); + hbitmap_test_add("/hbitmap/set/two-elem", test_hbitmap_set_two_elem); + hbitmap_test_add("/hbitmap/set/general", test_hbitmap_set); + hbitmap_test_add("/hbitmap/set/twice", test_hbitmap_set_twice); + hbitmap_test_add("/hbitmap/set/overlap", test_hbitmap_set_overlap); + hbitmap_test_add("/hbitmap/reset/empty", test_hbitmap_reset_empty); + hbitmap_test_add("/hbitmap/reset/general", test_hbitmap_reset); + hbitmap_test_add("/hbitmap/granularity", test_hbitmap_granularity); + g_test_run(); + + return 0; +} diff --git a/trace-events b/trace-events index 09091e6d17..732cb12a00 100644 --- a/trace-events +++ b/trace-events @@ -1060,3 +1060,8 @@ xics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]" xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x" xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]" xics_ics_eoi(int nr) "ics_eoi: irq %#x" + +# hbitmap.c +hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx" +hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64 +hbitmap_set(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64 diff --git a/util/Makefile.objs b/util/Makefile.objs index 5baeb53af6..495a178557 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -2,7 +2,7 @@ util-obj-y = osdep.o cutils.o qemu-timer-common.o util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win32.o util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o -util-obj-y += bitmap.o bitops.o +util-obj-y += bitmap.o bitops.o hbitmap.o util-obj-y += acl.o util-obj-y += error.o qemu-error.o util-obj-$(CONFIG_POSIX) += compatfd.o diff --git a/util/hbitmap.c b/util/hbitmap.c new file mode 100644 index 0000000000..fb7e01e8c5 --- /dev/null +++ b/util/hbitmap.c @@ -0,0 +1,400 @@ +/* + * Hierarchical Bitmap Data Type + * + * Copyright Red Hat, Inc., 2012 + * + * Author: Paolo Bonzini + * + * 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 +#include +#include +#include "qemu/osdep.h" +#include "qemu/hbitmap.h" +#include "qemu/host-utils.h" +#include "trace.h" + +/* HBitmaps provides an array of bits. The bits are stored as usual in an + * array of unsigned longs, but HBitmap is also optimized to provide fast + * iteration over set bits; going from one bit to the next is O(logB n) + * worst case, with B = sizeof(long) * CHAR_BIT: the result is low enough + * that the number of levels is in fact fixed. + * + * In order to do this, it stacks multiple bitmaps with progressively coarser + * granularity; in all levels except the last, bit N is set iff the N-th + * unsigned long is nonzero in the immediately next level. When iteration + * completes on the last level it can examine the 2nd-last level to quickly + * skip entire words, and even do so recursively to skip blocks of 64 words or + * powers thereof (32 on 32-bit machines). + * + * Given an index in the bitmap, it can be split in group of bits like + * this (for the 64-bit case): + * + * bits 0-57 => word in the last bitmap | bits 58-63 => bit in the word + * bits 0-51 => word in the 2nd-last bitmap | bits 52-57 => bit in the word + * bits 0-45 => word in the 3rd-last bitmap | bits 46-51 => bit in the word + * + * So it is easy to move up simply by shifting the index right by + * log2(BITS_PER_LONG) bits. To move down, you shift the index left + * similarly, and add the word index within the group. Iteration uses + * ffs (find first set bit) to find the next word to examine; this + * operation can be done in constant time in most current architectures. + * + * Setting or clearing a range of m bits on all levels, the work to perform + * is O(m + m/W + m/W^2 + ...), which is O(m) like on a regular bitmap. + * + * When iterating on a bitmap, each bit (on any level) is only visited + * once. Hence, The total cost of visiting a bitmap with m bits in it is + * the number of bits that are set in all bitmaps. Unless the bitmap is + * extremely sparse, this is also O(m + m/W + m/W^2 + ...), so the amortized + * cost of advancing from one bit to the next is usually constant (worst case + * O(logB n) as in the non-amortized complexity). + */ + +struct HBitmap { + /* Number of total bits in the bottom level. */ + uint64_t size; + + /* Number of set bits in the bottom level. */ + uint64_t count; + + /* A scaling factor. Given a granularity of G, each bit in the bitmap will + * will actually represent a group of 2^G elements. Each operation on a + * range of bits first rounds the bits to determine which group they land + * in, and then affect the entire page; iteration will only visit the first + * bit of each group. Here is an example of operations in a size-16, + * granularity-1 HBitmap: + * + * initial state 00000000 + * set(start=0, count=9) 11111000 (iter: 0, 2, 4, 6, 8) + * reset(start=1, count=3) 00111000 (iter: 4, 6, 8) + * set(start=9, count=2) 00111100 (iter: 4, 6, 8, 10) + * reset(start=5, count=5) 00000000 + * + * From an implementation point of view, when setting or resetting bits, + * the bitmap will scale bit numbers right by this amount of bits. When + * iterating, the bitmap will scale bit numbers left by this amount of + * bits. + */ + int granularity; + + /* A number of progressively less coarse bitmaps (i.e. level 0 is the + * coarsest). Each bit in level N represents a word in level N+1 that + * has a set bit, except the last level where each bit represents the + * actual bitmap. + * + * Note that all bitmaps have the same number of levels. Even a 1-bit + * bitmap will still allocate HBITMAP_LEVELS arrays. + */ + unsigned long *levels[HBITMAP_LEVELS]; +}; + +static inline int popcountl(unsigned long l) +{ + return BITS_PER_LONG == 32 ? ctpop32(l) : ctpop64(l); +} + +/* Advance hbi to the next nonzero word and return it. hbi->pos + * is updated. Returns zero if we reach the end of the bitmap. + */ +unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) +{ + size_t pos = hbi->pos; + const HBitmap *hb = hbi->hb; + unsigned i = HBITMAP_LEVELS - 1; + + unsigned long cur; + do { + cur = hbi->cur[--i]; + pos >>= BITS_PER_LEVEL; + } while (cur == 0); + + /* Check for end of iteration. We always use fewer than BITS_PER_LONG + * bits in the level 0 bitmap; thus we can repurpose the most significant + * bit as a sentinel. The sentinel is set in hbitmap_alloc and ensures + * that the above loop ends even without an explicit check on i. + */ + + if (i == 0 && cur == (1UL << (BITS_PER_LONG - 1))) { + return 0; + } + for (; i < HBITMAP_LEVELS - 1; i++) { + /* Shift back pos to the left, matching the right shifts above. + * The index of this word's least significant set bit provides + * the low-order bits. + */ + pos = (pos << BITS_PER_LEVEL) + ffsl(cur) - 1; + hbi->cur[i] = cur & (cur - 1); + + /* Set up next level for iteration. */ + cur = hb->levels[i + 1][pos]; + } + + hbi->pos = pos; + trace_hbitmap_iter_skip_words(hbi->hb, hbi, pos, cur); + + assert(cur); + return cur; +} + +void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first) +{ + unsigned i, bit; + uint64_t pos; + + hbi->hb = hb; + pos = first >> hb->granularity; + hbi->pos = pos >> BITS_PER_LEVEL; + hbi->granularity = hb->granularity; + + for (i = HBITMAP_LEVELS; i-- > 0; ) { + bit = pos & (BITS_PER_LONG - 1); + pos >>= BITS_PER_LEVEL; + + /* Drop bits representing items before first. */ + hbi->cur[i] = hb->levels[i][pos] & ~((1UL << bit) - 1); + + /* We have already added level i+1, so the lowest set bit has + * been processed. Clear it. + */ + if (i != HBITMAP_LEVELS - 1) { + hbi->cur[i] &= ~(1UL << bit); + } + } +} + +bool hbitmap_empty(const HBitmap *hb) +{ + return hb->count == 0; +} + +int hbitmap_granularity(const HBitmap *hb) +{ + return hb->granularity; +} + +uint64_t hbitmap_count(const HBitmap *hb) +{ + return hb->count << hb->granularity; +} + +/* Count the number of set bits between start and end, not accounting for + * the granularity. Also an example of how to use hbitmap_iter_next_word. + */ +static uint64_t hb_count_between(HBitmap *hb, uint64_t start, uint64_t last) +{ + HBitmapIter hbi; + uint64_t count = 0; + uint64_t end = last + 1; + unsigned long cur; + size_t pos; + + hbitmap_iter_init(&hbi, hb, start << hb->granularity); + for (;;) { + pos = hbitmap_iter_next_word(&hbi, &cur); + if (pos >= (end >> BITS_PER_LEVEL)) { + break; + } + count += popcountl(cur); + } + + if (pos == (end >> BITS_PER_LEVEL)) { + /* Drop bits representing the END-th and subsequent items. */ + int bit = end & (BITS_PER_LONG - 1); + cur &= (1UL << bit) - 1; + count += popcountl(cur); + } + + return count; +} + +/* Setting starts at the last layer and propagates up if an element + * changes from zero to non-zero. + */ +static inline bool hb_set_elem(unsigned long *elem, uint64_t start, uint64_t last) +{ + unsigned long mask; + bool changed; + + assert((last >> BITS_PER_LEVEL) == (start >> BITS_PER_LEVEL)); + assert(start <= last); + + mask = 2UL << (last & (BITS_PER_LONG - 1)); + mask -= 1UL << (start & (BITS_PER_LONG - 1)); + changed = (*elem == 0); + *elem |= mask; + return changed; +} + +/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */ +static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last) +{ + size_t pos = start >> BITS_PER_LEVEL; + size_t lastpos = last >> BITS_PER_LEVEL; + bool changed = false; + size_t i; + + i = pos; + if (i < lastpos) { + uint64_t next = (start | (BITS_PER_LONG - 1)) + 1; + changed |= hb_set_elem(&hb->levels[level][i], start, next - 1); + for (;;) { + start = next; + next += BITS_PER_LONG; + if (++i == lastpos) { + break; + } + changed |= (hb->levels[level][i] == 0); + hb->levels[level][i] = ~0UL; + } + } + changed |= hb_set_elem(&hb->levels[level][i], start, last); + + /* If there was any change in this layer, we may have to update + * the one above. + */ + if (level > 0 && changed) { + hb_set_between(hb, level - 1, pos, lastpos); + } +} + +void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count) +{ + /* Compute range in the last layer. */ + uint64_t last = start + count - 1; + + trace_hbitmap_set(hb, start, count, + start >> hb->granularity, last >> hb->granularity); + + start >>= hb->granularity; + last >>= hb->granularity; + count = last - start + 1; + + hb->count += count - hb_count_between(hb, start, last); + hb_set_between(hb, HBITMAP_LEVELS - 1, start, last); +} + +/* Resetting works the other way round: propagate up if the new + * value is zero. + */ +static inline bool hb_reset_elem(unsigned long *elem, uint64_t start, uint64_t last) +{ + unsigned long mask; + bool blanked; + + assert((last >> BITS_PER_LEVEL) == (start >> BITS_PER_LEVEL)); + assert(start <= last); + + mask = 2UL << (last & (BITS_PER_LONG - 1)); + mask -= 1UL << (start & (BITS_PER_LONG - 1)); + blanked = *elem != 0 && ((*elem & ~mask) == 0); + *elem &= ~mask; + return blanked; +} + +/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */ +static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t last) +{ + size_t pos = start >> BITS_PER_LEVEL; + size_t lastpos = last >> BITS_PER_LEVEL; + bool changed = false; + size_t i; + + i = pos; + if (i < lastpos) { + uint64_t next = (start | (BITS_PER_LONG - 1)) + 1; + + /* Here we need a more complex test than when setting bits. Even if + * something was changed, we must not blank bits in the upper level + * unless the lower-level word became entirely zero. So, remove pos + * from the upper-level range if bits remain set. + */ + if (hb_reset_elem(&hb->levels[level][i], start, next - 1)) { + changed = true; + } else { + pos++; + } + + for (;;) { + start = next; + next += BITS_PER_LONG; + if (++i == lastpos) { + break; + } + changed |= (hb->levels[level][i] != 0); + hb->levels[level][i] = 0UL; + } + } + + /* Same as above, this time for lastpos. */ + if (hb_reset_elem(&hb->levels[level][i], start, last)) { + changed = true; + } else { + lastpos--; + } + + if (level > 0 && changed) { + hb_reset_between(hb, level - 1, pos, lastpos); + } +} + +void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count) +{ + /* Compute range in the last layer. */ + uint64_t last = start + count - 1; + + trace_hbitmap_reset(hb, start, count, + start >> hb->granularity, last >> hb->granularity); + + start >>= hb->granularity; + last >>= hb->granularity; + + hb->count -= hb_count_between(hb, start, last); + hb_reset_between(hb, HBITMAP_LEVELS - 1, start, last); +} + +bool hbitmap_get(const HBitmap *hb, uint64_t item) +{ + /* Compute position and bit in the last layer. */ + uint64_t pos = item >> hb->granularity; + unsigned long bit = 1UL << (pos & (BITS_PER_LONG - 1)); + + return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0; +} + +void hbitmap_free(HBitmap *hb) +{ + unsigned i; + for (i = HBITMAP_LEVELS; i-- > 0; ) { + g_free(hb->levels[i]); + } + g_free(hb); +} + +HBitmap *hbitmap_alloc(uint64_t size, int granularity) +{ + HBitmap *hb = g_malloc0(sizeof (struct HBitmap)); + unsigned i; + + assert(granularity >= 0 && granularity < 64); + size = (size + (1ULL << granularity) - 1) >> granularity; + assert(size <= ((uint64_t)1 << HBITMAP_LOG_MAX_SIZE)); + + hb->size = size; + hb->granularity = granularity; + for (i = HBITMAP_LEVELS; i-- > 0; ) { + size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1); + hb->levels[i] = g_malloc0(size * sizeof(unsigned long)); + } + + /* We necessarily have free bits in level 0 due to the definition + * of HBITMAP_LEVELS, so use one for a sentinel. This speeds up + * hbitmap_iter_skip_words. + */ + assert(size == 1); + hb->levels[0][0] |= 1UL << (BITS_PER_LONG - 1); + return hb; +} From 4c37ef022381e777251d7084591978a4dc622efe Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:39 +0100 Subject: [PATCH 0638/1634] host-utils: add ffsl We can provide fast versions based on the other functions defined by host-utils.h. Some care is required on glibc, which provides ffsl already. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- include/qemu/host-utils.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 81c9a754ae..2a32be4cc0 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -26,6 +26,7 @@ #define HOST_UTILS_H 1 #include "qemu/compiler.h" /* QEMU_GNUC_PREREQ */ +#include /* ffsl */ #if defined(__x86_64__) #define __HAVE_FAST_MULU64__ @@ -237,4 +238,29 @@ static inline int ctpop64(uint64_t val) #endif } +/* glibc does not provide an inline version of ffsl, so always define + * ours. We need to give it a different name, however. + */ +#ifdef __GLIBC__ +#define ffsl qemu_ffsl +#endif +static inline int ffsl(long val) +{ + if (!val) { + return 0; + } + +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_ctzl(val) + 1; +#else + if (sizeof(long) == 4) { + return ctz32(val) + 1; + } else if (sizeof(long) == 8) { + return ctz64(val) + 1; + } else { + abort(); + } +#endif +} + #endif From 8f0720ecbc3677e13fc7531588fc3831cc972ee4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:41 +0100 Subject: [PATCH 0639/1634] block: implement dirty bitmap using HBitmap This actually uses the dirty bitmap in the block layer, and converts mirroring to use an HBitmapIter. Reviewed-by: Laszlo Ersek (except block/mirror.c parts) Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block.c | 96 +++++++-------------------------------- block/mirror.c | 12 ++++- include/block/block.h | 6 ++- include/block/block_int.h | 4 +- trace-events | 1 + 5 files changed, 33 insertions(+), 86 deletions(-) diff --git a/block.c b/block.c index 6fa7c90144..e0ff736403 100644 --- a/block.c +++ b/block.c @@ -1286,7 +1286,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest, bs_dest->iostatus = bs_src->iostatus; /* dirty bitmap */ - bs_dest->dirty_count = bs_src->dirty_count; bs_dest->dirty_bitmap = bs_src->dirty_bitmap; /* job */ @@ -2035,36 +2034,6 @@ int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num, return ret; } -#define BITS_PER_LONG (sizeof(unsigned long) * 8) - -static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, int dirty) -{ - int64_t start, end; - unsigned long val, idx, bit; - - start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK; - end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK; - - for (; start <= end; start++) { - idx = start / BITS_PER_LONG; - bit = start % BITS_PER_LONG; - val = bs->dirty_bitmap[idx]; - if (dirty) { - if (!(val & (1UL << bit))) { - bs->dirty_count++; - val |= 1UL << bit; - } - } else { - if (val & (1UL << bit)) { - bs->dirty_count--; - val &= ~(1UL << bit); - } - } - bs->dirty_bitmap[idx] = val; - } -} - /* Return < 0 if error. Important errors are: -EIO generic I/O error (may happen for all errors) -ENOMEDIUM No media inserted. @@ -4173,7 +4142,7 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, } if (bs->dirty_bitmap) { - set_dirty_bitmap(bs, sector_num, nb_sectors, 0); + bdrv_reset_dirty(bs, sector_num, nb_sectors); } if (bs->drv->bdrv_co_discard) { @@ -4335,18 +4304,15 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) { int64_t bitmap_size; - bs->dirty_count = 0; if (enable) { if (!bs->dirty_bitmap) { - bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) + - BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG - 1; - bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG; - - bs->dirty_bitmap = g_new0(unsigned long, bitmap_size); + bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS); + bs->dirty_bitmap = hbitmap_alloc(bitmap_size, + BDRV_LOG_SECTORS_PER_DIRTY_CHUNK); } } else { if (bs->dirty_bitmap) { - g_free(bs->dirty_bitmap); + hbitmap_free(bs->dirty_bitmap); bs->dirty_bitmap = NULL; } } @@ -4354,67 +4320,37 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) int bdrv_get_dirty(BlockDriverState *bs, int64_t sector) { - int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; - - if (bs->dirty_bitmap && - (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) { - return !!(bs->dirty_bitmap[chunk / BITS_PER_LONG] & - (1UL << (chunk % BITS_PER_LONG))); + if (bs->dirty_bitmap) { + return hbitmap_get(bs->dirty_bitmap, sector); } else { return 0; } } -int64_t bdrv_get_next_dirty(BlockDriverState *bs, int64_t sector) +void bdrv_dirty_iter_init(BlockDriverState *bs, HBitmapIter *hbi) { - int64_t chunk; - int bit, elem; - - /* Avoid an infinite loop. */ - assert(bs->dirty_count > 0); - - sector = (sector | (BDRV_SECTORS_PER_DIRTY_CHUNK - 1)) + 1; - chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; - - QEMU_BUILD_BUG_ON(sizeof(bs->dirty_bitmap[0]) * 8 != BITS_PER_LONG); - elem = chunk / BITS_PER_LONG; - bit = chunk % BITS_PER_LONG; - for (;;) { - if (sector >= bs->total_sectors) { - sector = 0; - bit = elem = 0; - } - if (bit == 0 && bs->dirty_bitmap[elem] == 0) { - sector += BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG; - elem++; - } else { - if (bs->dirty_bitmap[elem] & (1UL << bit)) { - return sector; - } - sector += BDRV_SECTORS_PER_DIRTY_CHUNK; - if (++bit == BITS_PER_LONG) { - bit = 0; - elem++; - } - } - } + hbitmap_iter_init(hbi, bs->dirty_bitmap, 0); } void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors) { - set_dirty_bitmap(bs, cur_sector, nr_sectors, 1); + hbitmap_set(bs->dirty_bitmap, cur_sector, nr_sectors); } void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors) { - set_dirty_bitmap(bs, cur_sector, nr_sectors, 0); + hbitmap_reset(bs->dirty_bitmap, cur_sector, nr_sectors); } int64_t bdrv_get_dirty_count(BlockDriverState *bs) { - return bs->dirty_count; + if (bs->dirty_bitmap) { + return hbitmap_count(bs->dirty_bitmap) >> BDRV_LOG_SECTORS_PER_DIRTY_CHUNK; + } else { + return 0; + } } void bdrv_set_in_use(BlockDriverState *bs, int in_use) diff --git a/block/mirror.c b/block/mirror.c index 6180aa30e5..20cb1e777f 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -36,6 +36,7 @@ typedef struct MirrorBlockJob { bool synced; bool should_complete; int64_t sector_num; + HBitmapIter hbi; uint8_t *buf; } MirrorBlockJob; @@ -62,8 +63,15 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s, int64_t end; struct iovec iov; + s->sector_num = hbitmap_iter_next(&s->hbi); + if (s->sector_num < 0) { + bdrv_dirty_iter_init(source, &s->hbi); + s->sector_num = hbitmap_iter_next(&s->hbi); + trace_mirror_restart_iter(s, bdrv_get_dirty_count(source)); + assert(s->sector_num >= 0); + } + end = s->common.len >> BDRV_SECTOR_BITS; - s->sector_num = bdrv_get_next_dirty(source, s->sector_num); nb_sectors = MIN(BDRV_SECTORS_PER_DIRTY_CHUNK, end - s->sector_num); bdrv_reset_dirty(source, s->sector_num, nb_sectors); @@ -136,7 +144,7 @@ static void coroutine_fn mirror_run(void *opaque) } } - s->sector_num = -1; + bdrv_dirty_iter_init(bs, &s->hbi); for (;;) { uint64_t delay_ns; int64_t cnt; diff --git a/include/block/block.h b/include/block/block.h index ffd193637d..678fc60dc1 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -351,13 +351,15 @@ void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); void *qemu_blockalign(BlockDriverState *bs, size_t size); bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); -#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048 +#define BDRV_SECTORS_PER_DIRTY_CHUNK (1 << BDRV_LOG_SECTORS_PER_DIRTY_CHUNK) +#define BDRV_LOG_SECTORS_PER_DIRTY_CHUNK 11 +struct HBitmapIter; void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); -int64_t bdrv_get_next_dirty(BlockDriverState *bs, int64_t sector); +void bdrv_dirty_iter_init(BlockDriverState *bs, struct HBitmapIter *hbi); int64_t bdrv_get_dirty_count(BlockDriverState *bs); void bdrv_enable_copy_on_read(BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index f83ffb8a08..b81c061cd9 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -32,6 +32,7 @@ #include "qapi-types.h" #include "qapi/qmp/qerror.h" #include "monitor/monitor.h" +#include "qemu/hbitmap.h" #define BLOCK_FLAG_ENCRYPT 1 #define BLOCK_FLAG_COMPAT6 4 @@ -275,8 +276,7 @@ struct BlockDriverState { bool iostatus_enabled; BlockDeviceIoStatus iostatus; char device_name[32]; - unsigned long *dirty_bitmap; - int64_t dirty_count; + HBitmap *dirty_bitmap; int in_use; /* users other than guest access, eg. block migration */ QTAILQ_ENTRY(BlockDriverState) list; diff --git a/trace-events b/trace-events index 732cb12a00..61ed349765 100644 --- a/trace-events +++ b/trace-events @@ -79,6 +79,7 @@ commit_start(void *bs, void *base, void *top, void *s, void *co, void *opaque) " # block/mirror.c mirror_start(void *bs, void *s, void *co, void *opaque) "bs %p s %p co %p opaque %p" +mirror_restart_iter(void *s, int64_t cnt) "s %p dirty count %"PRId64 mirror_before_flush(void *s) "s %p" mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64 mirror_before_sleep(void *s, int64_t cnt, int synced) "s %p dirty count %"PRId64" synced %d" From 343bded4ecfc467012e2ab675da75749f1d90f70 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:42 +0100 Subject: [PATCH 0640/1634] block: make round_to_clusters public This is needed in the following patch. Reviewed-by: Laszlo Ersek Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block.c | 16 ++++++++-------- include/block/block.h | 4 ++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index e0ff736403..4a4ab162f7 100644 --- a/block.c +++ b/block.c @@ -1673,10 +1673,10 @@ static void tracked_request_begin(BdrvTrackedRequest *req, /** * Round a region to cluster boundaries */ -static void round_to_clusters(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, - int64_t *cluster_sector_num, - int *cluster_nb_sectors) +void bdrv_round_to_clusters(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + int64_t *cluster_sector_num, + int *cluster_nb_sectors) { BlockDriverInfo bdi; @@ -1718,8 +1718,8 @@ static void coroutine_fn wait_for_overlapping_requests(BlockDriverState *bs, * CoR read and write operations are atomic and guest writes cannot * interleave between them. */ - round_to_clusters(bs, sector_num, nb_sectors, - &cluster_sector_num, &cluster_nb_sectors); + bdrv_round_to_clusters(bs, sector_num, nb_sectors, + &cluster_sector_num, &cluster_nb_sectors); do { retry = false; @@ -2185,8 +2185,8 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs, /* Cover entire cluster so no additional backing file I/O is required when * allocating cluster in the image file. */ - round_to_clusters(bs, sector_num, nb_sectors, - &cluster_sector_num, &cluster_nb_sectors); + bdrv_round_to_clusters(bs, sector_num, nb_sectors, + &cluster_sector_num, &cluster_nb_sectors); trace_bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors, cluster_sector_num, cluster_nb_sectors); diff --git a/include/block/block.h b/include/block/block.h index 678fc60dc1..9ee9068aec 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -309,6 +309,10 @@ int bdrv_get_flags(BlockDriverState *bs); int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); +void bdrv_round_to_clusters(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + int64_t *cluster_sector_num, + int *cluster_nb_sectors); const char *bdrv_get_encrypted_filename(BlockDriverState *bs); void bdrv_get_backing_filename(BlockDriverState *bs, From b812f6719c21921a819709098dc018ed151c999b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:43 +0100 Subject: [PATCH 0641/1634] mirror: perform COW if the cluster size is bigger than the granularity When mirroring runs, the backing files for the target may not yet be ready. However, this means that a copy-on-write operation on the target would fill the missing sectors with zeros. Copy-on-write only happens if the granularity of the dirty bitmap is smaller than the cluster size (and only for clusters that are allocated in the source after the job has started copying). So far, the granularity was fixed to 1MB; to avoid the problem we detected the situation and required the backing files to be available in that case only. However, we want to lower the granularity for efficiency, so we need a better solution. The solution is to always copy a whole cluster the first time it is touched. The code keeps a bitmap of clusters that have already been allocated by the mirroring job, and only does "manual" copy-on-write if the chunk being copied is zero in the bitmap. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/mirror.c | 62 ++++++++++++++++++++++++++++++++------ blockdev.c | 15 ++------- tests/qemu-iotests/041 | 50 ++++++++++++++++++++++++++++++ tests/qemu-iotests/041.out | 4 +-- trace-events | 1 + 5 files changed, 109 insertions(+), 23 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 20cb1e777f..307bcf101e 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -15,6 +15,7 @@ #include "block/blockjob.h" #include "block/block_int.h" #include "qemu/ratelimit.h" +#include "qemu/bitmap.h" enum { /* @@ -36,6 +37,8 @@ typedef struct MirrorBlockJob { bool synced; bool should_complete; int64_t sector_num; + size_t buf_size; + unsigned long *cow_bitmap; HBitmapIter hbi; uint8_t *buf; } MirrorBlockJob; @@ -60,7 +63,7 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s, BlockDriverState *target = s->target; QEMUIOVector qiov; int ret, nb_sectors; - int64_t end; + int64_t end, sector_num, chunk_num; struct iovec iov; s->sector_num = hbitmap_iter_next(&s->hbi); @@ -71,32 +74,53 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s, assert(s->sector_num >= 0); } + /* If we have no backing file yet in the destination, and the cluster size + * is very large, we need to do COW ourselves. The first time a cluster is + * copied, copy it entirely. + * + * Because both BDRV_SECTORS_PER_DIRTY_CHUNK and the cluster size are + * powers of two, the number of sectors to copy cannot exceed one cluster. + */ + sector_num = s->sector_num; + nb_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; + chunk_num = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK; + if (s->cow_bitmap && !test_bit(chunk_num, s->cow_bitmap)) { + trace_mirror_cow(s, sector_num); + bdrv_round_to_clusters(s->target, + sector_num, BDRV_SECTORS_PER_DIRTY_CHUNK, + §or_num, &nb_sectors); + } + end = s->common.len >> BDRV_SECTOR_BITS; - nb_sectors = MIN(BDRV_SECTORS_PER_DIRTY_CHUNK, end - s->sector_num); - bdrv_reset_dirty(source, s->sector_num, nb_sectors); + nb_sectors = MIN(nb_sectors, end - sector_num); + bdrv_reset_dirty(source, sector_num, nb_sectors); /* Copy the dirty cluster. */ iov.iov_base = s->buf; iov.iov_len = nb_sectors * 512; qemu_iovec_init_external(&qiov, &iov, 1); - trace_mirror_one_iteration(s, s->sector_num, nb_sectors); - ret = bdrv_co_readv(source, s->sector_num, nb_sectors, &qiov); + trace_mirror_one_iteration(s, sector_num, nb_sectors); + ret = bdrv_co_readv(source, sector_num, nb_sectors, &qiov); if (ret < 0) { *p_action = mirror_error_action(s, true, -ret); goto fail; } - ret = bdrv_co_writev(target, s->sector_num, nb_sectors, &qiov); + ret = bdrv_co_writev(target, sector_num, nb_sectors, &qiov); if (ret < 0) { *p_action = mirror_error_action(s, false, -ret); s->synced = false; goto fail; } + if (s->cow_bitmap) { + bitmap_set(s->cow_bitmap, sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK, + nb_sectors / BDRV_SECTORS_PER_DIRTY_CHUNK); + } return 0; fail: /* Try again later. */ - bdrv_set_dirty(source, s->sector_num, nb_sectors); + bdrv_set_dirty(source, sector_num, nb_sectors); return ret; } @@ -104,7 +128,9 @@ static void coroutine_fn mirror_run(void *opaque) { MirrorBlockJob *s = opaque; BlockDriverState *bs = s->common.bs; - int64_t sector_num, end; + int64_t sector_num, end, length; + BlockDriverInfo bdi; + char backing_filename[1024]; int ret = 0; int n; @@ -118,8 +144,23 @@ static void coroutine_fn mirror_run(void *opaque) return; } + /* If we have no backing file yet in the destination, we cannot let + * the destination do COW. Instead, we copy sectors around the + * dirty data if needed. We need a bitmap to do that. + */ + bdrv_get_backing_filename(s->target, backing_filename, + sizeof(backing_filename)); + if (backing_filename[0] && !s->target->backing_hd) { + bdrv_get_info(s->target, &bdi); + if (s->buf_size < bdi.cluster_size) { + s->buf_size = bdi.cluster_size; + length = (bdrv_getlength(bs) + BLOCK_SIZE - 1) / BLOCK_SIZE; + s->cow_bitmap = bitmap_new(length); + } + } + end = s->common.len >> BDRV_SECTOR_BITS; - s->buf = qemu_blockalign(bs, BLOCK_SIZE); + s->buf = qemu_blockalign(bs, s->buf_size); if (s->mode != MIRROR_SYNC_MODE_NONE) { /* First part, loop on the sectors and initialize the dirty bitmap. */ @@ -234,6 +275,7 @@ static void coroutine_fn mirror_run(void *opaque) immediate_exit: qemu_vfree(s->buf); + g_free(s->cow_bitmap); bdrv_set_dirty_tracking(bs, false); bdrv_iostatus_disable(s->target); if (s->should_complete && ret == 0) { @@ -320,6 +362,8 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, s->on_target_error = on_target_error; s->target = target; s->mode = mode; + s->buf_size = BLOCK_SIZE; + bdrv_set_dirty_tracking(bs, true); bdrv_set_enable_write_cache(s->target, true); bdrv_set_on_error(s->target, on_target_error, on_target_error); diff --git a/blockdev.c b/blockdev.c index 9126587c45..1eb62b637c 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1197,7 +1197,6 @@ void qmp_drive_mirror(const char *device, const char *target, bool has_on_target_error, BlockdevOnError on_target_error, Error **errp) { - BlockDriverInfo bdi; BlockDriverState *bs; BlockDriverState *source, *target_bs; BlockDriver *proto_drv; @@ -1288,6 +1287,9 @@ void qmp_drive_mirror(const char *device, const char *target, return; } + /* Mirroring takes care of copy-on-write using the source's backing + * file. + */ target_bs = bdrv_new(""); ret = bdrv_open(target_bs, target, flags | BDRV_O_NO_BACKING, drv); @@ -1297,17 +1299,6 @@ void qmp_drive_mirror(const char *device, const char *target, return; } - /* We need a backing file if we will copy parts of a cluster. */ - if (bdrv_get_info(target_bs, &bdi) >= 0 && bdi.cluster_size != 0 && - bdi.cluster_size >= BDRV_SECTORS_PER_DIRTY_CHUNK * 512) { - ret = bdrv_open_backing_file(target_bs); - if (ret < 0) { - bdrv_delete(target_bs); - error_set(errp, QERR_OPEN_FILE_FAILED, target); - return; - } - } - mirror_start(bs, target_bs, speed, sync, on_source_error, on_target_error, block_job_cb, bs, &local_err); if (local_err != NULL) { diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index c6eb851871..a1299b348e 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -292,6 +292,27 @@ class TestMirrorNoBacking(ImageMirroringTestCase): self.assertTrue(self.compare_images(test_img, target_img), 'target image does not match source after mirroring') + def test_large_cluster(self): + self.assert_no_active_mirrors() + + # qemu-img create fails if the image is not there + qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d' + %(TestMirrorNoBacking.image_len), target_backing_img) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' + % (TestMirrorNoBacking.image_len, target_backing_img), target_img) + os.remove(target_backing_img) + + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + mode='existing', target=target_img) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait() + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/inserted/file', target_img) + self.vm.shutdown() + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + class TestReadErrors(ImageMirroringTestCase): image_len = 2 * 1024 * 1024 # MB @@ -330,6 +351,9 @@ new_state = "1" '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' % (self.blkdebug_file, backing_img), test_img) + # Write something for tests that use sync='top' + qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536), + test_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() @@ -383,6 +407,32 @@ new_state = "1" self.complete_and_wait() self.vm.shutdown() + def test_large_cluster(self): + self.assert_no_active_mirrors() + + # Test COW into the target image. The first half of the + # cluster at MIRROR_GRANULARITY has to be copied from + # backing_img, even though sync='top'. + qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img) + result = self.vm.qmp('drive-mirror', device='drive0', sync='top', + on_source_error='ignore', + mode='existing', target=target_img) + self.assert_qmp(result, 'return', {}) + + event = self.vm.get_qmp_event(wait=True) + self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/operation', 'read') + result = self.vm.qmp('query-block-jobs') + self.assert_qmp(result, 'return[0]/paused', False) + self.complete_and_wait() + self.vm.shutdown() + + # Detach blkdebug to compare images successfully + qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img) + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + def test_stop_read(self): self.assert_no_active_mirrors() diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out index 71009c239f..3a89159833 100644 --- a/tests/qemu-iotests/041.out +++ b/tests/qemu-iotests/041.out @@ -1,5 +1,5 @@ -.................. +.................... ---------------------------------------------------------------------- -Ran 18 tests +Ran 20 tests OK diff --git a/trace-events b/trace-events index 61ed349765..ffa27568ee 100644 --- a/trace-events +++ b/trace-events @@ -84,6 +84,7 @@ mirror_before_flush(void *s) "s %p" mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64 mirror_before_sleep(void *s, int64_t cnt, int synced) "s %p dirty count %"PRId64" synced %d" mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d" +mirror_cow(void *s, int64_t sector_num) "s %p sector_num %"PRId64 # blockdev.c qmp_block_job_cancel(void *job) "job %p" From acc906c6c5d5745fe7a3a2ed1bb5f0b1d6d1f21b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:44 +0100 Subject: [PATCH 0642/1634] block: return count of dirty sectors, not chunks Reviewed-by: Laszlo Ersek Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block-migration.c | 2 +- block.c | 5 ++--- block/mirror.c | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/block-migration.c b/block-migration.c index 6acf3e1682..9d0b037029 100644 --- a/block-migration.c +++ b/block-migration.c @@ -478,7 +478,7 @@ static int64_t get_remaining_dirty(void) dirty += bdrv_get_dirty_count(bmds->bs); } - return dirty * BLOCK_SIZE; + return dirty << BDRV_SECTOR_BITS; } static void blk_mig_cleanup(void) diff --git a/block.c b/block.c index 4a4ab162f7..a27454453e 100644 --- a/block.c +++ b/block.c @@ -2832,8 +2832,7 @@ BlockInfo *bdrv_query_info(BlockDriverState *bs) if (bs->dirty_bitmap) { info->has_dirty = true; info->dirty = g_malloc0(sizeof(*info->dirty)); - info->dirty->count = bdrv_get_dirty_count(bs) * - BDRV_SECTORS_PER_DIRTY_CHUNK * BDRV_SECTOR_SIZE; + info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; } if (bs->drv) { @@ -4347,7 +4346,7 @@ void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int64_t bdrv_get_dirty_count(BlockDriverState *bs) { if (bs->dirty_bitmap) { - return hbitmap_count(bs->dirty_bitmap) >> BDRV_LOG_SECTORS_PER_DIRTY_CHUNK; + return hbitmap_count(bs->dirty_bitmap); } else { return 0; } diff --git a/block/mirror.c b/block/mirror.c index 307bcf101e..7884b3bc78 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -245,7 +245,7 @@ static void coroutine_fn mirror_run(void *opaque) trace_mirror_before_sleep(s, cnt, s->synced); if (!s->synced) { /* Publish progress */ - s->common.offset = end * BDRV_SECTOR_SIZE - cnt * BLOCK_SIZE; + s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE; if (s->common.speed) { delay_ns = ratelimit_calculate_delay(&s->limit, BDRV_SECTORS_PER_DIRTY_CHUNK); From 50717e941b9f306a45292621999eeafbaa954418 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:45 +0100 Subject: [PATCH 0643/1634] block: allow customizing the granularity of the dirty bitmap Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block-migration.c | 5 +++-- block.c | 17 ++++++++++------- block/mirror.c | 14 ++++---------- include/block/block.h | 5 +---- qapi-schema.json | 4 +++- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/block-migration.c b/block-migration.c index 9d0b037029..9ac7de6d78 100644 --- a/block-migration.c +++ b/block-migration.c @@ -23,7 +23,8 @@ #include "sysemu/blockdev.h" #include -#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS) +#define BLOCK_SIZE (1 << 20) +#define BDRV_SECTORS_PER_DIRTY_CHUNK (BLOCK_SIZE >> BDRV_SECTOR_BITS) #define BLK_MIG_FLAG_DEVICE_BLOCK 0x01 #define BLK_MIG_FLAG_EOS 0x02 @@ -254,7 +255,7 @@ static void set_dirty_tracking(int enable) BlkMigDevState *bmds; QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { - bdrv_set_dirty_tracking(bmds->bs, enable); + bdrv_set_dirty_tracking(bmds->bs, enable ? BLOCK_SIZE : 0); } } diff --git a/block.c b/block.c index a27454453e..ba67c0def2 100644 --- a/block.c +++ b/block.c @@ -2833,6 +2833,8 @@ BlockInfo *bdrv_query_info(BlockDriverState *bs) info->has_dirty = true; info->dirty = g_malloc0(sizeof(*info->dirty)); info->dirty->count = bdrv_get_dirty_count(bs) * BDRV_SECTOR_SIZE; + info->dirty->granularity = + ((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bs->dirty_bitmap)); } if (bs->drv) { @@ -4299,16 +4301,17 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) return true; } -void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable) +void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity) { int64_t bitmap_size; - if (enable) { - if (!bs->dirty_bitmap) { - bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS); - bs->dirty_bitmap = hbitmap_alloc(bitmap_size, - BDRV_LOG_SECTORS_PER_DIRTY_CHUNK); - } + assert((granularity & (granularity - 1)) == 0); + + if (granularity) { + granularity >>= BDRV_SECTOR_BITS; + assert(!bs->dirty_bitmap); + bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS); + bs->dirty_bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1); } else { if (bs->dirty_bitmap) { hbitmap_free(bs->dirty_bitmap); diff --git a/block/mirror.c b/block/mirror.c index 7884b3bc78..e425927ee5 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -17,14 +17,8 @@ #include "qemu/ratelimit.h" #include "qemu/bitmap.h" -enum { - /* - * Size of data buffer for populating the image file. This should be large - * enough to process multiple clusters in a single call, so that populating - * contiguous regions of the image is efficient. - */ - BLOCK_SIZE = 512 * BDRV_SECTORS_PER_DIRTY_CHUNK, /* in bytes */ -}; +#define BLOCK_SIZE (1 << 20) +#define BDRV_SECTORS_PER_DIRTY_CHUNK (BLOCK_SIZE >> BDRV_SECTOR_BITS) #define SLICE_TIME 100000000ULL /* ns */ @@ -276,7 +270,7 @@ static void coroutine_fn mirror_run(void *opaque) immediate_exit: qemu_vfree(s->buf); g_free(s->cow_bitmap); - bdrv_set_dirty_tracking(bs, false); + bdrv_set_dirty_tracking(bs, 0); bdrv_iostatus_disable(s->target); if (s->should_complete && ret == 0) { if (bdrv_get_flags(s->target) != bdrv_get_flags(s->common.bs)) { @@ -364,7 +358,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, s->mode = mode; s->buf_size = BLOCK_SIZE; - bdrv_set_dirty_tracking(bs, true); + bdrv_set_dirty_tracking(bs, BLOCK_SIZE); bdrv_set_enable_write_cache(s->target, true); bdrv_set_on_error(s->target, on_target_error, on_target_error); bdrv_iostatus_enable(s->target); diff --git a/include/block/block.h b/include/block/block.h index 9ee9068aec..5c3b911c1b 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -355,11 +355,8 @@ void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); void *qemu_blockalign(BlockDriverState *bs, size_t size); bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov); -#define BDRV_SECTORS_PER_DIRTY_CHUNK (1 << BDRV_LOG_SECTORS_PER_DIRTY_CHUNK) -#define BDRV_LOG_SECTORS_PER_DIRTY_CHUNK 11 - struct HBitmapIter; -void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); +void bdrv_set_dirty_tracking(BlockDriverState *bs, int granularity); int bdrv_get_dirty(BlockDriverState *bs, int64_t sector); void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors); diff --git a/qapi-schema.json b/qapi-schema.json index 6d7252b9e8..ce4f901dc6 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -667,10 +667,12 @@ # # @count: number of dirty bytes according to the dirty bitmap # +# @granularity: granularity of the dirty bitmap in bytes (since 1.4) +# # Since: 1.3 ## { 'type': 'BlockDirtyInfo', - 'data': {'count': 'int'} } + 'data': {'count': 'int', 'granularity': 'int'} } ## # @BlockInfo: From eee13dfe302833944d1176677d12a6ea421a94ea Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 21 Jan 2013 17:09:46 +0100 Subject: [PATCH 0644/1634] mirror: allow customizing the granularity The desired granularity may be very different depending on the kind of operation (e.g. continuous replication vs. collapse-to-raw) and whether the VM is expected to perform lots of I/O while mirroring is in progress. Allow the user to customize it, while providing a sane default so that in general there will be no extra allocated space in the target compared to the source. Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/mirror.c | 52 +++++++++++++++++++++++++-------------- blockdev.c | 15 ++++++++++- hmp.c | 2 +- include/block/block_int.h | 3 ++- qapi-schema.json | 8 +++++- qmp-commands.hx | 8 +++++- 6 files changed, 64 insertions(+), 24 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index e425927ee5..0fecb40c10 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -17,9 +17,6 @@ #include "qemu/ratelimit.h" #include "qemu/bitmap.h" -#define BLOCK_SIZE (1 << 20) -#define BDRV_SECTORS_PER_DIRTY_CHUNK (BLOCK_SIZE >> BDRV_SECTOR_BITS) - #define SLICE_TIME 100000000ULL /* ns */ typedef struct MirrorBlockJob { @@ -31,6 +28,7 @@ typedef struct MirrorBlockJob { bool synced; bool should_complete; int64_t sector_num; + int64_t granularity; size_t buf_size; unsigned long *cow_bitmap; HBitmapIter hbi; @@ -56,7 +54,7 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s, BlockDriverState *source = s->common.bs; BlockDriverState *target = s->target; QEMUIOVector qiov; - int ret, nb_sectors; + int ret, nb_sectors, sectors_per_chunk; int64_t end, sector_num, chunk_num; struct iovec iov; @@ -72,16 +70,16 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s, * is very large, we need to do COW ourselves. The first time a cluster is * copied, copy it entirely. * - * Because both BDRV_SECTORS_PER_DIRTY_CHUNK and the cluster size are - * powers of two, the number of sectors to copy cannot exceed one cluster. + * Because both the granularity and the cluster size are powers of two, the + * number of sectors to copy cannot exceed one cluster. */ sector_num = s->sector_num; - nb_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK; - chunk_num = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK; + sectors_per_chunk = nb_sectors = s->granularity >> BDRV_SECTOR_BITS; + chunk_num = sector_num / sectors_per_chunk; if (s->cow_bitmap && !test_bit(chunk_num, s->cow_bitmap)) { trace_mirror_cow(s, sector_num); bdrv_round_to_clusters(s->target, - sector_num, BDRV_SECTORS_PER_DIRTY_CHUNK, + sector_num, sectors_per_chunk, §or_num, &nb_sectors); } @@ -107,8 +105,8 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s, goto fail; } if (s->cow_bitmap) { - bitmap_set(s->cow_bitmap, sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK, - nb_sectors / BDRV_SECTORS_PER_DIRTY_CHUNK); + bitmap_set(s->cow_bitmap, sector_num / sectors_per_chunk, + nb_sectors / sectors_per_chunk); } return 0; @@ -122,7 +120,7 @@ static void coroutine_fn mirror_run(void *opaque) { MirrorBlockJob *s = opaque; BlockDriverState *bs = s->common.bs; - int64_t sector_num, end, length; + int64_t sector_num, end, sectors_per_chunk, length; BlockDriverInfo bdi; char backing_filename[1024]; int ret = 0; @@ -146,22 +144,23 @@ static void coroutine_fn mirror_run(void *opaque) sizeof(backing_filename)); if (backing_filename[0] && !s->target->backing_hd) { bdrv_get_info(s->target, &bdi); - if (s->buf_size < bdi.cluster_size) { + if (s->granularity < bdi.cluster_size) { s->buf_size = bdi.cluster_size; - length = (bdrv_getlength(bs) + BLOCK_SIZE - 1) / BLOCK_SIZE; + length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity; s->cow_bitmap = bitmap_new(length); } } end = s->common.len >> BDRV_SECTOR_BITS; s->buf = qemu_blockalign(bs, s->buf_size); + sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; if (s->mode != MIRROR_SYNC_MODE_NONE) { /* First part, loop on the sectors and initialize the dirty bitmap. */ BlockDriverState *base; base = s->mode == MIRROR_SYNC_MODE_FULL ? NULL : bs->backing_hd; for (sector_num = 0; sector_num < end; ) { - int64_t next = (sector_num | (BDRV_SECTORS_PER_DIRTY_CHUNK - 1)) + 1; + int64_t next = (sector_num | (sectors_per_chunk - 1)) + 1; ret = bdrv_co_is_allocated_above(bs, base, sector_num, next - sector_num, &n); @@ -242,7 +241,7 @@ static void coroutine_fn mirror_run(void *opaque) s->common.offset = (end - cnt) * BDRV_SECTOR_SIZE; if (s->common.speed) { - delay_ns = ratelimit_calculate_delay(&s->limit, BDRV_SECTORS_PER_DIRTY_CHUNK); + delay_ns = ratelimit_calculate_delay(&s->limit, sectors_per_chunk); } else { delay_ns = 0; } @@ -332,7 +331,7 @@ static BlockJobType mirror_job_type = { }; void mirror_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, MirrorSyncMode mode, + int64_t speed, int64_t granularity, MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, @@ -340,6 +339,20 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, { MirrorBlockJob *s; + if (granularity == 0) { + /* Choose the default granularity based on the target file's cluster + * size, clamped between 4k and 64k. */ + BlockDriverInfo bdi; + if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) { + granularity = MAX(4096, bdi.cluster_size); + granularity = MIN(65536, granularity); + } else { + granularity = 65536; + } + } + + assert ((granularity & (granularity - 1)) == 0); + if ((on_source_error == BLOCKDEV_ON_ERROR_STOP || on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) && !bdrv_iostatus_is_enabled(bs)) { @@ -356,9 +369,10 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, s->on_target_error = on_target_error; s->target = target; s->mode = mode; - s->buf_size = BLOCK_SIZE; + s->granularity = granularity; + s->buf_size = granularity; - bdrv_set_dirty_tracking(bs, BLOCK_SIZE); + bdrv_set_dirty_tracking(bs, granularity); bdrv_set_enable_write_cache(s->target, true); bdrv_set_on_error(s->target, on_target_error, on_target_error); bdrv_iostatus_enable(s->target); diff --git a/blockdev.c b/blockdev.c index 1eb62b637c..07fd3273ed 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1193,6 +1193,7 @@ void qmp_drive_mirror(const char *device, const char *target, enum MirrorSyncMode sync, bool has_mode, enum NewImageMode mode, bool has_speed, int64_t speed, + bool has_granularity, uint32_t granularity, bool has_on_source_error, BlockdevOnError on_source_error, bool has_on_target_error, BlockdevOnError on_target_error, Error **errp) @@ -1218,6 +1219,17 @@ void qmp_drive_mirror(const char *device, const char *target, if (!has_mode) { mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; } + if (!has_granularity) { + granularity = 0; + } + if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) { + error_set(errp, QERR_INVALID_PARAMETER, device); + return; + } + if (granularity & (granularity - 1)) { + error_set(errp, QERR_INVALID_PARAMETER, device); + return; + } bs = bdrv_find(device); if (!bs) { @@ -1299,7 +1311,8 @@ void qmp_drive_mirror(const char *device, const char *target, return; } - mirror_start(bs, target_bs, speed, sync, on_source_error, on_target_error, + mirror_start(bs, target_bs, speed, granularity, sync, + on_source_error, on_target_error, block_job_cb, bs, &local_err); if (local_err != NULL) { bdrv_delete(target_bs); diff --git a/hmp.c b/hmp.c index c7b6ba02fc..0f3347dd76 100644 --- a/hmp.c +++ b/hmp.c @@ -796,7 +796,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) qmp_drive_mirror(device, filename, !!format, format, full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, - true, mode, false, 0, + true, mode, false, 0, false, 0, false, 0, false, 0, &errp); hmp_handle_error(mon, &errp); } diff --git a/include/block/block_int.h b/include/block/block_int.h index b81c061cd9..1165339fd1 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -344,6 +344,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * @bs: Block device to operate on. * @target: Block device to write to. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. + * @granularity: The chosen granularity for the dirty bitmap. * @mode: Whether to collapse all images in the chain to the target. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. @@ -357,7 +358,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * @bs will be switched to read from @target. */ void mirror_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, MirrorSyncMode mode, + int64_t speed, int64_t granularity, MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, diff --git a/qapi-schema.json b/qapi-schema.json index ce4f901dc6..fd5ec93c03 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1636,6 +1636,11 @@ # (all the disk, only the sectors allocated in the topmost image, or # only new I/O). # +# @granularity: #optional granularity of the dirty bitmap, default is 64K +# if the image format doesn't have clusters, 4K if the clusters +# are smaller than that, else the cluster size. Must be a +# power of 2 between 512 and 64M (since 1.4). +# # @on-source-error: #optional the action to take on an error on the source, # default 'report'. 'stop' and 'enospc' can only be used # if the block device supports io-status (see BlockInfo). @@ -1652,7 +1657,8 @@ { 'command': 'drive-mirror', 'data': { 'device': 'str', 'target': 'str', '*format': 'str', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', - '*speed': 'int', '*on-source-error': 'BlockdevOnError', + '*speed': 'int', '*granularity': 'uint32', + '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } ## diff --git a/qmp-commands.hx b/qmp-commands.hx index cbf12804be..835ea26e9d 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -938,7 +938,8 @@ EQMP { .name = "drive-mirror", .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?," - "on-source-error:s?,on-target-error:s?", + "on-source-error:s?,on-target-error:s?," + "granularity:i?", .mhandler.cmd_new = qmp_marshal_input_drive_mirror, }, @@ -962,6 +963,7 @@ Arguments: file/device (NewImageMode, optional, default 'absolute-paths') - "speed": maximum speed of the streaming job, in bytes per second (json-int) +- "granularity": granularity of the dirty bitmap, in bytes (json-int, optional) - "sync": what parts of the disk image should be copied to the destination; possibilities include "full" for all the disk, "top" for only the sectors allocated in the topmost image, or "none" to only replicate new I/O @@ -971,6 +973,10 @@ Arguments: - "on-target-error": the action to take on an error on the target (BlockdevOnError, default 'report') +The default value of the granularity is the image cluster size clamped +between 4096 and 65536, if the image format defines one. If the format +does not define a cluster size, the default value of the granularity +is 65536. Example: From bd48bde8f0fa08dfc8edcafc2bc8aa6d43734463 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jan 2013 09:03:12 +0100 Subject: [PATCH 0645/1634] mirror: switch mirror_iteration to AIO There is really no change in the behavior of the job here, since there is still a maximum of one in-flight I/O operation between the source and the target. However, this patch already introduces the AIO callbacks (which are unmodified in the next patch) and some of the logic to count in-flight operations and only complete the job when there is none. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/mirror.c | 167 +++++++++++++++++++++++++++++++++++++------------ trace-events | 2 + 2 files changed, 128 insertions(+), 41 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 0fecb40c10..fc6b9b7118 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -33,8 +33,19 @@ typedef struct MirrorBlockJob { unsigned long *cow_bitmap; HBitmapIter hbi; uint8_t *buf; + + int in_flight; + int ret; } MirrorBlockJob; +typedef struct MirrorOp { + MirrorBlockJob *s; + QEMUIOVector qiov; + struct iovec iov; + int64_t sector_num; + int nb_sectors; +} MirrorOp; + static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read, int error) { @@ -48,15 +59,70 @@ static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read, } } -static int coroutine_fn mirror_iteration(MirrorBlockJob *s, - BlockErrorAction *p_action) +static void mirror_iteration_done(MirrorOp *op, int ret) +{ + MirrorBlockJob *s = op->s; + int64_t chunk_num; + int nb_chunks, sectors_per_chunk; + + trace_mirror_iteration_done(s, op->sector_num, op->nb_sectors, ret); + + s->in_flight--; + sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; + chunk_num = op->sector_num / sectors_per_chunk; + nb_chunks = op->nb_sectors / sectors_per_chunk; + if (s->cow_bitmap && ret >= 0) { + bitmap_set(s->cow_bitmap, chunk_num, nb_chunks); + } + + g_slice_free(MirrorOp, op); + qemu_coroutine_enter(s->common.co, NULL); +} + +static void mirror_write_complete(void *opaque, int ret) +{ + MirrorOp *op = opaque; + MirrorBlockJob *s = op->s; + if (ret < 0) { + BlockDriverState *source = s->common.bs; + BlockErrorAction action; + + bdrv_set_dirty(source, op->sector_num, op->nb_sectors); + action = mirror_error_action(s, false, -ret); + if (action == BDRV_ACTION_REPORT && s->ret >= 0) { + s->ret = ret; + } + } + mirror_iteration_done(op, ret); +} + +static void mirror_read_complete(void *opaque, int ret) +{ + MirrorOp *op = opaque; + MirrorBlockJob *s = op->s; + if (ret < 0) { + BlockDriverState *source = s->common.bs; + BlockErrorAction action; + + bdrv_set_dirty(source, op->sector_num, op->nb_sectors); + action = mirror_error_action(s, true, -ret); + if (action == BDRV_ACTION_REPORT && s->ret >= 0) { + s->ret = ret; + } + + mirror_iteration_done(op, ret); + return; + } + bdrv_aio_writev(s->target, op->sector_num, &op->qiov, op->nb_sectors, + mirror_write_complete, op); +} + +static void coroutine_fn mirror_iteration(MirrorBlockJob *s) { BlockDriverState *source = s->common.bs; - BlockDriverState *target = s->target; - QEMUIOVector qiov; - int ret, nb_sectors, sectors_per_chunk; + int nb_sectors, sectors_per_chunk; int64_t end, sector_num, chunk_num; - struct iovec iov; + MirrorOp *op; s->sector_num = hbitmap_iter_next(&s->hbi); if (s->sector_num < 0) { @@ -85,35 +151,30 @@ static int coroutine_fn mirror_iteration(MirrorBlockJob *s, end = s->common.len >> BDRV_SECTOR_BITS; nb_sectors = MIN(nb_sectors, end - sector_num); + + /* Allocate a MirrorOp that is used as an AIO callback. */ + op = g_slice_new(MirrorOp); + op->s = s; + op->iov.iov_base = s->buf; + op->iov.iov_len = nb_sectors * 512; + op->sector_num = sector_num; + op->nb_sectors = nb_sectors; + qemu_iovec_init_external(&op->qiov, &op->iov, 1); + bdrv_reset_dirty(source, sector_num, nb_sectors); /* Copy the dirty cluster. */ - iov.iov_base = s->buf; - iov.iov_len = nb_sectors * 512; - qemu_iovec_init_external(&qiov, &iov, 1); - + s->in_flight++; trace_mirror_one_iteration(s, sector_num, nb_sectors); - ret = bdrv_co_readv(source, sector_num, nb_sectors, &qiov); - if (ret < 0) { - *p_action = mirror_error_action(s, true, -ret); - goto fail; - } - ret = bdrv_co_writev(target, sector_num, nb_sectors, &qiov); - if (ret < 0) { - *p_action = mirror_error_action(s, false, -ret); - s->synced = false; - goto fail; - } - if (s->cow_bitmap) { - bitmap_set(s->cow_bitmap, sector_num / sectors_per_chunk, - nb_sectors / sectors_per_chunk); - } - return 0; + bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors, + mirror_read_complete, op); +} -fail: - /* Try again later. */ - bdrv_set_dirty(source, sector_num, nb_sectors); - return ret; +static void mirror_drain(MirrorBlockJob *s) +{ + while (s->in_flight > 0) { + qemu_coroutine_yield(); + } } static void coroutine_fn mirror_run(void *opaque) @@ -121,6 +182,7 @@ static void coroutine_fn mirror_run(void *opaque) MirrorBlockJob *s = opaque; BlockDriverState *bs = s->common.bs; int64_t sector_num, end, sectors_per_chunk, length; + uint64_t last_pause_ns; BlockDriverInfo bdi; char backing_filename[1024]; int ret = 0; @@ -179,23 +241,38 @@ static void coroutine_fn mirror_run(void *opaque) } bdrv_dirty_iter_init(bs, &s->hbi); + last_pause_ns = qemu_get_clock_ns(rt_clock); for (;;) { uint64_t delay_ns; int64_t cnt; bool should_complete; + if (s->ret < 0) { + ret = s->ret; + goto immediate_exit; + } + cnt = bdrv_get_dirty_count(bs); - if (cnt != 0) { - BlockErrorAction action = BDRV_ACTION_REPORT; - ret = mirror_iteration(s, &action); - if (ret < 0 && action == BDRV_ACTION_REPORT) { - goto immediate_exit; + + /* Note that even when no rate limit is applied we need to yield + * periodically with no pending I/O so that qemu_aio_flush() returns. + * We do so every SLICE_TIME nanoseconds, or when there is an error, + * or when the source is clean, whichever comes first. + */ + if (qemu_get_clock_ns(rt_clock) - last_pause_ns < SLICE_TIME && + s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { + if (s->in_flight > 0) { + trace_mirror_yield(s, s->in_flight, cnt); + qemu_coroutine_yield(); + continue; + } else if (cnt != 0) { + mirror_iteration(s); + continue; } - cnt = bdrv_get_dirty_count(bs); } should_complete = false; - if (cnt == 0) { + if (s->in_flight == 0 && cnt == 0) { trace_mirror_before_flush(s); ret = bdrv_flush(s->target); if (ret < 0) { @@ -246,15 +323,12 @@ static void coroutine_fn mirror_run(void *opaque) delay_ns = 0; } - /* Note that even when no rate limit is applied we need to yield - * with no pending I/O here so that bdrv_drain_all() returns. - */ block_job_sleep_ns(&s->common, rt_clock, delay_ns); if (block_job_is_cancelled(&s->common)) { break; } } else if (!should_complete) { - delay_ns = (cnt == 0 ? SLICE_TIME : 0); + delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); block_job_sleep_ns(&s->common, rt_clock, delay_ns); } else if (cnt == 0) { /* The two disks are in sync. Exit and report successful @@ -264,9 +338,20 @@ static void coroutine_fn mirror_run(void *opaque) s->common.cancelled = false; break; } + last_pause_ns = qemu_get_clock_ns(rt_clock); } immediate_exit: + if (s->in_flight > 0) { + /* We get here only if something went wrong. Either the job failed, + * or it was cancelled prematurely so that we do not guarantee that + * the target is a copy of the source. + */ + assert(ret < 0 || (!s->synced && block_job_is_cancelled(&s->common))); + mirror_drain(s); + } + + assert(s->in_flight == 0); qemu_vfree(s->buf); g_free(s->cow_bitmap); bdrv_set_dirty_tracking(bs, 0); diff --git a/trace-events b/trace-events index ffa27568ee..43e6b73fa5 100644 --- a/trace-events +++ b/trace-events @@ -85,6 +85,8 @@ mirror_before_drain(void *s, int64_t cnt) "s %p dirty count %"PRId64 mirror_before_sleep(void *s, int64_t cnt, int synced) "s %p dirty count %"PRId64" synced %d" mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d" mirror_cow(void *s, int64_t sector_num) "s %p sector_num %"PRId64 +mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d" +mirror_yield(void *s, int64_t cnt, int in_flight) "s %p dirty count %"PRId64" in_flight %d" # blockdev.c qmp_block_job_cancel(void *job) "job %p" From 08e4ed6cdeeee7912072cf14aa8ab6c60dacb4fb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jan 2013 09:03:13 +0100 Subject: [PATCH 0646/1634] mirror: add buf-size argument to drive-mirror This makes sense when the next commit starts using the extra buffer space to perform many I/O operations asynchronously. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/mirror.c | 8 ++++---- blockdev.c | 9 ++++++++- hmp.c | 2 +- include/block/block_int.h | 5 +++-- qapi-schema.json | 5 ++++- qmp-commands.hx | 4 +++- tests/qemu-iotests/041 | 31 +++++++++++++++++++++++++++++++ tests/qemu-iotests/041.out | 4 ++-- 8 files changed, 56 insertions(+), 12 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index fc6b9b7118..896972c297 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -207,7 +207,7 @@ static void coroutine_fn mirror_run(void *opaque) if (backing_filename[0] && !s->target->backing_hd) { bdrv_get_info(s->target, &bdi); if (s->granularity < bdi.cluster_size) { - s->buf_size = bdi.cluster_size; + s->buf_size = MAX(s->buf_size, bdi.cluster_size); length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity; s->cow_bitmap = bitmap_new(length); } @@ -416,8 +416,8 @@ static BlockJobType mirror_job_type = { }; void mirror_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, int64_t granularity, MirrorSyncMode mode, - BlockdevOnError on_source_error, + int64_t speed, int64_t granularity, int64_t buf_size, + MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp) @@ -455,7 +455,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target, s->target = target; s->mode = mode; s->granularity = granularity; - s->buf_size = granularity; + s->buf_size = MAX(buf_size, granularity); bdrv_set_dirty_tracking(bs, granularity); bdrv_set_enable_write_cache(s->target, true); diff --git a/blockdev.c b/blockdev.c index 07fd3273ed..ad25b9b86e 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1188,12 +1188,15 @@ void qmp_block_commit(const char *device, drive_get_ref(drive_get_by_blockdev(bs)); } +#define DEFAULT_MIRROR_BUF_SIZE (10 << 20) + void qmp_drive_mirror(const char *device, const char *target, bool has_format, const char *format, enum MirrorSyncMode sync, bool has_mode, enum NewImageMode mode, bool has_speed, int64_t speed, bool has_granularity, uint32_t granularity, + bool has_buf_size, int64_t buf_size, bool has_on_source_error, BlockdevOnError on_source_error, bool has_on_target_error, BlockdevOnError on_target_error, Error **errp) @@ -1222,6 +1225,10 @@ void qmp_drive_mirror(const char *device, const char *target, if (!has_granularity) { granularity = 0; } + if (!has_buf_size) { + buf_size = DEFAULT_MIRROR_BUF_SIZE; + } + if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) { error_set(errp, QERR_INVALID_PARAMETER, device); return; @@ -1311,7 +1318,7 @@ void qmp_drive_mirror(const char *device, const char *target, return; } - mirror_start(bs, target_bs, speed, granularity, sync, + mirror_start(bs, target_bs, speed, granularity, buf_size, sync, on_source_error, on_target_error, block_job_cb, bs, &local_err); if (local_err != NULL) { diff --git a/hmp.c b/hmp.c index 0f3347dd76..99fd89206b 100644 --- a/hmp.c +++ b/hmp.c @@ -796,7 +796,7 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict) qmp_drive_mirror(device, filename, !!format, format, full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP, - true, mode, false, 0, false, 0, + true, mode, false, 0, false, 0, false, 0, false, 0, false, 0, &errp); hmp_handle_error(mon, &errp); } diff --git a/include/block/block_int.h b/include/block/block_int.h index 1165339fd1..f7279b978a 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -345,6 +345,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * @target: Block device to write to. * @speed: The maximum speed, in bytes per second, or 0 for unlimited. * @granularity: The chosen granularity for the dirty bitmap. + * @buf_size: The amount of data that can be in flight at one time. * @mode: Whether to collapse all images in the chain to the target. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. @@ -358,8 +359,8 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, * @bs will be switched to read from @target. */ void mirror_start(BlockDriverState *bs, BlockDriverState *target, - int64_t speed, int64_t granularity, MirrorSyncMode mode, - BlockdevOnError on_source_error, + int64_t speed, int64_t granularity, int64_t buf_size, + MirrorSyncMode mode, BlockdevOnError on_source_error, BlockdevOnError on_target_error, BlockDriverCompletionFunc *cb, void *opaque, Error **errp); diff --git a/qapi-schema.json b/qapi-schema.json index fd5ec93c03..ba75c4de12 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1641,6 +1641,9 @@ # are smaller than that, else the cluster size. Must be a # power of 2 between 512 and 64M (since 1.4). # +# @buf-size: #optional maximum amount of data in flight from source to +# target (since 1.4). +# # @on-source-error: #optional the action to take on an error on the source, # default 'report'. 'stop' and 'enospc' can only be used # if the block device supports io-status (see BlockInfo). @@ -1658,7 +1661,7 @@ 'data': { 'device': 'str', 'target': 'str', '*format': 'str', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode', '*speed': 'int', '*granularity': 'uint32', - '*on-source-error': 'BlockdevOnError', + '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', '*on-target-error': 'BlockdevOnError' } } ## diff --git a/qmp-commands.hx b/qmp-commands.hx index 835ea26e9d..273b4a67ba 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -939,7 +939,7 @@ EQMP .name = "drive-mirror", .args_type = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?," "on-source-error:s?,on-target-error:s?," - "granularity:i?", + "granularity:i?,buf-size:i?", .mhandler.cmd_new = qmp_marshal_input_drive_mirror, }, @@ -964,6 +964,8 @@ Arguments: - "speed": maximum speed of the streaming job, in bytes per second (json-int) - "granularity": granularity of the dirty bitmap, in bytes (json-int, optional) +- "buf_size": maximum amount of data in flight from source to target, in bytes + (json-int, default 10M) - "sync": what parts of the disk image should be copied to the destination; possibilities include "full" for all the disk, "top" for only the sectors allocated in the topmost image, or "none" to only replicate new I/O diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index a1299b348e..b040820c51 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -207,6 +207,37 @@ class TestSingleDrive(ImageMirroringTestCase): self.assertTrue(self.compare_images(test_img, target_img), 'target image does not match source after mirroring') + def test_small_buffer(self): + self.assert_no_active_mirrors() + + # A small buffer is rounded up automatically + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + buf_size=4096, target=target_img) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait() + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/inserted/file', target_img) + self.vm.shutdown() + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + + def test_small_buffer2(self): + self.assert_no_active_mirrors() + + qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' + % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img) + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + buf_size=65536, mode='existing', target=target_img) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait() + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/inserted/file', target_img) + self.vm.shutdown() + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + def test_large_cluster(self): self.assert_no_active_mirrors() diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out index 3a89159833..84bfd63fba 100644 --- a/tests/qemu-iotests/041.out +++ b/tests/qemu-iotests/041.out @@ -1,5 +1,5 @@ -.................... +...................... ---------------------------------------------------------------------- -Ran 20 tests +Ran 22 tests OK From 402a47411bff5e849dc880dd08ba7e6564e6e4f4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jan 2013 09:03:14 +0100 Subject: [PATCH 0647/1634] mirror: support more than one in-flight AIO operation With AIO support in place, we can start copying more than one chunk in parallel. This patch introduces the required infrastructure for this: the buffer is split into multiple granularity-sized chunks, and there is a free list to access them. Because of copy-on-write, a single operation may already require multiple chunks to be available on the free list. In addition, two different iterations on the HBitmap may want to copy the same cluster. We avoid this by keeping a bitmap of in-flight I/O operations, and blocking until the previous iteration completes. This should be a pretty rare occurrence, though; as long as there is no overlap the next iteration can start before the previous one finishes. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/mirror.c | 102 +++++++++++++++++++++++++++++++++++++++++++------ trace-events | 4 +- 2 files changed, 94 insertions(+), 12 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 896972c297..4696dc84ea 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -17,7 +17,15 @@ #include "qemu/ratelimit.h" #include "qemu/bitmap.h" -#define SLICE_TIME 100000000ULL /* ns */ +#define SLICE_TIME 100000000ULL /* ns */ +#define MAX_IN_FLIGHT 16 + +/* The mirroring buffer is a list of granularity-sized chunks. + * Free chunks are organized in a list. + */ +typedef struct MirrorBuffer { + QSIMPLEQ_ENTRY(MirrorBuffer) next; +} MirrorBuffer; typedef struct MirrorBlockJob { BlockJob common; @@ -33,7 +41,10 @@ typedef struct MirrorBlockJob { unsigned long *cow_bitmap; HBitmapIter hbi; uint8_t *buf; + QSIMPLEQ_HEAD(, MirrorBuffer) buf_free; + int buf_free_count; + unsigned long *in_flight_bitmap; int in_flight; int ret; } MirrorBlockJob; @@ -41,7 +52,6 @@ typedef struct MirrorBlockJob { typedef struct MirrorOp { MirrorBlockJob *s; QEMUIOVector qiov; - struct iovec iov; int64_t sector_num; int nb_sectors; } MirrorOp; @@ -62,15 +72,24 @@ static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read, static void mirror_iteration_done(MirrorOp *op, int ret) { MirrorBlockJob *s = op->s; + struct iovec *iov; int64_t chunk_num; - int nb_chunks, sectors_per_chunk; + int i, nb_chunks, sectors_per_chunk; trace_mirror_iteration_done(s, op->sector_num, op->nb_sectors, ret); s->in_flight--; + iov = op->qiov.iov; + for (i = 0; i < op->qiov.niov; i++) { + MirrorBuffer *buf = (MirrorBuffer *) iov[i].iov_base; + QSIMPLEQ_INSERT_TAIL(&s->buf_free, buf, next); + s->buf_free_count++; + } + sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; chunk_num = op->sector_num / sectors_per_chunk; nb_chunks = op->nb_sectors / sectors_per_chunk; + bitmap_clear(s->in_flight_bitmap, chunk_num, nb_chunks); if (s->cow_bitmap && ret >= 0) { bitmap_set(s->cow_bitmap, chunk_num, nb_chunks); } @@ -120,8 +139,8 @@ static void mirror_read_complete(void *opaque, int ret) static void coroutine_fn mirror_iteration(MirrorBlockJob *s) { BlockDriverState *source = s->common.bs; - int nb_sectors, sectors_per_chunk; - int64_t end, sector_num, chunk_num; + int nb_sectors, sectors_per_chunk, nb_chunks; + int64_t end, sector_num, chunk_num, next_sector, hbitmap_next_sector; MirrorOp *op; s->sector_num = hbitmap_iter_next(&s->hbi); @@ -132,6 +151,8 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s) assert(s->sector_num >= 0); } + hbitmap_next_sector = s->sector_num; + /* If we have no backing file yet in the destination, and the cluster size * is very large, we need to do COW ourselves. The first time a cluster is * copied, copy it entirely. @@ -147,19 +168,56 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s) bdrv_round_to_clusters(s->target, sector_num, sectors_per_chunk, §or_num, &nb_sectors); + + /* The rounding may make us copy sectors before the + * first dirty one. + */ + chunk_num = sector_num / sectors_per_chunk; + } + + /* Wait for I/O to this cluster (from a previous iteration) to be done. */ + while (test_bit(chunk_num, s->in_flight_bitmap)) { + trace_mirror_yield_in_flight(s, sector_num, s->in_flight); + qemu_coroutine_yield(); } end = s->common.len >> BDRV_SECTOR_BITS; nb_sectors = MIN(nb_sectors, end - sector_num); + nb_chunks = (nb_sectors + sectors_per_chunk - 1) / sectors_per_chunk; + while (s->buf_free_count < nb_chunks) { + trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight); + qemu_coroutine_yield(); + } + + /* We have enough free space to copy these sectors. */ + bitmap_set(s->in_flight_bitmap, chunk_num, nb_chunks); /* Allocate a MirrorOp that is used as an AIO callback. */ op = g_slice_new(MirrorOp); op->s = s; - op->iov.iov_base = s->buf; - op->iov.iov_len = nb_sectors * 512; op->sector_num = sector_num; op->nb_sectors = nb_sectors; - qemu_iovec_init_external(&op->qiov, &op->iov, 1); + + /* Now make a QEMUIOVector taking enough granularity-sized chunks + * from s->buf_free. + */ + qemu_iovec_init(&op->qiov, nb_chunks); + next_sector = sector_num; + while (nb_chunks-- > 0) { + MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free); + QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next); + s->buf_free_count--; + qemu_iovec_add(&op->qiov, buf, s->granularity); + + /* Advance the HBitmapIter in parallel, so that we do not examine + * the same sector twice. + */ + if (next_sector > hbitmap_next_sector && bdrv_get_dirty(source, next_sector)) { + hbitmap_next_sector = hbitmap_iter_next(&s->hbi); + } + + next_sector += sectors_per_chunk; + } bdrv_reset_dirty(source, sector_num, nb_sectors); @@ -170,6 +228,23 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s) mirror_read_complete, op); } +static void mirror_free_init(MirrorBlockJob *s) +{ + int granularity = s->granularity; + size_t buf_size = s->buf_size; + uint8_t *buf = s->buf; + + assert(s->buf_free_count == 0); + QSIMPLEQ_INIT(&s->buf_free); + while (buf_size != 0) { + MirrorBuffer *cur = (MirrorBuffer *)buf; + QSIMPLEQ_INSERT_TAIL(&s->buf_free, cur, next); + s->buf_free_count++; + buf_size -= granularity; + buf += granularity; + } +} + static void mirror_drain(MirrorBlockJob *s) { while (s->in_flight > 0) { @@ -198,6 +273,9 @@ static void coroutine_fn mirror_run(void *opaque) return; } + length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity; + s->in_flight_bitmap = bitmap_new(length); + /* If we have no backing file yet in the destination, we cannot let * the destination do COW. Instead, we copy sectors around the * dirty data if needed. We need a bitmap to do that. @@ -208,7 +286,6 @@ static void coroutine_fn mirror_run(void *opaque) bdrv_get_info(s->target, &bdi); if (s->granularity < bdi.cluster_size) { s->buf_size = MAX(s->buf_size, bdi.cluster_size); - length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity; s->cow_bitmap = bitmap_new(length); } } @@ -216,6 +293,7 @@ static void coroutine_fn mirror_run(void *opaque) end = s->common.len >> BDRV_SECTOR_BITS; s->buf = qemu_blockalign(bs, s->buf_size); sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; + mirror_free_init(s); if (s->mode != MIRROR_SYNC_MODE_NONE) { /* First part, loop on the sectors and initialize the dirty bitmap. */ @@ -261,8 +339,9 @@ static void coroutine_fn mirror_run(void *opaque) */ if (qemu_get_clock_ns(rt_clock) - last_pause_ns < SLICE_TIME && s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) { - if (s->in_flight > 0) { - trace_mirror_yield(s, s->in_flight, cnt); + if (s->in_flight == MAX_IN_FLIGHT || s->buf_free_count == 0 || + (cnt == 0 && s->in_flight > 0)) { + trace_mirror_yield(s, s->in_flight, s->buf_free_count, cnt); qemu_coroutine_yield(); continue; } else if (cnt != 0) { @@ -354,6 +433,7 @@ immediate_exit: assert(s->in_flight == 0); qemu_vfree(s->buf); g_free(s->cow_bitmap); + g_free(s->in_flight_bitmap); bdrv_set_dirty_tracking(bs, 0); bdrv_iostatus_disable(s->target); if (s->should_complete && ret == 0) { diff --git a/trace-events b/trace-events index 43e6b73fa5..b4a23cdc2e 100644 --- a/trace-events +++ b/trace-events @@ -86,7 +86,9 @@ mirror_before_sleep(void *s, int64_t cnt, int synced) "s %p dirty count %"PRId64 mirror_one_iteration(void *s, int64_t sector_num, int nb_sectors) "s %p sector_num %"PRId64" nb_sectors %d" mirror_cow(void *s, int64_t sector_num) "s %p sector_num %"PRId64 mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s %p sector_num %"PRId64" nb_sectors %d ret %d" -mirror_yield(void *s, int64_t cnt, int in_flight) "s %p dirty count %"PRId64" in_flight %d" +mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d" +mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d" +mirror_yield_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d" # blockdev.c qmp_block_job_cancel(void *job) "job %p" From 884fea4e87fbc6daf4e6df618bb3cadc188dcc6b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jan 2013 09:03:15 +0100 Subject: [PATCH 0648/1634] mirror: support arbitrarily-sized iterations Yet another optimization is to extend the mirroring iteration to include more adjacent dirty blocks. This limits the number of I/O operations and makes mirroring efficient even with a small granularity. Most of the infrastructure is already in place; we only need to put a loop around the computation of the origin and sector count of the iteration. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block/mirror.c | 99 ++++++++++++++++++++++++++++++++++---------------- trace-events | 1 + 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 4696dc84ea..9347533b9b 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -140,7 +140,7 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s) { BlockDriverState *source = s->common.bs; int nb_sectors, sectors_per_chunk, nb_chunks; - int64_t end, sector_num, chunk_num, next_sector, hbitmap_next_sector; + int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector; MirrorOp *op; s->sector_num = hbitmap_iter_next(&s->hbi); @@ -152,45 +152,82 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s) } hbitmap_next_sector = s->sector_num; - - /* If we have no backing file yet in the destination, and the cluster size - * is very large, we need to do COW ourselves. The first time a cluster is - * copied, copy it entirely. - * - * Because both the granularity and the cluster size are powers of two, the - * number of sectors to copy cannot exceed one cluster. - */ sector_num = s->sector_num; - sectors_per_chunk = nb_sectors = s->granularity >> BDRV_SECTOR_BITS; - chunk_num = sector_num / sectors_per_chunk; - if (s->cow_bitmap && !test_bit(chunk_num, s->cow_bitmap)) { - trace_mirror_cow(s, sector_num); - bdrv_round_to_clusters(s->target, - sector_num, sectors_per_chunk, - §or_num, &nb_sectors); + sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS; + end = s->common.len >> BDRV_SECTOR_BITS; - /* The rounding may make us copy sectors before the - * first dirty one. - */ - chunk_num = sector_num / sectors_per_chunk; - } + /* Extend the QEMUIOVector to include all adjacent blocks that will + * be copied in this operation. + * + * We have to do this if we have no backing file yet in the destination, + * and the cluster size is very large. Then we need to do COW ourselves. + * The first time a cluster is copied, copy it entirely. Note that, + * because both the granularity and the cluster size are powers of two, + * the number of sectors to copy cannot exceed one cluster. + * + * We also want to extend the QEMUIOVector to include more adjacent + * dirty blocks if possible, to limit the number of I/O operations and + * run efficiently even with a small granularity. + */ + nb_chunks = 0; + nb_sectors = 0; + next_sector = sector_num; + next_chunk = sector_num / sectors_per_chunk; /* Wait for I/O to this cluster (from a previous iteration) to be done. */ - while (test_bit(chunk_num, s->in_flight_bitmap)) { + while (test_bit(next_chunk, s->in_flight_bitmap)) { trace_mirror_yield_in_flight(s, sector_num, s->in_flight); qemu_coroutine_yield(); } - end = s->common.len >> BDRV_SECTOR_BITS; - nb_sectors = MIN(nb_sectors, end - sector_num); - nb_chunks = (nb_sectors + sectors_per_chunk - 1) / sectors_per_chunk; - while (s->buf_free_count < nb_chunks) { - trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight); - qemu_coroutine_yield(); - } + do { + int added_sectors, added_chunks; - /* We have enough free space to copy these sectors. */ - bitmap_set(s->in_flight_bitmap, chunk_num, nb_chunks); + if (!bdrv_get_dirty(source, next_sector) || + test_bit(next_chunk, s->in_flight_bitmap)) { + assert(nb_sectors > 0); + break; + } + + added_sectors = sectors_per_chunk; + if (s->cow_bitmap && !test_bit(next_chunk, s->cow_bitmap)) { + bdrv_round_to_clusters(s->target, + next_sector, added_sectors, + &next_sector, &added_sectors); + + /* On the first iteration, the rounding may make us copy + * sectors before the first dirty one. + */ + if (next_sector < sector_num) { + assert(nb_sectors == 0); + sector_num = next_sector; + next_chunk = next_sector / sectors_per_chunk; + } + } + + added_sectors = MIN(added_sectors, end - (sector_num + nb_sectors)); + added_chunks = (added_sectors + sectors_per_chunk - 1) / sectors_per_chunk; + + /* When doing COW, it may happen that there is not enough space for + * a full cluster. Wait if that is the case. + */ + while (nb_chunks == 0 && s->buf_free_count < added_chunks) { + trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight); + qemu_coroutine_yield(); + } + if (s->buf_free_count < nb_chunks + added_chunks) { + trace_mirror_break_buf_busy(s, nb_chunks, s->in_flight); + break; + } + + /* We have enough free space to copy these sectors. */ + bitmap_set(s->in_flight_bitmap, next_chunk, added_chunks); + + nb_sectors += added_sectors; + nb_chunks += added_chunks; + next_sector += added_sectors; + next_chunk += added_chunks; + } while (next_sector < end); /* Allocate a MirrorOp that is used as an AIO callback. */ op = g_slice_new(MirrorOp); diff --git a/trace-events b/trace-events index b4a23cdc2e..2b28076e45 100644 --- a/trace-events +++ b/trace-events @@ -89,6 +89,7 @@ mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors, int ret) "s % mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d" mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d" mirror_yield_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d" +mirror_break_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d" # blockdev.c qmp_block_job_cancel(void *job) "job %p" From 02582abd48aa3d860015e9a8fcd0d7ec1c34ec62 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 17 Jan 2013 21:45:24 +0100 Subject: [PATCH 0649/1634] block: Add special error code for wrong format The block drivers need a special error code for "wrong format". From the available error codes EMEDIUMTYPE fits best. It is not available on all platforms, so a definition in qemu-common.h and a specific error report are needed. Signed-off-by: Stefan Weil Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- blockdev.c | 9 +++++++-- include/qemu-common.h | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/blockdev.c b/blockdev.c index ad25b9b86e..ac396f3c94 100644 --- a/blockdev.c +++ b/blockdev.c @@ -617,8 +617,13 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv); if (ret < 0) { - error_report("could not open disk image %s: %s", - file, strerror(-ret)); + if (ret == -EMEDIUMTYPE) { + error_report("could not open disk image %s: not in %s format", + file, drv->format_name); + } else { + error_report("could not open disk image %s: %s", + file, strerror(-ret)); + } goto err; } diff --git a/include/qemu-common.h b/include/qemu-common.h index ca464bb367..af2379ff38 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -68,6 +68,9 @@ #if !defined(ECANCELED) #define ECANCELED 4097 #endif +#if !defined(EMEDIUMTYPE) +#define EMEDIUMTYPE 4098 +#endif #ifndef TIME_MAX #define TIME_MAX LONG_MAX #endif From 15bac0d54f78adb5e255155a69e56ab7f6d8c8ea Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 17 Jan 2013 21:45:25 +0100 Subject: [PATCH 0650/1634] block: Use error code EMEDIUMTYPE for wrong format in some block drivers This improves error reports for bochs, cow, qcow, qcow2, qed and vmdk when a file with the wrong format is selected. Signed-off-by: Stefan Weil Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/bochs.c | 2 +- block/cow.c | 2 +- block/qcow.c | 2 +- block/qcow2.c | 2 +- block/qed.c | 2 +- block/vmdk.c | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/block/bochs.c b/block/bochs.c index 1b1d9cdbe5..37375834e9 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -126,7 +126,7 @@ static int bochs_open(BlockDriverState *bs, int flags) strcmp(bochs.subtype, GROWING_TYPE) || ((le32_to_cpu(bochs.version) != HEADER_VERSION) && (le32_to_cpu(bochs.version) != HEADER_V1))) { - goto fail; + return -EMEDIUMTYPE; } if (le32_to_cpu(bochs.version) == HEADER_V1) { diff --git a/block/cow.c b/block/cow.c index a33ce950d4..4baf9042fe 100644 --- a/block/cow.c +++ b/block/cow.c @@ -73,7 +73,7 @@ static int cow_open(BlockDriverState *bs, int flags) } if (be32_to_cpu(cow_header.magic) != COW_MAGIC) { - ret = -EINVAL; + ret = -EMEDIUMTYPE; goto fail; } diff --git a/block/qcow.c b/block/qcow.c index 4276610afd..a7135eea47 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -112,7 +112,7 @@ static int qcow_open(BlockDriverState *bs, int flags) be64_to_cpus(&header.l1_table_offset); if (header.magic != QCOW_MAGIC) { - ret = -EINVAL; + ret = -EMEDIUMTYPE; goto fail; } if (header.version != QCOW_VERSION) { diff --git a/block/qcow2.c b/block/qcow2.c index f6abff6111..7610e569e3 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -311,7 +311,7 @@ static int qcow2_open(BlockDriverState *bs, int flags) be32_to_cpus(&header.nb_snapshots); if (header.magic != QCOW_MAGIC) { - ret = -EINVAL; + ret = -EMEDIUMTYPE; goto fail; } if (header.version < 2 || header.version > 3) { diff --git a/block/qed.c b/block/qed.c index cf85d8f2b4..b8515e58b3 100644 --- a/block/qed.c +++ b/block/qed.c @@ -390,7 +390,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags) qed_header_le_to_cpu(&le_header, &s->header); if (s->header.magic != QED_MAGIC) { - return -EINVAL; + return -EMEDIUMTYPE; } if (s->header.features & ~QED_FEATURE_MASK) { /* image uses unsupported feature bits */ diff --git a/block/vmdk.c b/block/vmdk.c index 19298c2a3e..8333afb5e3 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -616,7 +616,7 @@ static int vmdk_open_sparse(BlockDriverState *bs, return vmdk_open_vmdk4(bs, file, flags); break; default: - return -EINVAL; + return -EMEDIUMTYPE; break; } } @@ -718,7 +718,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, } buf[2047] = '\0'; if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { - return -EINVAL; + return -EMEDIUMTYPE; } if (strcmp(ct, "monolithicFlat") && strcmp(ct, "twoGbMaxExtentSparse") && From 9f0470bb2d7942c28977296ff2598cdf30886e07 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 17 Jan 2013 21:45:26 +0100 Subject: [PATCH 0651/1634] block/vdi: Improve debug output for signature The signature is a 32 bit value and needs up to 8 hex digits for printing. Signed-off-by: Stefan Weil Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/vdi.c b/block/vdi.c index 021abaa227..0e1ed617f3 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -246,7 +246,7 @@ static void vdi_header_print(VdiHeader *header) { char uuid[37]; logout("text %s", header->text); - logout("signature 0x%04x\n", header->signature); + logout("signature 0x%08x\n", header->signature); logout("header size 0x%04x\n", header->header_size); logout("image type 0x%04x\n", header->image_type); logout("image flags 0x%04x\n", header->image_flags); From 8937f8222c14ab42140a5645c34e17cc620c05bb Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 17 Jan 2013 21:45:27 +0100 Subject: [PATCH 0652/1634] block/vdi: Improved return values from vdi_open vdi_open returned -1 in case of any error, but it should return an error code (negative value of errno or -EMEDIUMTYPE). Signed-off-by: Stefan Weil Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vdi.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/block/vdi.c b/block/vdi.c index 0e1ed617f3..8b768bfa49 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -369,10 +369,12 @@ static int vdi_open(BlockDriverState *bs, int flags) BDRVVdiState *s = bs->opaque; VdiHeader header; size_t bmap_size; + int ret; logout("\n"); - if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) { + ret = bdrv_read(bs->file, 0, (uint8_t *)&header, 1); + if (ret < 0) { goto fail; } @@ -393,30 +395,38 @@ static int vdi_open(BlockDriverState *bs, int flags) if (header.version != VDI_VERSION_1_1) { logout("unsupported version %u.%u\n", header.version >> 16, header.version & 0xffff); + ret = -ENOTSUP; goto fail; } else if (header.offset_bmap % SECTOR_SIZE != 0) { /* We only support block maps which start on a sector boundary. */ logout("unsupported block map offset 0x%x B\n", header.offset_bmap); + ret = -ENOTSUP; goto fail; } else if (header.offset_data % SECTOR_SIZE != 0) { /* We only support data blocks which start on a sector boundary. */ logout("unsupported data offset 0x%x B\n", header.offset_data); + ret = -ENOTSUP; goto fail; } else if (header.sector_size != SECTOR_SIZE) { logout("unsupported sector size %u B\n", header.sector_size); + ret = -ENOTSUP; goto fail; } else if (header.block_size != 1 * MiB) { logout("unsupported block size %u B\n", header.block_size); + ret = -ENOTSUP; goto fail; } else if (header.disk_size > (uint64_t)header.blocks_in_image * header.block_size) { logout("unsupported disk size %" PRIu64 " B\n", header.disk_size); + ret = -ENOTSUP; goto fail; } else if (!uuid_is_null(header.uuid_link)) { logout("link uuid != 0, unsupported\n"); + ret = -ENOTSUP; goto fail; } else if (!uuid_is_null(header.uuid_parent)) { logout("parent uuid != 0, unsupported\n"); + ret = -ENOTSUP; goto fail; } @@ -432,7 +442,8 @@ static int vdi_open(BlockDriverState *bs, int flags) if (bmap_size > 0) { s->bmap = g_malloc(bmap_size * SECTOR_SIZE); } - if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) { + ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size); + if (ret < 0) { goto fail_free_bmap; } @@ -448,7 +459,7 @@ static int vdi_open(BlockDriverState *bs, int flags) g_free(s->bmap); fail: - return -1; + return ret; } static int vdi_reopen_prepare(BDRVReopenState *state, From 0e87ba2ccbf900cc5a56b95e0671e5a5d2c2f6a0 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 17 Jan 2013 21:45:28 +0100 Subject: [PATCH 0653/1634] block/vdi: Check for bad signature vdi_open did not check for a bad signature. This check was only in vdi_probe. Signed-off-by: Stefan Weil Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/vdi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/block/vdi.c b/block/vdi.c index 8b768bfa49..257a592ea9 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -392,7 +392,11 @@ static int vdi_open(BlockDriverState *bs, int flags) header.disk_size &= ~(SECTOR_SIZE - 1); } - if (header.version != VDI_VERSION_1_1) { + if (header.signature != VDI_SIGNATURE) { + logout("bad vdi signature %08x\n", header.signature); + ret = -EMEDIUMTYPE; + goto fail; + } else if (header.version != VDI_VERSION_1_1) { logout("unsupported version %u.%u\n", header.version >> 16, header.version & 0xffff); ret = -ENOTSUP; From 88ff0e48eedd679a9dc1122676d8aa29f8d07571 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jan 2013 15:01:11 +0100 Subject: [PATCH 0654/1634] mirror: do nothing on zero-sized disk On a zero-sized disk we need to break out of the job successfully before bdrv_dirty_iter_init is called, otherwise you will get an assertion failure with the next patch. Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Reviewed-by: Laszlo Ersek Signed-off-by: Kevin Wolf --- block/mirror.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/mirror.c b/block/mirror.c index 9347533b9b..a62ad86c28 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -305,7 +305,7 @@ static void coroutine_fn mirror_run(void *opaque) } s->common.len = bdrv_getlength(bs); - if (s->common.len < 0) { + if (s->common.len <= 0) { block_job_completed(&s->common, s->common.len); return; } From 1b0952445522af73b0e78420a9078b3653923703 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 22 Jan 2013 15:01:12 +0100 Subject: [PATCH 0655/1634] hbitmap: add assertion on hbitmap_iter_init hbitmap_iter_init causes an out-of-bounds access when the "first" argument is or greater than or equal to the size of the bitmap. Forbid this with an assertion, and remove the failing testcase. Reported-by: Kevin Wolf Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Reviewed-by: Laszlo Ersek Signed-off-by: Kevin Wolf --- include/qemu/hbitmap.h | 3 ++- tests/test-hbitmap.c | 13 +++---------- util/hbitmap.c | 1 + 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 7ddfb66808..73f5d1d8d3 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -128,7 +128,8 @@ void hbitmap_free(HBitmap *hb); * hbitmap_iter_init: * @hbi: HBitmapIter to initialize. * @hb: HBitmap to iterate on. - * @first: First bit to visit (0-based). + * @first: First bit to visit (0-based, must be strictly less than the + * size of the bitmap). * * Set up @hbi to iterate on the HBitmap @hb. hbitmap_iter_next will return * the lowest-numbered bit that is set in @hb, starting at @first. diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c index fcc6a00fc3..8c902f2055 100644 --- a/tests/test-hbitmap.c +++ b/tests/test-hbitmap.c @@ -86,7 +86,9 @@ static void hbitmap_test_init(TestHBitmapData *data, data->bits = g_new0(unsigned long, n); data->size = size; data->granularity = granularity; - hbitmap_test_check(data, 0); + if (size) { + hbitmap_test_check(data, 0); + } } static void hbitmap_test_teardown(TestHBitmapData *data, @@ -198,14 +200,6 @@ static void test_hbitmap_iter_partial(TestHBitmapData *data, hbitmap_test_check(data, L3 / 2); } -static void test_hbitmap_iter_past(TestHBitmapData *data, - const void *unused) -{ - hbitmap_test_init(data, L3, 0); - hbitmap_test_set(data, 0, L3); - hbitmap_test_check(data, L3); -} - static void test_hbitmap_set_all(TestHBitmapData *data, const void *unused) { @@ -388,7 +382,6 @@ int main(int argc, char **argv) hbitmap_test_add("/hbitmap/size/0", test_hbitmap_zero); hbitmap_test_add("/hbitmap/size/unaligned", test_hbitmap_unaligned); hbitmap_test_add("/hbitmap/iter/empty", test_hbitmap_iter_empty); - hbitmap_test_add("/hbitmap/iter/past", test_hbitmap_iter_past); hbitmap_test_add("/hbitmap/iter/partial", test_hbitmap_iter_partial); hbitmap_test_add("/hbitmap/iter/granularity", test_hbitmap_iter_granularity); hbitmap_test_add("/hbitmap/get/all", test_hbitmap_get_all); diff --git a/util/hbitmap.c b/util/hbitmap.c index fb7e01e8c5..2aa487db74 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -147,6 +147,7 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first) hbi->hb = hb; pos = first >> hb->granularity; + assert(pos < hb->size); hbi->pos = pos >> BITS_PER_LEVEL; hbi->granularity = hb->granularity; From 1147bb15a715a907a91195c2ed601fc926e43d46 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Fri, 4 Jan 2013 14:44:41 -0500 Subject: [PATCH 0656/1634] ahci: Remove unused AHCIDevice fields 'dma_status' and 'dma_cb' are written to, but never read. Remove these fields in preparation for AHCI migration bits. Signed-off-by: Jason Baron Reviewed-by: Juan Quintela Signed-off-by: Kevin Wolf --- hw/ide/ahci.c | 8 ++------ hw/ide/ahci.h | 2 -- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 21f50ea5be..2d185cb20f 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1035,11 +1035,10 @@ out: static void ahci_start_dma(IDEDMA *dma, IDEState *s, BlockDriverCompletionFunc *dma_cb) { +#ifdef DEBUG_AHCI AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - +#endif DPRINTF(ad->port_no, "\n"); - ad->dma_cb = dma_cb; - ad->dma_status |= BM_STATUS_DMAING; s->io_buffer_offset = 0; dma_cb(s, 0); } @@ -1095,7 +1094,6 @@ static int ahci_dma_set_unit(IDEDMA *dma, int unit) static int ahci_dma_add_status(IDEDMA *dma, int status) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - ad->dma_status |= status; DPRINTF(ad->port_no, "set status: %x\n", status); if (status & BM_STATUS_INT) { @@ -1114,8 +1112,6 @@ static int ahci_dma_set_inactive(IDEDMA *dma) /* update d2h status */ ahci_write_fis_d2h(ad, NULL); - ad->dma_cb = NULL; - if (!ad->check_bh) { /* maybe we still have something to process, check later */ ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad); diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 1200a56ada..735b379e82 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -281,11 +281,9 @@ struct AHCIDevice { QEMUBH *check_bh; uint8_t *lst; uint8_t *res_fis; - int dma_status; int done_atapi_packet; int busy_slot; int init_d2h_sent; - BlockDriverCompletionFunc *dma_cb; AHCICmdHdr *cur_cmd; NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; }; From 4ac557c89b04d506c876a0a378e815d822261c8a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 15 Jan 2013 16:12:09 +0100 Subject: [PATCH 0657/1634] ahci: Change data types in preparation for migration The size of an int depends on the host, so in order to be able to migrate these fields, make them either int32_t or bool, depending on the use. Signed-off-by: Kevin Wolf --- hw/ide/ahci.c | 8 ++++---- hw/ide/ahci.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 2d185cb20f..f91cff2b4d 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -241,7 +241,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) if ((pr->cmd & PORT_CMD_FIS_ON) && !s->dev[port].init_d2h_sent) { ahci_init_d2h(&s->dev[port]); - s->dev[port].init_d2h_sent = 1; + s->dev[port].init_d2h_sent = true; } check_cmd(s, port); @@ -494,7 +494,7 @@ static void ahci_reset_port(AHCIState *s, int port) pr->scr_err = 0; pr->scr_act = 0; d->busy_slot = -1; - d->init_d2h_sent = 0; + d->init_d2h_sent = false; ide_state = &s->dev[port].port.ifs[0]; if (!ide_state->bs) { @@ -946,7 +946,7 @@ static int handle_cmd(AHCIState *s, int port, int slot) ide_state->hcyl = 0xeb; debug_print_fis(ide_state->io_buffer, 0x10); ide_state->feature = IDE_FEATURE_DMA; - s->dev[port].done_atapi_packet = 0; + s->dev[port].done_atapi_packet = false; /* XXX send PIO setup FIS */ } @@ -991,7 +991,7 @@ static int ahci_start_transfer(IDEDMA *dma) if (is_atapi && !ad->done_atapi_packet) { /* already prepopulated iobuffer */ - ad->done_atapi_packet = 1; + ad->done_atapi_packet = true; goto out; } diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 735b379e82..70d3b57adf 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -281,9 +281,9 @@ struct AHCIDevice { QEMUBH *check_bh; uint8_t *lst; uint8_t *res_fis; - int done_atapi_packet; - int busy_slot; - int init_d2h_sent; + bool done_atapi_packet; + int32_t busy_slot; + bool init_d2h_sent; AHCICmdHdr *cur_cmd; NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; }; @@ -295,7 +295,7 @@ typedef struct AHCIState { MemoryRegion idp; /* Index-Data Pair I/O port space */ unsigned idp_offset; /* Offset of index in I/O port space */ uint32_t idp_index; /* Current IDP index */ - int ports; + int32_t ports; qemu_irq irq; DMAContext *dma; } AHCIState; From a26230218d7d66ec5cb1aec101ceaf0e7400ef7f Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Fri, 4 Jan 2013 14:44:42 -0500 Subject: [PATCH 0658/1634] ahci: Add migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jason tested these patches by migrating Windows 7 and Fedora 17 guests (while under I/O) on both piix with ahci attached and on q35 (which has a built-in AHCI controller). Signed-off-by: Andreas Färber Signed-off-by: Jason Baron Signed-off-by: Kevin Wolf --- hw/ide/ahci.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++- hw/ide/ahci.h | 10 +++++++ hw/ide/ich.c | 14 ++++++--- 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index f91cff2b4d..ad0094f532 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1199,6 +1199,82 @@ void ahci_reset(AHCIState *s) } } +static const VMStateDescription vmstate_ahci_device = { + .name = "ahci port", + .version_id = 1, + .fields = (VMStateField []) { + VMSTATE_IDE_BUS(port, AHCIDevice), + VMSTATE_UINT32(port_state, AHCIDevice), + VMSTATE_UINT32(finished, AHCIDevice), + VMSTATE_UINT32(port_regs.lst_addr, AHCIDevice), + VMSTATE_UINT32(port_regs.lst_addr_hi, AHCIDevice), + VMSTATE_UINT32(port_regs.fis_addr, AHCIDevice), + VMSTATE_UINT32(port_regs.fis_addr_hi, AHCIDevice), + VMSTATE_UINT32(port_regs.irq_stat, AHCIDevice), + VMSTATE_UINT32(port_regs.irq_mask, AHCIDevice), + VMSTATE_UINT32(port_regs.cmd, AHCIDevice), + VMSTATE_UINT32(port_regs.tfdata, AHCIDevice), + VMSTATE_UINT32(port_regs.sig, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_stat, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_ctl, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_err, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_act, AHCIDevice), + VMSTATE_UINT32(port_regs.cmd_issue, AHCIDevice), + VMSTATE_BOOL(done_atapi_packet, AHCIDevice), + VMSTATE_INT32(busy_slot, AHCIDevice), + VMSTATE_BOOL(init_d2h_sent, AHCIDevice), + VMSTATE_END_OF_LIST() + }, +}; + +static int ahci_state_post_load(void *opaque, int version_id) +{ + int i; + struct AHCIDevice *ad; + AHCIState *s = opaque; + + for (i = 0; i < s->ports; i++) { + ad = &s->dev[i]; + AHCIPortRegs *pr = &ad->port_regs; + + map_page(&ad->lst, + ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); + map_page(&ad->res_fis, + ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); + /* + * All pending i/o should be flushed out on a migrate. However, + * we might not have cleared the busy_slot since this is done + * in a bh. Also, issue i/o against any slots that are pending. + */ + if ((ad->busy_slot != -1) && + !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) { + pr->cmd_issue &= ~(1 << ad->busy_slot); + ad->busy_slot = -1; + } + check_cmd(s, i); + } + + return 0; +} + +const VMStateDescription vmstate_ahci = { + .name = "ahci", + .version_id = 1, + .post_load = ahci_state_post_load, + .fields = (VMStateField []) { + VMSTATE_STRUCT_VARRAY_POINTER_INT32(dev, AHCIState, ports, + vmstate_ahci_device, AHCIDevice), + VMSTATE_UINT32(control_regs.cap, AHCIState), + VMSTATE_UINT32(control_regs.ghc, AHCIState), + VMSTATE_UINT32(control_regs.irqstatus, AHCIState), + VMSTATE_UINT32(control_regs.impl, AHCIState), + VMSTATE_UINT32(control_regs.version, AHCIState), + VMSTATE_UINT32(idp_index, AHCIState), + VMSTATE_INT32(ports, AHCIState), + VMSTATE_END_OF_LIST() + }, +}; + typedef struct SysbusAHCIState { SysBusDevice busdev; AHCIState ahci; @@ -1207,7 +1283,11 @@ typedef struct SysbusAHCIState { static const VMStateDescription vmstate_sysbus_ahci = { .name = "sysbus-ahci", - .unmigratable = 1, + .unmigratable = 1, /* Still buggy under I/O load */ + .fields = (VMStateField []) { + VMSTATE_AHCI(ahci, AHCIPCIState), + VMSTATE_END_OF_LIST() + }, }; static void sysbus_ahci_reset(DeviceState *dev) diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 70d3b57adf..85f37fe99d 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -305,6 +305,16 @@ typedef struct AHCIPCIState { AHCIState ahci; } AHCIPCIState; +extern const VMStateDescription vmstate_ahci; + +#define VMSTATE_AHCI(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(AHCIState), \ + .vmsd = &vmstate_ahci, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, AHCIState), \ +} + typedef struct NCQFrame { uint8_t fis_type; uint8_t c; diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 1fb803d340..cc30adc701 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -79,9 +79,15 @@ #define ICH9_IDP_INDEX 0x10 #define ICH9_IDP_INDEX_LOG2 0x04 -static const VMStateDescription vmstate_ahci = { - .name = "ahci", - .unmigratable = 1, +static const VMStateDescription vmstate_ich9_ahci = { + .name = "ich9_ahci", + .unmigratable = 1, /* Still buggy under I/O load */ + .version_id = 1, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(card, AHCIPCIState), + VMSTATE_AHCI(ahci, AHCIPCIState), + VMSTATE_END_OF_LIST() + }, }; static void pci_ich9_reset(DeviceState *dev) @@ -152,7 +158,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_INTEL_82801IR; k->revision = 0x02; k->class_id = PCI_CLASS_STORAGE_SATA; - dc->vmsd = &vmstate_ahci; + dc->vmsd = &vmstate_ich9_ahci; dc->reset = pci_ich9_reset; } From 8689907266b649b757c2203d9652cbe928a3ae0b Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 24 Jan 2013 10:00:40 -0800 Subject: [PATCH 0659/1634] block: Create proper size file for disk mirror The qmp monitor command to mirror a disk was passing -1 for size along with the disk's backing file. This size of the resulting disk is the size of the backing file, which is incorrect if the disk has been resized. Therefore we should always pass in the size of the current disk. Signed-off-by: Vishvananda Ishaya Signed-off-by: Kevin Wolf --- blockdev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blockdev.c b/blockdev.c index ac396f3c94..fdc573f519 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1282,11 +1282,11 @@ void qmp_drive_mirror(const char *device, const char *target, return; } + bdrv_get_geometry(bs, &size); + size *= 512; if (sync == MIRROR_SYNC_MODE_FULL && mode != NEW_IMAGE_MODE_EXISTING) { /* create new image w/o backing file */ assert(format && drv); - bdrv_get_geometry(bs, &size); - size *= 512; bdrv_img_create(target, format, NULL, NULL, NULL, size, flags, &local_err); } else { @@ -1299,7 +1299,7 @@ void qmp_drive_mirror(const char *device, const char *target, bdrv_img_create(target, format, source->filename, source->drv->format_name, - NULL, -1, flags, &local_err); + NULL, size, flags, &local_err); break; default: abort(); From 67bec53d9f2ccd3aa7d37a7e0689122587929220 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 24 Jan 2013 12:50:28 +0100 Subject: [PATCH 0660/1634] ide: Add fall through annotations Add comments to help static analysers detect that these cases are intentional, and clean up some whitespace in the environment of these comments. Signed-off-by: Kevin Wolf Reviewed-by: Markus Armbruster --- hw/ide/core.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/hw/ide/core.c b/hw/ide/core.c index 14ad0799c3..3743dc3b55 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1149,8 +1149,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) } ide_set_irq(s->bus); break; + case WIN_VERIFY_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_VERIFY: case WIN_VERIFY_ONCE: /* do sector number check ? */ @@ -1158,8 +1160,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; + case WIN_READ_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_READ: case WIN_READ_ONCE: if (s->drive_kind == IDE_CD) { @@ -1173,8 +1177,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) s->req_nb_sectors = 1; ide_sector_read(s); break; + case WIN_WRITE_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_WRITE: case WIN_WRITE_ONCE: case CFA_WRITE_SECT_WO_ERASE: @@ -1189,8 +1195,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); s->media_changed = 1; break; + case WIN_MULTREAD_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_MULTREAD: if (!s->bs) { goto abort_cmd; @@ -1202,8 +1210,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) s->req_nb_sectors = s->mult_sectors; ide_sector_read(s); break; + case WIN_MULTWRITE_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_MULTWRITE: case CFA_WRITE_MULTI_WO_ERASE: if (!s->bs) { @@ -1222,8 +1232,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); s->media_changed = 1; break; + case WIN_READDMA_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_READDMA: case WIN_READDMA_ONCE: if (!s->bs) { @@ -1232,8 +1244,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_cmd_lba48_transform(s, lba48); ide_sector_start_dma(s, IDE_DMA_READ); break; + case WIN_WRITEDMA_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_WRITEDMA: case WIN_WRITEDMA_ONCE: if (!s->bs) { @@ -1243,14 +1257,17 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_sector_start_dma(s, IDE_DMA_WRITE); s->media_changed = 1; break; + case WIN_READ_NATIVE_MAX_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_READ_NATIVE_MAX: ide_cmd_lba48_transform(s, lba48); ide_set_sector(s, s->nb_sectors - 1); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; + case WIN_CHECKPOWERMODE1: case WIN_CHECKPOWERMODE2: s->error = 0; From baec19105bb9824593bf6f37556302da2f67e583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:03:54 +0000 Subject: [PATCH 0661/1634] ppc: Move Mac machines to hw/ppc/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber [agraf: squash in MAINTAINERS fix] Signed-off-by: Alexander Graf --- MAINTAINERS | 4 ++-- hw/cuda.c | 2 +- hw/grackle_pci.c | 2 +- hw/heathrow_pic.c | 2 +- hw/ide/macio.c | 6 ++--- hw/mac_nvram.c | 2 +- hw/macio.c | 2 +- hw/openpic.c | 2 +- hw/ppc/Makefile.objs | 9 ++++---- hw/{ppc_mac.h => ppc/mac.h} | 0 hw/{ppc_newworld.c => ppc/mac_newworld.c} | 28 +++++++++++------------ hw/{ppc_oldworld.c => ppc/mac_oldworld.c} | 26 ++++++++++----------- hw/unin_pci.c | 2 +- 13 files changed, 44 insertions(+), 43 deletions(-) rename hw/{ppc_mac.h => ppc/mac.h} (100%) rename hw/{ppc_newworld.c => ppc/mac_newworld.c} (98%) rename hw/{ppc_oldworld.c => ppc/mac_oldworld.c} (97%) diff --git a/MAINTAINERS b/MAINTAINERS index 35c260d549..9dd4c20798 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -380,7 +380,7 @@ New World M: Alexander Graf L: qemu-ppc@nongnu.org S: Maintained -F: hw/ppc_newworld.c +F: hw/ppc/mac_newworld.c F: hw/unin_pci.c F: hw/dec_pci.[hc] @@ -388,7 +388,7 @@ Old World M: Alexander Graf L: qemu-ppc@nongnu.org S: Maintained -F: hw/ppc_oldworld.c +F: hw/ppc/mac_oldworld.c F: hw/grackle_pci.c PReP diff --git a/hw/cuda.c b/hw/cuda.c index d59e0aeaa9..bbd1fdaab8 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "adb.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 948416632a..95639d5735 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -24,7 +24,7 @@ */ #include "pci/pci_host.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" /* debug Grackle */ diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index b9ec8e7b4d..c0a71c3d5f 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" /* debug PIC */ //#define DEBUG_PIC diff --git a/hw/ide/macio.c b/hw/ide/macio.c index d8f9b4bce1..e0f04dc333 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -22,9 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/mac_dbdma.h" #include "block/block.h" #include "sysemu/dma.h" diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 71093c2b10..eec7ca4301 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -25,7 +25,7 @@ #include "hw.h" #include "firmware_abi.h" #include "sysemu/sysemu.h" -#include "ppc_mac.h" +#include "ppc/mac.h" /* debug NVR */ //#define DEBUG_NVR diff --git a/hw/macio.c b/hw/macio.c index 675a71c051..f01fc57619 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" #include "escc.h" diff --git a/hw/openpic.c b/hw/openpic.c index d414f47b7d..25aa9bf45e 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -34,7 +34,7 @@ * */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" #include "openpic.h" #include "sysbus.h" diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index afdcc0e531..462146b0b0 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -3,10 +3,6 @@ obj-y = ppc.o ppc_booke.o # PREP target obj-y += mc146818rtc.o obj-y += ppc_prep.o -# OldWorld PowerMac -obj-y += ppc_oldworld.o -# NewWorld PowerMac -obj-y += ppc_newworld.o # IBM pSeries (sPAPR) obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o @@ -28,4 +24,9 @@ obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) +# OldWorld PowerMac +obj-y += mac_oldworld.o +# NewWorld PowerMac +obj-y += mac_newworld.o +# e500 obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o diff --git a/hw/ppc_mac.h b/hw/ppc/mac.h similarity index 100% rename from hw/ppc_mac.h rename to hw/ppc/mac.h diff --git a/hw/ppc_newworld.c b/hw/ppc/mac_newworld.c similarity index 98% rename from hw/ppc_newworld.c rename to hw/ppc/mac_newworld.c index b1973f18ff..f3c01bfc58 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -46,28 +46,28 @@ * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240] * */ -#include "hw.h" -#include "ppc.h" -#include "ppc_mac.h" -#include "adb.h" -#include "mac_dbdma.h" -#include "nvram.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc/mac.h" +#include "hw/adb.h" +#include "hw/mac_dbdma.h" +#include "hw/nvram.h" +#include "hw/pci/pci.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "fw_cfg.h" -#include "escc.h" -#include "openpic.h" -#include "ide.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/fw_cfg.h" +#include "hw/escc.h" +#include "hw/openpic.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "hw/usb.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 diff --git a/hw/ppc_oldworld.c b/hw/ppc/mac_oldworld.c similarity index 97% rename from hw/ppc_oldworld.c rename to hw/ppc/mac_oldworld.c index de34e7530a..dfbfa546fc 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -23,21 +23,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc_mac.h" -#include "adb.h" -#include "mac_dbdma.h" -#include "nvram.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "mac.h" +#include "hw/adb.h" +#include "hw/mac_dbdma.h" +#include "hw/nvram.h" #include "sysemu/sysemu.h" #include "net/net.h" -#include "isa.h" -#include "pci/pci.h" -#include "boards.h" -#include "fw_cfg.h" -#include "escc.h" -#include "ide.h" -#include "loader.h" +#include "hw/isa.h" +#include "hw/pci/pci.h" +#include "hw/boards.h" +#include "hw/fw_cfg.h" +#include "hw/escc.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 46757924b6..f1c3c20f37 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" #include "pci/pci_host.h" From fcf1bbabf4de3bc125c4dff18ea1cb76d76f042a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:03:55 +0000 Subject: [PATCH 0662/1634] macio: QOM'ify some more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move bar MemoryRegion initialization to an instance_init. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/macio.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/hw/macio.c b/hw/macio.c index f01fc57619..770e3bdb97 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -27,9 +27,15 @@ #include "pci/pci.h" #include "escc.h" +#define TYPE_MACIO "macio" +#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO) + typedef struct MacIOState { + /*< private >*/ PCIDevice parent; + /*< public >*/ + int is_oldworld; MemoryRegion bar; MemoryRegion *pic_mem; @@ -46,7 +52,6 @@ static void macio_bar_setup(MacIOState *macio_state) int i; MemoryRegion *bar = &macio_state->bar; - memory_region_init(bar, "macio", 0x80000); if (macio_state->pic_mem) { if (macio_state->is_oldworld) { /* Heathrow PIC */ @@ -81,6 +86,13 @@ static int macio_initfn(PCIDevice *d) return 0; } +static void macio_instance_init(Object *obj) +{ + MacIOState *s = MACIO(obj); + + memory_region_init(&s->bar, "macio", 0x80000); +} + static void macio_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -90,16 +102,17 @@ static void macio_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_OTHERS << 8; } -static const TypeInfo macio_info = { - .name = "macio", +static const TypeInfo macio_type_info = { + .name = TYPE_MACIO, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MacIOState), + .instance_init = macio_instance_init, .class_init = macio_class_init, }; static void macio_register_types(void) { - type_register_static(&macio_info); + type_register_static(&macio_type_info); } type_init(macio_register_types) @@ -114,9 +127,9 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, MacIOState *macio_state; int i; - d = pci_create_simple(bus, -1, "macio"); + d = pci_create_simple(bus, -1, TYPE_MACIO); - macio_state = DO_UPCAST(MacIOState, parent, d); + macio_state = MACIO(d); macio_state->is_oldworld = is_oldworld; macio_state->pic_mem = pic_mem; macio_state->dbdma_mem = dbdma_mem; From 7b925079e36cf26ca2e1f8db84b771ddc3d6340c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:03:56 +0000 Subject: [PATCH 0663/1634] macio: Delay qdev init until all fields are initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This turns macio_bar_setup() into an implementation detail of the qdev initfn, to be removed step by step. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/macio.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hw/macio.c b/hw/macio.c index 770e3bdb97..8b4b48d135 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -82,7 +82,13 @@ static void macio_bar_setup(MacIOState *macio_state) static int macio_initfn(PCIDevice *d) { + MacIOState *s = MACIO(d); + d->config[0x3d] = 0x01; // interrupt on pin 1 + + macio_bar_setup(s); + pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); + return 0; } @@ -127,7 +133,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, MacIOState *macio_state; int i; - d = pci_create_simple(bus, -1, TYPE_MACIO); + d = pci_create(bus, -1, TYPE_MACIO); macio_state = MACIO(d); macio_state->is_oldworld = is_oldworld; @@ -148,6 +154,5 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, pci_config_set_device_id(d->config, device_id); - macio_bar_setup(macio_state); - pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar); + qdev_init_nofail(DEVICE(d)); } From d037834a9d3847499e8a146bd1893a5c856411be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:03:57 +0000 Subject: [PATCH 0664/1634] macio: Split MacIO in two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let the machines create two different types. This prepares to move knowledge about sub-devices from the machines into the devices. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/macio.c | 97 +++++++++++++++++++++++++++++++------------ hw/ppc/mac.h | 10 +++-- hw/ppc/mac_newworld.c | 4 +- hw/ppc/mac_oldworld.c | 4 +- 4 files changed, 82 insertions(+), 33 deletions(-) diff --git a/hw/macio.c b/hw/macio.c index 8b4b48d135..0e6fc8d5ff 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -36,7 +36,6 @@ typedef struct MacIOState PCIDevice parent; /*< public >*/ - int is_oldworld; MemoryRegion bar; MemoryRegion *pic_mem; MemoryRegion *dbdma_mem; @@ -52,15 +51,6 @@ static void macio_bar_setup(MacIOState *macio_state) int i; MemoryRegion *bar = &macio_state->bar; - if (macio_state->pic_mem) { - if (macio_state->is_oldworld) { - /* Heathrow PIC */ - memory_region_add_subregion(bar, 0x00000, macio_state->pic_mem); - } else { - /* OpenPIC */ - memory_region_add_subregion(bar, 0x40000, macio_state->pic_mem); - } - } if (macio_state->dbdma_mem) { memory_region_add_subregion(bar, 0x08000, macio_state->dbdma_mem); } @@ -80,7 +70,7 @@ static void macio_bar_setup(MacIOState *macio_state) macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000); } -static int macio_initfn(PCIDevice *d) +static int macio_common_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); @@ -92,6 +82,38 @@ static int macio_initfn(PCIDevice *d) return 0; } +static int macio_oldworld_initfn(PCIDevice *d) +{ + MacIOState *s = MACIO(d); + int ret = macio_common_initfn(d); + if (ret < 0) { + return ret; + } + + if (s->pic_mem) { + /* Heathrow PIC */ + memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); + } + + return 0; +} + +static int macio_newworld_initfn(PCIDevice *d) +{ + MacIOState *s = MACIO(d); + int ret = macio_common_initfn(d); + if (ret < 0) { + return ret; + } + + if (s->pic_mem) { + /* OpenPIC */ + memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); + } + + return 0; +} + static void macio_instance_init(Object *obj) { MacIOState *s = MACIO(obj); @@ -99,44 +121,69 @@ static void macio_instance_init(Object *obj) memory_region_init(&s->bar, "macio", 0x80000); } +static void macio_oldworld_class_init(ObjectClass *oc, void *data) +{ + PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); + + pdc->init = macio_oldworld_initfn; + pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201; +} + +static void macio_newworld_class_init(ObjectClass *oc, void *data) +{ + PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); + + pdc->init = macio_newworld_initfn; + pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL; +} + static void macio_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->init = macio_initfn; k->vendor_id = PCI_VENDOR_ID_APPLE; k->class_id = PCI_CLASS_OTHERS << 8; } +static const TypeInfo macio_oldworld_type_info = { + .name = TYPE_OLDWORLD_MACIO, + .parent = TYPE_MACIO, + .class_init = macio_oldworld_class_init, +}; + +static const TypeInfo macio_newworld_type_info = { + .name = TYPE_NEWWORLD_MACIO, + .parent = TYPE_MACIO, + .class_init = macio_newworld_class_init, +}; + static const TypeInfo macio_type_info = { .name = TYPE_MACIO, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MacIOState), .instance_init = macio_instance_init, + .abstract = true, .class_init = macio_class_init, }; static void macio_register_types(void) { type_register_static(&macio_type_info); + type_register_static(&macio_oldworld_type_info); + type_register_static(&macio_newworld_type_info); } type_init(macio_register_types) -void macio_init (PCIBus *bus, int device_id, int is_oldworld, - MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, - MemoryRegion *cuda_mem, void *nvram, - int nb_ide, MemoryRegion **ide_mem, - MemoryRegion *escc_mem) +void macio_init(PCIDevice *d, + MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, + MemoryRegion *cuda_mem, void *nvram, + int nb_ide, MemoryRegion **ide_mem, + MemoryRegion *escc_mem) { - PCIDevice *d; - MacIOState *macio_state; + MacIOState *macio_state = MACIO(d); int i; - d = pci_create(bus, -1, TYPE_MACIO); - - macio_state = MACIO(d); - macio_state->is_oldworld = is_oldworld; macio_state->pic_mem = pic_mem; macio_state->dbdma_mem = dbdma_mem; macio_state->cuda_mem = cuda_mem; @@ -147,12 +194,8 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, macio_state->nb_ide = nb_ide; for (i = 0; i < nb_ide; i++) macio_state->ide_mem[i] = ide_mem[i]; - for (; i < 4; i++) - macio_state->ide_mem[i] = NULL; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ - pci_config_set_device_id(d->config, device_id); - qdev_init_nofail(DEVICE(d)); } diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 89c7d66386..864a610860 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -45,10 +45,12 @@ void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq); /* MacIO */ -void macio_init (PCIBus *bus, int device_id, int is_oldworld, - MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, - MemoryRegion *cuda_mem, void *nvram, - int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem); +#define TYPE_OLDWORLD_MACIO "macio-oldworld" +#define TYPE_NEWWORLD_MACIO "macio-newworld" +void macio_init(PCIDevice *dev, + MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, + MemoryRegion *cuda_mem, void *nvram, + int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem); /* Heathrow PIC */ qemu_irq *heathrow_pic_init(MemoryRegion **pmem, diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index f3c01bfc58..a62a6e9a3c 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -147,6 +147,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) hwaddr kernel_base, initrd_base, cmdline_base = 0; long kernel_size, initrd_size; PCIBus *pci_bus; + PCIDevice *macio; MacIONVRAMState *nvr; int bios_size; MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem, *escc_mem; @@ -374,7 +375,8 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem, + macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO); + macio_init(macio, pic_mem, dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar); if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index dfbfa546fc..2801992b9f 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -90,6 +90,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) uint32_t kernel_base, initrd_base, cmdline_base = 0; int32_t kernel_size, initrd_size; PCIBus *pci_bus; + PCIDevice *macio; MacIONVRAMState *nvr; int bios_size; MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem; @@ -283,7 +284,8 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) nvr = macio_nvram_init(0x2000, 4); pmac_format_nvram_partition(nvr, 0x2000); - macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem, + macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); + macio_init(macio, pic_mem, dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar); if (usb_enabled(false)) { From 3743cca7d55c700e727e958d4a0b0b5d6c15e2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:03:58 +0000 Subject: [PATCH 0665/1634] mac_nvram: Clean up public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The state data field is accessed in uint8_t quantities, so switch from uint32_t argument and return value to uint8_t. Fix debug format specifiers while at it. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/mac_nvram.c | 21 ++++++++++----------- hw/ppc/mac.h | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index eec7ca4301..bcde07d061 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -47,27 +47,26 @@ struct MacIONVRAMState { #define DEF_SYSTEM_SIZE 0xc10 /* Direct access to NVRAM */ -uint32_t macio_nvram_read (void *opaque, uint32_t addr) +uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr) { - MacIONVRAMState *s = opaque; uint32_t ret; - if (addr < s->size) + if (addr < s->size) { ret = s->data[addr]; - else + } else { ret = -1; - NVR_DPRINTF("read addr %04x val %x\n", addr, ret); + } + NVR_DPRINTF("read addr %04" PRIx32 " val %" PRIx8 "\n", addr, ret); return ret; } -void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val) +void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val) { - MacIONVRAMState *s = opaque; - - NVR_DPRINTF("write addr %04x val %x\n", addr, val); - if (addr < s->size) + NVR_DPRINTF("write addr %04" PRIx32 " val %" PRIx8 "\n", addr, val); + if (addr < s->size) { s->data[addr] = val; + } } /* macio style NVRAM device */ @@ -78,7 +77,7 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr, addr = (addr >> s->it_shift) & (s->size - 1); s->data[addr] = value; - NVR_DPRINTF("writeb addr %04x val %x\n", (int)addr, value); + NVR_DPRINTF("writeb addr %04" PHYS_PRIx " val %" PRIx64 "\n", addr, value); } static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 864a610860..6441794600 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -78,6 +78,6 @@ MacIONVRAMState *macio_nvram_init (hwaddr size, void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar, hwaddr mem_base); void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); -uint32_t macio_nvram_read (void *opaque, uint32_t addr); -void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val); +uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr); +void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val); #endif /* !defined(__PPC_MAC_H__) */ From d8c6d07fdff2523ca78f95c7d8a7fe90ee7ea5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:03:59 +0000 Subject: [PATCH 0666/1634] mac_nvram: Mark as Big Endian 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/mac_nvram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index bcde07d061..0a22e66052 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -96,7 +96,7 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, static const MemoryRegionOps macio_nvram_ops = { .read = macio_nvram_readb, .write = macio_nvram_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_BIG_ENDIAN, }; static const VMStateDescription vmstate_macio_nvram = { From 95ed3b7cf1677dc9f995a6e1fcc7bf377cf94a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:04:00 +0000 Subject: [PATCH 0667/1634] mac_nvram: QOM'ify MacIO NVRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was not qdev'ified before. Turn it into a SysBusDevice and initialize it via static properties. Prepare Old World specific MacIO state and embed the NVRAM state there. Drop macio_nvram_setup_bar() in favor of sysbus_mmio_map() or direct use of Memory API. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/mac_nvram.c | 65 ++++++++++++++++++++++++++++--------------- hw/macio.c | 41 +++++++++++++++++++++++---- hw/ppc/mac.h | 23 +++++++++++---- hw/ppc/mac_newworld.c | 10 +++++-- hw/ppc/mac_oldworld.c | 6 +--- 5 files changed, 103 insertions(+), 42 deletions(-) diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 0a22e66052..25121fa482 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -37,13 +37,6 @@ #define NVR_DPRINTF(fmt, ...) #endif -struct MacIONVRAMState { - uint32_t size; - MemoryRegion mem; - unsigned int it_shift; - uint8_t *data; -}; - #define DEF_SYSTEM_SIZE 0xc10 /* Direct access to NVRAM */ @@ -111,32 +104,56 @@ static const VMStateDescription vmstate_macio_nvram = { }; -static void macio_nvram_reset(void *opaque) +static void macio_nvram_reset(DeviceState *dev) { } -MacIONVRAMState *macio_nvram_init (hwaddr size, - unsigned int it_shift) +static void macio_nvram_realizefn(DeviceState *dev, Error **errp) { - MacIONVRAMState *s; + SysBusDevice *d = SYS_BUS_DEVICE(dev); + MacIONVRAMState *s = MACIO_NVRAM(dev); - s = g_malloc0(sizeof(MacIONVRAMState)); - s->data = g_malloc0(size); - s->size = size; - s->it_shift = it_shift; + s->data = g_malloc0(s->size); memory_region_init_io(&s->mem, &macio_nvram_ops, s, "macio-nvram", - size << it_shift); - vmstate_register(NULL, -1, &vmstate_macio_nvram, s); - qemu_register_reset(macio_nvram_reset, s); - - return s; + s->size << s->it_shift); + sysbus_init_mmio(d, &s->mem); } -void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar, - hwaddr mem_base) +static void macio_nvram_unrealizefn(DeviceState *dev, Error **errp) { - memory_region_add_subregion(bar, mem_base, &s->mem); + MacIONVRAMState *s = MACIO_NVRAM(dev); + + g_free(s->data); +} + +static Property macio_nvram_properties[] = { + DEFINE_PROP_UINT32("size", MacIONVRAMState, size, 0), + DEFINE_PROP_UINT32("it_shift", MacIONVRAMState, it_shift, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void macio_nvram_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = macio_nvram_realizefn; + dc->unrealize = macio_nvram_unrealizefn; + dc->reset = macio_nvram_reset; + dc->vmsd = &vmstate_macio_nvram; + dc->props = macio_nvram_properties; +} + +static const TypeInfo macio_nvram_type_info = { + .name = TYPE_MACIO_NVRAM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MacIONVRAMState), + .class_init = macio_nvram_class_init, +}; + +static void macio_nvram_register_types(void) +{ + type_register_static(&macio_nvram_type_info); } /* Set up a system OpenBIOS NVRAM partition */ @@ -175,3 +192,5 @@ void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len) end = len; OpenBIOS_finish_partition(part_header, end - start); } + +type_init(macio_nvram_register_types) diff --git a/hw/macio.c b/hw/macio.c index 0e6fc8d5ff..32f359cc7e 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -41,11 +41,21 @@ typedef struct MacIOState MemoryRegion *dbdma_mem; MemoryRegion *cuda_mem; MemoryRegion *escc_mem; - void *nvram; int nb_ide; MemoryRegion *ide_mem[4]; } MacIOState; +#define OLDWORLD_MACIO(obj) \ + OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO) + +typedef struct OldWorldMacIOState { + /*< private >*/ + MacIOState parent_obj; + /*< public >*/ + + MacIONVRAMState nvram; +} OldWorldMacIOState; + static void macio_bar_setup(MacIOState *macio_state) { int i; @@ -66,8 +76,6 @@ static void macio_bar_setup(MacIOState *macio_state) macio_state->ide_mem[i]); } } - if (macio_state->nvram != NULL) - macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000); } static int macio_common_initfn(PCIDevice *d) @@ -85,11 +93,22 @@ static int macio_common_initfn(PCIDevice *d) static int macio_oldworld_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); + OldWorldMacIOState *os = OLDWORLD_MACIO(d); + SysBusDevice *sysbus_dev; int ret = macio_common_initfn(d); if (ret < 0) { return ret; } + ret = qdev_init(DEVICE(&os->nvram)); + if (ret < 0) { + return ret; + } + sysbus_dev = SYS_BUS_DEVICE(&os->nvram); + memory_region_add_subregion(&s->bar, 0x60000, + sysbus_mmio_get_region(sysbus_dev, 0)); + pmac_format_nvram_partition(&os->nvram, os->nvram.size); + if (s->pic_mem) { /* Heathrow PIC */ memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); @@ -98,6 +117,17 @@ static int macio_oldworld_initfn(PCIDevice *d) return 0; } +static void macio_oldworld_init(Object *obj) +{ + OldWorldMacIOState *os = OLDWORLD_MACIO(obj); + DeviceState *dev; + + object_initialize(&os->nvram, TYPE_MACIO_NVRAM); + dev = DEVICE(&os->nvram); + qdev_prop_set_uint32(dev, "size", 0x2000); + qdev_prop_set_uint32(dev, "it_shift", 4); +} + static int macio_newworld_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); @@ -148,6 +178,8 @@ static void macio_class_init(ObjectClass *klass, void *data) static const TypeInfo macio_oldworld_type_info = { .name = TYPE_OLDWORLD_MACIO, .parent = TYPE_MACIO, + .instance_size = sizeof(OldWorldMacIOState), + .instance_init = macio_oldworld_init, .class_init = macio_oldworld_class_init, }; @@ -177,7 +209,7 @@ type_init(macio_register_types) void macio_init(PCIDevice *d, MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, - MemoryRegion *cuda_mem, void *nvram, + MemoryRegion *cuda_mem, int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem) { @@ -188,7 +220,6 @@ void macio_init(PCIDevice *d, macio_state->dbdma_mem = dbdma_mem; macio_state->cuda_mem = cuda_mem; macio_state->escc_mem = escc_mem; - macio_state->nvram = nvram; if (nb_ide > 4) nb_ide = 4; macio_state->nb_ide = nb_ide; diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 6441794600..581e95cf7c 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -26,6 +26,7 @@ #define __PPC_MAC_H__ #include "exec/memory.h" +#include "hw/sysbus.h" /* SMP is not enabled, for now */ #define MAX_CPUS 1 @@ -49,7 +50,7 @@ void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq); #define TYPE_NEWWORLD_MACIO "macio-newworld" void macio_init(PCIDevice *dev, MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, - MemoryRegion *cuda_mem, void *nvram, + MemoryRegion *cuda_mem, int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem); /* Heathrow PIC */ @@ -71,12 +72,22 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, MemoryRegion *address_space_io); /* Mac NVRAM */ -typedef struct MacIONVRAMState MacIONVRAMState; +#define TYPE_MACIO_NVRAM "macio-nvram" +#define MACIO_NVRAM(obj) \ + OBJECT_CHECK(MacIONVRAMState, (obj), TYPE_MACIO_NVRAM) + +typedef struct MacIONVRAMState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + uint32_t size; + uint32_t it_shift; + + MemoryRegion mem; + uint8_t *data; +} MacIONVRAMState; -MacIONVRAMState *macio_nvram_init (hwaddr size, - unsigned int it_shift); -void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar, - hwaddr mem_base); void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr); void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index a62a6e9a3c..a4b38fba1e 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -377,7 +377,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO); macio_init(macio, pic_mem, - dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar); + dbdma_mem, cuda_mem, 3, ide_mem, escc_bar); if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { pci_create_simple(pci_bus, -1, "pci-ohci"); @@ -393,9 +393,13 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) graphic_depth = 15; /* The NewWorld NVRAM is not located in the MacIO device */ - nvr = macio_nvram_init(0x2000, 1); + dev = qdev_create(NULL, TYPE_MACIO_NVRAM); + qdev_prop_set_uint32(dev, "size", 0x2000); + qdev_prop_set_uint32(dev, "it_shift", 1); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xFFF04000); + nvr = MACIO_NVRAM(dev); pmac_format_nvram_partition(nvr, 0x2000); - macio_nvram_setup_bar(nvr, get_system_memory(), 0xFFF04000); /* No PCI init: the BIOS will do it */ fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 2801992b9f..29b3277df7 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -91,7 +91,6 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) int32_t kernel_size, initrd_size; PCIBus *pci_bus; PCIDevice *macio; - MacIONVRAMState *nvr; int bios_size; MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem; MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1), *ide_mem[2]; @@ -281,12 +280,9 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - nvr = macio_nvram_init(0x2000, 4); - pmac_format_nvram_partition(nvr, 0x2000); - macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); macio_init(macio, pic_mem, - dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar); + dbdma_mem, cuda_mem, 2, ide_mem, escc_bar); if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); From 07a7484e5d713f1eb7c1c37b18a8ab0d56d88875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:04:01 +0000 Subject: [PATCH 0668/1634] ide/macio: QOM'ify MacIO IDE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was not qdev'ified before. Turn it into a SysBusDevice. Embed them into the MacIO devices. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ide.h | 4 -- hw/ide/macio.c | 84 +++++++++++++++++++++++----------- hw/macio.c | 102 +++++++++++++++++++++++++++++++++--------- hw/ppc/mac.h | 25 ++++++++++- hw/ppc/mac_newworld.c | 28 +++++++----- hw/ppc/mac_oldworld.c | 36 ++++++++------- 6 files changed, 198 insertions(+), 81 deletions(-) diff --git a/hw/ide.h b/hw/ide.h index 7e23cda8e0..9b357c05a5 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -19,10 +19,6 @@ PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); -/* ide-macio.c */ -MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq, - void *dbdma, int channel, qemu_irq dma_irq); - /* ide-mmio.c */ void mmio_ide_init (hwaddr membase, hwaddr membase2, MemoryRegion *address_space, diff --git a/hw/ide/macio.c b/hw/ide/macio.c index e0f04dc333..375c46f9da 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -33,12 +33,6 @@ /***********************************************************/ /* MacIO based PowerPC IDE */ -typedef struct MACIOIDEState { - MemoryRegion mem; - IDEBus bus; - BlockDriverAIOCB *aiocb; -} MACIOIDEState; - #define MACIO_PAGE_SIZE 4096 static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) @@ -321,30 +315,70 @@ static const VMStateDescription vmstate_pmac = { } }; -static void pmac_ide_reset(void *opaque) +static void macio_ide_reset(DeviceState *dev) { - MACIOIDEState *d = opaque; + MACIOIDEState *d = MACIO_IDE(dev); ide_bus_reset(&d->bus); } -/* hd_table must contain 4 block drivers */ -/* PowerMac uses memory mapped registers, not I/O. Return the memory - I/O index to access the ide. */ -MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq, - void *dbdma, int channel, qemu_irq dma_irq) +static void macio_ide_realizefn(DeviceState *dev, Error **errp) { - MACIOIDEState *d; + MACIOIDEState *s = MACIO_IDE(dev); - d = g_malloc0(sizeof(MACIOIDEState)); - ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq); - - if (dbdma) - DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d); - - memory_region_init_io(&d->mem, &pmac_ide_ops, d, "pmac-ide", 0x1000); - vmstate_register(NULL, 0, &vmstate_pmac, d); - qemu_register_reset(pmac_ide_reset, d); - - return &d->mem; + ide_init2(&s->bus, s->irq); } + +static void macio_ide_initfn(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + MACIOIDEState *s = MACIO_IDE(obj); + + ide_bus_new(&s->bus, DEVICE(obj), 0); + memory_region_init_io(&s->mem, &pmac_ide_ops, s, "pmac-ide", 0x1000); + sysbus_init_mmio(d, &s->mem); + sysbus_init_irq(d, &s->irq); + sysbus_init_irq(d, &s->dma_irq); +} + +static void macio_ide_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = macio_ide_realizefn; + dc->reset = macio_ide_reset; + dc->vmsd = &vmstate_pmac; +} + +static const TypeInfo macio_ide_type_info = { + .name = TYPE_MACIO_IDE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MACIOIDEState), + .instance_init = macio_ide_initfn, + .class_init = macio_ide_class_init, +}; + +static void macio_ide_register_types(void) +{ + type_register_static(&macio_ide_type_info); +} + +/* hd_table must contain 4 block drivers */ +void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) +{ + int i; + + for (i = 0; i < 2; i++) { + if (hd_table[i]) { + ide_create_drive(&s->bus, i, hd_table[i]); + } + } +} + +void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel) +{ + DBDMA_register_channel(dbdma, channel, s->dma_irq, + pmac_ide_transfer, pmac_ide_flush, s); +} + +type_init(macio_ide_register_types) diff --git a/hw/macio.c b/hw/macio.c index 32f359cc7e..36c00e33a1 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -25,6 +25,7 @@ #include "hw.h" #include "ppc/mac.h" #include "pci/pci.h" +#include "mac_dbdma.h" #include "escc.h" #define TYPE_MACIO "macio" @@ -37,12 +38,10 @@ typedef struct MacIOState /*< public >*/ MemoryRegion bar; + void *dbdma; MemoryRegion *pic_mem; - MemoryRegion *dbdma_mem; MemoryRegion *cuda_mem; MemoryRegion *escc_mem; - int nb_ide; - MemoryRegion *ide_mem[4]; } MacIOState; #define OLDWORLD_MACIO(obj) \ @@ -53,29 +52,33 @@ typedef struct OldWorldMacIOState { MacIOState parent_obj; /*< public >*/ + qemu_irq irqs[2]; + MacIONVRAMState nvram; + MACIOIDEState ide; } OldWorldMacIOState; +#define NEWWORLD_MACIO(obj) \ + OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO) + +typedef struct NewWorldMacIOState { + /*< private >*/ + MacIOState parent_obj; + /*< public >*/ + qemu_irq irqs[4]; + MACIOIDEState ide[2]; +} NewWorldMacIOState; + static void macio_bar_setup(MacIOState *macio_state) { - int i; MemoryRegion *bar = &macio_state->bar; - if (macio_state->dbdma_mem) { - memory_region_add_subregion(bar, 0x08000, macio_state->dbdma_mem); - } if (macio_state->escc_mem) { memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem); } if (macio_state->cuda_mem) { memory_region_add_subregion(bar, 0x16000, macio_state->cuda_mem); } - for (i = 0; i < macio_state->nb_ide; i++) { - if (macio_state->ide_mem[i]) { - memory_region_add_subregion(bar, 0x1f000 + (i * 0x1000), - macio_state->ide_mem[i]); - } - } } static int macio_common_initfn(PCIDevice *d) @@ -114,23 +117,42 @@ static int macio_oldworld_initfn(PCIDevice *d) memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); } + sysbus_dev = SYS_BUS_DEVICE(&os->ide); + sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]); + sysbus_connect_irq(sysbus_dev, 1, os->irqs[1]); + macio_ide_register_dma(&os->ide, s->dbdma, 0x16); + ret = qdev_init(DEVICE(&os->ide)); + if (ret < 0) { + return ret; + } + return 0; } static void macio_oldworld_init(Object *obj) { + MacIOState *s = MACIO(obj); OldWorldMacIOState *os = OLDWORLD_MACIO(obj); DeviceState *dev; + qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs)); + object_initialize(&os->nvram, TYPE_MACIO_NVRAM); dev = DEVICE(&os->nvram); qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "it_shift", 4); + + object_initialize(&os->ide, TYPE_MACIO_IDE); + qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default()); + memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem); + object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL); } static int macio_newworld_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); + NewWorldMacIOState *ns = NEWWORLD_MACIO(d); + SysBusDevice *sysbus_dev; int ret = macio_common_initfn(d); if (ret < 0) { return ret; @@ -141,14 +163,56 @@ static int macio_newworld_initfn(PCIDevice *d) memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); } + sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]); + sysbus_connect_irq(sysbus_dev, 1, ns->irqs[1]); + macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16); + ret = qdev_init(DEVICE(&ns->ide[0])); + if (ret < 0) { + return ret; + } + + sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[2]); + sysbus_connect_irq(sysbus_dev, 1, ns->irqs[3]); + macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x1a); + ret = qdev_init(DEVICE(&ns->ide[1])); + if (ret < 0) { + return ret; + } + return 0; } +static void macio_newworld_init(Object *obj) +{ + MacIOState *s = MACIO(obj); + NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); + int i; + gchar *name; + + qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); + + for (i = 0; i < 2; i++) { + object_initialize(&ns->ide[i], TYPE_MACIO_IDE); + qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default()); + memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000), + &ns->ide[i].mem); + name = g_strdup_printf("ide[%i]", i); + object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL); + g_free(name); + } +} + static void macio_instance_init(Object *obj) { MacIOState *s = MACIO(obj); + MemoryRegion *dbdma_mem; memory_region_init(&s->bar, "macio", 0x80000); + + s->dbdma = DBDMA_init(&dbdma_mem); + memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem); } static void macio_oldworld_class_init(ObjectClass *oc, void *data) @@ -186,6 +250,8 @@ static const TypeInfo macio_oldworld_type_info = { static const TypeInfo macio_newworld_type_info = { .name = TYPE_NEWWORLD_MACIO, .parent = TYPE_MACIO, + .instance_size = sizeof(NewWorldMacIOState), + .instance_init = macio_newworld_init, .class_init = macio_newworld_class_init, }; @@ -208,23 +274,15 @@ static void macio_register_types(void) type_init(macio_register_types) void macio_init(PCIDevice *d, - MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, + MemoryRegion *pic_mem, MemoryRegion *cuda_mem, - int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem) { MacIOState *macio_state = MACIO(d); - int i; macio_state->pic_mem = pic_mem; - macio_state->dbdma_mem = dbdma_mem; macio_state->cuda_mem = cuda_mem; macio_state->escc_mem = escc_mem; - if (nb_ide > 4) - nb_ide = 4; - macio_state->nb_ide = nb_ide; - for (i = 0; i < nb_ide; i++) - macio_state->ide_mem[i] = ide_mem[i]; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 581e95cf7c..3e390d3ee9 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -27,6 +27,7 @@ #include "exec/memory.h" #include "hw/sysbus.h" +#include "hw/ide/internal.h" /* SMP is not enabled, for now */ #define MAX_CPUS 1 @@ -48,10 +49,30 @@ void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq); /* MacIO */ #define TYPE_OLDWORLD_MACIO "macio-oldworld" #define TYPE_NEWWORLD_MACIO "macio-newworld" + +#define TYPE_MACIO_IDE "macio-ide" +#define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE) + +typedef struct MACIOIDEState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + qemu_irq irq; + qemu_irq dma_irq; + + MemoryRegion mem; + IDEBus bus; + BlockDriverAIOCB *aiocb; +} MACIOIDEState; + +void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table); +void macio_ide_register_dma(MACIOIDEState *ide, void *dbdma, int channel); + void macio_init(PCIDevice *dev, - MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, + MemoryRegion *pic_mem, MemoryRegion *cuda_mem, - int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem); + MemoryRegion *escc_mem); /* Heathrow PIC */ qemu_irq *heathrow_pic_init(MemoryRegion **pmem, diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index a4b38fba1e..4fd86b042a 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -148,15 +148,14 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) long kernel_size, initrd_size; PCIBus *pci_bus; PCIDevice *macio; + MACIOIDEState *macio_ide; MacIONVRAMState *nvr; int bios_size; - MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem, *escc_mem; + MemoryRegion *pic_mem, *cuda_mem, *escc_mem; MemoryRegion *escc_bar = g_new(MemoryRegion, 1); - MemoryRegion *ide_mem[3]; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; - void *dbdma; int machine_arch; SysBusDevice *s; DeviceState *dev; @@ -363,12 +362,6 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); ide_drive_get(hd, MAX_IDE_BUS); - dbdma = DBDMA_init(&dbdma_mem); - - /* We only emulate 2 out of 3 IDE controllers for now */ - ide_mem[0] = NULL; - ide_mem[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]); - ide_mem[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]); cuda_init(&cuda_mem, pic[0x19]); @@ -376,8 +369,21 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) adb_mouse_init(&adb_bus); macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO); - macio_init(macio, pic_mem, - dbdma_mem, cuda_mem, 3, ide_mem, escc_bar); + dev = DEVICE(macio); + qdev_connect_gpio_out(dev, 0, pic[0x0d]); /* IDE */ + qdev_connect_gpio_out(dev, 1, pic[0x02]); /* IDE DMA */ + qdev_connect_gpio_out(dev, 2, pic[0x0e]); /* IDE */ + qdev_connect_gpio_out(dev, 3, pic[0x02]); /* IDE DMA */ + macio_init(macio, pic_mem, cuda_mem, escc_bar); + + /* We only emulate 2 out of 3 IDE controllers for now */ + macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), + "ide[0]")); + macio_ide_init_drives(macio_ide, hd); + + macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), + "ide[1]")); + macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { pci_create_simple(pci_bus, -1, "pci-ohci"); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 29b3277df7..6039ea61f4 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -27,7 +27,6 @@ #include "hw/ppc.h" #include "mac.h" #include "hw/adb.h" -#include "hw/mac_dbdma.h" #include "hw/nvram.h" #include "sysemu/sysemu.h" #include "net/net.h" @@ -91,13 +90,14 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) int32_t kernel_size, initrd_size; PCIBus *pci_bus; PCIDevice *macio; + MACIOIDEState *macio_ide; + DeviceState *dev; int bios_size; - MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem; - MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1), *ide_mem[2]; + MemoryRegion *pic_mem, *cuda_mem; + MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1); uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; - void *dbdma; linux_boot = (kernel_filename != NULL); @@ -263,17 +263,6 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) ide_drive_get(hd, MAX_IDE_BUS); - /* First IDE channel is a MAC IDE on the MacIO bus */ - dbdma = DBDMA_init(&dbdma_mem); - ide_mem[0] = NULL; - ide_mem[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]); - - /* Second IDE channel is a CMD646 on the PCI bus */ - hd[0] = hd[MAX_IDE_DEVS]; - hd[1] = hd[MAX_IDE_DEVS + 1]; - hd[3] = hd[2] = NULL; - pci_cmd646_ide_init(pci_bus, hd, 0); - /* cuda also initialize ADB */ cuda_init(&cuda_mem, pic[0x12]); @@ -281,8 +270,21 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) adb_mouse_init(&adb_bus); macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); - macio_init(macio, pic_mem, - dbdma_mem, cuda_mem, 2, ide_mem, escc_bar); + dev = DEVICE(macio); + qdev_connect_gpio_out(dev, 0, pic[0x0D]); /* IDE */ + qdev_connect_gpio_out(dev, 1, pic[0x02]); /* IDE DMA */ + macio_init(macio, pic_mem, cuda_mem, escc_bar); + + /* First IDE channel is a MAC IDE on the MacIO bus */ + macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), + "ide")); + macio_ide_init_drives(macio_ide, hd); + + /* Second IDE channel is a CMD646 on the PCI bus */ + hd[0] = hd[MAX_IDE_DEVS]; + hd[1] = hd[MAX_IDE_DEVS + 1]; + hd[3] = hd[2] = NULL; + pci_cmd646_ide_init(pci_bus, hd, 0); if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); From 45fa67fb68e73b395cd93ec97e45785944d4ee6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:04:02 +0000 Subject: [PATCH 0669/1634] cuda: QOM'ify CUDA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was not qdev'ified before. Turn it into a SysBusDevice and embed it in MacIO. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/cuda.c | 99 +++++++++++++++++++------------------------ hw/macio.c | 43 +++++++++++++------ hw/ppc/mac.h | 68 ++++++++++++++++++++++++++++- hw/ppc/mac_newworld.c | 21 +++++---- hw/ppc/mac_oldworld.c | 18 ++++---- 5 files changed, 156 insertions(+), 93 deletions(-) diff --git a/hw/cuda.c b/hw/cuda.c index bbd1fdaab8..f863c38a89 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -108,48 +108,6 @@ /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ #define RTC_OFFSET 2082844800 -typedef struct CUDATimer { - int index; - uint16_t latch; - uint16_t counter_value; /* counter value at load time */ - int64_t load_time; - int64_t next_irq_time; - QEMUTimer *timer; -} CUDATimer; - -typedef struct CUDAState { - MemoryRegion mem; - /* cuda registers */ - uint8_t b; /* B-side data */ - uint8_t a; /* A-side data */ - uint8_t dirb; /* B-side direction (1=output) */ - uint8_t dira; /* A-side direction (1=output) */ - uint8_t sr; /* Shift register */ - uint8_t acr; /* Auxiliary control register */ - uint8_t pcr; /* Peripheral control register */ - uint8_t ifr; /* Interrupt flag register */ - uint8_t ier; /* Interrupt enable register */ - uint8_t anh; /* A-side data, no handshake */ - - CUDATimer timers[2]; - - uint32_t tick_offset; - - uint8_t last_b; /* last value of B register */ - uint8_t last_acr; /* last value of B register */ - - int data_in_size; - int data_in_index; - int data_out_index; - - qemu_irq irq; - uint8_t autopoll; - uint8_t data_in[128]; - uint8_t data_out[16]; - QEMUTimer *adb_poll_timer; -} CUDAState; - -static CUDAState cuda_state; ADBBusState adb_bus; static void cuda_update(CUDAState *s); @@ -701,9 +659,9 @@ static const VMStateDescription vmstate_cuda = { } }; -static void cuda_reset(void *opaque) +static void cuda_reset(DeviceState *dev) { - CUDAState *s = opaque; + CUDAState *s = CUDA(dev); s->b = 0; s->a = 0; @@ -728,25 +686,54 @@ static void cuda_reset(void *opaque) set_counter(s, &s->timers[1], 0xffff); } -void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq) +static void cuda_realizefn(DeviceState *dev, Error **errp) { + CUDAState *s = CUDA(dev); struct tm tm; - CUDAState *s = &cuda_state; - s->irq = irq; - - s->timers[0].index = 0; s->timers[0].timer = qemu_new_timer_ns(vm_clock, cuda_timer1, s); - s->timers[1].index = 1; - qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s); - memory_region_init_io(&s->mem, &cuda_ops, s, "cuda", 0x2000); - - *cuda_mem = &s->mem; - vmstate_register(NULL, -1, &vmstate_cuda, s); - qemu_register_reset(cuda_reset, s); } + +static void cuda_initfn(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + CUDAState *s = CUDA(obj); + int i; + + memory_region_init_io(&s->mem, &cuda_ops, s, "cuda", 0x2000); + sysbus_init_mmio(d, &s->mem); + sysbus_init_irq(d, &s->irq); + + for (i = 0; i < ARRAY_SIZE(s->timers); i++) { + s->timers[i].index = i; + } +} + +static void cuda_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = cuda_realizefn; + dc->reset = cuda_reset; + dc->vmsd = &vmstate_cuda; +} + +static const TypeInfo cuda_type_info = { + .name = TYPE_CUDA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(CUDAState), + .instance_init = cuda_initfn, + .class_init = cuda_class_init, +}; + +static void cuda_register_types(void) +{ + type_register_static(&cuda_type_info); +} + +type_init(cuda_register_types) diff --git a/hw/macio.c b/hw/macio.c index 36c00e33a1..74bdcd1039 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -38,9 +38,9 @@ typedef struct MacIOState /*< public >*/ MemoryRegion bar; + CUDAState cuda; void *dbdma; MemoryRegion *pic_mem; - MemoryRegion *cuda_mem; MemoryRegion *escc_mem; } MacIOState; @@ -52,7 +52,7 @@ typedef struct OldWorldMacIOState { MacIOState parent_obj; /*< public >*/ - qemu_irq irqs[2]; + qemu_irq irqs[3]; MacIONVRAMState nvram; MACIOIDEState ide; @@ -65,7 +65,7 @@ typedef struct NewWorldMacIOState { /*< private >*/ MacIOState parent_obj; /*< public >*/ - qemu_irq irqs[4]; + qemu_irq irqs[5]; MACIOIDEState ide[2]; } NewWorldMacIOState; @@ -76,17 +76,24 @@ static void macio_bar_setup(MacIOState *macio_state) if (macio_state->escc_mem) { memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem); } - if (macio_state->cuda_mem) { - memory_region_add_subregion(bar, 0x16000, macio_state->cuda_mem); - } } static int macio_common_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); + SysBusDevice *sysbus_dev; + int ret; d->config[0x3d] = 0x01; // interrupt on pin 1 + ret = qdev_init(DEVICE(&s->cuda)); + if (ret < 0) { + return ret; + } + sysbus_dev = SYS_BUS_DEVICE(&s->cuda); + memory_region_add_subregion(&s->bar, 0x16000, + sysbus_mmio_get_region(sysbus_dev, 0)); + macio_bar_setup(s); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); @@ -103,6 +110,9 @@ static int macio_oldworld_initfn(PCIDevice *d) return ret; } + sysbus_dev = SYS_BUS_DEVICE(&s->cuda); + sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]); + ret = qdev_init(DEVICE(&os->nvram)); if (ret < 0) { return ret; @@ -118,8 +128,8 @@ static int macio_oldworld_initfn(PCIDevice *d) } sysbus_dev = SYS_BUS_DEVICE(&os->ide); - sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]); - sysbus_connect_irq(sysbus_dev, 1, os->irqs[1]); + sysbus_connect_irq(sysbus_dev, 0, os->irqs[1]); + sysbus_connect_irq(sysbus_dev, 1, os->irqs[2]); macio_ide_register_dma(&os->ide, s->dbdma, 0x16); ret = qdev_init(DEVICE(&os->ide)); if (ret < 0) { @@ -158,14 +168,17 @@ static int macio_newworld_initfn(PCIDevice *d) return ret; } + sysbus_dev = SYS_BUS_DEVICE(&s->cuda); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]); + if (s->pic_mem) { /* OpenPIC */ memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); } sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]); - sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]); - sysbus_connect_irq(sysbus_dev, 1, ns->irqs[1]); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]); + sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]); macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16); ret = qdev_init(DEVICE(&ns->ide[0])); if (ret < 0) { @@ -173,8 +186,8 @@ static int macio_newworld_initfn(PCIDevice *d) } sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]); - sysbus_connect_irq(sysbus_dev, 0, ns->irqs[2]); - sysbus_connect_irq(sysbus_dev, 1, ns->irqs[3]); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]); + sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]); macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x1a); ret = qdev_init(DEVICE(&ns->ide[1])); if (ret < 0) { @@ -211,6 +224,10 @@ static void macio_instance_init(Object *obj) memory_region_init(&s->bar, "macio", 0x80000); + object_initialize(&s->cuda, TYPE_CUDA); + qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default()); + object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL); + s->dbdma = DBDMA_init(&dbdma_mem); memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem); } @@ -275,13 +292,11 @@ type_init(macio_register_types) void macio_init(PCIDevice *d, MemoryRegion *pic_mem, - MemoryRegion *cuda_mem, MemoryRegion *escc_mem) { MacIOState *macio_state = MACIO(d); macio_state->pic_mem = pic_mem; - macio_state->cuda_mem = cuda_mem; macio_state->escc_mem = escc_mem; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 3e390d3ee9..26cb497b2d 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -44,7 +44,72 @@ #define ESCC_CLOCK 3686400 /* Cuda */ -void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq); +#define TYPE_CUDA "cuda" +#define CUDA(obj) OBJECT_CHECK(CUDAState, (obj), TYPE_CUDA) + +/** + * CUDATimer: + * @counter_value: counter value at load time + */ +typedef struct CUDATimer { + int index; + uint16_t latch; + uint16_t counter_value; + int64_t load_time; + int64_t next_irq_time; + QEMUTimer *timer; +} CUDATimer; + +/** + * CUDAState: + * @b: B-side data + * @a: A-side data + * @dirb: B-side direction (1=output) + * @dira: A-side direction (1=output) + * @sr: Shift register + * @acr: Auxiliary control register + * @pcr: Peripheral control register + * @ifr: Interrupt flag register + * @ier: Interrupt enable register + * @anh: A-side data, no handshake + * @last_b: last value of B register + * @last_acr: last value of ACR register + */ +typedef struct CUDAState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion mem; + /* cuda registers */ + uint8_t b; + uint8_t a; + uint8_t dirb; + uint8_t dira; + uint8_t sr; + uint8_t acr; + uint8_t pcr; + uint8_t ifr; + uint8_t ier; + uint8_t anh; + + CUDATimer timers[2]; + + uint32_t tick_offset; + + uint8_t last_b; + uint8_t last_acr; + + int data_in_size; + int data_in_index; + int data_out_index; + + qemu_irq irq; + uint8_t autopoll; + uint8_t data_in[128]; + uint8_t data_out[16]; + QEMUTimer *adb_poll_timer; +} CUDAState; /* MacIO */ #define TYPE_OLDWORLD_MACIO "macio-oldworld" @@ -71,7 +136,6 @@ void macio_ide_register_dma(MACIOIDEState *ide, void *dbdma, int channel); void macio_init(PCIDevice *dev, MemoryRegion *pic_mem, - MemoryRegion *cuda_mem, MemoryRegion *escc_mem); /* Heathrow PIC */ diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 4fd86b042a..b9c58c188d 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -151,7 +151,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) MACIOIDEState *macio_ide; MacIONVRAMState *nvr; int bios_size; - MemoryRegion *pic_mem, *cuda_mem, *escc_mem; + MemoryRegion *pic_mem, *escc_mem; MemoryRegion *escc_bar = g_new(MemoryRegion, 1); int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; @@ -363,18 +363,14 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) ide_drive_get(hd, MAX_IDE_BUS); - cuda_init(&cuda_mem, pic[0x19]); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO); dev = DEVICE(macio); - qdev_connect_gpio_out(dev, 0, pic[0x0d]); /* IDE */ - qdev_connect_gpio_out(dev, 1, pic[0x02]); /* IDE DMA */ - qdev_connect_gpio_out(dev, 2, pic[0x0e]); /* IDE */ - qdev_connect_gpio_out(dev, 3, pic[0x02]); /* IDE DMA */ - macio_init(macio, pic_mem, cuda_mem, escc_bar); + qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */ + qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */ + qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ + qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ + qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */ + macio_init(macio, pic_mem, escc_bar); /* We only emulate 2 out of 3 IDE controllers for now */ macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), @@ -385,6 +381,9 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) "ide[1]")); macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); + adb_kbd_init(&adb_bus); + adb_mouse_init(&adb_bus); + if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { pci_create_simple(pci_bus, -1, "pci-ohci"); /* U3 needs to use USB for input because Linux doesn't support via-cuda diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 6039ea61f4..9d9212a37e 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -93,7 +93,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) MACIOIDEState *macio_ide; DeviceState *dev; int bios_size; - MemoryRegion *pic_mem, *cuda_mem; + MemoryRegion *pic_mem; MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1); uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; @@ -263,17 +263,12 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) ide_drive_get(hd, MAX_IDE_BUS); - /* cuda also initialize ADB */ - cuda_init(&cuda_mem, pic[0x12]); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); dev = DEVICE(macio); - qdev_connect_gpio_out(dev, 0, pic[0x0D]); /* IDE */ - qdev_connect_gpio_out(dev, 1, pic[0x02]); /* IDE DMA */ - macio_init(macio, pic_mem, cuda_mem, escc_bar); + qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */ + qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE */ + qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ + macio_init(macio, pic_mem, escc_bar); /* First IDE channel is a MAC IDE on the MacIO bus */ macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), @@ -286,6 +281,9 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) hd[3] = hd[2] = NULL; pci_cmd646_ide_init(pci_bus, hd, 0); + adb_kbd_init(&adb_bus); + adb_mouse_init(&adb_bus); + if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); } From 84ede329083b649c54f078276e7e06d48e910b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:04:03 +0000 Subject: [PATCH 0670/1634] adb: QOM'ify Apple Desktop Bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was not a qbus before, turn it into a first-class bus and initialize it properly from CUDA. Leave it a global variable as long as devices are not QOM'ified yet. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/adb.c | 14 ++++++++++++++ hw/adb.h | 16 +++++++++++++--- hw/cuda.c | 3 +++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index cc8ad8e057..5d46f59696 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -126,6 +126,12 @@ static ADBDevice *adb_register_device(ADBBusState *s, int devaddr, return d; } +static const TypeInfo adb_bus_type_info = { + .name = TYPE_ADB_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(ADBBusState), +}; + /***************************************************************/ /* Keyboard ADB device */ @@ -453,3 +459,11 @@ void adb_mouse_init(ADBBusState *bus) qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse"); vmstate_register(NULL, -1, &vmstate_adb_mouse, s); } + + +static void adb_register_types(void) +{ + type_register_static(&adb_bus_type_info); +} + +type_init(adb_register_types) diff --git a/hw/adb.h b/hw/adb.h index 5b27da2dd3..c23f804fe4 100644 --- a/hw/adb.h +++ b/hw/adb.h @@ -26,10 +26,13 @@ #if !defined(__ADB_H__) #define __ADB_H__ +#include "qdev.h" + #define MAX_ADB_DEVICES 16 #define ADB_MAX_OUT_LEN 16 +typedef struct ADBBusState ADBBusState; typedef struct ADBDevice ADBDevice; /* buf = NULL means polling */ @@ -38,7 +41,7 @@ typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, typedef int ADBDeviceReset(ADBDevice *d); struct ADBDevice { - struct ADBBusState *bus; + ADBBusState *bus; int devaddr; int handler; ADBDeviceRequest *devreq; @@ -46,11 +49,18 @@ struct ADBDevice { void *opaque; }; -typedef struct ADBBusState { +#define TYPE_ADB_BUS "apple-desktop-bus" +#define ADB_BUS(obj) OBJECT_CHECK(ADBBusState, (obj), TYPE_ADB_BUS) + +struct ADBBusState { + /*< private >*/ + BusState parent_obj; + /*< public >*/ + ADBDevice devices[MAX_ADB_DEVICES]; int nb_devices; int poll_index; -} ADBBusState; +}; int adb_request(ADBBusState *s, uint8_t *buf_out, const uint8_t *buf, int len); diff --git a/hw/cuda.c b/hw/cuda.c index f863c38a89..b3a875c3bc 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -712,6 +712,9 @@ static void cuda_initfn(Object *obj) for (i = 0; i < ARRAY_SIZE(s->timers); i++) { s->timers[i].index = i; } + + qbus_create_inplace((BusState *)&adb_bus, TYPE_ADB_BUS, DEVICE(obj), + "adb.0"); } static void cuda_class_init(ObjectClass *oc, void *data) From 2e4a7c9c5df442d4223e738f7e8f73192b8b2a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:04:04 +0000 Subject: [PATCH 0671/1634] adb: QOM'ify ADB devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They were not qdev'ified before. Derive ADBDevice from DeviceState and convert reset callbacks to DeviceClass::reset, ADBDevice::opaque pointer to ADBDevice subtypes for mouse and keyboard and adb_{kbd,mouse}_init() to regular qdev functions. Fixing Coding Style issues and splitting keyboard and mouse off into their own files is left for a later point in time. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/adb.c | 244 ++++++++++++++++++++++++++++++------------ hw/adb.h | 31 ++++-- hw/ppc/mac_newworld.c | 6 +- hw/ppc/mac_oldworld.c | 6 +- 4 files changed, 209 insertions(+), 78 deletions(-) diff --git a/hw/adb.c b/hw/adb.c index 5d46f59696..6cf54650c8 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -48,16 +48,21 @@ do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0) #define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 /* ADB default device IDs (upper 4 bits of ADB command byte) */ -#define ADB_DONGLE 1 -#define ADB_KEYBOARD 2 -#define ADB_MOUSE 3 -#define ADB_TABLET 4 -#define ADB_MODEM 5 -#define ADB_MISC 7 +#define ADB_DEVID_DONGLE 1 +#define ADB_DEVID_KEYBOARD 2 +#define ADB_DEVID_MOUSE 3 +#define ADB_DEVID_TABLET 4 +#define ADB_DEVID_MODEM 5 +#define ADB_DEVID_MISC 7 /* error codes */ #define ADB_RET_NOTPRESENT (-2) +static void adb_device_reset(ADBDevice *d) +{ + qdev_reset_all(DEVICE(d)); +} + int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { ADBDevice *d; @@ -66,18 +71,17 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) cmd = buf[0] & 0xf; if (cmd == ADB_BUSRESET) { for(i = 0; i < s->nb_devices; i++) { - d = &s->devices[i]; - if (d->devreset) { - d->devreset(d); - } + d = s->devices[i]; + adb_device_reset(d); } return 0; } devaddr = buf[0] >> 4; for(i = 0; i < s->nb_devices; i++) { - d = &s->devices[i]; + d = s->devices[i]; if (d->devaddr == devaddr) { - return d->devreq(d, obuf, buf, len); + ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d); + return adc->devreq(d, obuf, buf, len); } } return ADB_RET_NOTPRESENT; @@ -94,7 +98,7 @@ int adb_poll(ADBBusState *s, uint8_t *obuf) for(i = 0; i < s->nb_devices; i++) { if (s->poll_index >= s->nb_devices) s->poll_index = 0; - d = &s->devices[s->poll_index]; + d = s->devices[s->poll_index]; buf[0] = ADB_READREG | (d->devaddr << 4); olen = adb_request(s, obuf + 1, buf, 1); /* if there is data, we poll again the same device */ @@ -108,38 +112,67 @@ int adb_poll(ADBBusState *s, uint8_t *obuf) return olen; } -static ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, - void *opaque) -{ - ADBDevice *d; - if (s->nb_devices >= MAX_ADB_DEVICES) - return NULL; - d = &s->devices[s->nb_devices++]; - d->bus = s; - d->devaddr = devaddr; - d->devreq = devreq; - d->devreset = devreset; - d->opaque = opaque; - qemu_register_reset((QEMUResetHandler *)devreset, d); - return d; -} - static const TypeInfo adb_bus_type_info = { .name = TYPE_ADB_BUS, .parent = TYPE_BUS, .instance_size = sizeof(ADBBusState), }; +static void adb_device_realizefn(DeviceState *dev, Error **errp) +{ + ADBDevice *d = ADB_DEVICE(dev); + ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev)); + + if (bus->nb_devices >= MAX_ADB_DEVICES) { + return; + } + + bus->devices[bus->nb_devices++] = d; +} + +static void adb_device_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = adb_device_realizefn; + dc->bus_type = TYPE_ADB_BUS; +} + +static const TypeInfo adb_device_type_info = { + .name = TYPE_ADB_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ADBDevice), + .abstract = true, + .class_init = adb_device_class_init, +}; + /***************************************************************/ /* Keyboard ADB device */ +#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD) + typedef struct KBDState { + /*< private >*/ + ADBDevice parent_obj; + /*< public >*/ + uint8_t data[128]; int rptr, wptr, count; } KBDState; +#define ADB_KEYBOARD_CLASS(class) \ + OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD) +#define ADB_KEYBOARD_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD) + +typedef struct ADBKeyboardClass { + /*< private >*/ + ADBDeviceClass parent_class; + /*< public >*/ + + DeviceRealize parent_realize; +} ADBKeyboardClass; + static const uint8_t pc_to_adb_keycode[256] = { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, @@ -161,8 +194,7 @@ static const uint8_t pc_to_adb_keycode[256] = { static void adb_kbd_put_keycode(void *opaque, int keycode) { - ADBDevice *d = opaque; - KBDState *s = d->opaque; + KBDState *s = opaque; if (s->count < sizeof(s->data)) { s->data[s->wptr] = keycode; @@ -175,7 +207,7 @@ static void adb_kbd_put_keycode(void *opaque, int keycode) static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) { static int ext_keycode; - KBDState *s = d->opaque; + KBDState *s = ADB_KEYBOARD(d); int adb_keycode, keycode; int olen; @@ -209,7 +241,7 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, const uint8_t *buf, int len) { - KBDState *s = d->opaque; + KBDState *s = ADB_KEYBOARD(d); int cmd, reg, olen; if ((buf[0] & 0x0f) == ADB_FLUSH) { @@ -281,41 +313,90 @@ static const VMStateDescription vmstate_adb_kbd = { } }; -static int adb_kbd_reset(ADBDevice *d) +static void adb_kbd_reset(DeviceState *dev) { - KBDState *s = d->opaque; + ADBDevice *d = ADB_DEVICE(dev); + KBDState *s = ADB_KEYBOARD(dev); d->handler = 1; - d->devaddr = ADB_KEYBOARD; - memset(s, 0, sizeof(KBDState)); - - return 0; + d->devaddr = ADB_DEVID_KEYBOARD; + memset(s->data, 0, sizeof(s->data)); + s->rptr = 0; + s->wptr = 0; + s->count = 0; } -void adb_kbd_init(ADBBusState *bus) +static void adb_kbd_realizefn(DeviceState *dev, Error **errp) { - ADBDevice *d; - KBDState *s; - s = g_malloc0(sizeof(KBDState)); - d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, - adb_kbd_reset, s); + ADBDevice *d = ADB_DEVICE(dev); + ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev); + + akc->parent_realize(dev, errp); + qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); - vmstate_register(NULL, -1, &vmstate_adb_kbd, s); } +static void adb_kbd_initfn(Object *obj) +{ + ADBDevice *d = ADB_DEVICE(obj); + + d->devaddr = ADB_DEVID_KEYBOARD; +} + +static void adb_kbd_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); + ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc); + + akc->parent_realize = dc->realize; + dc->realize = adb_kbd_realizefn; + + adc->devreq = adb_kbd_request; + dc->reset = adb_kbd_reset; + dc->vmsd = &vmstate_adb_kbd; +} + +static const TypeInfo adb_kbd_type_info = { + .name = TYPE_ADB_KEYBOARD, + .parent = TYPE_ADB_DEVICE, + .instance_size = sizeof(KBDState), + .instance_init = adb_kbd_initfn, + .class_init = adb_kbd_class_init, + .class_size = sizeof(ADBKeyboardClass), +}; + /***************************************************************/ /* Mouse ADB device */ +#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE) + typedef struct MouseState { + /*< public >*/ + ADBDevice parent_obj; + /*< private >*/ + int buttons_state, last_buttons_state; int dx, dy, dz; } MouseState; +#define ADB_MOUSE_CLASS(class) \ + OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE) +#define ADB_MOUSE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE) + +typedef struct ADBMouseClass { + /*< public >*/ + ADBDeviceClass parent_class; + /*< private >*/ + + DeviceRealize parent_realize; +} ADBMouseClass; + static void adb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { - ADBDevice *d = opaque; - MouseState *s = d->opaque; + MouseState *s = opaque; s->dx += dx1; s->dy += dy1; @@ -326,7 +407,7 @@ static void adb_mouse_event(void *opaque, static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) { - MouseState *s = d->opaque; + MouseState *s = ADB_MOUSE(d); int dx, dy; if (s->last_buttons_state == s->buttons_state && @@ -365,7 +446,7 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, const uint8_t *buf, int len) { - MouseState *s = d->opaque; + MouseState *s = ADB_MOUSE(d); int cmd, reg, olen; if ((buf[0] & 0x0f) == ADB_FLUSH) { @@ -422,15 +503,15 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, return olen; } -static int adb_mouse_reset(ADBDevice *d) +static void adb_mouse_reset(DeviceState *dev) { - MouseState *s = d->opaque; + ADBDevice *d = ADB_DEVICE(dev); + MouseState *s = ADB_MOUSE(dev); d->handler = 2; - d->devaddr = ADB_MOUSE; - memset(s, 0, sizeof(MouseState)); - - return 0; + d->devaddr = ADB_DEVID_MOUSE; + s->last_buttons_state = s->buttons_state = 0; + s->dx = s->dy = s->dz = 0; } static const VMStateDescription vmstate_adb_mouse = { @@ -448,22 +529,53 @@ static const VMStateDescription vmstate_adb_mouse = { } }; -void adb_mouse_init(ADBBusState *bus) +static void adb_mouse_realizefn(DeviceState *dev, Error **errp) { - ADBDevice *d; - MouseState *s; + MouseState *s = ADB_MOUSE(dev); + ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev); - s = g_malloc0(sizeof(MouseState)); - d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, - adb_mouse_reset, s); - qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse"); - vmstate_register(NULL, -1, &vmstate_adb_mouse, s); + amc->parent_realize(dev, errp); + + qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse"); } +static void adb_mouse_initfn(Object *obj) +{ + ADBDevice *d = ADB_DEVICE(obj); + + d->devaddr = ADB_DEVID_MOUSE; +} + +static void adb_mouse_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); + ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); + + amc->parent_realize = dc->realize; + dc->realize = adb_mouse_realizefn; + + adc->devreq = adb_mouse_request; + dc->reset = adb_mouse_reset; + dc->vmsd = &vmstate_adb_mouse; +} + +static const TypeInfo adb_mouse_type_info = { + .name = TYPE_ADB_MOUSE, + .parent = TYPE_ADB_DEVICE, + .instance_size = sizeof(MouseState), + .instance_init = adb_mouse_initfn, + .class_init = adb_mouse_class_init, + .class_size = sizeof(ADBMouseClass), +}; + static void adb_register_types(void) { type_register_static(&adb_bus_type_info); + type_register_static(&adb_device_type_info); + type_register_static(&adb_kbd_type_info); + type_register_static(&adb_mouse_type_info); } type_init(adb_register_types) diff --git a/hw/adb.h b/hw/adb.h index c23f804fe4..2fe981ffaa 100644 --- a/hw/adb.h +++ b/hw/adb.h @@ -38,17 +38,32 @@ typedef struct ADBDevice ADBDevice; /* buf = NULL means polling */ typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, const uint8_t *buf, int len); -typedef int ADBDeviceReset(ADBDevice *d); + +#define TYPE_ADB_DEVICE "adb-device" +#define ADB_DEVICE(obj) OBJECT_CHECK(ADBDevice, (obj), TYPE_ADB_DEVICE) struct ADBDevice { - ADBBusState *bus; + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + int devaddr; int handler; - ADBDeviceRequest *devreq; - ADBDeviceReset *devreset; - void *opaque; }; +#define ADB_DEVICE_CLASS(cls) \ + OBJECT_CLASS_CHECK(ADBDeviceClass, (cls), TYPE_ADB_DEVICE) +#define ADB_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBDeviceClass, (obj), TYPE_ADB_DEVICE) + +typedef struct ADBDeviceClass { + /*< private >*/ + DeviceClass parent_class; + /*< public >*/ + + ADBDeviceRequest *devreq; +} ADBDeviceClass; + #define TYPE_ADB_BUS "apple-desktop-bus" #define ADB_BUS(obj) OBJECT_CHECK(ADBBusState, (obj), TYPE_ADB_BUS) @@ -57,7 +72,7 @@ struct ADBBusState { BusState parent_obj; /*< public >*/ - ADBDevice devices[MAX_ADB_DEVICES]; + ADBDevice *devices[MAX_ADB_DEVICES]; int nb_devices; int poll_index; }; @@ -66,8 +81,8 @@ int adb_request(ADBBusState *s, uint8_t *buf_out, const uint8_t *buf, int len); int adb_poll(ADBBusState *s, uint8_t *buf_out); -void adb_kbd_init(ADBBusState *bus); -void adb_mouse_init(ADBBusState *bus); +#define TYPE_ADB_KEYBOARD "adb-keyboard" +#define TYPE_ADB_MOUSE "adb-mouse" extern ADBBusState adb_bus; #endif /* !defined(__ADB_H__) */ diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index b9c58c188d..2892b362ee 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -381,8 +381,10 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) "ide[1]")); macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); + dev = qdev_create(BUS(&adb_bus), TYPE_ADB_KEYBOARD); + qdev_init_nofail(dev); + dev = qdev_create(BUS(&adb_bus), TYPE_ADB_MOUSE); + qdev_init_nofail(dev); if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { pci_create_simple(pci_bus, -1, "pci-ohci"); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 9d9212a37e..59b7199a92 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -281,8 +281,10 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) hd[3] = hd[2] = NULL; pci_cmd646_ide_init(pci_bus, hd, 0); - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); + dev = qdev_create(BUS(&adb_bus), TYPE_ADB_KEYBOARD); + qdev_init_nofail(dev); + dev = qdev_create(BUS(&adb_bus), TYPE_ADB_MOUSE); + qdev_init_nofail(dev); if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); From 293c867d8c7399d17e6b593053411a6515171f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 23:04:05 +0000 Subject: [PATCH 0672/1634] cuda: Move ADB bus into CUDA state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the global adb_bus with a CUDA-internal one, accessed using regular qdev child bus accessor. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/adb.h | 1 - hw/cuda.c | 8 +++----- hw/ppc/mac.h | 2 ++ hw/ppc/mac_newworld.c | 7 +++++-- hw/ppc/mac_oldworld.c | 7 +++++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/hw/adb.h b/hw/adb.h index 2fe981ffaa..721f1ac43e 100644 --- a/hw/adb.h +++ b/hw/adb.h @@ -84,5 +84,4 @@ int adb_poll(ADBBusState *s, uint8_t *buf_out); #define TYPE_ADB_KEYBOARD "adb-keyboard" #define TYPE_ADB_MOUSE "adb-mouse" -extern ADBBusState adb_bus; #endif /* !defined(__ADB_H__) */ diff --git a/hw/cuda.c b/hw/cuda.c index b3a875c3bc..b36c53527a 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -108,8 +108,6 @@ /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ #define RTC_OFFSET 2082844800 -ADBBusState adb_bus; - static void cuda_update(CUDAState *s); static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len); @@ -459,7 +457,7 @@ static void cuda_adb_poll(void *opaque) uint8_t obuf[ADB_MAX_OUT_LEN + 2]; int olen; - olen = adb_poll(&adb_bus, obuf + 2); + olen = adb_poll(&s->adb_bus, obuf + 2); if (olen > 0) { obuf[0] = ADB_PACKET; obuf[1] = 0x40; /* polled data */ @@ -555,7 +553,7 @@ static void cuda_receive_packet_from_host(CUDAState *s, { uint8_t obuf[ADB_MAX_OUT_LEN + 2]; int olen; - olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1); + olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1); if (olen > 0) { obuf[0] = ADB_PACKET; obuf[1] = 0x00; @@ -713,7 +711,7 @@ static void cuda_initfn(Object *obj) s->timers[i].index = i; } - qbus_create_inplace((BusState *)&adb_bus, TYPE_ADB_BUS, DEVICE(obj), + qbus_create_inplace((BusState *)&s->adb_bus, TYPE_ADB_BUS, DEVICE(obj), "adb.0"); } diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 26cb497b2d..b17107b797 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -28,6 +28,7 @@ #include "exec/memory.h" #include "hw/sysbus.h" #include "hw/ide/internal.h" +#include "hw/adb.h" /* SMP is not enabled, for now */ #define MAX_CPUS 1 @@ -93,6 +94,7 @@ typedef struct CUDAState { uint8_t ier; uint8_t anh; + ADBBusState adb_bus; CUDATimer timers[2]; uint32_t tick_offset; diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 2892b362ee..6de810bde1 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -149,6 +149,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) PCIBus *pci_bus; PCIDevice *macio; MACIOIDEState *macio_ide; + BusState *adb_bus; MacIONVRAMState *nvr; int bios_size; MemoryRegion *pic_mem, *escc_mem; @@ -381,9 +382,11 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) "ide[1]")); macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); - dev = qdev_create(BUS(&adb_bus), TYPE_ADB_KEYBOARD); + dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); + adb_bus = qdev_get_child_bus(dev, "adb.0"); + dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); qdev_init_nofail(dev); - dev = qdev_create(BUS(&adb_bus), TYPE_ADB_MOUSE); + dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); qdev_init_nofail(dev); if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 59b7199a92..9ed303a5e5 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -92,6 +92,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) PCIDevice *macio; MACIOIDEState *macio_ide; DeviceState *dev; + BusState *adb_bus; int bios_size; MemoryRegion *pic_mem; MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1); @@ -281,9 +282,11 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) hd[3] = hd[2] = NULL; pci_cmd646_ide_init(pci_bus, hd, 0); - dev = qdev_create(BUS(&adb_bus), TYPE_ADB_KEYBOARD); + dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); + adb_bus = qdev_get_child_bus(dev, "adb.0"); + dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); qdev_init_nofail(dev); - dev = qdev_create(BUS(&adb_bus), TYPE_ADB_MOUSE); + dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); qdev_init_nofail(dev); if (usb_enabled(false)) { From fe828a4d4b7a5617cda7b24e95e327bfb71d790e Mon Sep 17 00:00:00 2001 From: Mike Qiu Date: Wed, 23 Jan 2013 17:20:38 +0000 Subject: [PATCH 0673/1634] target-ppc: Give a meaningful error if too many threads are specified Currently the target-ppc tcg code only supports a single thread. You can specify more, but they're treated identically to multiple cores. On KVM we obviously can't support more threads than the hardware; if more are specified it will cause strange and cryptic errors. This patch clarifies the situation by giving a simple meaningful error if more threads are specified than we can support. Signed-off-by: Mike Qiu Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2d78529273..4f767c9751 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -28,6 +28,7 @@ #include #include "kvm_ppc.h" #include "sysemu/arch_init.h" +#include "sysemu/cpus.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -10036,6 +10037,17 @@ static void ppc_cpu_realize(Object *obj, Error **errp) PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); ppc_def_t *def = pcc->info; Error *local_err = NULL; +#if !defined(CONFIG_USER_ONLY) + int max_smt = kvm_enabled() ? kvmppc_smt_threads() : 1; +#endif + +#if !defined(CONFIG_USER_ONLY) + if (smp_threads > max_smt) { + fprintf(stderr, "Cannot support more than %d threads on PPC with %s\n", + max_smt, kvm_enabled() ? "KVM" : "TCG"); + exit(1); + } +#endif if (kvm_enabled()) { if (kvmppc_fixup_cpu(cpu) != 0) { From caae58cba07efec5f0616f568531c9dfaf1e9179 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 23 Jan 2013 17:20:39 +0000 Subject: [PATCH 0674/1634] pseries: Improve handling of multiple PCI host bridges Multiple - even many - PCI host bridges (i.e. PCI domains) are very common on real PAPR compliant hardware. For reasons related to the PAPR specified IOMMU interfaces, PCI device assignment with VFIO will generally require at least two (virtual) PHBs and possibly more depending on which devices are assigned. At the moment the qemu PAPR PCI code will not deal with this well, leaving several crucial parameters of PHBs other than the default one uninitialized. This patch reworks the code to allow this. Every PHB needs a unique BUID (Bus Unit Identifier, the id used for the PAPR PCI related interfaces) and a unique LIOBN (Logical IO Bus Number, the id used for the PAPR IOMMU related interfaces). In addition they need windows in CPU real address space to access PCI memory space, PCI IO space and MSIs. Properties are added to the PCI host bridge qdevice to allow configuration of all these. To simplify configuration of multiple PHBs for common cases, a convenience "index" property is also added. This can be set instead of the low-level properties, and will generate suitable values for the other parameters, different for each index value. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 13 +------ hw/spapr_pci.c | 102 +++++++++++++++++++++++++++++++++++++------------ hw/spapr_pci.h | 22 +++++++---- 3 files changed, 94 insertions(+), 43 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index d80b792b37..e88a27aa71 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -77,12 +77,6 @@ #define MAX_CPUS 256 #define XICS_IRQS 1024 -#define SPAPR_PCI_BUID 0x800000020000001ULL -#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000) -#define SPAPR_PCI_MEM_WIN_SIZE 0x20000000 -#define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000) -#define SPAPR_PCI_MSI_WIN_ADDR (0x10000000000ULL + 0x90000000) - #define PHANDLE_XICP 0x00001111 #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) @@ -857,12 +851,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Set up PCI */ spapr_pci_rtas_init(); - spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID, - SPAPR_PCI_MEM_WIN_ADDR, - SPAPR_PCI_MEM_WIN_SIZE, - SPAPR_PCI_IO_WIN_ADDR, - SPAPR_PCI_MSI_WIN_ADDR); - phb = PCI_HOST_BRIDGE(QLIST_FIRST(&spapr->phbs)); + phb = spapr_create_phb(spapr, 0, "pci"); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index bbcc9fc968..4eacbcfd58 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -435,7 +435,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) */ sPAPRPHBState *phb = opaque; - trace_spapr_pci_lsi_set(phb->busname, irq_num, phb->lsi_table[irq_num].irq); + trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq); qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); } @@ -522,7 +522,63 @@ static int spapr_phb_init(SysBusDevice *s) int i; PCIBus *bus; + if (sphb->index != -1) { + hwaddr windows_base; + + if ((sphb->buid != -1) || (sphb->dma_liobn != -1) + || (sphb->mem_win_addr != -1) + || (sphb->io_win_addr != -1) + || (sphb->msi_win_addr != -1)) { + fprintf(stderr, "Either \"index\" or other parameters must" + " be specified for PAPR PHB, not both\n"); + return -1; + } + + sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index; + sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN + sphb->index; + + windows_base = SPAPR_PCI_WINDOW_BASE + + sphb->index * SPAPR_PCI_WINDOW_SPACING; + sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF; + sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF; + sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF; + } + + if (sphb->buid == -1) { + fprintf(stderr, "BUID not specified for PHB\n"); + return -1; + } + + if (sphb->dma_liobn == -1) { + fprintf(stderr, "LIOBN not specified for PHB\n"); + return -1; + } + + if (sphb->mem_win_addr == -1) { + fprintf(stderr, "Memory window address not specified for PHB\n"); + return -1; + } + + if (sphb->io_win_addr == -1) { + fprintf(stderr, "IO window address not specified for PHB\n"); + return -1; + } + + if (sphb->msi_win_addr == -1) { + fprintf(stderr, "MSI window address not specified for PHB\n"); + return -1; + } + + if (find_phb(spapr, sphb->buid)) { + fprintf(stderr, "PCI host bridges must have unique BUIDs\n"); + return -1; + } + sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid); + if (!sphb->busname) { + sphb->busname = sphb->dtbusname; + } + namebuf = alloca(strlen(sphb->dtbusname) + 32); /* Initialize memory regions */ @@ -565,17 +621,19 @@ static int spapr_phb_init(SysBusDevice *s) &sphb->msiwindow); } - bus = pci_register_bus(DEVICE(s), - sphb->busname ? sphb->busname : sphb->dtbusname, + bus = pci_register_bus(DEVICE(s), sphb->busname, pci_spapr_set_irq, pci_spapr_map_irq, sphb, &sphb->memspace, &sphb->iospace, PCI_DEVFN(0, 0), PCI_NUM_PINS); phb->bus = bus; - sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16); sphb->dma_window_start = 0; sphb->dma_window_size = 0x40000000; sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size); + if (!sphb->dma) { + fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname); + return -1; + } pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb); QLIST_INSERT_HEAD(&spapr->phbs, sphb, list); @@ -605,13 +663,17 @@ static void spapr_phb_reset(DeviceState *qdev) } static Property spapr_phb_properties[] = { - DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0), DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), - DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, 0), - DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000), - DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0), - DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000), - DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, 0), + DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1), + DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1), + DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1), + DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1), + DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, + SPAPR_PCI_MMIO_WIN_SIZE), + DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1), + DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, + SPAPR_PCI_IO_WIN_SIZE), + DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1), DEFINE_PROP_END_OF_LIST(), }; @@ -632,25 +694,17 @@ static const TypeInfo spapr_phb_info = { .class_init = spapr_phb_class_init, }; -void spapr_create_phb(sPAPREnvironment *spapr, - const char *busname, uint64_t buid, - uint64_t mem_win_addr, uint64_t mem_win_size, - uint64_t io_win_addr, uint64_t msi_win_addr) +PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index, + const char *busname) { DeviceState *dev; dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); - - if (busname) { - qdev_prop_set_string(dev, "busname", g_strdup(busname)); - } - qdev_prop_set_uint64(dev, "buid", buid); - qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr); - qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size); - qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr); - qdev_prop_set_uint64(dev, "msi_win_addr", msi_win_addr); - + qdev_prop_set_uint32(dev, "index", index); + qdev_prop_set_string(dev, "busname", busname); qdev_init_nofail(dev); + + return PCI_HOST_BRIDGE(dev); } /* Macros to operate with address in OF binding to PCI */ diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index 7b26ba1561..8bb3c62c3d 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -37,6 +37,7 @@ typedef struct sPAPRPHBState { PCIHostState parent_obj; + int32_t index; uint64_t buid; char *busname; char *dtbusname; @@ -64,18 +65,25 @@ typedef struct sPAPRPHBState { QLIST_ENTRY(sPAPRPHBState) list; } sPAPRPHBState; +#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL + +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE 0x20000000 +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 +#define SPAPR_PCI_MSI_WIN_OFF 0x90000000 + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL + static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) { return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq); } -#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL -#define SPAPR_PCI_IO_WIN_SIZE 0x10000 - -void spapr_create_phb(sPAPREnvironment *spapr, - const char *busname, uint64_t buid, - uint64_t mem_win_addr, uint64_t mem_win_size, - uint64_t io_win_addr, uint64_t msi_win_addr); +PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index, + const char *busname); int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t xics_phandle, From 1ea1ce8ac305d9e006bc8b0f5f3554793fd2fa43 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 23 Jan 2013 17:20:43 +0000 Subject: [PATCH 0675/1634] pseries: Adjust default VIO address allocations to play better with libvirt Currently, if VIO devices for pseries don't have addresses explicitly allocated, they get automatically numbered from 0x1000. This is in the same general range that libvirt will typically assign VIO device addresses. That means that if there is a device libvirt doesn't know about, and it gets an address assigned before the libvirt assigned devices are processed, we can end up with an address conflict (qemu will abort with an error). While the real solution is to teach libvirt about the other devices, so it can correctly manage the whole allocation, this patch reduces the interim inconvenience by moving qemu allocations to a range that libvirt is less likely to conflict with. Because the guest gets the device addresses through the device tree, these addresses are truly arbitrary and can be changed without breaking guests. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 2054219c95..34c9ca6b65 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -492,7 +492,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void) qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); bus = DO_UPCAST(VIOsPAPRBus, bus, qbus); - bus->next_reg = 0x1000; + bus->next_reg = 0x71000000; /* hcall-vio */ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); From f40c360c0da020a1a478f8e60dd205d7412bc315 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 21 Jan 2013 15:53:51 +0000 Subject: [PATCH 0676/1634] openpic: fix remaining issues from idr-to-destmask conversion openpic_update_irq() was checking idr rather than destmask, treating it as if it were a simple bitmap of cpus. Changed to use destmask. IPI delivery was removing bits directly from .idr, without calling write_IRQreg_idr so that the change could be conveyed to destmask. Changed to use destmask directly. Save/restore destmask when serializing, as due to the IPI change it cannot be reproduced from idr. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 25aa9bf45e..a4488c2d44 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -436,13 +436,13 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) src->ivpr &= ~IVPR_ACTIVITY_MASK; } - if (src->idr == 0) { + if (src->destmask == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } - if (src->idr == (1 << src->last_cpu)) { + if (src->destmask == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); } else if (!(src->ivpr & IVPR_MODE_MASK)) { @@ -1000,8 +1000,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0x70: idx = (addr - 0x40) >> 4; /* we use IDE as mask which CPUs to deliver the IPI to still. */ - write_IRQreg_idr(opp, opp->irq_ipi0 + idx, - opp->src[opp->irq_ipi0 + idx].idr | val); + opp->src[opp->irq_ipi0 + idx].destmask |= val; openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; @@ -1101,8 +1100,8 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) } if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { - src->idr &= ~(1 << cpu); - if (src->idr && !src->level) { + src->destmask &= ~(1 << cpu); + if (src->destmask && !src->level) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, irq, 1); openpic_set_irq(opp, irq, 0); @@ -1307,6 +1306,7 @@ static void openpic_save(QEMUFile* f, void *opaque) for (i = 0; i < opp->max_irq; i++) { qemu_put_be32s(f, &opp->src[i].ivpr); qemu_put_be32s(f, &opp->src[i].idr); + qemu_get_be32s(f, &opp->src[i].destmask); qemu_put_sbe32s(f, &opp->src[i].last_cpu); qemu_put_sbe32s(f, &opp->src[i].pending); } @@ -1372,6 +1372,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->src[i].ivpr); qemu_get_be32s(f, &opp->src[i].idr); + qemu_get_be32s(f, &opp->src[i].destmask); qemu_get_sbe32s(f, &opp->src[i].last_cpu); qemu_get_sbe32s(f, &opp->src[i].pending); } From 03274d44f655f7b822e845e79fa32b261cdb0774 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 21 Jan 2013 15:53:52 +0000 Subject: [PATCH 0677/1634] openpic: fix timer address decoding The timer memory range begins at 0x10f0, so that address 0x1120 shows up as 0x30, 0x1130 shows up as 0x40, etc. However, the address decoding (other than TFRR) is not adjusted for this, causing the wrong registers to be accessed. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index a4488c2d44..0a4379ff5c 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -792,19 +792,23 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; + addr += 0x10f0; + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", __func__, addr, val); if (addr & 0xF) { return; } - idx = (addr >> 6) & 0x3; - addr = addr & 0x30; - if (addr == 0x0) { + if (addr == 0x10f0) { /* TFRR */ opp->tfrr = val; return; } + + idx = (addr >> 6) & 0x3; + addr = addr & 0x30; + switch (addr & 0x30) { case 0x00: /* TCCR */ break; From e0dfe5b18919a6a4deb841dcf3212e3e998c95e5 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 21 Jan 2013 15:53:53 +0000 Subject: [PATCH 0678/1634] openpic: add basic support for MPIC v4.2 Besides the new value in the version register, this provides: - ILR support, which includes: - IDR becoming a pure CPU bitmap, allowing 32 CPUs - machine check output support (though other parts of QEMU need to be fixed for it to do something other than immediately reboot the guest) - dummy error interrupt support (EISR0/EIMR0 read as zero) - actually all FSL MPICs get all summary registers returning zero for now, which includes EISR0/EIMR0 Various refactoring is done to support these changes and to ease new functionality (e.g. a more flexible way of declaring regions). Just as the code was already not a full implementation of MPIC v2.0, this is not a full implementation of MPIC v4.2 -- e.g. it still has only one bank of MSIs. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/openpic.c | 348 ++++++++++++++++++++++++++++++++++----------------- hw/openpic.h | 1 + 2 files changed, 232 insertions(+), 117 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 0a4379ff5c..20a479c794 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -56,7 +56,7 @@ static const int debug_openpic = 0; } \ } while (0) -#define MAX_CPU 15 +#define MAX_CPU 32 #define MAX_SRC 256 #define MAX_TMR 4 #define MAX_IPI 4 @@ -66,6 +66,7 @@ static const int debug_openpic = 0; /* OpenPIC capability flags */ #define OPENPIC_FLAG_IDR_CRIT (1 << 0) +#define OPENPIC_FLAG_ILR (2 << 0) /* OpenPIC address map */ #define OPENPIC_GLB_REG_START 0x0 @@ -74,6 +75,8 @@ static const int debug_openpic = 0; #define OPENPIC_TMR_REG_SIZE 0x220 #define OPENPIC_MSI_REG_START 0x1600 #define OPENPIC_MSI_REG_SIZE 0x200 +#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_CPU_REG_START 0x20000 @@ -94,33 +97,17 @@ static const int debug_openpic = 0; /* First doorbell IRQ */ #define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI)) -/* FSL_MPIC_20 */ -#define FSL_MPIC_20_MAX_CPU 1 -#define FSL_MPIC_20_MAX_EXT 12 -#define FSL_MPIC_20_MAX_INT 64 -#define FSL_MPIC_20_MAX_IRQ MAX_IRQ +typedef struct FslMpicInfo { + int max_ext; +} FslMpicInfo; -/* Interrupt definitions */ -/* IRQs, accessible through the IRQ region */ -#define FSL_MPIC_20_EXT_IRQ 0x00 -#define FSL_MPIC_20_INT_IRQ 0x10 -#define FSL_MPIC_20_MSG_IRQ 0xb0 -#define FSL_MPIC_20_MSI_IRQ 0xe0 -/* These are available through separate regions, but - for simplicity's sake mapped into the same number space */ -#define FSL_MPIC_20_TMR_IRQ 0x100 -#define FSL_MPIC_20_IPI_IRQ 0x104 +static FslMpicInfo fsl_mpic_20 = { + .max_ext = 12, +}; -/* - * Block Revision Register1 (BRR1): QEMU does not fully emulate - * any version on MPIC. So to start with, set the IP version to 0. - * - * NOTE: This is Freescale MPIC specific register. Keep it here till - * this code is refactored for different variants of OPENPIC and MPIC. - */ -#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */ -#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ -#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ +static FslMpicInfo fsl_mpic_42 = { + .max_ext = 12, +}; #define FRR_NIRQ_SHIFT 16 #define FRR_NCPU_SHIFT 8 @@ -146,6 +133,49 @@ static const int debug_openpic = 0; #define IDR_P1_SHIFT 1 #define IDR_P0_SHIFT 0 +#define ILR_INTTGT_MASK 0x000000ff +#define ILR_INTTGT_INT 0x00 +#define ILR_INTTGT_CINT 0x01 /* critical */ +#define ILR_INTTGT_MCP 0x02 /* machine check */ + +/* The currently supported INTTGT values happen to be the same as QEMU's + * openpic output codes, but don't depend on this. The output codes + * could change (unlikely, but...) or support could be added for + * more INTTGT values. + */ +static const int inttgt_output[][2] = { + { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT }, + { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT }, + { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK }, +}; + +static int inttgt_to_output(int inttgt) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { + if (inttgt_output[i][0] == inttgt) { + return inttgt_output[i][1]; + } + } + + fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt); + return OPENPIC_OUTPUT_INT; +} + +static int output_to_inttgt(int output) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { + if (inttgt_output[i][1] == output) { + return inttgt_output[i][0]; + } + } + + abort(); +} + #define MSIIR_OFFSET 0x140 #define MSIIR_SRS_SHIFT 29 #define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) @@ -230,6 +260,7 @@ typedef struct OpenPICState { MemoryRegion mem; /* Behavior control */ + FslMpicInfo *fsl; uint32_t model; uint32_t flags; uint32_t nb_irqs; @@ -243,7 +274,7 @@ typedef struct OpenPICState { uint32_t mpic_mode_mask; /* Sub-regions */ - MemoryRegion sub_io_mem[5]; + MemoryRegion sub_io_mem[6]; /* Global registers */ uint32_t frr; /* Feature reporting register */ @@ -558,6 +589,15 @@ static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) return opp->src[n_IRQ].idr; } +static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ) +{ + if (opp->flags & OPENPIC_FLAG_ILR) { + return output_to_inttgt(opp->src[n_IRQ].output); + } + + return 0xffffffff; +} + static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) { return opp->src[n_IRQ].ivpr; @@ -608,6 +648,19 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } } +static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val) +{ + if (opp->flags & OPENPIC_FLAG_ILR) { + IRQSource *src = &opp->src[n_IRQ]; + + src->output = inttgt_to_output(val & ILR_INTTGT_MASK); + DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, + src->output); + + /* TODO: on MPIC v4.0 only, set nomask for non-INT */ + } +} + static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t mask; @@ -874,17 +927,20 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", __func__, addr, val); - if (addr & 0xF) { - return; - } - addr = addr & 0xFFF0; + + addr = addr & 0xffff; idx = addr >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_idr(opp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ + + switch (addr & 0x1f) { + case 0x00: write_IRQreg_ivpr(opp, idx, val); + break; + case 0x10: + write_IRQreg_idr(opp, idx, val); + break; + case 0x18: + write_IRQreg_ilr(opp, idx, val); + break; } } @@ -896,20 +952,23 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) { - return retval; - } - addr = addr & 0xFFF0; - idx = addr >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_idr(opp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ivpr(opp, idx); - } - DPRINTF("%s: => 0x%08x\n", __func__, retval); + addr = addr & 0xffff; + idx = addr >> 5; + + switch (addr & 0x1f) { + case 0x00: + retval = read_IRQreg_ivpr(opp, idx); + break; + case 0x10: + retval = read_IRQreg_idr(opp, idx); + break; + case 0x18: + retval = read_IRQreg_ilr(opp, idx); + break; + } + + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -977,6 +1036,26 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) return r; } +static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t r = 0; + + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); + + /* TODO: EISR/EIMR */ + + return r; +} + +static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", + __func__, addr, val); + + /* TODO: EISR/EIMR */ +} + static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx) { @@ -1242,19 +1321,19 @@ static const MemoryRegionOps openpic_src_ops_be = { }, }; -static const MemoryRegionOps openpic_msi_ops_le = { +static const MemoryRegionOps openpic_msi_ops_be = { .read = openpic_msi_read, .write = openpic_msi_write, - .endianness = DEVICE_LITTLE_ENDIAN, + .endianness = DEVICE_BIG_ENDIAN, .impl = { .min_access_size = 4, .max_access_size = 4, }, }; -static const MemoryRegionOps openpic_msi_ops_be = { - .read = openpic_msi_read, - .write = openpic_msi_write, +static const MemoryRegionOps openpic_summary_ops_be = { + .read = openpic_summary_read, + .write = openpic_summary_write, .endianness = DEVICE_BIG_ENDIAN, .impl = { .min_access_size = 4, @@ -1387,78 +1466,128 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) typedef struct MemReg { const char *name; MemoryRegionOps const *ops; - bool map; hwaddr start_addr; ram_addr_t size; } MemReg; +static void fsl_common_init(OpenPICState *opp) +{ + int i; + int virq = MAX_SRC; + + opp->vid = VID_REVISION_1_2; + opp->vir = VIR_GENERIC; + opp->vector_mask = 0xFFFF; + opp->tfrr_reset = 0; + opp->ivpr_reset = IVPR_MASK_MASK; + opp->idr_reset = 1 << 0; + opp->max_irq = MAX_IRQ; + + opp->irq_ipi0 = virq; + virq += MAX_IPI; + opp->irq_tim0 = virq; + virq += MAX_TMR; + + assert(virq <= MAX_IRQ); + + opp->irq_msi = 224; + + msi_supported = true; + for (i = 0; i < opp->fsl->max_ext; i++) { + opp->src[i].level = false; + } + + /* Internal interrupts, including message and MSI */ + for (i = 16; i < 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++) { + opp->src[i].type = IRQ_TYPE_FSLSPECIAL; + opp->src[i].level = false; + } +} + +static void map_list(OpenPICState *opp, const MemReg *list, int *count) +{ + while (list->name) { + assert(*count < ARRAY_SIZE(opp->sub_io_mem)); + + memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp, + list->name, list->size); + + memory_region_add_subregion(&opp->mem, list->start_addr, + &opp->sub_io_mem[*count]); + + (*count)++; + list++; + } +} + static int openpic_init(SysBusDevice *dev) { OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); int i, j; - MemReg list_le[] = { - {"glb", &openpic_glb_ops_le, true, + int list_count = 0; + static const MemReg list_le[] = { + {"glb", &openpic_glb_ops_le, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, - {"tmr", &openpic_tmr_ops_le, true, + {"tmr", &openpic_tmr_ops_le, OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, - {"msi", &openpic_msi_ops_le, true, - OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, - {"src", &openpic_src_ops_le, true, + {"src", &openpic_src_ops_le, OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, - {"cpu", &openpic_cpu_ops_le, true, + {"cpu", &openpic_cpu_ops_le, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + {NULL} }; - MemReg list_be[] = { - {"glb", &openpic_glb_ops_be, true, + static const MemReg list_be[] = { + {"glb", &openpic_glb_ops_be, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, - {"tmr", &openpic_tmr_ops_be, true, + {"tmr", &openpic_tmr_ops_be, OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, - {"msi", &openpic_msi_ops_be, true, - OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, - {"src", &openpic_src_ops_be, true, + {"src", &openpic_src_ops_be, OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, - {"cpu", &openpic_cpu_ops_be, true, + {"cpu", &openpic_cpu_ops_be, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + {NULL} }; - MemReg *list; + static const MemReg list_fsl[] = { + {"msi", &openpic_msi_ops_be, + OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, + {"summary", &openpic_summary_ops_be, + OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE}, + {NULL} + }; + + memory_region_init(&opp->mem, "openpic", 0x40000); switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: + opp->fsl = &fsl_mpic_20; + opp->brr1 = 0x00400200; opp->flags |= OPENPIC_FLAG_IDR_CRIT; opp->nb_irqs = 80; - opp->vid = VID_REVISION_1_2; - opp->vir = VIR_GENERIC; - opp->vector_mask = 0xFFFF; - opp->tfrr_reset = 0; - opp->ivpr_reset = IVPR_MASK_MASK; - opp->idr_reset = 1 << 0; - opp->max_irq = FSL_MPIC_20_MAX_IRQ; - opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; - opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; - opp->irq_msi = FSL_MPIC_20_MSI_IRQ; - opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; - /* XXX really only available as of MPIC 4.0 */ + opp->mpic_mode_mask = GCR_MODE_MIXED; + + fsl_common_init(opp); + map_list(opp, list_be, &list_count); + map_list(opp, list_fsl, &list_count); + + break; + + case OPENPIC_MODEL_FSL_MPIC_42: + opp->fsl = &fsl_mpic_42; + opp->brr1 = 0x00400402; + opp->flags |= OPENPIC_FLAG_ILR; + opp->nb_irqs = 196; opp->mpic_mode_mask = GCR_MODE_PROXY; - msi_supported = true; - list = list_be; - - for (i = 0; i < FSL_MPIC_20_MAX_EXT; i++) { - opp->src[i].level = false; - } - - /* Internal interrupts, including message and MSI */ - for (i = 16; i < MAX_SRC; i++) { - opp->src[i].type = IRQ_TYPE_FSLINT; - opp->src[i].level = true; - } - - /* timers and IPIs */ - for (i = MAX_SRC; i < MAX_IRQ; i++) { - opp->src[i].type = IRQ_TYPE_FSLSPECIAL; - opp->src[i].level = false; - } + fsl_common_init(opp); + map_list(opp, list_be, &list_count); + map_list(opp, list_fsl, &list_count); break; @@ -1475,31 +1604,16 @@ static int openpic_init(SysBusDevice *dev) opp->irq_tim0 = RAVEN_TMR_IRQ; opp->brr1 = -1; opp->mpic_mode_mask = GCR_MODE_MIXED; - list = list_le; - /* Don't map MSI region */ - list[2].map = false; /* Only UP supported today */ if (opp->nb_cpus != 1) { return -EINVAL; } + + map_list(opp, list_le, &list_count); break; } - memory_region_init(&opp->mem, "openpic", 0x40000); - - for (i = 0; i < ARRAY_SIZE(list_le); i++) { - if (!list[i].map) { - continue; - } - - memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp, - list[i].name, list[i].size); - - memory_region_add_subregion(&opp->mem, list[i].start_addr, - &opp->sub_io_mem[i]); - } - 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++) { diff --git a/hw/openpic.h b/hw/openpic.h index e226d7b563..9dcaf0e7cd 100644 --- a/hw/openpic.h +++ b/hw/openpic.h @@ -13,5 +13,6 @@ enum { #define OPENPIC_MODEL_RAVEN 0 #define OPENPIC_MODEL_FSL_MPIC_20 1 +#define OPENPIC_MODEL_FSL_MPIC_42 2 #endif /* __OPENPIC_H__ */ From bd25922e737a2c90668a7bdd1e1319413a7a51f3 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 21 Jan 2013 15:53:54 +0000 Subject: [PATCH 0679/1634] PPC: e500: fix mpic_iack address MPIC+0xa0 is IACK for the current CPU. MPIC+0x200a0 is IACK for CPU 0. This fix allows EPR to work with an SMP target. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 9ccf4d1840..530f9290f0 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -505,7 +505,7 @@ void ppce500_init(PPCE500Params *params) irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i; env->mpic_iack = MPC8544_CCSRBAR_BASE + - MPC8544_MPIC_REGS_OFFSET + 0x200A0; + MPC8544_MPIC_REGS_OFFSET + 0xa0; ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); From f5fba9d27f14603dc7f85779e7b7362fb1cfcbd8 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 21 Jan 2013 15:53:55 +0000 Subject: [PATCH 0680/1634] PPC: e500: Select MPIC v4.2 on ppce500 platform The compatible string is changed to fsl,mpic on all e500 platforms, to advertise the existence of BRR1. This matches what the device tree will have on real hardware. With MPIC v4.2 max_cpu can be increased from 15 to 32. Signed-off-by: Scott Wood Signed-off-by: Alexander Graf --- hw/ppc/e500.c | 4 ++-- hw/ppc/e500.h | 2 ++ hw/ppc/e500plat.c | 4 +++- hw/ppc/mpc8544ds.c | 2 ++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 530f9290f0..b7474c05f9 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -297,7 +297,7 @@ static int ppce500_load_device_tree(CPUPPCState *env, snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); qemu_devtree_add_subnode(fdt, mpic); qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); - qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); + qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 0x40000); qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); @@ -545,7 +545,7 @@ void ppce500_init(PPCE500Params *params) 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", OPENPIC_MODEL_FSL_MPIC_20); + qdev_prop_set_uint32(dev, "model", params->mpic_version); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index f5ff27385b..226c93d248 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -16,6 +16,8 @@ typedef struct PPCE500Params { /* required -- must at least add toplevel board compatible */ void (*fixup_devtree)(struct PPCE500Params *params, void *fdt); + + int mpic_version; } PPCE500Params; void ppce500_init(PPCE500Params *params); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 2dcc4a9852..25ac4b1dae 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -15,6 +15,7 @@ #include "../boards.h" #include "sysemu/device_tree.h" #include "hw/pci/pci.h" +#include "hw/openpic.h" static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) { @@ -44,6 +45,7 @@ static void e500plat_init(QEMUMachineInitArgs *args) .pci_first_slot = 0x1, .pci_nr_slots = PCI_SLOT_MAX - 1, .fixup_devtree = e500plat_fixup_devtree, + .mpic_version = OPENPIC_MODEL_FSL_MPIC_42, }; ppce500_init(¶ms); @@ -53,7 +55,7 @@ static QEMUMachine e500plat_machine = { .name = "ppce500", .desc = "generic paravirt e500 platform", .init = e500plat_init, - .max_cpus = 15, + .max_cpus = 32, DEFAULT_MACHINE_OPTIONS, }; diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index 8e05e55c87..e25c70b1f3 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -14,6 +14,7 @@ #include "e500.h" #include "../boards.h" #include "sysemu/device_tree.h" +#include "hw/openpic.h" static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) { @@ -43,6 +44,7 @@ static void mpc8544ds_init(QEMUMachineInitArgs *args) .pci_first_slot = 0x11, .pci_nr_slots = 2, .fixup_devtree = mpc8544ds_fixup_devtree, + .mpic_version = OPENPIC_MODEL_FSL_MPIC_20, }; ppce500_init(¶ms); From 5f7a74a1a605d2065c3d74e42b563d69241089ec Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 15 Jan 2013 09:49:35 +0100 Subject: [PATCH 0681/1634] tests: adjust gcov variables for directory movement I had missed the introduction of the gcov-files-* variables. Cc: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Blue Swirl --- tests/Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index d86e95a400..d2e326f050 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,17 +1,17 @@ export SRC_PATH check-unit-y = tests/check-qdict$(EXESUF) -gcov-files-check-qdict-y = qdict.c +gcov-files-check-qdict-y = qobject/qdict.c check-unit-y += tests/check-qfloat$(EXESUF) -gcov-files-check-qfloat-y = qfloat.c +gcov-files-check-qfloat-y = qobject/qfloat.c check-unit-y += tests/check-qint$(EXESUF) -gcov-files-check-qint-y = qint.c +gcov-files-check-qint-y = qobject/qint.c check-unit-y += tests/check-qstring$(EXESUF) -gcov-files-check-qstring-y = qstring.c +gcov-files-check-qstring-y = qobject/qstring.c check-unit-y += tests/check-qlist$(EXESUF) -gcov-files-check-qlist-y = qlist.c +gcov-files-check-qlist-y = qobject/qlist.c check-unit-y += tests/check-qjson$(EXESUF) -gcov-files-check-qjson-y = qjson.c +gcov-files-check-qjson-y = qobject/qjson.c check-unit-y += tests/test-qmp-output-visitor$(EXESUF) gcov-files-test-qmp-output-visitor-y = qapi/qmp-output-visitor.c check-unit-y += tests/test-qmp-input-visitor$(EXESUF) @@ -39,7 +39,7 @@ endif endif check-unit-y += tests/test-visitor-serialization$(EXESUF) check-unit-y += tests/test-iov$(EXESUF) -gcov-files-test-iov-y = iov.c +gcov-files-test-iov-y = util/iov.c check-unit-y += tests/test-aio$(EXESUF) gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c From 659800159092333593084593abed2d85c51c5a16 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 19 Jan 2013 11:06:45 +0100 Subject: [PATCH 0682/1634] build: move around libcacard-y definition It is also needed if !CONFIG_SOFTMMU, unlike everything that surrounds it. Signed-off-by: Paolo Bonzini Signed-off-by: Blue Swirl --- Makefile.objs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index d465a72030..3548f9be95 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -33,6 +33,15 @@ ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) CONFIG_REALLY_VIRTFS=y endif +###################################################################### +# smartcard + +libcacard-y += libcacard/cac.o libcacard/event.o +libcacard-y += libcacard/vcard.o libcacard/vreader.o +libcacard-y += libcacard/vcard_emul_nss.o +libcacard-y += libcacard/vcard_emul_type.o +libcacard-y += libcacard/card_7816.o + ###################################################################### # Target independent part of system emulation. The long term path is to # suppress *all* target specific code in case of system emulation, i.e. a @@ -77,15 +86,6 @@ ifeq ($(CONFIG_SECCOMP),y) common-obj-y += qemu-seccomp.o endif -###################################################################### -# smartcard - -libcacard-y += libcacard/cac.o libcacard/event.o -libcacard-y += libcacard/vcard.o libcacard/vreader.o -libcacard-y += libcacard/vcard_emul_nss.o -libcacard-y += libcacard/vcard_emul_type.o -libcacard-y += libcacard/card_7816.o - common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) ###################################################################### From 737f351892e271fb3080c3c26e6453d939dd1d68 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 19 Jan 2013 11:06:46 +0100 Subject: [PATCH 0683/1634] build: use -$(CONFIG_SECCOMP) instead of ifeq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paolo Bonzini Acked-by: Andreas Färber Signed-off-by: Blue Swirl --- Makefile.objs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 3548f9be95..3bdb248f0c 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -80,11 +80,7 @@ common-obj-$(CONFIG_SLIRP) += slirp/ common-obj-y += backends/ -###################################################################### -# libseccomp -ifeq ($(CONFIG_SECCOMP),y) -common-obj-y += qemu-seccomp.o -endif +common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) From 000823449ca07e50086413338f907d7a817db2ce Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 19 Jan 2013 11:06:47 +0100 Subject: [PATCH 0684/1634] build: remove universal-obj-y All of universal-obj-y, user-obj-y (right now unused) and common-obj-y can be unified into common-obj-y if we take care of defining CONFIG_SOFTMMU and CONFIG_USER_ONLY in the toplevel makefile. This is similar to how we define symbols for hardware components. Signed-off-by: Paolo Bonzini Signed-off-by: Blue Swirl --- Makefile | 8 +++----- Makefile.objs | 14 +++++++------- Makefile.target | 3 +-- disas/Makefile.objs | 30 +++++++++++++++--------------- hw/Makefile.objs | 8 +++++--- qom/Makefile.objs | 4 ++-- 6 files changed, 33 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 73adf429d7..55b5d36ed3 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,8 @@ defconfig: -include config-all-devices.mak -include config-all-disas.mak +CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y) +CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y) ifneq ($(wildcard config-host.mak),) include $(SRC_PATH)/Makefile.objs @@ -133,11 +135,7 @@ pixman/Makefile: $(SRC_PATH)/pixman/configure $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) -$(SUBDIR_RULES): libqemuutil.a libqemustub.a - -$(filter %-softmmu,$(SUBDIR_RULES)): $(universal-obj-y) $(common-obj-y) $(extra-obj-y) - -$(filter %-user,$(SUBDIR_RULES)): $(universal-obj-y) $(user-obj-y) +$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(extra-obj-y) ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) romsubdir-%: diff --git a/Makefile.objs b/Makefile.objs index 3bdb248f0c..63ddaaf725 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -47,6 +47,7 @@ libcacard-y += libcacard/card_7816.o # suppress *all* target specific code in case of system emulation, i.e. a # single QEMU executable should support all CPUs and machines. +ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ common-obj-y += readline.o @@ -89,15 +90,15 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o common-obj-y += qmp.o hmp.o +endif ####################################################################### # Target-independent parts used in system and user emulation -universal-obj-y = -universal-obj-y += qemu-log.o -universal-obj-y += tcg-runtime.o -universal-obj-y += hw/ -universal-obj-y += qom/ -universal-obj-y += disas/ +common-obj-y += qemu-log.o +common-obj-y += tcg-runtime.o +common-obj-y += hw/ +common-obj-y += qom/ +common-obj-y += disas/ ###################################################################### # guest agent @@ -118,6 +119,5 @@ nested-vars += \ qga-obj-y \ block-obj-y \ common-obj-y \ - universal-obj-y \ extra-obj-y dummy := $(call unnest-vars) diff --git a/Makefile.target b/Makefile.target index eb84b1f8e3..760da1edf6 100644 --- a/Makefile.target +++ b/Makefile.target @@ -145,8 +145,7 @@ nested-vars += obj-y include $(SRC_PATH)/Makefile.objs all-obj-y = $(obj-y) -all-obj-y += $(addprefix ../, $(universal-obj-y)) -all-obj-$(CONFIG_SOFTMMU) += $(addprefix ../, $(common-obj-y)) +all-obj-y += $(addprefix ../, $(common-obj-y)) ifdef QEMU_PROGW # The linker builds a windows executable. Make also a console executable. diff --git a/disas/Makefile.objs b/disas/Makefile.objs index 3f5c5b9a21..ed75f9a99b 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -1,18 +1,18 @@ -universal-obj-$(CONFIG_ALPHA_DIS) += alpha.o -universal-obj-$(CONFIG_ARM_DIS) += arm.o -universal-obj-$(CONFIG_CRIS_DIS) += cris.o -universal-obj-$(CONFIG_HPPA_DIS) += hppa.o -universal-obj-$(CONFIG_I386_DIS) += i386.o -universal-obj-$(CONFIG_IA64_DIS) += ia64.o -universal-obj-$(CONFIG_M68K_DIS) += m68k.o -universal-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o -universal-obj-$(CONFIG_MIPS_DIS) += mips.o -universal-obj-$(CONFIG_PPC_DIS) += ppc.o -universal-obj-$(CONFIG_S390_DIS) += s390.o -universal-obj-$(CONFIG_SH4_DIS) += sh4.o -universal-obj-$(CONFIG_SPARC_DIS) += sparc.o -universal-obj-$(CONFIG_LM32_DIS) += lm32.o +common-obj-$(CONFIG_ALPHA_DIS) += alpha.o +common-obj-$(CONFIG_ARM_DIS) += arm.o +common-obj-$(CONFIG_CRIS_DIS) += cris.o +common-obj-$(CONFIG_HPPA_DIS) += hppa.o +common-obj-$(CONFIG_I386_DIS) += i386.o +common-obj-$(CONFIG_IA64_DIS) += ia64.o +common-obj-$(CONFIG_M68K_DIS) += m68k.o +common-obj-$(CONFIG_MICROBLAZE_DIS) += microblaze.o +common-obj-$(CONFIG_MIPS_DIS) += mips.o +common-obj-$(CONFIG_PPC_DIS) += ppc.o +common-obj-$(CONFIG_S390_DIS) += s390.o +common-obj-$(CONFIG_SH4_DIS) += sh4.o +common-obj-$(CONFIG_SPARC_DIS) += sparc.o +common-obj-$(CONFIG_LM32_DIS) += lm32.o # TODO: As long as the TCG interpreter and its generated code depend # on the QEMU target, we cannot compile the disassembler here. -#universal-obj-$(CONFIG_TCI_DIS) += tci.o +#common-obj-$(CONFIG_TCI_DIS) += tci.o diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 23ac24977e..260885d2cb 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,9 +1,10 @@ # core qdev-related obj files, also used by *-user: -universal-obj-y += qdev.o qdev-properties.o +common-obj-y += qdev.o qdev-properties.o # irq.o needed for qdev GPIO handling: -universal-obj-y += irq.o +common-obj-y += irq.o -common-obj-y = usb/ ide/ pci/ +ifeq ($(CONFIG_SOFTMMU),y) +common-obj-y += usb/ ide/ pci/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o common-obj-$(CONFIG_VIRTIO) += virtio-rng.o @@ -217,3 +218,4 @@ obj-$(CONFIG_LINUX) += vfio_pci.o endif $(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) +endif diff --git a/qom/Makefile.objs b/qom/Makefile.objs index 1899a4ce42..6a93ac7398 100644 --- a/qom/Makefile.objs +++ b/qom/Makefile.objs @@ -1,2 +1,2 @@ -universal-obj-y = object.o container.o qom-qobject.o -universal-obj-y += cpu.o +common-obj-y = object.o container.o qom-qobject.o +common-obj-y += cpu.o From 82cb6b041c307bd96c067147af69cd98be91a682 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 19 Jan 2013 11:06:48 +0100 Subject: [PATCH 0685/1634] build: remove extra-obj-y extra-obj-y is somewhat complicated to understand. Replace it with a special CONFIG_ALL symbol that is defined only at toplevel. This limits the case of directories defining more than one *-obj-y target. Signed-off-by: Paolo Bonzini Signed-off-by: Blue Swirl --- Makefile | 3 ++- Makefile.objs | 5 +---- fsdev/Makefile.objs | 8 ++++---- hw/Makefile.objs | 2 -- hw/pci/Makefile.objs | 2 +- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 55b5d36ed3..bd885caa4a 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ defconfig: -include config-all-disas.mak CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y) CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y) +CONFIG_ALL=y ifneq ($(wildcard config-host.mak),) include $(SRC_PATH)/Makefile.objs @@ -135,7 +136,7 @@ pixman/Makefile: $(SRC_PATH)/pixman/configure $(SRC_PATH)/pixman/configure: (cd $(SRC_PATH)/pixman; autoreconf -v --install) -$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(extra-obj-y) +$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) romsubdir-%: diff --git a/Makefile.objs b/Makefile.objs index 63ddaaf725..68eb0cef1a 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -55,7 +55,6 @@ common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o common-obj-$(CONFIG_LINUX) += fsdev/ -extra-obj-$(CONFIG_LINUX) += fsdev/ common-obj-y += migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o @@ -68,7 +67,6 @@ common-obj-$(CONFIG_SPICE) += spice-qemu-char.o common-obj-y += audio/ common-obj-y += hw/ -extra-obj-y += hw/ common-obj-y += ui/ common-obj-y += bt-host.o bt-vhci.o @@ -118,6 +116,5 @@ nested-vars += \ util-obj-y \ qga-obj-y \ block-obj-y \ - common-obj-y \ - extra-obj-y + common-obj-y dummy := $(call unnest-vars) diff --git a/fsdev/Makefile.objs b/fsdev/Makefile.objs index ee16ca600c..206289c49f 100644 --- a/fsdev/Makefile.objs +++ b/fsdev/Makefile.objs @@ -1,10 +1,10 @@ ifeq ($(CONFIG_REALLY_VIRTFS),y) common-obj-y = qemu-fsdev.o virtio-9p-marshal.o - -# Toplevel always builds this; targets without virtio will put it in -# common-obj-y -extra-obj-y = qemu-fsdev-dummy.o else common-obj-y = qemu-fsdev-dummy.o endif common-obj-y += qemu-fsdev-opts.o + +# Toplevel always builds this; targets without virtio will put it in +# common-obj-y +common-obj-$(CONFIG_ALL) += qemu-fsdev-dummy.o diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 260885d2cb..447e32a42e 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -44,8 +44,6 @@ common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-y += fifo.o common-obj-y += pam.o -extra-obj-y += pci/ - # PPC devices common-obj-$(CONFIG_PREP_PCI) += prep_pci.o common-obj-$(CONFIG_I82378) += i82378.o diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs index fe965fe2f6..1cd6cde2ee 100644 --- a/hw/pci/Makefile.objs +++ b/hw/pci/Makefile.objs @@ -6,4 +6,4 @@ common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o common-obj-$(CONFIG_NO_PCI) += pci-stub.o -extra-obj-y += pci-stub.o +common-obj-$(CONFIG_ALL) += pci-stub.o From 0360ccffbe41bd732b42a90cd04de63335933bea Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 19 Jan 2013 09:49:09 +0000 Subject: [PATCH 0686/1634] bsd-user: avoid conflict with qemu_vmalloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename qemu_vmalloc() to bsd_vmalloc(), adjust the only user. Remove #ifdeffery in oslib-posix.c. Tested-by: Andreas Färber Signed-off-by: Blue Swirl --- bsd-user/mmap.c | 4 ++-- util/oslib-posix.c | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 5d6cffc458..aae8ea10be 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -74,7 +74,7 @@ void mmap_unlock(void) } #endif -void *qemu_vmalloc(size_t size) +static void *bsd_vmalloc(size_t size) { void *p; mmap_lock(); @@ -98,7 +98,7 @@ void *g_malloc(size_t size) { char * p; size += 16; - p = qemu_vmalloc(size); + p = bsd_vmalloc(size); *(size_t *)p = size; return p + 16; } diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 4f5ec6788b..b4152fb33c 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -105,8 +105,6 @@ void *qemu_memalign(size_t alignment, size_t size) return ptr; } -/* conflicts with qemu_vmalloc in bsd-user/mmap.c */ -#if !defined(CONFIG_BSD_USER) /* alloc shared memory pages */ void *qemu_vmalloc(size_t size) { @@ -129,7 +127,6 @@ void *qemu_vmalloc(size_t size) trace_qemu_vmalloc(size, ptr); return ptr; } -#endif void qemu_vfree(void *ptr) { From b4451996e712653f9ef4d53d975a158572b8574d Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sat, 19 Jan 2013 18:58:09 +0400 Subject: [PATCH 0687/1634] link seccomp only with softmmu targets Now, if seccomp is detected, it is linked into every executable, but is used only by softmmu targets (from vl.c). So link it only where it is actually needed. Signed-off-by: Michael Tokarev Signed-off-by: Blue Swirl --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index c6172ef88e..b7635e4fec 100755 --- a/configure +++ b/configure @@ -1434,7 +1434,7 @@ fi if test "$seccomp" != "no" ; then if $pkg_config --atleast-version=1.0.0 libseccomp --modversion >/dev/null 2>&1; then - LIBS=`$pkg_config --libs libseccomp` + libs_softmmu="$libs_softmmu `$pkg_config --libs libseccomp`" seccomp="yes" else if test "$seccomp" = "yes"; then From bf4229d3cb09be2efc0add569feba33834fc5d93 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jan 2013 12:50:51 +0000 Subject: [PATCH 0688/1634] hw/arm_sysctl.c: Add missing 'break' statements Add some break statements that were accidentally omitted from some cases of arm_sysctl_write(). The omission was harmless because in both cases the following case did an immediate break, but adding the breaks explicitly placates static analysers and avoids weird behaviour if the following register is ever implemented as something other than a no-op. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/arm_sysctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 755a5df2c9..da36f8a435 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -199,6 +199,7 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, switch (offset) { case 0x08: /* LED */ s->leds = val; + break; case 0x0c: /* OSC0 */ case 0x10: /* OSC1 */ case 0x14: /* OSC2 */ @@ -295,6 +296,7 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, /* On VExpress this register is unimplemented and will RAZ/WI */ break; } + break; case 0x54: /* CLCDSER */ case 0x64: /* DMAPSR0 */ case 0x68: /* DMAPSR1 */ From 139bd956eaf1675209009b22764a46bd220e287c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jan 2013 12:50:52 +0000 Subject: [PATCH 0689/1634] hw/omap1.c: Add fallthrough markers and breaks Explicitly mark cases where we are deliberately falling through to the following code. In one case we insert a 'break' instead of falling through to a 'break', as this seems slightly clearer. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/omap1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/omap1.c b/hw/omap1.c index 1870f4dfed..623b101f80 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -529,6 +529,7 @@ static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, case 0x28: /* Reserved */ case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); + /* fall through */ case 0x00: /* COUNTER_32_LSB */ case 0x04: /* COUNTER_32_MSB */ case 0x08: /* COUNTER_HIGH_FREQ_LSB */ @@ -633,6 +634,7 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, case 0x28: /* Reserved */ case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); + /* fall through */ case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ case 0x38: /* COUNTER_32_FIQ */ case 0x48: /* LOCL_TIME */ @@ -1089,6 +1091,7 @@ static void omap_mpui_write(void *opaque, hwaddr addr, /* Not in OMAP310 */ case 0x14: /* DSP_STATUS */ OMAP_RO_REG(addr); + break; case 0x18: /* DSP_BOOT_CONFIG */ case 0x1c: /* DSP_MPUI_CONFIG */ break; From be688dfb8ddf7841fb277800977a0a878b68ae42 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jan 2013 12:50:53 +0000 Subject: [PATCH 0690/1634] hw/omap_dma, hw/omap_spi: Explicitly mark fallthroughs Explicitly mark the fallthroughs as intentional in the code pattern where we gradually increment an index before falling into the code to read/write that array entry: case THINGY_3: idx++; case THINGY_2: idx++; case THINGY_1: idx++; case THINGY_0: return s->thingy[idx]; This makes static analysers happy. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/omap_dma.c | 12 ++++++++++++ hw/omap_spi.c | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/hw/omap_dma.c b/hw/omap_dma.c index aec5874311..0c878b6ef2 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -1709,19 +1709,25 @@ static uint64_t omap_dma4_read(void *opaque, hwaddr addr, case 0x14: /* DMA4_IRQSTATUS_L3 */ irqn ++; + /* fall through */ case 0x10: /* DMA4_IRQSTATUS_L2 */ irqn ++; + /* fall through */ case 0x0c: /* DMA4_IRQSTATUS_L1 */ irqn ++; + /* fall through */ case 0x08: /* DMA4_IRQSTATUS_L0 */ return s->irqstat[irqn]; case 0x24: /* DMA4_IRQENABLE_L3 */ irqn ++; + /* fall through */ case 0x20: /* DMA4_IRQENABLE_L2 */ irqn ++; + /* fall through */ case 0x1c: /* DMA4_IRQENABLE_L1 */ irqn ++; + /* fall through */ case 0x18: /* DMA4_IRQENABLE_L0 */ return s->irqen[irqn]; @@ -1856,10 +1862,13 @@ static void omap_dma4_write(void *opaque, hwaddr addr, switch (addr) { case 0x14: /* DMA4_IRQSTATUS_L3 */ irqn ++; + /* fall through */ case 0x10: /* DMA4_IRQSTATUS_L2 */ irqn ++; + /* fall through */ case 0x0c: /* DMA4_IRQSTATUS_L1 */ irqn ++; + /* fall through */ case 0x08: /* DMA4_IRQSTATUS_L0 */ s->irqstat[irqn] &= ~value; if (!s->irqstat[irqn]) @@ -1868,10 +1877,13 @@ static void omap_dma4_write(void *opaque, hwaddr addr, case 0x24: /* DMA4_IRQENABLE_L3 */ irqn ++; + /* fall through */ case 0x20: /* DMA4_IRQENABLE_L2 */ irqn ++; + /* fall through */ case 0x1c: /* DMA4_IRQENABLE_L1 */ irqn ++; + /* fall through */ case 0x18: /* DMA4_IRQENABLE_L0 */ s->irqen[irqn] = value; return; diff --git a/hw/omap_spi.c b/hw/omap_spi.c index 42d5149a2b..8ff01ed99d 100644 --- a/hw/omap_spi.c +++ b/hw/omap_spi.c @@ -167,32 +167,47 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, return s->control; case 0x68: ch ++; + /* fall through */ case 0x54: ch ++; + /* fall through */ case 0x40: ch ++; + /* fall through */ case 0x2c: /* MCSPI_CHCONF */ return s->ch[ch].config; case 0x6c: ch ++; + /* fall through */ case 0x58: ch ++; + /* fall through */ case 0x44: ch ++; + /* fall through */ case 0x30: /* MCSPI_CHSTAT */ return s->ch[ch].status; case 0x70: ch ++; + /* fall through */ case 0x5c: ch ++; + /* fall through */ case 0x48: ch ++; + /* fall through */ case 0x34: /* MCSPI_CHCTRL */ return s->ch[ch].control; case 0x74: ch ++; + /* fall through */ case 0x60: ch ++; + /* fall through */ case 0x4c: ch ++; + /* fall through */ case 0x38: /* MCSPI_TX */ return s->ch[ch].tx; case 0x78: ch ++; + /* fall through */ case 0x64: ch ++; + /* fall through */ case 0x50: ch ++; + /* fall through */ case 0x3c: /* MCSPI_RX */ s->ch[ch].status &= ~(1 << 0); /* RXS */ ret = s->ch[ch].rx; @@ -269,8 +284,11 @@ static void omap_mcspi_write(void *opaque, hwaddr addr, break; case 0x68: ch ++; + /* fall through */ case 0x54: ch ++; + /* fall through */ case 0x40: ch ++; + /* fall through */ case 0x2c: /* MCSPI_CHCONF */ if ((value ^ s->ch[ch].config) & (3 << 14)) /* DMAR | DMAW */ omap_mcspi_dmarequest_update(s->ch + ch); @@ -283,8 +301,11 @@ static void omap_mcspi_write(void *opaque, hwaddr addr, break; case 0x70: ch ++; + /* fall through */ case 0x5c: ch ++; + /* fall through */ case 0x48: ch ++; + /* fall through */ case 0x34: /* MCSPI_CHCTRL */ if (value & ~s->ch[ch].control & 1) { /* EN */ s->ch[ch].control |= 1; @@ -294,8 +315,11 @@ static void omap_mcspi_write(void *opaque, hwaddr addr, break; case 0x74: ch ++; + /* fall through */ case 0x60: ch ++; + /* fall through */ case 0x4c: ch ++; + /* fall through */ case 0x38: /* MCSPI_TX */ s->ch[ch].tx = value; s->ch[ch].status &= ~(1 << 1); /* TXS */ From 3095485029ddbd061aa4f8e26c0437f200975d18 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jan 2013 12:50:54 +0000 Subject: [PATCH 0691/1634] hw/pflash_cfi02.c: Mark deliberate fallthrough Mark the deliberate fallthrough where we treat the case of an attempt to read flash when it is an unknown command state as if it were a normal read. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pflash_cfi02.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index b4220c1896..44bd4654f0 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -157,6 +157,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); pfl->wcycle = 0; pfl->cmd = 0; + /* fall through to the read code */ case 0x80: /* We accept reads during second unlock sequence... */ case 0x00: From 89556d1725d7c10a54ec66087e940727873f38a3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jan 2013 12:50:55 +0000 Subject: [PATCH 0692/1634] hw/smc91c111: Add explicit 'return' rather than relying on fallthrough Add an explicit 'return' statement to a case in smc91c111_readb rather than relying on fallthrough to the following case's return statement, for code clarity and to placate static analysers. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/smc91c111.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 36cb4ed74f..fe2389bf25 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -442,6 +442,7 @@ static void smc91c111_writeb(void *opaque, hwaddr offset, return; case 12: /* Early receive. */ s->ercv = value & 0x1f; + return; case 13: /* Ignore. */ return; From de16017dc8f2c33c73bd3faebf3c626c400af5e4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jan 2013 12:50:56 +0000 Subject: [PATCH 0693/1634] hw/pxa2xx_timer: Explicitly mark fallthroughs Explicitly mark the fallthroughs as intentional in the code pattern where we gradually increment an index before falling into the code to read/write that array entry: case THINGY_3: idx++; case THINGY_2: idx++; case THINGY_1: idx++; case THINGY_0: return s->thingy[idx]; This makes static analysers happy. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/pxa2xx_timer.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 32c1872680..5c9d2e8bc6 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -157,17 +157,27 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, switch (offset) { case OSMR3: tm ++; + /* fall through */ case OSMR2: tm ++; + /* fall through */ case OSMR1: tm ++; + /* fall through */ case OSMR0: return s->timer[tm].value; case OSMR11: tm ++; + /* fall through */ case OSMR10: tm ++; + /* fall through */ case OSMR9: tm ++; + /* fall through */ case OSMR8: tm ++; + /* fall through */ case OSMR7: tm ++; + /* fall through */ case OSMR6: tm ++; + /* fall through */ case OSMR5: tm ++; + /* fall through */ case OSMR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -176,12 +186,19 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) - s->lastload, s->freq, get_ticks_per_sec()); case OSCR11: tm ++; + /* fall through */ case OSCR10: tm ++; + /* fall through */ case OSCR9: tm ++; + /* fall through */ case OSCR8: tm ++; + /* fall through */ case OSCR7: tm ++; + /* fall through */ case OSCR6: tm ++; + /* fall through */ case OSCR5: tm ++; + /* fall through */ case OSCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -207,12 +224,19 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, case OWER: return s->reset3; case OMCR11: tm ++; + /* fall through */ case OMCR10: tm ++; + /* fall through */ case OMCR9: tm ++; + /* fall through */ case OMCR8: tm ++; + /* fall through */ case OMCR7: tm ++; + /* fall through */ case OMCR6: tm ++; + /* fall through */ case OMCR5: tm ++; + /* fall through */ case OMCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -235,19 +259,29 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, switch (offset) { case OSMR3: tm ++; + /* fall through */ case OSMR2: tm ++; + /* fall through */ case OSMR1: tm ++; + /* fall through */ case OSMR0: s->timer[tm].value = value; pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock)); break; case OSMR11: tm ++; + /* fall through */ case OSMR10: tm ++; + /* fall through */ case OSMR9: tm ++; + /* fall through */ case OSMR8: tm ++; + /* fall through */ case OSMR7: tm ++; + /* fall through */ case OSMR6: tm ++; + /* fall through */ case OSMR5: tm ++; + /* fall through */ case OSMR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -261,12 +295,19 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, pxa2xx_timer_update(s, s->lastload); break; case OSCR11: tm ++; + /* fall through */ case OSCR10: tm ++; + /* fall through */ case OSCR9: tm ++; + /* fall through */ case OSCR8: tm ++; + /* fall through */ case OSCR7: tm ++; + /* fall through */ case OSCR6: tm ++; + /* fall through */ case OSCR5: tm ++; + /* fall through */ case OSCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -291,8 +332,11 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, s->reset3 = value; break; case OMCR7: tm ++; + /* fall through */ case OMCR6: tm ++; + /* fall through */ case OMCR5: tm ++; + /* fall through */ case OMCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -306,8 +350,11 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, } break; case OMCR11: tm ++; + /* fall through */ case OMCR10: tm ++; + /* fall through */ case OMCR9: tm ++; + /* fall through */ case OMCR8: tm += 4; if (!pxa2xx_timer_has_tm4(s)) goto badreg; From a6e7c18476f5383720b3f57ef4f467b2e7c2565e Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 22 Jan 2013 17:03:05 +0000 Subject: [PATCH 0694/1634] softfloat: Handle float_muladd_negate_c when product is zero Honour float_muladd_negate_c in the case where the product is zero and c is nonzero. Previously we would fail to negate c. Seen in (and tested against) the gfortran testsuite on MIPS. Signed-off-by: Richard Sandiford Reviewed-by: Peter Maydell Signed-off-by: Blue Swirl --- fpu/softfloat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ac3d150015..83ccc4b8cd 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2234,7 +2234,7 @@ float32 float32_muladd(float32 a, float32 b, float32 c, int flags STATUS_PARAM) } } /* Zero plus something non-zero : just return the something */ - return make_float32(float32_val(c) ^ (signflip << 31)); + return packFloat32(cSign ^ signflip, cExp, cSig); } if (aExp == 0) { @@ -3787,7 +3787,7 @@ float64 float64_muladd(float64 a, float64 b, float64 c, int flags STATUS_PARAM) } } /* Zero plus something non-zero : just return the something */ - return make_float64(float64_val(c) ^ ((uint64_t)signflip << 63)); + return packFloat64(cSign ^ signflip, cExp, cSig); } if (aExp == 0) { From d09acb9b5ef0bb4fa94d3d459919a6ebaf8804bc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 23 Jan 2013 18:25:08 +0100 Subject: [PATCH 0695/1634] fw_cfg: Splash image loader can overrun a stack variable, fix read_splashfile() passes the address of an int variable as size_t * parameter to g_file_get_contents(), with a cast to gag the compiler. No problem on machines where sizeof(size_t) == sizeof(int). Happens to work on my x86_64 box (64 bit little endian): the least significant 32 bits of the file size end up in the right place (caller's variable file_size), and the most significant 32 bits clobber a place that gets assigned to before its next use (caller's variable file_type). I'd expect it to break on a 64 bit big-endian box. Fix up the variable types and drop the problematic cast. Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Signed-off-by: Blue Swirl --- hw/fw_cfg.c | 7 ++++--- include/sysemu/sysemu.h | 2 +- vl.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index e4dc7c3c31..b7da5c768e 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -54,7 +54,8 @@ struct FWCfgState { #define JPG_FILE 0 #define BMP_FILE 1 -static char *read_splashfile(char *filename, int *file_sizep, int *file_typep) +static char *read_splashfile(char *filename, size_t *file_sizep, + int *file_typep) { GError *err = NULL; gboolean res; @@ -63,7 +64,7 @@ static char *read_splashfile(char *filename, int *file_sizep, int *file_typep) unsigned int filehead = 0; int bmp_bpp; - res = g_file_get_contents(filename, &content, (gsize *)file_sizep, &err); + res = g_file_get_contents(filename, &content, file_sizep, &err); if (res == FALSE) { error_report("failed to read splash file '%s'", filename); g_error_free(err); @@ -111,7 +112,7 @@ static void fw_cfg_bootsplash(FWCfgState *s) const char *boot_splash_filename = NULL; char *p; char *filename, *file_data; - int file_size; + size_t file_size; int file_type = -1; const char *temp; diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 337ce7df0c..1d9599e5f4 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -122,7 +122,7 @@ extern int semihosting_enabled; extern int old_param; extern int boot_menu; extern uint8_t *boot_splash_filedata; -extern int boot_splash_filedata_size; +extern size_t boot_splash_filedata_size; extern uint8_t qemu_extra_params_fw[2]; extern QEMUClock *rtc_clock; diff --git a/vl.c b/vl.c index 4ee1302595..7aab73b736 100644 --- a/vl.c +++ b/vl.c @@ -231,7 +231,7 @@ unsigned int nb_prom_envs = 0; const char *prom_envs[MAX_PROM_ENVS]; int boot_menu; uint8_t *boot_splash_filedata; -int boot_splash_filedata_size; +size_t boot_splash_filedata_size; uint8_t qemu_extra_params_fw[2]; typedef struct FWBootEntry FWBootEntry; From 9f8863ebd7f584762a906881a62a04ac05ce4898 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 23 Jan 2013 18:25:09 +0100 Subject: [PATCH 0696/1634] fw_cfg: Drop a few superfluous initializers Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Signed-off-by: Blue Swirl --- hw/fw_cfg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index b7da5c768e..bdcd836986 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -60,8 +60,8 @@ static char *read_splashfile(char *filename, size_t *file_sizep, GError *err = NULL; gboolean res; gchar *content; - int file_type = -1; - unsigned int filehead = 0; + int file_type; + unsigned int filehead; int bmp_bpp; res = g_file_get_contents(filename, &content, file_sizep, &err); @@ -113,7 +113,7 @@ static void fw_cfg_bootsplash(FWCfgState *s) char *p; char *filename, *file_data; size_t file_size; - int file_type = -1; + int file_type; const char *temp; /* get user configuration */ From 23bf49b5eca716aaad073f2b47613434e1515cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 24 Jan 2013 16:47:55 +0100 Subject: [PATCH 0697/1634] make_device_config.sh: Fix target path in generated dependency file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit config-devices.mak.d is included from Makefile.target, i.e. from inside the *-softmmu/ directory. It included the directory path, so never applied to the actual ./config-devices.mak. Symptoms were spurious build failures due to missing dependency on default-configs/pci.mak. Fix this by using `basename` to strip the directory path. Reported-by: Gerhard Wiesinger Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- scripts/make_device_config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh index 5d14885dfc..0778fe2a42 100644 --- a/scripts/make_device_config.sh +++ b/scripts/make_device_config.sh @@ -25,4 +25,4 @@ done process_includes $src > $dest cat $src $all_includes | grep -v '^include' > $dest -echo "$1: $all_includes" > $dep +echo "`basename $1`: $all_includes" > $dep From 390999910bf1b1be59e04a0314867f4dea7a28f3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 24 Jan 2013 16:14:39 +0000 Subject: [PATCH 0698/1634] qemu-char: Avoid unused variable warning in some configs Avoid unused variable warnings: qemu-char.c: In function 'qmp_chardev_open_port': qemu-char.c:3132: warning: unused variable 'fd' qemu-char.c:3132: warning: unused variable 'flags' in configurations with neither HAVE_CHARDEV_TTY nor HAVE_CHARDEV_PARPORT set. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- qemu-char.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 9ba0573c6a..da1db1d104 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3129,11 +3129,11 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) { - int flags, fd; - switch (port->type) { #ifdef HAVE_CHARDEV_TTY case CHARDEV_PORT_KIND_SERIAL: + { + int flags, fd; flags = O_RDWR; fd = qmp_chardev_open_file_source(port->device, flags, errp); if (error_is_set(errp)) { @@ -3141,15 +3141,19 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) } socket_set_nonblock(fd); return qemu_chr_open_tty_fd(fd); + } #endif #ifdef HAVE_CHARDEV_PARPORT case CHARDEV_PORT_KIND_PARALLEL: + { + int flags, fd; flags = O_RDWR; fd = qmp_chardev_open_file_source(port->device, flags, errp); if (error_is_set(errp)) { return NULL; } return qemu_chr_open_pp_fd(fd); + } #endif default: error_setg(errp, "unknown chardev port (%d)", port->type); From 98ed805c388baaf4ce7d9acbbbc04bbf185f30fc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 24 Jan 2013 19:02:28 +0000 Subject: [PATCH 0699/1634] hw/arm_boot: Align device tree to 4KB boundary, not page Align the device tree blob to a 4KB boundary, not to QEMU's idea of a page boundary -- the latter is the smallest possible page size for the architecture, which on ARM is 1KB. The documentation for Linux does not impose separation or alignment requirements on the device tree blob, but in practice some kernels will happily trash the entire page the initrd ends in after they have finished uncompressing the initrd. So 4KB-align the DTB to ensure it does not get trampled by these kernels. Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- hw/arm_boot.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 115f583876..4065424d60 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -441,9 +441,12 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) * we point to the kernel args. */ if (info->dtb_filename) { - /* Place the DTB after the initrd in memory */ - hwaddr dtb_start = TARGET_PAGE_ALIGN(info->initrd_start + - initrd_size); + /* Place the DTB after the initrd in memory. Note that some + * kernels will trash anything in the 4K page the initrd + * ends in, so make sure the DTB isn't caught up in that. + */ + hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, + 4096); if (load_dtb(dtb_start, info)) { exit(1); } From 0c3c89d649d029b29bf245f739c82339fcf2e699 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 15 Jan 2013 09:49:37 +0100 Subject: [PATCH 0700/1634] build: remove *.lo, *.a, *.la files from all subdirectories on make clean .lo files in stubs/, util/ and libcacard/ were not cleaned. Fix this. Cc: Blue Swirl Reported-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi Reviewed-by: Michal Privoznik Signed-off-by: Blue Swirl --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index bd885caa4a..0d9099a473 100644 --- a/Makefile +++ b/Makefile @@ -213,9 +213,9 @@ clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h rm -f qemu-options.def - find . -name '*.[od]' -type f -exec rm -f {} + - rm -f *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ - rm -f *.la + find . -name '*.[oda]' -type f -exec rm -f {} + + find . -name '*.l[oa]' -type f -exec rm -f {} + + rm -f $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -Rf .libs rm -f qemu-img-cmds.h @# May not be present in GENERATED_HEADERS From 3f0f31a0f1c9a89314e9f9ed423371f4d925d5a6 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 19 Jan 2013 15:43:53 +0000 Subject: [PATCH 0701/1634] tests: add fuzzing to visitor tests Perform input tests on random data. Improvement to code coverage for qapi/string-input-visitor.c is about 3 percentage points. Signed-off-by: Blue Swirl --- tests/test-string-input-visitor.c | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index 899feda579..f6b0093554 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -165,6 +165,53 @@ static void test_visitor_in_enum(TestInputVisitorData *data, data->siv = NULL; } +/* Try to crash the visitors */ +static void test_visitor_in_fuzz(TestInputVisitorData *data, + const void *unused) +{ + int64_t ires; + bool bres; + double nres; + char *sres; + EnumOne eres; + Error *errp = NULL; + Visitor *v; + unsigned int i; + char buf[10000]; + + for (i = 0; i < 100; i++) { + unsigned int j; + + j = g_test_rand_int_range(0, sizeof(buf) - 1); + + buf[j] = '\0'; + + if (j != 0) { + for (j--; j != 0; j--) { + buf[j - 1] = (char)g_test_rand_int_range(0, 256); + } + } + + v = visitor_input_test_init(data, buf); + visit_type_int(v, &ires, NULL, &errp); + + v = visitor_input_test_init(data, buf); + visit_type_bool(v, &bres, NULL, &errp); + visitor_input_teardown(data, NULL); + + v = visitor_input_test_init(data, buf); + visit_type_number(v, &nres, NULL, &errp); + + v = visitor_input_test_init(data, buf); + visit_type_str(v, &sres, NULL, &errp); + g_free(sres); + + v = visitor_input_test_init(data, buf); + visit_type_EnumOne(v, &eres, NULL, &errp); + visitor_input_teardown(data, NULL); + } +} + static void input_visitor_test_add(const char *testpath, TestInputVisitorData *data, void (*test_func)(TestInputVisitorData *data, const void *user_data)) @@ -189,6 +236,8 @@ int main(int argc, char **argv) &in_visitor_data, test_visitor_in_string); input_visitor_test_add("/string-visitor/input/enum", &in_visitor_data, test_visitor_in_enum); + input_visitor_test_add("/string-visitor/input/fuzz", + &in_visitor_data, test_visitor_in_fuzz); g_test_run(); From 8cb6bfb54e91b1a31a6ae704def595c2099efde1 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Fri, 25 Jan 2013 21:23:24 +0400 Subject: [PATCH 0702/1634] vmware_vga: fix out of bounds and invalid rects updating This is a follow up for several attempts to fix this issue. Previous incarnations: 1. http://thread.gmane.org/gmane.linux.ubuntu.bugs.general/3156089 https://bugs.launchpad.net/bugs/918791 "qemu-kvm dies when using vmvga driver and unity in the guest" bug. Fix by Serge Hallyn: https://launchpadlibrarian.net/94916786/qemu-vmware.debdiff This fix is incomplete, since it does not check width and height for being negative. Serge weren't sure if that's the right place to fix it, maybe the fix should be up the stack somewhere. 2. http://thread.gmane.org/gmane.comp.emulators.qemu/166064 by Marek Vasut: "vmware_vga: Redraw only visible area" This one adds the (incomplete) check to vmsvga_update_rect_delayed(), the routine just queues the rect updating but does no interesting stuff. It is also incomplete in the same way as patch by Serge, but also does not touch width&height at all after adjusting x&y, which is wrong. As far as I can see, when processing guest requests, the device places them into a queue (vmsvga_update_rect_delayed()) and processes this queue in different place/time, namely, in vmsvga_update_rect(). Sometimes, vmsvga_update_rect() is called directly, without placing the request to the gueue. This is the place this patch changes, which is the last (deepest) in the stack. I'm not sure if this is the right place still, since it is possible we have some queue optimization (or may have in the future) which will be upset by negative/wrong values here, so maybe we should check for validity of input right when receiving request from the guest (and maybe even use unsigned types there). But I don't know the protocol and implementation enough to have a definitive answer. But since vmsvga_update_rect() has other sanity checks already, I'm adding the missing ones there as well. Cc'ing BALATON Zoltan and Andrzej Zaborowski who shows in `git blame' output and may know something in this area. If this patch is accepted, it should be applied to all active stable branches (at least since 1.1, maybe even before), with minor context change (ds_get_*(s->vga.ds) => s->*). I'm not Cc'ing -stable yet, will do it explicitly once the patch is accepted. BTW, these checks use fprintf(stderr) -- it should be converted to something more appropriate, since stderr will most likely disappear somewhere. Cc: Marek Vasut CC: Serge Hallyn Cc: BALATON Zoltan Cc: Andrzej Zaborowski Signed-off-by: Michael Tokarev Reviewed-by: Marek Vasut Signed-off-by: Serge Hallyn Signed-off-by: Blue Swirl --- hw/vmware_vga.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 62771bb7b5..cd15ee40a8 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -296,6 +296,15 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, uint8_t *src; uint8_t *dst; + if (x < 0) { + fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x); + w += x; + x = 0; + } + if (w < 0) { + fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w); + w = 0; + } if (x + w > ds_get_width(s->vga.ds)) { fprintf(stderr, "%s: update width too large x: %d, w: %d\n", __func__, x, w); @@ -303,6 +312,15 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, w = ds_get_width(s->vga.ds) - x; } + if (y < 0) { + fprintf(stderr, "%s: update y was < 0 (%d)\n", __func__, y); + h += y; + y = 0; + } + if (h < 0) { + fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h); + h = 0; + } if (y + h > ds_get_height(s->vga.ds)) { fprintf(stderr, "%s: update height too large y: %d, h: %d\n", __func__, y, h); From 6a6944957801f5b981e09d6bff4f1bd5529f7019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 26 Jan 2013 12:45:12 +0100 Subject: [PATCH 0703/1634] tests: Fix gcov typo for tmp105-test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6e9989034b176a8e4cfdccd85892abfa73977ba7 introduced a new qtest test case but misspelled gcov, leading to no coverage analysis. Fix it. Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index d2e326f050..a4cc554469 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -61,7 +61,7 @@ check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) gcov-files-sparc-y += hw/m48t59.c check-qtest-arm-y = tests/tmp105-test$(EXESUF) -qcov-files-arm-y += hw/tmp105.c +gcov-files-arm-y += hw/tmp105.c GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h From cba040c2b19f584bb33ae83af8517ecc9796e328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 26 Jan 2013 12:45:13 +0100 Subject: [PATCH 0704/1634] tests: Add gcov support for sparc64 qtest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m48t59-test is individually being executed for sparc and sparc64, so add the gcov source file for sparc64 as well. Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- tests/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile b/tests/Makefile index a4cc554469..a6341f2303 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -60,6 +60,7 @@ gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) gcov-files-sparc-y += hw/m48t59.c +gcov-files-sparc64-y += hw/m48t59.c check-qtest-arm-y = tests/tmp105-test$(EXESUF) gcov-files-arm-y += hw/tmp105.c From c5cd02ba16e784699d04456c8e406445db997121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 26 Jan 2013 12:45:14 +0100 Subject: [PATCH 0705/1634] tests: Add gcov support for x86_64 qtest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since x86_64 is a superset of i386 and reuses all its test cases, adopt all the i386 gcov source files as well, substituting their paths appropriately. Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- tests/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Makefile b/tests/Makefile index a6341f2303..442b286ccf 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -57,6 +57,7 @@ gcov-files-i386-y += hw/hd-geometry.c check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c +gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) gcov-files-sparc-y += hw/m48t59.c From 808fb9f277abda16601e9db938d29aeaf2548585 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Sat, 26 Jan 2013 12:36:22 -0800 Subject: [PATCH 0706/1634] xilinx_ethlite: fix eth_can_rx() for ping-pong The eth_can_rx() function only checks the first buffers status ("ping"). The controller should be able to receive into "pong" when ping-pong is enabled. Checks the active buffer (either "ping" or "pong") when determining can_rx() rather than just testing "ping". Signed-off-by: Peter Crosthwaite Signed-off-by: Edgar E. Iglesias --- hw/xilinx_ethlite.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 2254851f0a..972b85e291 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -163,9 +163,9 @@ static const MemoryRegionOps eth_ops = { static int eth_can_rx(NetClientState *nc) { struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; - int r; - r = !(s->regs[R_RX_CTRL0] & CTRL_S); - return r; + unsigned int rxbase = s->rxbuf * (0x800 / 4); + + return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S); } static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) From 2f991adb8e8cad3233ae653be12cfd72d44168ba Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Sat, 26 Jan 2013 12:36:23 -0800 Subject: [PATCH 0707/1634] xilinx_ethlite: Flush queued packets on SW service Software services a received packet by clearing the CTRL_S bit in the RX_CTRLn register. If this bit is cleared, flush any packets queued for the device. Reported-by: John Williams Signed-off-by: Peter Crosthwaite Signed-off-by: Edgar E. Iglesias --- hw/xilinx_ethlite.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 972b85e291..9463e921b9 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -135,11 +135,14 @@ eth_write(void *opaque, hwaddr addr, break; /* Keep these native. */ + case R_RX_CTRL0: + case R_RX_CTRL1: + if (!(value & CTRL_S)) { + qemu_flush_queued_packets(&s->nic->nc); + } case R_TX_LEN0: case R_TX_LEN1: case R_TX_GIE0: - case R_RX_CTRL0: - case R_RX_CTRL1: D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); s->regs[addr] = value; break; From a56d305a6d706cd75cfe0fa473f45772694f2a4a Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 25 Jan 2013 17:58:38 -0800 Subject: [PATCH 0708/1634] m25p80.c: Return state to IDLE after COLLECTING Default to moving back to the IDLE state after the COLLECTING_DATA state. For a well behaved guest this patch has no consequence, but A bad guest could crash QEMU by using one of the erase commands followed by a longer than 5 byte argument (undefined behaviour). Signed-off-by: Peter Crosthwaite Signed-off-by: Edgar E. Iglesias --- hw/m25p80.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/m25p80.c b/hw/m25p80.c index d39265632b..788c19608c 100644 --- a/hw/m25p80.c +++ b/hw/m25p80.c @@ -358,6 +358,8 @@ static void complete_collecting_data(Flash *s) s->cur_addr |= s->data[1] << 8; s->cur_addr |= s->data[2]; + s->state = STATE_IDLE; + switch (s->cmd_in_progress) { case DPP: case QPP: From 6034fe7bdb555c43022706e228cde8d52a8b341a Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Sun, 27 Jan 2013 01:05:00 +0100 Subject: [PATCH 0709/1634] xilinx_ethlite: Avoid build warnings in debug code Signed-off-by: Edgar E. Iglesias --- hw/xilinx_ethlite.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 9463e921b9..11dfbc3ac1 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -89,7 +89,7 @@ eth_read(void *opaque, hwaddr addr, unsigned int size) case R_RX_CTRL1: case R_RX_CTRL0: r = s->regs[addr]; - D(qemu_log("%s %x=%x\n", __func__, addr * 4, r)); + D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r)); break; default: @@ -115,7 +115,8 @@ eth_write(void *opaque, hwaddr addr, if (addr == R_TX_CTRL1) base = 0x800 / 4; - D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); + D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", + __func__, addr * 4, value)); if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { qemu_send_packet(&s->nic->nc, (void *) &s->regs[base], @@ -143,7 +144,8 @@ eth_write(void *opaque, hwaddr addr, case R_TX_LEN0: case R_TX_LEN1: case R_TX_GIE0: - D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); + D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", + __func__, addr * 4, value)); s->regs[addr] = value; break; @@ -185,7 +187,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) return -1; } - D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase)); + D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase)); memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size); s->regs[rxbase + R_RX_CTRL0] |= CTRL_S; From 8486af93771302fa3154857a7c05612f0f61cc90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 14:14:27 +0100 Subject: [PATCH 0710/1634] target-openrisc: Drop OpenRISCCPUList MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was missed in 92a3136174f60ee45b113296cb2c2a5225b00369 (cpu: Introduce CPUListState struct) because its naming did not match the *CPUListState pattern. Use the generalized CPUListState instead. Signed-off-by: Andreas Färber --- target-openrisc/cpu.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 56544d8ab5..7a55112bf1 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -170,11 +170,6 @@ OpenRISCCPU *cpu_openrisc_init(const char *cpu_model) return cpu; } -typedef struct OpenRISCCPUList { - fprintf_function cpu_fprintf; - FILE *file; -} OpenRISCCPUList; - /* Sort alphabetically by type name, except for "any". */ static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b) { @@ -196,7 +191,7 @@ static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b) static void openrisc_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; - OpenRISCCPUList *s = user_data; + CPUListState *s = user_data; (*s->cpu_fprintf)(s->file, " %s\n", object_class_get_name(oc)); @@ -204,7 +199,7 @@ static void openrisc_cpu_list_entry(gpointer data, gpointer user_data) void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf) { - OpenRISCCPUList s = { + CPUListState s = { .file = f, .cpu_fprintf = cpu_fprintf, }; From dd51dc5262b718c5f045c86ce1175842ab42d2cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Jan 2013 17:30:08 +0100 Subject: [PATCH 0711/1634] target-openrisc: Clean up triple QOM casts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of calling openrisc_env_get_cpu(), casting to CPU() via the ENV_GET_CPU() compatibility macro and casting back to OPENRISC_CPU(), just call openrisc_env_get_cpu() directly. ENV_GET_CPU() is meant as workaround for target-independent code only. Signed-off-by: Andreas Färber --- target-openrisc/exception_helper.c | 2 +- target-openrisc/fpu_helper.c | 32 +++++++++++++++--------------- target-openrisc/int_helper.c | 2 +- target-openrisc/interrupt_helper.c | 2 +- target-openrisc/mmu.c | 6 +++--- target-openrisc/sys_helper.c | 4 ++-- 6 files changed, 24 insertions(+), 24 deletions(-) diff --git a/target-openrisc/exception_helper.c b/target-openrisc/exception_helper.c index dab4148151..0c53b7755b 100644 --- a/target-openrisc/exception_helper.c +++ b/target-openrisc/exception_helper.c @@ -23,7 +23,7 @@ void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) { - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); raise_exception(cpu, excp); } diff --git a/target-openrisc/fpu_helper.c b/target-openrisc/fpu_helper.c index b184d5ef73..4615a366d1 100644 --- a/target-openrisc/fpu_helper.c +++ b/target-openrisc/fpu_helper.c @@ -68,7 +68,7 @@ static inline void update_fpcsr(OpenRISCCPU *cpu) uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val) { uint64_t itofd; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); set_float_exception_flags(0, &cpu->env.fp_status); itofd = int32_to_float64(val, &cpu->env.fp_status); @@ -80,7 +80,7 @@ uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val) uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val) { uint32_t itofs; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); set_float_exception_flags(0, &cpu->env.fp_status); itofs = int32_to_float32(val, &cpu->env.fp_status); @@ -92,7 +92,7 @@ uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val) uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val) { uint64_t ftoid; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); set_float_exception_flags(0, &cpu->env.fp_status); ftoid = float32_to_int64(val, &cpu->env.fp_status); @@ -104,7 +104,7 @@ uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val) uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val) { uint32_t ftois; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); set_float_exception_flags(0, &cpu->env.fp_status); ftois = float32_to_int32(val, &cpu->env.fp_status); @@ -120,7 +120,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ uint64_t fdt0, uint64_t fdt1) \ { \ uint64_t result; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -131,7 +131,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ uint32_t fdt0, uint32_t fdt1) \ { \ uint32_t result; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -152,7 +152,7 @@ uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env, \ { \ uint64_t result, temp, hi, lo; \ uint32_t val1, val2; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ hi = env->fpmaddhi; \ lo = env->fpmaddlo; \ set_float_exception_flags(0, &cpu->env.fp_status); \ @@ -174,7 +174,7 @@ uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env, \ { \ uint64_t result, temp, hi, lo; \ uint32_t val1, val2; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ hi = cpu->env.fpmaddhi; \ lo = cpu->env.fpmaddlo; \ set_float_exception_flags(0, &cpu->env.fp_status); \ @@ -198,7 +198,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ uint64_t fdt0, uint64_t fdt1) \ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -209,7 +209,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ uint32_t fdt0, uint32_t fdt1)\ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -227,7 +227,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ uint64_t fdt0, uint64_t fdt1) \ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -238,7 +238,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ uint32_t fdt0, uint32_t fdt1) \ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -253,7 +253,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ uint64_t fdt0, uint64_t fdt1) \ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = !float64_le(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -264,7 +264,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ uint32_t fdt0, uint32_t fdt1) \ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = !float32_le(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -278,7 +278,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \ uint64_t fdt0, uint64_t fdt1) \ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ @@ -289,7 +289,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \ uint32_t fdt0, uint32_t fdt1) \ { \ int res; \ - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \ + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \ set_float_exception_flags(0, &cpu->env.fp_status); \ res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status); \ update_fpcsr(cpu); \ diff --git a/target-openrisc/int_helper.c b/target-openrisc/int_helper.c index 20f9837e6a..16cb5abfcd 100644 --- a/target-openrisc/int_helper.c +++ b/target-openrisc/int_helper.c @@ -48,7 +48,7 @@ uint32_t HELPER(mul32)(CPUOpenRISCState *env, uint64_t result; uint32_t high, cy; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); result = (uint64_t)ra * rb; /* regisiers in or32 is 32bit, so 32 is NOT a magic number. diff --git a/target-openrisc/interrupt_helper.c b/target-openrisc/interrupt_helper.c index 79f5afed44..a176441b01 100644 --- a/target-openrisc/interrupt_helper.c +++ b/target-openrisc/interrupt_helper.c @@ -23,7 +23,7 @@ void HELPER(rfe)(CPUOpenRISCState *env) { - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); #ifndef CONFIG_USER_ONLY int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^ (cpu->env.esr & (SR_SM | SR_IME | SR_DME)); diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c index 836465259a..d354e1f8b2 100644 --- a/target-openrisc/mmu.c +++ b/target-openrisc/mmu.c @@ -187,7 +187,7 @@ int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, int ret = 0; hwaddr physical = 0; int prot = 0; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot, address, rw); @@ -209,7 +209,7 @@ int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, target_ulong address, int rw, int mmu_idx) { int ret = 0; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret); ret = 1; @@ -224,7 +224,7 @@ hwaddr cpu_get_phys_page_debug(CPUOpenRISCState *env, { hwaddr phys_addr; int prot; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) { return -1; diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c index f160dc397c..3c5f45ab75 100644 --- a/target-openrisc/sys_helper.c +++ b/target-openrisc/sys_helper.c @@ -30,7 +30,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, int spr = (ra | offset); int idx; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); switch (spr) { case TO_SPR(0, 0): /* VR */ @@ -177,7 +177,7 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, int spr = (ra | offset); int idx; - OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); + OpenRISCCPU *cpu = openrisc_env_get_cpu(env); switch (spr) { case TO_SPR(0, 0): /* VR */ From d61a23ba77deefd88fd2457c2dba7d5bf13f5f5b Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 17 Jan 2013 18:59:27 -0200 Subject: [PATCH 0712/1634] kvm: Add fake KVM_FEATURE_CLOCKSOURCE_STABLE_BIT for builds without KVM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Eduardo Habkost Acked-by: Marcelo Tosatti Signed-off-by: Andreas Färber --- include/sysemu/kvm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 6bdd51373e..22acf91de7 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -36,6 +36,7 @@ #define KVM_FEATURE_ASYNC_PF 0 #define KVM_FEATURE_STEAL_TIME 0 #define KVM_FEATURE_PV_EOI 0 +#define KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 0 #endif extern int kvm_allowed; From aa87d45855c7b255b451622a84a3e5b9b4393425 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 17 Jan 2013 18:59:28 -0200 Subject: [PATCH 0713/1634] target-i386: Don't set any KVM flag by default if KVM is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a cleanup that tries to solve two small issues: - We don't need a separate kvm_pv_eoi_features variable just to keep a constant calculated at compile-time, and this style would require adding a separate variable (that's declared twice because of the CONFIG_KVM ifdef) for each feature that's going to be enabled/disabled by machine-type compat code. - The pc-1.3 code is setting the kvm_pv_eoi flag on cpuid_kvm_features even when KVM is disabled at runtime. This small inconsistency in the cpuid_kvm_features field isn't a problem today because cpuid_kvm_features is ignored by the TCG code, but it may cause unexpected problems later when refactoring the CPUID handling code. This patch eliminates the kvm_pv_eoi_features variable and simply uses kvm_enabled() inside the enable_kvm_pv_eoi() compat function, so it enables kvm_pv_eoi only if KVM is enabled. I believe this makes the behavior of enable_kvm_pv_eoi() clearer and easier to understand. Signed-off-by: Eduardo Habkost Acked-by: Gleb Natapov Reviewed-by: Marcelo Tosatti Signed-off-by: Andreas Färber --- target-i386/cpu.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 376d4c8737..ac2ec243e1 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -206,22 +206,16 @@ typedef struct model_features_t { int check_cpuid = 0; int enforce_cpuid = 0; -#if defined(CONFIG_KVM) static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) | (1 << KVM_FEATURE_NOP_IO_DELAY) | (1 << KVM_FEATURE_CLOCKSOURCE2) | (1 << KVM_FEATURE_ASYNC_PF) | (1 << KVM_FEATURE_STEAL_TIME) | (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT); -static const uint32_t kvm_pv_eoi_features = (0x1 << KVM_FEATURE_PV_EOI); -#else -static uint32_t kvm_default_features = 0; -static const uint32_t kvm_pv_eoi_features = 0; -#endif void enable_kvm_pv_eoi(void) { - kvm_default_features |= kvm_pv_eoi_features; + kvm_default_features |= (1UL << KVM_FEATURE_PV_EOI); } void host_cpuid(uint32_t function, uint32_t count, @@ -1602,7 +1596,9 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) goto out; } - def->kvm_features |= kvm_default_features; + if (kvm_enabled()) { + def->kvm_features |= kvm_default_features; + } def->ext_features |= CPUID_EXT_HYPERVISOR; if (cpu_x86_parse_featurestr(def, features) < 0) { From 2969475869a6f33b8883c2fbf90252dcf617902e Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 17 Jan 2013 18:59:29 -0200 Subject: [PATCH 0714/1634] pc: Reverse pc_init_pci() compatibility logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the pc-1.4 machine init function enables PV EOI and then calls the pc-1.2 machine init function. The problem with this approach is that now we can't enable any additional compatibility code inside the pc-1.2 init function because it would end up enabling the compatibility behavior on pc-1.3 and pc-1.4 as well. This reverses the logic so that the pc-1.2 machine init function will disable PV EOI, and then call the pc-1.4 machine init function. This way we can change older machine-types to enable compatibility behavior, and the newer machine-types (pc-1.3, pc-q35-1.4 and pc-i440fx-1.4) would just use the default behavior. (This means that one nice side-effect of this change is that pc-q35-1.4 will get PV EOI enabled by default, too) It would be interesting to eventually change pc_init_pci_no_kvmclock() and pc_init_isa() to reuse pc_init_pci_1_2() as well (so we don't need to duplicate compatibility code on those two functions). But this will be probably much easier to do after we create a PCInitArgs struct for the PC initialization arguments, and/or after we use global-properties to implement the compatibility modes present in pc_init_pci_1_2(). Signed-off-by: Eduardo Habkost Acked-by: Michael S. Tsirkin Reviewed-by: Marcelo Tosatti Signed-off-by: Andreas Färber --- hw/pc_piix.c | 22 +++++++++++++--------- target-i386/cpu.c | 5 +++-- target-i386/cpu.h | 2 +- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 0a6923dcef..f9cfe782bc 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -233,12 +233,14 @@ static void pc_init_pci(QEMUMachineInitArgs *args) initrd_filename, cpu_model, 1, 1); } -static void pc_init_pci_1_3(QEMUMachineInitArgs *args) +/* PC machine init function for pc-0.14 to pc-1.2 */ +static void pc_init_pci_1_2(QEMUMachineInitArgs *args) { - enable_kvm_pv_eoi(); + disable_kvm_pv_eoi(); pc_init_pci(args); } +/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) { ram_addr_t ram_size = args->ram_size; @@ -247,6 +249,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; const char *boot_device = args->boot_device; + disable_kvm_pv_eoi(); pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -264,6 +267,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args) const char *boot_device = args->boot_device; if (cpu_model == NULL) cpu_model = "486"; + disable_kvm_pv_eoi(); pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -286,7 +290,7 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { .name = "pc-i440fx-1.4", .alias = "pc", .desc = "Standard PC (i440FX + PIIX, 1996)", - .init = pc_init_pci_1_3, + .init = pc_init_pci, .max_cpus = 255, .is_default = 1, DEFAULT_MACHINE_OPTIONS, @@ -302,7 +306,7 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { static QEMUMachine pc_machine_v1_3 = { .name = "pc-1.3", .desc = "Standard PC", - .init = pc_init_pci_1_3, + .init = pc_init_pci, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_3, @@ -342,7 +346,7 @@ static QEMUMachine pc_machine_v1_3 = { static QEMUMachine pc_machine_v1_2 = { .name = "pc-1.2", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_2, @@ -386,7 +390,7 @@ static QEMUMachine pc_machine_v1_2 = { static QEMUMachine pc_machine_v1_1 = { .name = "pc-1.1", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_1, @@ -422,7 +426,7 @@ static QEMUMachine pc_machine_v1_1 = { static QEMUMachine pc_machine_v1_0 = { .name = "pc-1.0", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_0, @@ -438,7 +442,7 @@ static QEMUMachine pc_machine_v1_0 = { static QEMUMachine pc_machine_v0_15 = { .name = "pc-0.15", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_0_15, @@ -471,7 +475,7 @@ static QEMUMachine pc_machine_v0_15 = { static QEMUMachine pc_machine_v0_14 = { .name = "pc-0.14", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_0_14, diff --git a/target-i386/cpu.c b/target-i386/cpu.c index ac2ec243e1..db9086e7ce 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -211,11 +211,12 @@ static uint32_t kvm_default_features = (1 << KVM_FEATURE_CLOCKSOURCE) | (1 << KVM_FEATURE_CLOCKSOURCE2) | (1 << KVM_FEATURE_ASYNC_PF) | (1 << KVM_FEATURE_STEAL_TIME) | + (1 << KVM_FEATURE_PV_EOI) | (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT); -void enable_kvm_pv_eoi(void) +void disable_kvm_pv_eoi(void) { - kvm_default_features |= (1UL << KVM_FEATURE_PV_EOI); + kvm_default_features &= ~(1UL << KVM_FEATURE_PV_EOI); } void host_cpuid(uint32_t function, uint32_t count, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 4e091cdec3..9d4fcf93b6 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1250,7 +1250,7 @@ void do_smm_enter(CPUX86State *env1); void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); -void enable_kvm_pv_eoi(void); +void disable_kvm_pv_eoi(void); /* Return name of 32-bit register, from a R_* constant */ const char *get_register_name_32(unsigned int reg); From b164e48ed1600055bc190aa3ab42c18004d2c711 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:01 -0200 Subject: [PATCH 0715/1634] kvm: Create kvm_arch_vcpu_id() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow each architecture to define how the VCPU ID is set on the KVM_CREATE_VCPU ioctl call. Signed-off-by: Eduardo Habkost Acked-by: Gleb Natapov Signed-off-by: Andreas Färber --- include/sysemu/kvm.h | 3 +++ kvm-all.c | 2 +- target-i386/kvm.c | 5 +++++ target-ppc/kvm.c | 5 +++++ target-s390x/kvm.c | 5 +++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 22acf91de7..384ee66c46 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -196,6 +196,9 @@ int kvm_arch_init(KVMState *s); int kvm_arch_init_vcpu(CPUState *cpu); +/* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */ +unsigned long kvm_arch_vcpu_id(CPUState *cpu); + void kvm_arch_reset_vcpu(CPUState *cpu); int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); diff --git a/kvm-all.c b/kvm-all.c index 6278d615b1..363a358a39 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -222,7 +222,7 @@ int kvm_init_vcpu(CPUState *cpu) DPRINTF("kvm_init_vcpu\n"); - ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, cpu->cpu_index); + ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)kvm_arch_vcpu_id(cpu)); if (ret < 0) { DPRINTF("kvm_create_vcpu failed\n"); goto err; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 3acff40c47..5f3f7894c1 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -411,6 +411,11 @@ static void cpu_update_state(void *opaque, int running, RunState state) } } +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + int kvm_arch_init_vcpu(CPUState *cs) { struct { diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 2f4f06818a..2c64c634f1 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -384,6 +384,11 @@ static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu) #endif /* !defined (TARGET_PPC64) */ +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + int kvm_arch_init_vcpu(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index add6a58f9c..99deddf96d 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -76,6 +76,11 @@ int kvm_arch_init(KVMState *s) return 0; } +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + int kvm_arch_init_vcpu(CPUState *cpu) { int ret = 0; From 83b17af5e619abdf11721826b08fa4f30e9dc4ee Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:02 -0200 Subject: [PATCH 0716/1634] target-i386: kvm: Set vcpu_id to APIC ID instead of CPU index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPU ID in KVM is supposed to be the APIC ID, so change the KVM_CREATE_VCPU call to match it. The current behavior didn't break anything yet because today the APIC ID is assumed to be equal to the CPU index, but this won't be true in the future. Signed-off-by: Eduardo Habkost Reviewed-by: Marcelo Tosatti Acked-by: Gleb Natapov Signed-off-by: Andreas Färber --- target-i386/kvm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5f3f7894c1..c440809cb2 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -411,9 +411,10 @@ static void cpu_update_state(void *opaque, int running, RunState state) } } -unsigned long kvm_arch_vcpu_id(CPUState *cpu) +unsigned long kvm_arch_vcpu_id(CPUState *cs) { - return cpu->cpu_index; + X86CPU *cpu = X86_CPU(cs); + return cpu->env.cpuid_apic_id; } int kvm_arch_init_vcpu(CPUState *cs) From cb41bad3c2c7d82405cbe057c944ed4fd176d82a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:04 -0200 Subject: [PATCH 0717/1634] target-i386: Introduce x86_cpu_apic_id_from_index() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function will be used by both the CPU initialization code and the fw_cfg table initialization code. Later this function will be updated to generate APIC IDs according to the CPU topology. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 17 ++++++++++++++++- target-i386/cpu.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index db9086e7ce..75dc973e3b 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2194,6 +2194,21 @@ void x86_cpu_realize(Object *obj, Error **errp) cpu_reset(CPU(cpu)); } +/* Calculates initial APIC ID for a specific CPU index + * + * Currently we need to be able to calculate the APIC ID from the CPU index + * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have + * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of + * all CPUs up to max_cpus. + */ +uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index) +{ + /* right now APIC ID == CPU index. this will eventually change to use + * the CPU topology configuration properly + */ + return cpu_index; +} + static void x86_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); @@ -2228,7 +2243,7 @@ static void x86_cpu_initfn(Object *obj) x86_cpuid_get_tsc_freq, x86_cpuid_set_tsc_freq, NULL, NULL, NULL); - env->cpuid_apic_id = cs->cpu_index; + env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index); /* init various static tables used in TCG mode */ if (tcg_enabled() && !inited) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9d4fcf93b6..9442f08305 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1255,4 +1255,6 @@ void disable_kvm_pv_eoi(void); /* Return name of 32-bit register, from a R_* constant */ const char *get_register_name_32(unsigned int reg); +uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index); + #endif /* CPU_I386_H */ From 70db922278f7b42375ead340b793ff3938835242 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:03 -0200 Subject: [PATCH 0718/1634] fw_cfg: Remove FW_CFG_MAX_CPUS from fw_cfg_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PC will not use max_cpus for that field, so move it outside the common code so it can use a different value on PC. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/fw_cfg.c | 1 - hw/pc.c | 2 +- hw/ppc/mac_newworld.c | 1 + hw/ppc/mac_oldworld.c | 1 + hw/sun4m.c | 3 +++ hw/sun4u.c | 1 + 6 files changed, 7 insertions(+), 2 deletions(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index bdcd836986..02618f2480 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -504,7 +504,6 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC)); fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); - fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); fw_cfg_bootsplash(s); fw_cfg_reboot(s); diff --git a/hw/pc.c b/hw/pc.c index 780b1e4743..de53aa434c 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -560,7 +560,7 @@ static void *bochs_bios_init(void) int i, j; fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); - + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 6de810bde1..065ea871b3 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -413,6 +413,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) /* No PCI init: the BIOS will do it */ fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 9ed303a5e5..2778e45879 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -299,6 +299,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) /* No PCI init: the BIOS will do it */ fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW); diff --git a/hw/sun4m.c b/hw/sun4m.c index 035a011768..9903f443cb 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -1021,6 +1021,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, hwdef->ecc_version); fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); @@ -1665,6 +1666,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, "Sun4d"); fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); @@ -1865,6 +1867,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, "Sun4c"); fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); diff --git a/hw/sun4u.c b/hw/sun4u.c index b891b84c9c..9fbda29ac4 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -878,6 +878,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, (uint8_t *)&nd_table[0].macaddr); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); From 54fb7bf68516642c609738814f160ee2069301e8 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:05 -0200 Subject: [PATCH 0719/1634] cpus.h: Make constant smp_cores/smp_threads available on *-user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code that calculates the APIC ID will use smp_cores/smp_threads, so just define them as 1 on *-user to avoid #ifdefs in the code. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/sysemu/cpus.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 81bd81773f..f7f6854259 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -13,9 +13,16 @@ void cpu_synchronize_all_post_init(void); void qtest_clock_warp(int64_t dest); +#ifndef CONFIG_USER_ONLY /* vl.c */ extern int smp_cores; extern int smp_threads; +#else +/* *-user doesn't have configurable SMP topology */ +#define smp_cores 1 +#define smp_threads 1 +#endif + void set_numa_modes(void); void set_cpu_log(const char *optarg); void set_cpu_log_filename(const char *optarg); From 1d934e89793d2828e04af93abd181e5ed5349ef4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 23 Jan 2013 15:51:18 -0200 Subject: [PATCH 0720/1634] pc: Set fw_cfg data based on APIC ID calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes FW_CFG_MAX_CPUS and FW_CFG_NUMA to use apic_id_for_cpu(), so the NUMA table can be based on the APIC IDs, instead of CPU index (SeaBIOS knows nothing about CPU indexes, just APIC IDs). Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/pc.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index de53aa434c..34b6dff686 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -551,6 +551,18 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return index; } +/* Calculates the limit to CPU APIC ID values + * + * This function returns the limit for the APIC ID value, so that all + * CPU APIC IDs are < pc_apic_id_limit(). + * + * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). + */ +static unsigned int pc_apic_id_limit(unsigned int max_cpus) +{ + return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; +} + static void *bochs_bios_init(void) { void *fw_cfg; @@ -558,9 +570,24 @@ static void *bochs_bios_init(void) size_t smbios_len; uint64_t *numa_fw_cfg; int i, j; + unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); - fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); + /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: + * + * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug + * QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC + * ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the + * "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS + * may see". + * + * So, this means we must not use max_cpus, here, but the maximum possible + * APIC ID value, plus one. + * + * [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is + * the APIC ID, not the "CPU index" + */ + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, @@ -579,21 +606,24 @@ static void *bochs_bios_init(void) * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. */ - numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes); + numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes); numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); for (i = 0; i < max_cpus; i++) { + unsigned int apic_id = x86_cpu_apic_id_from_index(i); + assert(apic_id < apic_id_limit); for (j = 0; j < nb_numa_nodes; j++) { if (test_bit(i, node_cpumask[j])) { - numa_fw_cfg[i + 1] = cpu_to_le64(j); + numa_fw_cfg[apic_id + 1] = cpu_to_le64(j); break; } } } for (i = 0; i < nb_numa_nodes; i++) { - numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]); + numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]); } fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, - (1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg)); + (1 + apic_id_limit + nb_numa_nodes) * + sizeof(*numa_fw_cfg)); return fw_cfg; } From 247c9de13f9d54a94734875000a9faea8168c8ca Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Wed, 23 Jan 2013 15:58:27 -0200 Subject: [PATCH 0721/1634] target-i386: Topology & APIC ID utility functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces utility functions for the APIC ID calculation, based on: Intel® 64 Architecture Processor Topology Enumeration http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ The code should be compatible with AMD's "Extended Method" described at: AMD CPUID Specification (Publication #25481) Section 3: Multiple Core Calcuation as long as: - nr_threads is set to 1; - OFFSET_IDX is assumed to be 0; - CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). Unit tests included. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/topology.h | 136 +++++++++++++++++++++++++++++++++++++++++ tests/.gitignore | 1 + tests/Makefile | 9 ++- tests/test-x86-cpuid.c | 110 +++++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 target-i386/topology.h create mode 100644 tests/test-x86-cpuid.c diff --git a/target-i386/topology.h b/target-i386/topology.h new file mode 100644 index 0000000000..24ed525453 --- /dev/null +++ b/target-i386/topology.h @@ -0,0 +1,136 @@ +/* + * x86 CPU topology data structures and functions + * + * Copyright (c) 2012 Red Hat 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. + */ +#ifndef TARGET_I386_TOPOLOGY_H +#define TARGET_I386_TOPOLOGY_H + +/* This file implements the APIC-ID-based CPU topology enumeration logic, + * documented at the following document: + * Intel® 64 Architecture Processor Topology Enumeration + * http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/ + * + * This code should be compatible with AMD's "Extended Method" described at: + * AMD CPUID Specification (Publication #25481) + * Section 3: Multiple Core Calcuation + * as long as: + * nr_threads is set to 1; + * OFFSET_IDX is assumed to be 0; + * CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width(). + */ + +#include +#include + +#include "qemu/bitops.h" + +/* APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support + */ +typedef uint32_t apic_id_t; + +/* Return the bit width needed for 'count' IDs + */ +static unsigned apicid_bitwidth_for_count(unsigned count) +{ + g_assert(count >= 1); + if (count == 1) { + return 0; + } + return bitops_flsl(count - 1) + 1; +} + +/* Bit width of the SMT_ID (thread ID) field on the APIC ID + */ +static inline unsigned apicid_smt_width(unsigned nr_cores, unsigned nr_threads) +{ + return apicid_bitwidth_for_count(nr_threads); +} + +/* Bit width of the Core_ID field + */ +static inline unsigned apicid_core_width(unsigned nr_cores, unsigned nr_threads) +{ + return apicid_bitwidth_for_count(nr_cores); +} + +/* Bit offset of the Core_ID field + */ +static inline unsigned apicid_core_offset(unsigned nr_cores, + unsigned nr_threads) +{ + return apicid_smt_width(nr_cores, nr_threads); +} + +/* Bit offset of the Pkg_ID (socket ID) field + */ +static inline unsigned apicid_pkg_offset(unsigned nr_cores, unsigned nr_threads) +{ + return apicid_core_offset(nr_cores, nr_threads) + + apicid_core_width(nr_cores, nr_threads); +} + +/* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID + * + * The caller must make sure core_id < nr_cores and smt_id < nr_threads. + */ +static inline apic_id_t apicid_from_topo_ids(unsigned nr_cores, + unsigned nr_threads, + unsigned pkg_id, + unsigned core_id, + unsigned smt_id) +{ + return (pkg_id << apicid_pkg_offset(nr_cores, nr_threads)) | + (core_id << apicid_core_offset(nr_cores, nr_threads)) | + smt_id; +} + +/* Calculate thread/core/package IDs for a specific topology, + * based on (contiguous) CPU index + */ +static inline void x86_topo_ids_from_idx(unsigned nr_cores, + unsigned nr_threads, + unsigned cpu_index, + unsigned *pkg_id, + unsigned *core_id, + unsigned *smt_id) +{ + unsigned core_index = cpu_index / nr_threads; + *smt_id = cpu_index % nr_threads; + *core_id = core_index % nr_cores; + *pkg_id = core_index / nr_cores; +} + +/* Make APIC ID for the CPU 'cpu_index' + * + * 'cpu_index' is a sequential, contiguous ID for the CPU. + */ +static inline apic_id_t x86_apicid_from_cpu_idx(unsigned nr_cores, + unsigned nr_threads, + unsigned cpu_index) +{ + unsigned pkg_id, core_id, smt_id; + x86_topo_ids_from_idx(nr_cores, nr_threads, cpu_index, + &pkg_id, &core_id, &smt_id); + return apicid_from_topo_ids(nr_cores, nr_threads, pkg_id, core_id, smt_id); +} + +#endif /* TARGET_I386_TOPOLOGY_H */ diff --git a/tests/.gitignore b/tests/.gitignore index f9041f3d32..38c94ef1da 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -10,4 +10,5 @@ test-qmp-commands.h test-qmp-commands test-qmp-input-strict test-qmp-marshal.c +test-x86-cpuid *-test diff --git a/tests/Makefile b/tests/Makefile index 442b286ccf..804ce42962 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -45,6 +45,9 @@ gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c check-unit-y += tests/test-thread-pool$(EXESUF) gcov-files-test-thread-pool-y = thread-pool.c +check-unit-y += tests/test-x86-cpuid$(EXESUF) +# all code tested by test-x86-cpuid is inside topology.h +gcov-files-test-x86-cpuid-y = check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -72,12 +75,15 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-coroutine.o tests/test-string-output-visitor.o \ tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ - tests/test-qmp-commands.o tests/test-visitor-serialization.o + tests/test-qmp-commands.o tests/test-visitor-serialization.o \ + tests/test-x86-cpuid.o test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o $(test-obj-y): QEMU_INCLUDES += -Itests +tests/test-x86-cpuid.o: QEMU_INCLUDES += -I$(SRC_PATH)/target-i386 + tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a @@ -88,6 +94,7 @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a +tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py diff --git a/tests/test-x86-cpuid.c b/tests/test-x86-cpuid.c new file mode 100644 index 0000000000..8d9f96a113 --- /dev/null +++ b/tests/test-x86-cpuid.c @@ -0,0 +1,110 @@ +/* + * Test code for x86 CPUID and Topology functions + * + * Copyright (c) 2012 Red Hat 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 "topology.h" + +static void test_topo_bits(void) +{ + /* simple tests for 1 thread per core, 1 core per socket */ + g_assert_cmpuint(apicid_smt_width(1, 1), ==, 0); + g_assert_cmpuint(apicid_core_width(1, 1), ==, 0); + + g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 0), ==, 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 1), ==, 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 2), ==, 2); + g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 3), ==, 3); + + + /* Test field width calculation for multiple values + */ + g_assert_cmpuint(apicid_smt_width(1, 2), ==, 1); + g_assert_cmpuint(apicid_smt_width(1, 3), ==, 2); + g_assert_cmpuint(apicid_smt_width(1, 4), ==, 2); + + g_assert_cmpuint(apicid_smt_width(1, 14), ==, 4); + g_assert_cmpuint(apicid_smt_width(1, 15), ==, 4); + g_assert_cmpuint(apicid_smt_width(1, 16), ==, 4); + g_assert_cmpuint(apicid_smt_width(1, 17), ==, 5); + + + g_assert_cmpuint(apicid_core_width(30, 2), ==, 5); + g_assert_cmpuint(apicid_core_width(31, 2), ==, 5); + g_assert_cmpuint(apicid_core_width(32, 2), ==, 5); + g_assert_cmpuint(apicid_core_width(33, 2), ==, 6); + + + /* build a weird topology and see if IDs are calculated correctly + */ + + /* This will use 2 bits for thread ID and 3 bits for core ID + */ + g_assert_cmpuint(apicid_smt_width(6, 3), ==, 2); + g_assert_cmpuint(apicid_core_width(6, 3), ==, 3); + g_assert_cmpuint(apicid_pkg_offset(6, 3), ==, 5); + + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 0), ==, 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1), ==, 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2), ==, 2); + + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 0), ==, + (1 << 2) | 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 1), ==, + (1 << 2) | 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 2), ==, + (1 << 2) | 2); + + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 0), ==, + (2 << 2) | 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 1), ==, + (2 << 2) | 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 2), ==, + (2 << 2) | 2); + + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 0), ==, + (5 << 2) | 0); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 1), ==, + (5 << 2) | 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 2), ==, + (5 << 2) | 2); + + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 6 * 3 + 0 * 3 + 0), ==, + (1 << 5)); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 6 * 3 + 1 * 3 + 1), ==, + (1 << 5) | (1 << 2) | 1); + g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 3 * 6 * 3 + 5 * 3 + 2), ==, + (3 << 5) | (5 << 2) | 2); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/cpuid/topology/basic", test_topo_bits); + + g_test_run(); + + return 0; +} From 8932cfdf7b95734c9b4a114b8ed0b4527af77ce7 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 22 Jan 2013 18:25:09 -0200 Subject: [PATCH 0722/1634] pc: Generate APIC IDs according to CPU topology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This keeps compatibility on machine-types pc-1.2 and older, and prints a warning in case the requested configuration won't get the correct topology. I couldn't think of a better way to warn about broken topology when in compat mode other than using error_report(). The warning message will probably be buried in a log file somewhere, but it's better than nothing. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/pc_piix.c | 12 ++++++++++-- target-i386/cpu.c | 28 ++++++++++++++++++++++++---- target-i386/cpu.h | 1 + 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index f9cfe782bc..b9a9b2efe1 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -233,11 +233,17 @@ static void pc_init_pci(QEMUMachineInitArgs *args) initrd_filename, cpu_model, 1, 1); } +static void pc_init_pci_1_3(QEMUMachineInitArgs *args) +{ + enable_compat_apic_id_mode(); + pc_init_pci(args); +} + /* PC machine init function for pc-0.14 to pc-1.2 */ static void pc_init_pci_1_2(QEMUMachineInitArgs *args) { disable_kvm_pv_eoi(); - pc_init_pci(args); + pc_init_pci_1_3(args); } /* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ @@ -250,6 +256,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) const char *initrd_filename = args->initrd_filename; const char *boot_device = args->boot_device; disable_kvm_pv_eoi(); + enable_compat_apic_id_mode(); pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -268,6 +275,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args) if (cpu_model == NULL) cpu_model = "486"; disable_kvm_pv_eoi(); + enable_compat_apic_id_mode(); pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -306,7 +314,7 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { static QEMUMachine pc_machine_v1_3 = { .name = "pc-1.3", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_3, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_3, diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 75dc973e3b..c5acaa7523 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -23,6 +23,8 @@ #include "cpu.h" #include "sysemu/kvm.h" +#include "sysemu/cpus.h" +#include "topology.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -2194,6 +2196,14 @@ void x86_cpu_realize(Object *obj, Error **errp) cpu_reset(CPU(cpu)); } +/* Enables contiguous-apic-ID mode, for compatibility */ +static bool compat_apic_id_mode; + +void enable_compat_apic_id_mode(void) +{ + compat_apic_id_mode = true; +} + /* Calculates initial APIC ID for a specific CPU index * * Currently we need to be able to calculate the APIC ID from the CPU index @@ -2203,10 +2213,20 @@ void x86_cpu_realize(Object *obj, Error **errp) */ uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index) { - /* right now APIC ID == CPU index. this will eventually change to use - * the CPU topology configuration properly - */ - return cpu_index; + uint32_t correct_id; + static bool warned; + + correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index); + if (compat_apic_id_mode) { + if (cpu_index != correct_id && !warned) { + error_report("APIC IDs set in compatibility mode, " + "CPU topology won't match the configuration"); + warned = true; + } + return cpu_index; + } else { + return correct_id; + } } static void x86_cpu_initfn(Object *obj) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9442f08305..27efe59488 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1256,5 +1256,6 @@ void disable_kvm_pv_eoi(void); const char *get_register_name_32(unsigned int reg); uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index); +void enable_compat_apic_id_mode(void); #endif /* CPU_I386_H */ From 4bfe910d4728807e7d80de152a7ef33dd608033f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 01:00:24 +0100 Subject: [PATCH 0723/1634] target-i386: Simplify cpu_x86_find_by_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Catch NULL name argument early to avoid repeated checks. Similarly, check for -cpu host early and untangle from iterating through model definitions. This prepares for introducing X86CPU subclasses. Signed-off-by: Andreas Färber --- target-i386/cpu.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index c5acaa7523..37a4b03887 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1318,20 +1318,22 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) { x86_def_t *def; - for (def = x86_defs; def; def = def->next) { - if (name && !strcmp(name, def->name)) { - break; - } - } - if (kvm_enabled() && name && strcmp(name, "host") == 0) { - kvm_cpu_fill_host(x86_cpu_def); - } else if (!def) { + if (name == NULL) { return -1; - } else { - memcpy(x86_cpu_def, def, sizeof(*def)); + } + if (kvm_enabled() && strcmp(name, "host") == 0) { + kvm_cpu_fill_host(x86_cpu_def); + return 0; } - return 0; + for (def = x86_defs; def; def = def->next) { + if (strcmp(name, def->name) == 0) { + memcpy(x86_cpu_def, def, sizeof(*def)); + return 0; + } + } + + return -1; } /* Parse "+feature,-feature,feature=foo" CPU feature string From 7fc9b714eb4877ca83ce8e437ec93d34fca0eb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 01:02:28 +0100 Subject: [PATCH 0724/1634] target-i386: Drop redundant list of CPU definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is no longer needed since dropping cpudef config file support. Cleaning this up removes knowledge about other models from x86_def_t, in preparation for reusing x86_def_t as intermediate step towards pure QOM X86CPU subclasses. Signed-off-by: Andreas Färber --- target-i386/cpu.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 37a4b03887..df974d7ede 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -335,7 +335,6 @@ static void add_flagname_to_bitmaps(const char *flagname, } typedef struct x86_def_t { - struct x86_def_t *next; const char *name; uint32_t level; uint32_t vendor1, vendor2, vendor3; @@ -393,11 +392,7 @@ typedef struct x86_def_t { #define TCG_SVM_FEATURES 0 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP) -/* maintains list of cpu model definitions - */ -static x86_def_t *x86_defs = {NULL}; - -/* built-in cpu model definitions (deprecated) +/* built-in CPU model definitions */ static x86_def_t builtin_x86_defs[] = { { @@ -1317,6 +1312,7 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque, static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) { x86_def_t *def; + int i; if (name == NULL) { return -1; @@ -1326,7 +1322,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) return 0; } - for (def = x86_defs; def; def = def->next) { + for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { + def = &builtin_x86_defs[i]; if (strcmp(name, def->name) == 0) { memcpy(x86_cpu_def, def, sizeof(*def)); return 0; @@ -1512,8 +1509,10 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf) { x86_def_t *def; char buf[256]; + int i; - for (def = x86_defs; def; def = def->next) { + for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { + def = &builtin_x86_defs[i]; snprintf(buf, sizeof(buf), "%s", def->name); (*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id); } @@ -1535,11 +1534,13 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) { CpuDefinitionInfoList *cpu_list = NULL; x86_def_t *def; + int i; - for (def = x86_defs; def; def = def->next) { + for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { CpuDefinitionInfoList *entry; CpuDefinitionInfo *info; + def = &builtin_x86_defs[i]; info = g_malloc0(sizeof(*info)); info->name = g_strdup(def->name); @@ -1662,7 +1663,6 @@ void x86_cpudef_setup(void) for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) { x86_def_t *def = &builtin_x86_defs[i]; - def->next = x86_defs; /* Look for specific "cpudef" models that */ /* have the QEMU version in .model_id */ @@ -1675,8 +1675,6 @@ void x86_cpudef_setup(void) break; } } - - x86_defs = def; } } From 8ba8a69848f8b910207a4b57c68db9a7e92af578 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:35 +0100 Subject: [PATCH 0725/1634] target-i386: Print deprecation warning if xlevel < 0x80000000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index df974d7ede..b75ea9fc8f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1395,6 +1395,8 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) goto error; } if (numvalue < 0x80000000) { + fprintf(stderr, "xlevel value shall always be >= 0x80000000" + ", fixup will be removed in future versions\n"); numvalue += 0x80000000; } x86_cpu_def->xlevel = numvalue; From 99b88a1708919934f4092f7b6dcc2cca9d4072e9 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:36 +0100 Subject: [PATCH 0726/1634] target-i386: Replace uint32_t vendor fields by vendor string in x86_def_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vendor property setter takes string as vendor value but cpudefs use uint32_t vendor[123] fields to define vendor value. It makes it difficult to unify and use property setter for values from cpudefs. Simplify code by using vendor property setter, vendor[123] fields are converted into vendor[13] array to keep its value. And vendor property setter is used to access/set value on CPU. - Make for() cycle reusable for the next patch by adding x86_cpu_vendor_words2str() Intel's CPUID spec[1] says: " 5.1.1 ... These registers contain the ASCII string: GenuineIntel ... " List[2] of known vendor values shows that they all are 12 ASCII characters long, padded where necessary with space. Current supported values are all ASCII characters packed in ebx, edx, ecx. So lets state that QEMU supports 12 printable ASCII characters packed in ebx, edx, ecx registers for cpuid(0) instruction. *1 - http://www.intel.com/Assets/PDF/appnote/241618.pdf *2 - http://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 147 ++++++++++++++-------------------------------- target-i386/cpu.h | 6 +- 2 files changed, 47 insertions(+), 106 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b75ea9fc8f..043a21dcd7 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -47,6 +47,18 @@ #include "hw/apic_internal.h" #endif +static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + uint32_t vendor2, uint32_t vendor3) +{ + int i; + for (i = 0; i < 4; i++) { + dst[i] = vendor1 >> (8 * i); + dst[i + 4] = vendor2 >> (8 * i); + dst[i + 8] = vendor3 >> (8 * i); + } + dst[CPUID_VENDOR_SZ] = '\0'; +} + /* feature flags taken from "Intel Processor Identification and the CPUID * Instruction" and AMD's "CPUID Specification". In cases of disagreement * between feature naming conventions, aliases may be added. @@ -337,7 +349,8 @@ static void add_flagname_to_bitmaps(const char *flagname, typedef struct x86_def_t { const char *name; uint32_t level; - uint32_t vendor1, vendor2, vendor3; + /* vendor is zero-terminated, 12 character ASCII string */ + char vendor[CPUID_VENDOR_SZ + 1]; int family; int model; int stepping; @@ -398,9 +411,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "qemu64", .level = 4, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 6, .model = 2, .stepping = 3, @@ -417,9 +428,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "phenom", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 16, .model = 2, .stepping = 3, @@ -445,9 +454,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "core2duo", .level = 10, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 15, .stepping = 11, @@ -466,9 +473,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "kvm64", .level = 5, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 15, .model = 6, .stepping = 1, @@ -492,9 +497,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "qemu32", .level = 4, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 3, .stepping = 3, @@ -505,9 +508,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "kvm32", .level = 5, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 15, .model = 6, .stepping = 1, @@ -522,9 +523,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "coreduo", .level = 10, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 14, .stepping = 8, @@ -540,9 +539,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "486", .level = 1, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 4, .model = 0, .stepping = 0, @@ -552,9 +549,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium", .level = 1, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 5, .model = 4, .stepping = 3, @@ -564,9 +559,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium2", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 5, .stepping = 2, @@ -576,9 +569,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium3", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 7, .stepping = 3, @@ -588,9 +579,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "athlon", .level = 2, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 6, .model = 2, .stepping = 3, @@ -604,9 +593,7 @@ static x86_def_t builtin_x86_defs[] = { .name = "n270", /* original is on level 10 */ .level = 5, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 28, .stepping = 2, @@ -625,9 +612,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Conroe", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 2, .stepping = 3, @@ -645,9 +630,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Penryn", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 2, .stepping = 3, @@ -666,9 +649,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Nehalem", .level = 2, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 2, .stepping = 3, @@ -687,9 +668,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Westmere", .level = 11, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 44, .stepping = 1, @@ -709,9 +688,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "SandyBridge", .level = 0xd, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 42, .stepping = 1, @@ -734,9 +711,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Haswell", .level = 0xd, - .vendor1 = CPUID_VENDOR_INTEL_1, - .vendor2 = CPUID_VENDOR_INTEL_2, - .vendor3 = CPUID_VENDOR_INTEL_3, + .vendor = CPUID_VENDOR_INTEL, .family = 6, .model = 60, .stepping = 1, @@ -764,9 +739,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G1", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 15, .model = 6, .stepping = 1, @@ -788,9 +761,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G2", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 15, .model = 6, .stepping = 1, @@ -814,9 +785,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G3", .level = 5, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 15, .model = 6, .stepping = 1, @@ -842,9 +811,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G4", .level = 0xd, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 21, .model = 1, .stepping = 2, @@ -874,9 +841,7 @@ static x86_def_t builtin_x86_defs[] = { { .name = "Opteron_G5", .level = 0xd, - .vendor1 = CPUID_VENDOR_AMD_1, - .vendor2 = CPUID_VENDOR_AMD_2, - .vendor3 = CPUID_VENDOR_AMD_3, + .vendor = CPUID_VENDOR_AMD, .family = 21, .model = 2, .stepping = 0, @@ -937,9 +902,7 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) x86_cpu_def->name = "host"; host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); - x86_cpu_def->vendor1 = ebx; - x86_cpu_def->vendor2 = edx; - x86_cpu_def->vendor3 = ecx; + x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx); host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); @@ -967,9 +930,7 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) x86_cpu_def->vendor_override = 0; /* Call Centaur's CPUID instruction. */ - if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 && - x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 && - x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) { + if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) { host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx); eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); if (eax >= 0xC0000001) { @@ -1205,15 +1166,10 @@ static char *x86_cpuid_get_vendor(Object *obj, Error **errp) X86CPU *cpu = X86_CPU(obj); CPUX86State *env = &cpu->env; char *value; - int i; value = (char *)g_malloc(CPUID_VENDOR_SZ + 1); - for (i = 0; i < 4; i++) { - value[i ] = env->cpuid_vendor1 >> (8 * i); - value[i + 4] = env->cpuid_vendor2 >> (8 * i); - value[i + 8] = env->cpuid_vendor3 >> (8 * i); - } - value[CPUID_VENDOR_SZ] = '\0'; + x86_cpu_vendor_words2str(value, env->cpuid_vendor1, env->cpuid_vendor2, + env->cpuid_vendor3); return value; } @@ -1337,7 +1293,6 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) */ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) { - unsigned int i; char *featurestr; /* Single 'key=value" string being parsed */ /* Features to be added */ FeatureWordArray plus_features = { 0 }; @@ -1401,18 +1356,7 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } x86_cpu_def->xlevel = numvalue; } else if (!strcmp(featurestr, "vendor")) { - if (strlen(val) != 12) { - fprintf(stderr, "vendor string must be 12 chars long\n"); - goto error; - } - x86_cpu_def->vendor1 = 0; - x86_cpu_def->vendor2 = 0; - x86_cpu_def->vendor3 = 0; - for(i = 0; i < 4; i++) { - x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i); - x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i); - x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i); - } + pstrcpy(x86_cpu_def->vendor, sizeof(x86_cpu_def->vendor), val); x86_cpu_def->vendor_override = 1; } else if (!strcmp(featurestr, "model_id")) { pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), @@ -1613,10 +1557,7 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) error_setg(&error, "Invalid cpu_model string format: %s", cpu_model); goto out; } - assert(def->vendor1); - env->cpuid_vendor1 = def->vendor1; - env->cpuid_vendor2 = def->vendor2; - env->cpuid_vendor3 = def->vendor3; + object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error); env->cpuid_vendor_override = def->vendor_override; object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 27efe59488..3833e6f019 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -537,14 +537,14 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */ #define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */ #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */ +#define CPUID_VENDOR_INTEL "GenuineIntel" #define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */ #define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */ #define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */ +#define CPUID_VENDOR_AMD "AuthenticAMD" -#define CPUID_VENDOR_VIA_1 0x746e6543 /* "Cent" */ -#define CPUID_VENDOR_VIA_2 0x48727561 /* "aurH" */ -#define CPUID_VENDOR_VIA_3 0x736c7561 /* "auls" */ +#define CPUID_VENDOR_VIA "CentaurHauls" #define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */ From 11acfdd5a1647895ff9094e7f93f3317224eb4d8 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:37 +0100 Subject: [PATCH 0727/1634] target-i386: Remove vendor_override field from CPUX86State MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 8935499831312 makes cpuid return to guest host's vendor value instead of built-in one by default if kvm_enabled() == true and allows to override this behavior if 'vendor' is specified on -cpu command line. But every time guest calls cpuid to get 'vendor' value, host's value is read again and again in default case. It complicates semantics of vendor property and makes it harder to use. Instead of reading 'vendor' value from host every time cpuid[vendor] is called, override 'vendor' value only once in cpu_x86_find_by_name(), when built-in CPU model is found and if(kvm_enabled() == true). It provides the same default semantics if (kvm_enabled() == true) vendor = host's vendor else vendor = built-in vendor and then later: if (custom vendor) vendor = custom vendor 'vendor' value is overridden when user provides it on -cpu command line, and there is no need for vendor_override field anymore, remove it. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 27 ++++++++++++--------------- target-i386/cpu.h | 1 - 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 043a21dcd7..b11fe30f37 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -359,7 +359,6 @@ typedef struct x86_def_t { uint32_t kvm_features, svm_features; uint32_t xlevel; char model_id[48]; - int vendor_override; /* Store the results of Centaur's CPUID instructions */ uint32_t ext4_features; uint32_t xlevel2; @@ -927,7 +926,6 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX); cpu_x86_fill_model_id(x86_cpu_def->model_id); - x86_cpu_def->vendor_override = 0; /* Call Centaur's CPUID instruction. */ if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) { @@ -1194,7 +1192,6 @@ static void x86_cpuid_set_vendor(Object *obj, const char *value, env->cpuid_vendor2 |= ((uint8_t)value[i + 4]) << (8 * i); env->cpuid_vendor3 |= ((uint8_t)value[i + 8]) << (8 * i); } - env->cpuid_vendor_override = 1; } static char *x86_cpuid_get_model_id(Object *obj, Error **errp) @@ -1282,6 +1279,18 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) def = &builtin_x86_defs[i]; if (strcmp(name, def->name) == 0) { memcpy(x86_cpu_def, def, sizeof(*def)); + /* sysenter isn't supported in compatibility mode on AMD, + * syscall isn't supported in compatibility mode on Intel. + * Normally we advertise the actual CPU vendor, but you can + * override this using the 'vendor' property if you want to use + * KVM's sysenter/syscall emulation in compatibility mode and + * when doing cross vendor migration + */ + if (kvm_enabled()) { + uint32_t ebx = 0, ecx = 0, edx = 0; + host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx); + } return 0; } } @@ -1357,7 +1366,6 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) x86_cpu_def->xlevel = numvalue; } else if (!strcmp(featurestr, "vendor")) { pstrcpy(x86_cpu_def->vendor, sizeof(x86_cpu_def->vendor), val); - x86_cpu_def->vendor_override = 1; } else if (!strcmp(featurestr, "model_id")) { pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), val); @@ -1558,7 +1566,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) goto out; } object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error); - env->cpuid_vendor_override = def->vendor_override; object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); object_property_set_int(OBJECT(cpu), def->model, "model", &error); @@ -1627,16 +1634,6 @@ static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx, *ebx = env->cpuid_vendor1; *edx = env->cpuid_vendor2; *ecx = env->cpuid_vendor3; - - /* sysenter isn't supported on compatibility mode on AMD, syscall - * isn't supported in compatibility mode on Intel. - * Normally we advertise the actual cpu vendor, but you can override - * this if you want to use KVM's sysenter/syscall emulation - * in compatibility mode and when doing cross vendor migration - */ - if (kvm_enabled() && ! env->cpuid_vendor_override) { - host_cpuid(0, 0, NULL, ebx, ecx, edx); - } } void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 3833e6f019..62508dc688 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -835,7 +835,6 @@ typedef struct CPUX86State { uint32_t cpuid_ext2_features; uint32_t cpuid_ext3_features; uint32_t cpuid_apic_id; - int cpuid_vendor_override; /* Store the results of Centaur's CPUID instructions */ uint32_t cpuid_xlevel2; uint32_t cpuid_ext4_features; From a91987c25db38834091174681a6e1ffcbe582182 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:38 +0100 Subject: [PATCH 0728/1634] target-i386: Set custom features/properties without intermediate x86_def_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move custom features parsing after built-in cpu_model defaults are set and set custom features directly on CPU instance. That allows to make a clear distinction between built-in cpu model defaults that eventually should go into class_init() and extra property setting which is done after defaults are set on CPU instance. Impl. details: * use object_property_parse() property setter so it would be a mechanical change to switch to global properties later. * And after all current features/properties are converted into static properties, it will take a trivial patch to switch to global properties. Which will allow to: * get CPU instance initialized with all parameters passed on -cpu ... cmd. line from object_new() call. * call cpu_model/featurestr parsing only once before CPUs are created * open a road for removing CPUxxxState.cpu_model_str field, when other CPUs are similarly converted to subclasses and static properties. - re-factor error handling, to use Error instead of fprintf()s, since it is anyway passed in for property setter. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 118 ++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 67 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b11fe30f37..117b8b02db 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1300,7 +1300,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) /* Parse "+feature,-feature,feature=foo" CPU feature string */ -static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) +static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) { char *featurestr; /* Single 'key=value" string being parsed */ /* Features to be added */ @@ -1308,6 +1308,7 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) /* Features to be removed */ FeatureWordArray minus_features = { 0 }; uint32_t numvalue; + CPUX86State *env = &cpu->env; featurestr = features ? strtok(features, ",") : NULL; @@ -1320,77 +1321,57 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } else if ((val = strchr(featurestr, '='))) { *val = 0; val++; if (!strcmp(featurestr, "family")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err || numvalue > 0xff + 0xf) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->family = numvalue; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "model")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err || numvalue > 0xff) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->model = numvalue; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "stepping")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err || numvalue > 0xf) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->stepping = numvalue ; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "level")) { - char *err; - numvalue = strtoul(val, &err, 0); - if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; - } - x86_cpu_def->level = numvalue; + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "xlevel")) { char *err; + char num[32]; + numvalue = strtoul(val, &err, 0); if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; + error_setg(errp, "bad numerical value %s\n", val); + goto out; } if (numvalue < 0x80000000) { fprintf(stderr, "xlevel value shall always be >= 0x80000000" ", fixup will be removed in future versions\n"); numvalue += 0x80000000; } - x86_cpu_def->xlevel = numvalue; + snprintf(num, sizeof(num), "%" PRIu32, numvalue); + object_property_parse(OBJECT(cpu), num, featurestr, errp); } else if (!strcmp(featurestr, "vendor")) { - pstrcpy(x86_cpu_def->vendor, sizeof(x86_cpu_def->vendor), val); + object_property_parse(OBJECT(cpu), val, featurestr, errp); } else if (!strcmp(featurestr, "model_id")) { - pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), - val); + object_property_parse(OBJECT(cpu), val, "model-id", errp); } else if (!strcmp(featurestr, "tsc_freq")) { int64_t tsc_freq; char *err; + char num[32]; tsc_freq = strtosz_suffix_unit(val, &err, STRTOSZ_DEFSUFFIX_B, 1000); if (tsc_freq < 0 || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; + error_setg(errp, "bad numerical value %s\n", val); + goto out; } - x86_cpu_def->tsc_khz = tsc_freq / 1000; + snprintf(num, sizeof(num), "%" PRId64, tsc_freq); + object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp); } else if (!strcmp(featurestr, "hv_spinlocks")) { char *err; numvalue = strtoul(val, &err, 0); if (!*val || *err) { - fprintf(stderr, "bad numerical value %s\n", val); - goto error; + error_setg(errp, "bad numerical value %s\n", val); + goto out; } hyperv_set_spinlock_retries(numvalue); } else { - fprintf(stderr, "unrecognized feature %s\n", featurestr); - goto error; + error_setg(errp, "unrecognized feature %s\n", featurestr); + goto out; } } else if (!strcmp(featurestr, "check")) { check_cpuid = 1; @@ -1401,31 +1382,34 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features) } else if (!strcmp(featurestr, "hv_vapic")) { hyperv_enable_vapic_recommended(true); } else { - fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); - goto error; + error_setg(errp, "feature string `%s' not in format (+feature|" + "-feature|feature=xyz)\n", featurestr); + goto out; + } + if (error_is_set(errp)) { + goto out; } featurestr = strtok(NULL, ","); } - x86_cpu_def->features |= plus_features[FEAT_1_EDX]; - x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX]; - x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX]; - x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX]; - x86_cpu_def->ext4_features |= plus_features[FEAT_C000_0001_EDX]; - x86_cpu_def->kvm_features |= plus_features[FEAT_KVM]; - x86_cpu_def->svm_features |= plus_features[FEAT_SVM]; - x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; - x86_cpu_def->features &= ~minus_features[FEAT_1_EDX]; - x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX]; - x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; - x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; - x86_cpu_def->ext4_features &= ~minus_features[FEAT_C000_0001_EDX]; - x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM]; - x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM]; - x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; - return 0; + env->cpuid_features |= plus_features[FEAT_1_EDX]; + env->cpuid_ext_features |= plus_features[FEAT_1_ECX]; + env->cpuid_ext2_features |= plus_features[FEAT_8000_0001_EDX]; + env->cpuid_ext3_features |= plus_features[FEAT_8000_0001_ECX]; + env->cpuid_ext4_features |= plus_features[FEAT_C000_0001_EDX]; + env->cpuid_kvm_features |= plus_features[FEAT_KVM]; + env->cpuid_svm_features |= plus_features[FEAT_SVM]; + env->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; + env->cpuid_features &= ~minus_features[FEAT_1_EDX]; + env->cpuid_ext_features &= ~minus_features[FEAT_1_ECX]; + env->cpuid_ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; + env->cpuid_ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; + env->cpuid_ext4_features &= ~minus_features[FEAT_C000_0001_EDX]; + env->cpuid_kvm_features &= ~minus_features[FEAT_KVM]; + env->cpuid_svm_features &= ~minus_features[FEAT_SVM]; + env->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; -error: - return -1; +out: + return; } /* generate a composite string into buf of all cpuid names in featureset @@ -1561,10 +1545,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) } def->ext_features |= CPUID_EXT_HYPERVISOR; - if (cpu_x86_parse_featurestr(def, features) < 0) { - error_setg(&error, "Invalid cpu_model string format: %s", cpu_model); - goto out; - } object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error); object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); @@ -1584,7 +1564,11 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) "tsc-frequency", &error); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); + if (error) { + goto out; + } + cpu_x86_parse_featurestr(cpu, features, &error); out: g_strfreev(model_pieces); if (error) { From 2c728dfef56d468a6a80b4dacdfb7109220d2546 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 21 Jan 2013 15:06:39 +0100 Subject: [PATCH 0729/1634] target-i386: Remove setting tsc-frequency from x86_def_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setting tsc-frequency from x86_def_t is NOP because default tsc_khz in x86_def_t is 0 and CPUX86State.tsc_khz is also initialized to 0 by default. So there is no need to overwrite tsc_khz with default 0 because field was already initialized to 0. Custom tsc-frequency setting is not affected due to it being set without using x86_def_t. Field tsc_khz in x86_def_t becomes unused with this patch, so drop it as well. Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 117b8b02db..5c108e17ab 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -354,7 +354,6 @@ typedef struct x86_def_t { int family; int model; int stepping; - int tsc_khz; uint32_t features, ext_features, ext2_features, ext3_features; uint32_t kvm_features, svm_features; uint32_t xlevel; @@ -1560,8 +1559,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) env->cpuid_ext4_features = def->ext4_features; env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features; env->cpuid_xlevel2 = def->xlevel2; - object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000, - "tsc-frequency", &error); object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); if (error) { From 2b8c27549917b3e07fec5807dbd2b6528ceb4efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 18:26:21 +0100 Subject: [PATCH 0730/1634] cpu: Add model resolution support to CPUClass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce CPUClass::class_by_name and add a default implementation. Hook up the alpha and ppc implementations. Introduce a wrapper function cpu_class_by_name(). Signed-off-by: Andreas Färber --- include/qom/cpu.h | 15 +++++++++++++++ qom/cpu.c | 13 +++++++++++++ target-alpha/cpu.c | 8 ++++++++ target-ppc/translate_init.c | 2 ++ 4 files changed, 38 insertions(+) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 773caf9fa1..8097692bde 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -40,6 +40,8 @@ typedef struct CPUState CPUState; /** * CPUClass: + * @class_by_name: Callback to map -cpu command line model name to an + * instantiatable CPU type. * @reset: Callback to reset the #CPUState to its initial state. * * Represents a CPU family or model. @@ -49,6 +51,8 @@ typedef struct CPUClass { DeviceClass parent_class; /*< public >*/ + ObjectClass *(*class_by_name)(const char *cpu_model); + void (*reset)(CPUState *cpu); } CPUClass; @@ -107,6 +111,17 @@ struct CPUState { */ void cpu_reset(CPUState *cpu); +/** + * cpu_class_by_name: + * @typename: The CPU base type. + * @cpu_model: The model string without any parameters. + * + * Looks up a CPU #ObjectClass matching name @cpu_model. + * + * Returns: A #CPUClass or %NULL if not matching class is found. + */ +ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model); + /** * qemu_cpu_has_work: * @cpu: The vCPU to check. diff --git a/qom/cpu.c b/qom/cpu.c index 49e5134ea1..8fb538bf3b 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -34,11 +34,24 @@ static void cpu_common_reset(CPUState *cpu) { } +ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) +{ + CPUClass *cc = CPU_CLASS(object_class_by_name(typename)); + + return cc->class_by_name(cpu_model); +} + +static ObjectClass *cpu_common_class_by_name(const char *cpu_model) +{ + return NULL; +} + static void cpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); CPUClass *k = CPU_CLASS(klass); + k->class_by_name = cpu_common_class_by_name; k->reset = cpu_common_reset; dc->no_user = 1; } diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 40e980933f..3ac0fde2cd 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -244,6 +244,13 @@ static void alpha_cpu_initfn(Object *obj) env->fen = 1; } +static void alpha_cpu_class_init(ObjectClass *oc, void *data) +{ + CPUClass *cc = CPU_CLASS(oc); + + cc->class_by_name = alpha_cpu_class_by_name; +} + static const TypeInfo alpha_cpu_type_info = { .name = TYPE_ALPHA_CPU, .parent = TYPE_CPU, @@ -251,6 +258,7 @@ static const TypeInfo alpha_cpu_type_info = { .instance_init = alpha_cpu_initfn, .abstract = true, .class_size = sizeof(AlphaCPUClass), + .class_init = alpha_cpu_class_init, }; static void alpha_cpu_register_types(void) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4f767c9751..e143af532a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10578,6 +10578,8 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) pcc->parent_reset = cc->reset; cc->reset = ppc_cpu_reset; + + cc->class_by_name = ppc_cpu_class_by_name; } static const TypeInfo ppc_cpu_type_info = { From 5900d6b2d59875c9b11e4d8cead6d9ddaa9eb787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 16:11:43 +0100 Subject: [PATCH 0731/1634] target-arm: Detect attempt to instantiate non-CPU type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate model checking into a new arm_cpu_class_by_name(). If the name matches an existing type, also check whether that type is actually (a sub-type of) TYPE_ARM_CPU. This fixes, e.g., -cpu tmp105 asserting. Cc: qemu-stable Acked-by: Peter Maydell Signed-off-by: Andreas Färber --- target-arm/cpu.c | 17 +++++++++++++++++ target-arm/helper.c | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 07588a13b2..57126b6855 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -201,6 +201,21 @@ void arm_cpu_realize(ARMCPU *cpu) /* CPU models */ +static ObjectClass *arm_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + if (!cpu_model) { + return NULL; + } + + oc = object_class_by_name(cpu_model); + if (!oc || !object_class_dynamic_cast(oc, TYPE_ARM_CPU)) { + return NULL; + } + return oc; +} + static void arm926_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -766,6 +781,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) acc->parent_reset = cc->reset; cc->reset = arm_cpu_reset; + + cc->class_by_name = arm_cpu_class_by_name; } static void cpu_register(const ARMCPUInfo *info) diff --git a/target-arm/helper.c b/target-arm/helper.c index 37c34a11c4..7a10fddf25 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1262,12 +1262,14 @@ ARMCPU *cpu_arm_init(const char *cpu_model) { ARMCPU *cpu; CPUARMState *env; + ObjectClass *oc; static int inited = 0; - if (!object_class_by_name(cpu_model)) { + oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); + if (!oc) { return NULL; } - cpu = ARM_CPU(object_new(cpu_model)); + cpu = ARM_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; env->cpu_model_str = cpu_model; arm_cpu_realize(cpu); From 0e44a02301b081d36e686e767694a770c25160a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 17:27:54 +0100 Subject: [PATCH 0732/1634] target-alpha: Detect attempt to instantiate non-CPU type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check in alpha_cpu_class_by_name() whether the type found is actually (a sub-type of) TYPE_ALPHA_CPU. This fixes, e.g., -cpu typhoon-pcihost asserting. Signed-off-by: Andreas Färber --- target-alpha/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 3ac0fde2cd..0d6975ea9b 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -96,7 +96,7 @@ static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model) } oc = object_class_by_name(cpu_model); - if (oc != NULL) { + if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL) { return oc; } From bc5b2da32ba54d991e8669b14a771afb3a67f408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 21 Jan 2013 17:50:15 +0100 Subject: [PATCH 0733/1634] target-m68k: Detect attempt to instantiate non-CPU type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate model checking into a new m68k_cpu_class_by_name(). If the name matches an existing type, also check whether that type is (a sub-type of) TYPE_M68K_CPU. This fixes, e.g., -cpu ide-hd asserting. Signed-off-by: Andreas Färber --- target-m68k/cpu.c | 17 +++++++++++++++++ target-m68k/helper.c | 6 ++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index ce89674a08..b231d9ad38 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -55,6 +55,21 @@ static void m68k_cpu_reset(CPUState *s) /* CPU models */ +static ObjectClass *m68k_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + if (cpu_model == NULL) { + return NULL; + } + + oc = object_class_by_name(cpu_model); + if (oc != NULL && object_class_dynamic_cast(oc, TYPE_M68K_CPU) == NULL) { + return NULL; + } + return oc; +} + static void m5206_cpu_initfn(Object *obj) { M68kCPU *cpu = M68K_CPU(obj); @@ -134,6 +149,8 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) mcc->parent_reset = cc->reset; cc->reset = m68k_cpu_reset; + + cc->class_by_name = m68k_cpu_class_by_name; } static void register_cpu_type(const M68kCPUInfo *info) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 097fc789d4..f66e12b6ba 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -97,12 +97,14 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model) { M68kCPU *cpu; CPUM68KState *env; + ObjectClass *oc; static int inited; - if (object_class_by_name(cpu_model) == NULL) { + oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model); + if (oc == NULL) { return NULL; } - cpu = M68K_CPU(object_new(cpu_model)); + cpu = M68K_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; if (!inited) { From bd039ce0094f3724a87a193c846ee8468ce652b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 11:17:14 +0100 Subject: [PATCH 0734/1634] target-openrisc: Detect attempt to instantiate non-CPU type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate model checking into a new openrisc_cpu_class_by_name(). If the name matches an existing type, also check whether that type is actually (a sub-type of) TYPE_OPENRISC_CPU. This fixes, e.g., -cpu open_eth asserting. Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber --- target-openrisc/cpu.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 7a55112bf1..e23100fa09 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -88,6 +88,22 @@ static void openrisc_cpu_initfn(Object *obj) } /* CPU models */ + +static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + if (cpu_model == NULL) { + return NULL; + } + + oc = object_class_by_name(cpu_model); + if (oc != NULL && !object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU)) { + return NULL; + } + return oc; +} + static void or1200_initfn(Object *obj) { OpenRISCCPU *cpu = OPENRISC_CPU(obj); @@ -120,6 +136,8 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) occ->parent_reset = cc->reset; cc->reset = openrisc_cpu_reset; + + cc->class_by_name = openrisc_cpu_class_by_name; } static void cpu_register(const OpenRISCCPUInfo *info) @@ -158,11 +176,13 @@ static void openrisc_cpu_register_types(void) OpenRISCCPU *cpu_openrisc_init(const char *cpu_model) { OpenRISCCPU *cpu; + ObjectClass *oc; - if (!object_class_by_name(cpu_model)) { + oc = openrisc_cpu_class_by_name(cpu_model); + if (oc == NULL) { return NULL; } - cpu = OPENRISC_CPU(object_new(cpu_model)); + cpu = OPENRISC_CPU(object_new(object_class_get_name(oc))); cpu->env.cpu_model_str = cpu_model; openrisc_cpu_realize(OBJECT(cpu), NULL); From 98aca3c8e8778745cdd0670a792a41314115afa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 26 May 2012 19:14:52 +0200 Subject: [PATCH 0735/1634] prep_pci: Create PCIBus and PCIDevice in-place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares for QOM realizefn by removing object creation from qdev initfn. Signed-off-by: Andreas Färber --- hw/prep_pci.c | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 212a2ac4f1..e1420cac39 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -2,6 +2,7 @@ * QEMU PREP PCI host * * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2011-2013 Andreas Färber * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,12 +25,21 @@ #include "hw.h" #include "pci/pci.h" +#include "pci/pci_bus.h" #include "pci/pci_host.h" #include "pc.h" #include "exec/address-spaces.h" +#define TYPE_RAVEN_PCI_DEVICE "raven" #define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost" +#define RAVEN_PCI_DEVICE(obj) \ + OBJECT_CHECK(RavenPCIState, (obj), TYPE_RAVEN_PCI_DEVICE) + +typedef struct RavenPCIState { + PCIDevice dev; +} RavenPCIState; + #define RAVEN_PCI_HOST_BRIDGE(obj) \ OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE) @@ -38,12 +48,10 @@ typedef struct PRePPCIState { MemoryRegion intack; qemu_irq irq[4]; + PCIBus pci_bus; + RavenPCIState pci_dev; } PREPPCIState; -typedef struct RavenPCIState { - PCIDevice dev; -} RavenPCIState; - static inline uint32_t PPC_PCIIO_config(hwaddr addr) { int i; @@ -108,18 +116,13 @@ static int raven_pcihost_init(SysBusDevice *dev) PCIHostState *h = PCI_HOST_BRIDGE(dev); PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev); MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *address_space_io = get_system_io(); - PCIBus *bus; int i; for (i = 0; i < 4; i++) { sysbus_init_irq(dev, &s->irq[i]); } - bus = pci_register_bus(DEVICE(dev), NULL, - prep_set_irq, prep_map_irq, s->irq, - address_space_mem, address_space_io, 0, 4); - h->bus = bus; + pci_bus_irqs(&s->pci_bus, prep_set_irq, prep_map_irq, s->irq, 4); memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, s, "pci-conf-idx", 1); @@ -136,9 +139,29 @@ static int raven_pcihost_init(SysBusDevice *dev) memory_region_init_io(&s->intack, &PPC_intack_ops, s, "pci-intack", 1); memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->intack); - pci_create_simple(bus, 0, "raven"); - return 0; + /* TODO Remove once realize propagates to child devices. */ + return qdev_init(DEVICE(&s->pci_dev)); +} + +static void raven_pcihost_initfn(Object *obj) +{ + PCIHostState *h = PCI_HOST_BRIDGE(obj); + PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj); + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *address_space_io = get_system_io(); + DeviceState *pci_dev; + + pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), NULL, + address_space_mem, address_space_io, 0); + h->bus = &s->pci_bus; + + object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE); + pci_dev = DEVICE(&s->pci_dev); + qdev_set_parent_bus(pci_dev, BUS(&s->pci_bus)); + object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(0, 0), "addr", + NULL); + qdev_prop_set_bit(pci_dev, "multifunction", false); } static int raven_init(PCIDevice *d) @@ -176,7 +199,7 @@ static void raven_class_init(ObjectClass *klass, void *data) } static const TypeInfo raven_info = { - .name = "raven", + .name = TYPE_RAVEN_PCI_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(RavenPCIState), .class_init = raven_class_init, @@ -196,6 +219,7 @@ static const TypeInfo raven_pcihost_info = { .name = TYPE_RAVEN_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(PREPPCIState), + .instance_init = raven_pcihost_initfn, .class_init = raven_pcihost_class_init, }; From 8d5ce2e5643f4055b67ea012d91e812f1e607a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 15:45:34 +0100 Subject: [PATCH 0736/1634] prep_pci: Convert to QOM realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SysBusDeviceClass' initfn merely calls SysBusDeviceClass::init, so we can already hook up our own realizefn overwriting this behavior. A symmetric unrealizefn is not necessary, knowing that the child's unrealizefn is still no-op, too. Avoids ripping it out again when recursive realization at DeviceState-level is implemented. Signed-off-by: Andreas Färber --- hw/prep_pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/prep_pci.c b/hw/prep_pci.c index e1420cac39..52ee5d9401 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -111,8 +111,9 @@ static void prep_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num] , level); } -static int raven_pcihost_init(SysBusDevice *dev) +static void raven_pcihost_realizefn(DeviceState *d, Error **errp) { + SysBusDevice *dev = SYS_BUS_DEVICE(d); PCIHostState *h = PCI_HOST_BRIDGE(dev); PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev); MemoryRegion *address_space_mem = get_system_memory(); @@ -141,7 +142,7 @@ static int raven_pcihost_init(SysBusDevice *dev) memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->intack); /* TODO Remove once realize propagates to child devices. */ - return qdev_init(DEVICE(&s->pci_dev)); + object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); } static void raven_pcihost_initfn(Object *obj) @@ -207,10 +208,9 @@ static const TypeInfo raven_info = { static void raven_pcihost_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->init = raven_pcihost_init; + dc->realize = raven_pcihost_realizefn; dc->fw_name = "pci"; dc->no_user = 1; } From d89e12188d50f7f8a894027789f32fa7ba6226ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:07:17 +0100 Subject: [PATCH 0737/1634] target-unicore32: Detect attempt to instantiate non-CPU type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate model checking into a new uc32_cpu_class_by_name(). If the name matches an existing type, also check whether that type is actually (a sub-type of) TYPE_UNICORE32_CPU. This fixes, e.g., -cpu puv3_dma asserting. Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber --- target-unicore32/cpu.c | 23 +++++++++++++++++++++++ target-unicore32/helper.c | 6 ++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 884c101010..9239d49511 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -22,6 +22,21 @@ static inline void set_feature(CPUUniCore32State *env, int feature) /* CPU models */ +static ObjectClass *uc32_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + if (cpu_model == NULL) { + return NULL; + } + + oc = object_class_by_name(cpu_model); + if (oc != NULL && !object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU)) { + oc = NULL; + } + return oc; +} + typedef struct UniCore32CPUInfo { const char *name; void (*instance_init)(Object *obj); @@ -80,6 +95,13 @@ static void uc32_cpu_initfn(Object *obj) tlb_flush(env, 1); } +static void uc32_cpu_class_init(ObjectClass *oc, void *data) +{ + CPUClass *cc = CPU_CLASS(oc); + + cc->class_by_name = uc32_cpu_class_by_name; +} + static void uc32_register_cpu_type(const UniCore32CPUInfo *info) { TypeInfo type_info = { @@ -98,6 +120,7 @@ static const TypeInfo uc32_cpu_type_info = { .instance_init = uc32_cpu_initfn, .abstract = true, .class_size = sizeof(UniCore32CPUClass), + .class_init = uc32_cpu_class_init, }; static void uc32_cpu_register_types(void) diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index 5359538ea5..183b5b3577 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -29,12 +29,14 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model) { UniCore32CPU *cpu; CPUUniCore32State *env; + ObjectClass *oc; static int inited = 1; - if (object_class_by_name(cpu_model) == NULL) { + oc = cpu_class_by_name(TYPE_UNICORE32_CPU, cpu_model); + if (oc == NULL) { return NULL; } - cpu = UNICORE32_CPU(object_new(cpu_model)); + cpu = UNICORE32_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; if (inited) { From 178623789465287624c48f7ef12d0ab83a1dc380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:20:18 +0100 Subject: [PATCH 0738/1634] qom: Introduce object_class_is_abstract() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This lets a caller check if an ObjectClass as returned by, e.g., object_class_by_name() is instantiatable. Signed-off-by: Andreas Färber Cc: Anthony Liguori --- include/qom/object.h | 8 ++++++++ qom/object.c | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index 8e16ea8a44..48e80ba229 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -690,6 +690,14 @@ ObjectClass *object_class_get_parent(ObjectClass *klass); */ const char *object_class_get_name(ObjectClass *klass); +/** + * object_class_is_abstract: + * @klass: The class to obtain the abstractness for. + * + * Returns: %true if @klass is abstract, %false otherwise. + */ +bool object_class_is_abstract(ObjectClass *klass); + /** * object_class_by_name: * @typename: The QOM typename to obtain the class for. diff --git a/qom/object.c b/qom/object.c index 03e6f24d28..e200282172 100644 --- a/qom/object.c +++ b/qom/object.c @@ -501,6 +501,11 @@ ObjectClass *object_get_class(Object *obj) return obj->class; } +bool object_class_is_abstract(ObjectClass *klass) +{ + return klass->type->abstract; +} + const char *object_class_get_name(ObjectClass *klass) { return klass->type->name; From a120c287086e0b03a57f1f4ac7d7aa73fe3d1fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:28:22 +0100 Subject: [PATCH 0739/1634] target-alpha: Catch attempt to instantiate abstract type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes -cpu alpha-cpu asserting. Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber --- target-alpha/cpu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 0d6975ea9b..0ad69f0859 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -96,14 +96,15 @@ static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model) } oc = object_class_by_name(cpu_model); - if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL) { + if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL && + !object_class_is_abstract(oc)) { return oc; } for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) { if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) { oc = object_class_by_name(alpha_cpu_aliases[i].typename); - assert(oc != NULL); + assert(oc != NULL && !object_class_is_abstract(oc)); return oc; } } @@ -111,6 +112,9 @@ static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model) typename = g_strdup_printf("%s-" TYPE_ALPHA_CPU, cpu_model); oc = object_class_by_name(typename); g_free(typename); + if (oc != NULL && object_class_is_abstract(oc)) { + oc = NULL; + } return oc; } From 245fb54db5f8c88c9d73e037178bc3ca1f9a4bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:32:49 +0100 Subject: [PATCH 0740/1634] target-arm: Catch attempt to instantiate abstract type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes -cpu arm-cpu asserting. Cc: qemu-stable@nongnu.org Acked-by: Peter Maydell Signed-off-by: Andreas Färber --- target-arm/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 57126b6855..d1a4c82680 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -210,7 +210,8 @@ static ObjectClass *arm_cpu_class_by_name(const char *cpu_model) } oc = object_class_by_name(cpu_model); - if (!oc || !object_class_dynamic_cast(oc, TYPE_ARM_CPU)) { + if (!oc || !object_class_dynamic_cast(oc, TYPE_ARM_CPU) || + object_class_is_abstract(oc)) { return NULL; } return oc; From cae85065a44b731467dc6a5caee7cfc6d26d9ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:36:31 +0100 Subject: [PATCH 0741/1634] target-m68k: Catch attempt to instantiate abstract type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes -cpu m68k-cpu asserting. Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber --- target-m68k/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index b231d9ad38..e6df1eef58 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -64,7 +64,8 @@ static ObjectClass *m68k_cpu_class_by_name(const char *cpu_model) } oc = object_class_by_name(cpu_model); - if (oc != NULL && object_class_dynamic_cast(oc, TYPE_M68K_CPU) == NULL) { + if (oc != NULL && (object_class_dynamic_cast(oc, TYPE_M68K_CPU) == NULL || + object_class_is_abstract(oc))) { return NULL; } return oc; From c432b7840cfbc35fc0d097428d0a2f2a94983360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:39:38 +0100 Subject: [PATCH 0742/1634] target-openrisc: Catch attempt to instantiate abstract type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no abstract OpenRISCCPU yet, but that seems a bug of its own. Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber --- target-openrisc/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index e23100fa09..adc03ef779 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -98,7 +98,8 @@ static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model) } oc = object_class_by_name(cpu_model); - if (oc != NULL && !object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU)) { + if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU) || + object_class_is_abstract(oc))) { return NULL; } return oc; From 4933908ac5974252c1830d69e9493fa79c5ea606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:41:38 +0100 Subject: [PATCH 0743/1634] target-unicore32: Catch attempt to instantiate abstract type in cpu_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes -cpu unicore32-cpu asserting. Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber --- target-unicore32/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 9239d49511..6735b253c2 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -31,7 +31,8 @@ static ObjectClass *uc32_cpu_class_by_name(const char *cpu_model) } oc = object_class_by_name(cpu_model); - if (oc != NULL && !object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU)) { + if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU) || + object_class_is_abstract(oc))) { oc = NULL; } return oc; From a1ebd6ce3396954185bda6e94ada60c583f6cbea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 11:10:14 +0100 Subject: [PATCH 0744/1634] target-openrisc: Use type_register() instead of type_register_static() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to its documentation, type_register_static()'s TypeInfo argument should exist for the life type of the type. Therefore use type_register() when registering the list of CPU subtypes. No functional change with the current implementation. Cf. 918fd0839eeafc83bd4984364321a947d29041fe for arm. Signed-off-by: Andreas Färber --- target-openrisc/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index adc03ef779..54876d904b 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -151,7 +151,7 @@ static void cpu_register(const OpenRISCCPUInfo *info) .class_size = sizeof(OpenRISCCPUClass), }; - type_register_static(&type_info); + type_register(&type_info); } static const TypeInfo openrisc_cpu_type_info = { From 87fb5811e631e79c24adab1f62bee01987cf1606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 23 Jan 2013 12:01:00 +0100 Subject: [PATCH 0745/1634] target-unicore32: Use type_register() instead of type_register_static() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to its documentation, type_register_static()'s TypeInfo argument should exist for the life type of the type. Therefore use type_register() when registering the list of CPU subtypes. No functional change with the current implementation. Cf. 918fd0839eeafc83bd4984364321a947d29041fe for arm. Signed-off-by: Andreas Färber --- target-unicore32/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 6735b253c2..c120440653 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -111,7 +111,7 @@ static void uc32_register_cpu_type(const UniCore32CPUInfo *info) .instance_init = info->instance_init, }; - type_register_static(&type_info); + type_register(&type_info); } static const TypeInfo uc32_cpu_type_info = { From 2dddbc2123681f0cc37a891fa61d97a88d5e641c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 19:31:00 +0100 Subject: [PATCH 0746/1634] target-m68k: Use type_register() instead of type_register_static() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to its documentation, type_register_static()'s TypeInfo argument should exist for the life type of the type. Therefore use type_register() when registering the list of CPU subtypes. No functional change with the current implementation. Cf. 918fd0839eeafc83bd4984364321a947d29041fe for arm. Signed-off-by: Andreas Färber --- target-m68k/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index e6df1eef58..5c7803181d 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -162,7 +162,7 @@ static void register_cpu_type(const M68kCPUInfo *info) .instance_init = info->instance_init, }; - type_register_static(&type_info); + type_register(&type_info); } static const TypeInfo m68k_cpu_type_info = { From c03c520d508ba8b3a384f9849700987df8e4c328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 25 Jan 2013 16:11:42 +0100 Subject: [PATCH 0747/1634] cpu: Unconditionalize CPUState fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commits fc8c5b8c41ee5ba69d7a2be63b02a08c7b0b155b (Makefile.user: Define CONFIG_USER_ONLY for libuser/) and dd83b06ae61cfa2dc4381ab49f365bd0995fc930 (qom: Introduce CPU class) specifically prepared the qom/cpu.c file to be compiled differently for softmmu and *-user. This broke as part of build system refactorings while CPU patches were in flight, adding conditional fields kvm_fd (8737c51c0444f832c4e97d7eb7540eae457e08e4) and kvm_vcpu_dirty (20d695a9254c1b086a456d3b79a3c311236643ba) for softmmu. linux-user and bsd-user would therefore get a CPUState type with instance_size ~8 bytes longer than expected. Fix this by unconditionally having the fields in CPUState. In practice, target-specific CPU types' instance_size would compensate this, and upstream qom/cpu.c does not yet touch any affected field. Signed-off-by: Andreas Färber Reviewed-by: Paolo Bonzini --- include/qom/cpu.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 8097692bde..46f2247274 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -93,10 +93,8 @@ struct CPUState { bool stop; bool stopped; -#if !defined(CONFIG_USER_ONLY) int kvm_fd; bool kvm_vcpu_dirty; -#endif struct KVMState *kvm_state; struct kvm_run *kvm_run; From 290adf38967787bd985a5ec67dc4717e83c29eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Jan 2013 09:30:27 +0100 Subject: [PATCH 0748/1634] kvm: Pass CPUState to kvm_on_sigbus_vcpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 20d695a9254c1b086a456d3b79a3c311236643ba (kvm: Pass CPUState to kvm_arch_*) CPUArchState is no longer needed. Allows to change qemu_kvm_eat_signals() argument as well. Signed-off-by: Andreas Färber Reviewed-by: Gleb Natapov --- cpus.c | 8 ++++---- include/sysemu/kvm.h | 2 +- kvm-all.c | 3 +-- kvm-stub.c | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cpus.c b/cpus.c index a4390c3c3f..41779eb02e 100644 --- a/cpus.c +++ b/cpus.c @@ -517,7 +517,7 @@ static void qemu_init_sigbus(void) prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0); } -static void qemu_kvm_eat_signals(CPUArchState *env) +static void qemu_kvm_eat_signals(CPUState *cpu) { struct timespec ts = { 0, 0 }; siginfo_t siginfo; @@ -538,7 +538,7 @@ static void qemu_kvm_eat_signals(CPUArchState *env) switch (r) { case SIGBUS: - if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) { + if (kvm_on_sigbus_vcpu(cpu, siginfo.si_code, siginfo.si_addr)) { sigbus_reraise(); } break; @@ -560,7 +560,7 @@ static void qemu_init_sigbus(void) { } -static void qemu_kvm_eat_signals(CPUArchState *env) +static void qemu_kvm_eat_signals(CPUState *cpu) { } #endif /* !CONFIG_LINUX */ @@ -727,7 +727,7 @@ static void qemu_kvm_wait_io_event(CPUArchState *env) qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex); } - qemu_kvm_eat_signals(env); + qemu_kvm_eat_signals(cpu); qemu_wait_io_event_common(cpu); } diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 384ee66c46..6e6dfb374a 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -159,7 +159,7 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap); int kvm_set_signal_mask(CPUArchState *env, const sigset_t *sigset); #endif -int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr); +int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); int kvm_on_sigbus(int code, void *addr); /* internal API */ diff --git a/kvm-all.c b/kvm-all.c index 363a358a39..04ec2d541a 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -2026,9 +2026,8 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) return 0; } -int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr) +int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { - CPUState *cpu = ENV_GET_CPU(env); return kvm_arch_on_sigbus_vcpu(cpu, code, addr); } diff --git a/kvm-stub.c b/kvm-stub.c index 47f8dca7d5..760aadc874 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -112,7 +112,7 @@ int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign, uint return -ENOSYS; } -int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr) +int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) { return 1; } From 6f6867493cc00974de594a509cee5a3be61c64aa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 18:15:08 +0100 Subject: [PATCH 0749/1634] qemu-ga: Plug memory leak in guest_fsfreeze_cleanup() Neglects to free errors allocated by qmp_guest_fsfreeze_thaw(). Spotted by Coverity. While there, drop the test whether return value is negative (it's never true), and improve logging. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/commands-posix.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 0ad73f3430..498f5ca46a 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -611,13 +611,14 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err) static void guest_fsfreeze_cleanup(void) { - int64_t ret; Error *err = NULL; if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { - ret = qmp_guest_fsfreeze_thaw(&err); - if (ret < 0 || err) { - slog("failed to clean up frozen filesystems"); + qmp_guest_fsfreeze_thaw(&err); + if (err) { + slog("failed to clean up frozen filesystems: %s", + error_get_pretty(err)); + error_free(err); } } } From 10a2158f52796e5b2b7ce7991bde09a3c985a37b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 16 Jan 2013 18:15:09 +0100 Subject: [PATCH 0750/1634] qemu-ga: Plug leaks on qmp_guest_network_get_interfaces() error paths Spotted by Coverity. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Luiz Capitulino Signed-off-by: Michael Roth --- qga/commands-posix.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 498f5ca46a..7a0202eb2a 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -935,9 +935,11 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) error_setg_errno(errp, errno, "failed to get MAC address of %s", ifa->ifa_name); + close(sock); goto error; } + close(sock); mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data; info->value->hardware_address = @@ -947,20 +949,19 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) (int) mac_addr[4], (int) mac_addr[5]); info->value->has_hardware_address = true; - close(sock); } if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { /* interface with IPv4 address */ - address_item = g_malloc0(sizeof(*address_item)); - address_item->value = g_malloc0(sizeof(*address_item->value)); p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) { error_setg_errno(errp, errno, "inet_ntop failed"); goto error; } + address_item = g_malloc0(sizeof(*address_item)); + address_item->value = g_malloc0(sizeof(*address_item->value)); address_item->value->ip_address = g_strdup(addr4); address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4; @@ -973,14 +974,14 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) } else if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { /* interface with IPv6 address */ - address_item = g_malloc0(sizeof(*address_item)); - address_item->value = g_malloc0(sizeof(*address_item->value)); p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) { error_setg_errno(errp, errno, "inet_ntop failed"); goto error; } + address_item = g_malloc0(sizeof(*address_item)); + address_item->value = g_malloc0(sizeof(*address_item->value)); address_item->value->ip_address = g_strdup(addr6); address_item->value->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6; From f8bb056564ed719b2fa5e05028bc70aeb0cc5c6c Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 28 Jan 2013 12:49:26 +0100 Subject: [PATCH 0751/1634] target-i386: kvm: prevent buffer overflow if -cpu foo, [x]level is too big Stack corruption may occur if too big 'level' or 'xlevel' values passed on command line with KVM enabled, due to limited size of cpuid_data in kvm_arch_init_vcpu(). reproduces with: qemu -enable-kvm -cpu qemu64,level=4294967295 or qemu -enable-kvm -cpu qemu64,xlevel=4294967295 Check if there is space in cpuid_data before passing it to cpu_x86_cpuid() or abort() if there is not space. Reviewed-by: Laszlo Ersek Reviewed-by: Andreas Faerber Signed-off-by: Igor Mammedov Signed-off-by: Gleb Natapov --- target-i386/kvm.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 3acff40c47..4ecb728a5d 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -411,11 +411,12 @@ static void cpu_update_state(void *opaque, int running, RunState state) } } +#define KVM_MAX_CPUID_ENTRIES 100 int kvm_arch_init_vcpu(CPUState *cs) { struct { struct kvm_cpuid2 cpuid; - struct kvm_cpuid_entry2 entries[100]; + struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES]; } QEMU_PACKED cpuid_data; X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -502,6 +503,10 @@ int kvm_arch_init_vcpu(CPUState *cs) cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); for (i = 0; i <= limit; i++) { + if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { + fprintf(stderr, "unsupported level value: 0x%x\n", limit); + abort(); + } c = &cpuid_data.entries[cpuid_i++]; switch (i) { @@ -516,6 +521,11 @@ int kvm_arch_init_vcpu(CPUState *cs) times = c->eax & 0xff; for (j = 1; j < times; ++j) { + if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { + fprintf(stderr, "cpuid_data is full, no space for " + "cpuid(eax:2):eax & 0xf = 0x%x\n", times); + abort(); + } c = &cpuid_data.entries[cpuid_i++]; c->function = i; c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC; @@ -544,6 +554,11 @@ int kvm_arch_init_vcpu(CPUState *cs) if (i == 0xd && c->eax == 0) { continue; } + if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { + fprintf(stderr, "cpuid_data is full, no space for " + "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); + abort(); + } c = &cpuid_data.entries[cpuid_i++]; } break; @@ -557,6 +572,10 @@ int kvm_arch_init_vcpu(CPUState *cs) cpu_x86_cpuid(env, 0x80000000, 0, &limit, &unused, &unused, &unused); for (i = 0x80000000; i <= limit; i++) { + if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { + fprintf(stderr, "unsupported xlevel value: 0x%x\n", limit); + abort(); + } c = &cpuid_data.entries[cpuid_i++]; c->function = i; @@ -569,6 +588,10 @@ int kvm_arch_init_vcpu(CPUState *cs) cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused); for (i = 0xC0000000; i <= limit; i++) { + if (cpuid_i == KVM_MAX_CPUID_ENTRIES) { + fprintf(stderr, "unsupported xlevel2 value: 0x%x\n", limit); + abort(); + } c = &cpuid_data.entries[cpuid_i++]; c->function = i; From 3ef669e19401b3e504f0bd1ca3113c3aeacd4bed Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 24 Jan 2013 12:18:52 +0100 Subject: [PATCH 0752/1634] s390: Add default support for SCLP console MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current s390 machine uses the virtio console as default console, but this doesn't mean that we always want to keep it that way for new machines. This patch introduces a way for a machine type to specify that it wants the default console to be an SCLP console, which is a lot closer to what real hardware does. Signed-off-by: Alexander Graf Reviewed-by: Andreas Färber --- hw/boards.h | 1 + vl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/hw/boards.h b/hw/boards.h index 3ff9665b1f..3813d4e551 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -33,6 +33,7 @@ typedef struct QEMUMachine { unsigned int no_serial:1, no_parallel:1, use_virtcon:1, + use_sclp:1, no_floppy:1, no_cdrom:1, no_sdcard:1; diff --git a/vl.c b/vl.c index 7aab73b736..8b0961ef01 100644 --- a/vl.c +++ b/vl.c @@ -176,6 +176,7 @@ int main(int argc, char **argv) #define DEFAULT_RAM_SIZE 128 #define MAX_VIRTIO_CONSOLES 1 +#define MAX_SCLP_CONSOLES 1 static const char *data_dir; const char *bios_name = NULL; @@ -203,6 +204,7 @@ int no_quit = 0; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES]; +CharDriverState *sclp_hds[MAX_SCLP_CONSOLES]; int win2k_install_hack = 0; int singlestep = 0; int smp_cpus = 1; @@ -271,6 +273,7 @@ static int tcg_tb_size; static int default_serial = 1; static int default_parallel = 1; static int default_virtcon = 1; +static int default_sclp = 1; static int default_monitor = 1; static int default_floppy = 1; static int default_cdrom = 1; @@ -2340,6 +2343,7 @@ struct device_config { DEV_VIRTCON, /* -virtioconsole */ DEV_DEBUGCON, /* -debugcon */ DEV_GDB, /* -gdb, -s */ + DEV_SCLP, /* s390 sclp */ } type; const char *cmdline; Location loc; @@ -2458,6 +2462,39 @@ static int virtcon_parse(const char *devname) return 0; } +static int sclp_parse(const char *devname) +{ + QemuOptsList *device = qemu_find_opts("device"); + static int index = 0; + char label[32]; + QemuOpts *dev_opts; + + if (strcmp(devname, "none") == 0) { + return 0; + } + if (index == MAX_SCLP_CONSOLES) { + fprintf(stderr, "qemu: too many sclp consoles\n"); + exit(1); + } + + assert(arch_type == QEMU_ARCH_S390X); + + dev_opts = qemu_opts_create(device, NULL, 0, NULL); + qemu_opt_set(dev_opts, "driver", "sclpconsole"); + + snprintf(label, sizeof(label), "sclpcon%d", index); + sclp_hds[index] = qemu_chr_new(label, devname, NULL); + if (!sclp_hds[index]) { + fprintf(stderr, "qemu: could not connect sclp console" + " to character backend '%s'\n", devname); + return -1; + } + qemu_opt_set(dev_opts, "chardev", label); + + index++; + return 0; +} + static int debugcon_parse(const char *devname) { QemuOpts *opts; @@ -3832,6 +3869,9 @@ int main(int argc, char **argv, char **envp) if (!machine->use_virtcon) { default_virtcon = 0; } + if (!machine->use_sclp) { + default_sclp = 0; + } if (machine->no_floppy) { default_floppy = 0; } @@ -3873,11 +3913,16 @@ int main(int argc, char **argv, char **envp) add_device_config(DEV_SERIAL, "mon:stdio"); } else if (default_virtcon && default_monitor) { add_device_config(DEV_VIRTCON, "mon:stdio"); + } else if (default_sclp && default_monitor) { + add_device_config(DEV_SCLP, "mon:stdio"); } else { if (default_serial) add_device_config(DEV_SERIAL, "stdio"); if (default_virtcon) add_device_config(DEV_VIRTCON, "stdio"); + if (default_sclp) { + add_device_config(DEV_SCLP, "stdio"); + } if (default_monitor) monitor_parse("stdio", "readline"); } @@ -3890,6 +3935,9 @@ int main(int argc, char **argv, char **envp) monitor_parse("vc:80Cx24C", "readline"); if (default_virtcon) add_device_config(DEV_VIRTCON, "vc:80Cx24C"); + if (default_sclp) { + add_device_config(DEV_SCLP, "vc:80Cx24C"); + } } socket_init(); @@ -4060,6 +4108,9 @@ int main(int argc, char **argv, char **envp) exit(1); if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0) exit(1); + if (foreach_device_config(DEV_SCLP, sclp_parse) < 0) { + exit(1); + } if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0) exit(1); From 4782a23b270ecbb9ce0ca6f3f1b60857a09cef0e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:01 +0000 Subject: [PATCH 0753/1634] s390: Lowcore mapping helper. Create a lowcore mapping helper that includes a check for sufficient length. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- target-s390x/helper.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 9a132e6d2c..023c074150 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -471,13 +471,31 @@ static uint64_t get_psw_mask(CPUS390XState *env) return r; } +static LowCore *cpu_map_lowcore(CPUS390XState *env) +{ + LowCore *lowcore; + hwaddr len = sizeof(LowCore); + + lowcore = cpu_physical_memory_map(env->psa, &len, 1); + + if (len < sizeof(LowCore)) { + cpu_abort(env, "Could not map lowcore\n"); + } + + return lowcore; +} + +static void cpu_unmap_lowcore(LowCore *lowcore) +{ + cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore)); +} + static void do_svc_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; - hwaddr len = TARGET_PAGE_SIZE; - lowcore = cpu_physical_memory_map(env->psa, &len, 1); + lowcore = cpu_map_lowcore(env); lowcore->svc_code = cpu_to_be16(env->int_svc_code); lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); @@ -486,7 +504,7 @@ static void do_svc_interrupt(CPUS390XState *env) mask = be64_to_cpu(lowcore->svc_new_psw.mask); addr = be64_to_cpu(lowcore->svc_new_psw.addr); - cpu_physical_memory_unmap(lowcore, len, 1, len); + cpu_unmap_lowcore(lowcore); load_psw(env, mask, addr); } @@ -495,7 +513,6 @@ static void do_program_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; - hwaddr len = TARGET_PAGE_SIZE; int ilen = env->int_pgm_ilen; switch (ilen) { @@ -513,7 +530,7 @@ static void do_program_interrupt(CPUS390XState *env) qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", __func__, env->int_pgm_code, ilen); - lowcore = cpu_physical_memory_map(env->psa, &len, 1); + lowcore = cpu_map_lowcore(env); lowcore->pgm_ilen = cpu_to_be16(ilen); lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); @@ -522,7 +539,7 @@ static void do_program_interrupt(CPUS390XState *env) mask = be64_to_cpu(lowcore->program_new_psw.mask); addr = be64_to_cpu(lowcore->program_new_psw.addr); - cpu_physical_memory_unmap(lowcore, len, 1, len); + cpu_unmap_lowcore(lowcore); DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, env->int_pgm_code, ilen, env->psw.mask, @@ -537,7 +554,6 @@ static void do_ext_interrupt(CPUS390XState *env) { uint64_t mask, addr; LowCore *lowcore; - hwaddr len = TARGET_PAGE_SIZE; ExtQueue *q; if (!(env->psw.mask & PSW_MASK_EXT)) { @@ -549,7 +565,7 @@ static void do_ext_interrupt(CPUS390XState *env) } q = &env->ext_queue[env->ext_index]; - lowcore = cpu_physical_memory_map(env->psa, &len, 1); + lowcore = cpu_map_lowcore(env); lowcore->ext_int_code = cpu_to_be16(q->code); lowcore->ext_params = cpu_to_be32(q->param); @@ -560,7 +576,7 @@ static void do_ext_interrupt(CPUS390XState *env) mask = be64_to_cpu(lowcore->external_new_psw.mask); addr = be64_to_cpu(lowcore->external_new_psw.addr); - cpu_physical_memory_unmap(lowcore, len, 1, len); + cpu_unmap_lowcore(lowcore); env->ext_index--; if (env->ext_index == -1) { From 38322ed6518817066ce3a9037fd3795af57e1cdd Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:02 +0000 Subject: [PATCH 0754/1634] s390: Add mapping helper functions. Add s390_cpu_physical_memory_{map,unmap} with special handling for the lowcore. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 4 ++++ target-s390x/helper.c | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 1f2d94218a..7951aabefc 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -302,6 +302,10 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw #ifndef CONFIG_USER_ONLY +void *s390_cpu_physical_memory_map(CPUS390XState *env, hwaddr addr, hwaddr *len, + int is_write); +void s390_cpu_physical_memory_unmap(CPUS390XState *env, void *addr, hwaddr len, + int is_write); void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 023c074150..3109c77d98 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -490,6 +490,31 @@ static void cpu_unmap_lowcore(LowCore *lowcore) cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore)); } +void *s390_cpu_physical_memory_map(CPUS390XState *env, hwaddr addr, hwaddr *len, + int is_write) +{ + hwaddr start = addr; + + /* Mind the prefix area. */ + if (addr < 8192) { + /* Map the lowcore. */ + start += env->psa; + *len = MIN(*len, 8192 - addr); + } else if ((addr >= env->psa) && (addr < env->psa + 8192)) { + /* Map the 0 page. */ + start -= env->psa; + *len = MIN(*len, 8192 - start); + } + + return cpu_physical_memory_map(start, len, is_write); +} + +void s390_cpu_physical_memory_unmap(CPUS390XState *env, void *addr, hwaddr len, + int is_write) +{ + cpu_physical_memory_unmap(addr, len, is_write, len); +} + static void do_svc_interrupt(CPUS390XState *env) { uint64_t mask, addr; From db1c8f53bfb1b3bff4f904be4f929808a445522e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:03 +0000 Subject: [PATCH 0755/1634] s390: Channel I/O basic definitions. Basic channel I/O structures and helper function. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- target-s390x/Makefile.objs | 2 +- target-s390x/cpu.h | 1 + target-s390x/ioinst.c | 36 +++++++ target-s390x/ioinst.h | 207 +++++++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 target-s390x/ioinst.c create mode 100644 target-s390x/ioinst.h diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index e728abf759..3afb0b71f9 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,4 +1,4 @@ obj-y += translate.o helper.o cpu.o interrupt.o obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o -obj-$(CONFIG_SOFTMMU) += machine.o +obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 7951aabefc..c1a00402fa 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -300,6 +300,7 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw int mmu_idx); #define cpu_handle_mmu_fault cpu_s390x_handle_mmu_fault +#include "ioinst.h" #ifndef CONFIG_USER_ONLY void *s390_cpu_physical_memory_map(CPUS390XState *env, hwaddr addr, hwaddr *len, diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c new file mode 100644 index 0000000000..06a16eec0a --- /dev/null +++ b/target-s390x/ioinst.c @@ -0,0 +1,36 @@ +/* + * I/O instructions for S/390 + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include + +#include "cpu.h" +#include "ioinst.h" + +int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, + int *schid) +{ + if (!IOINST_SCHID_ONE(value)) { + return -EINVAL; + } + if (!IOINST_SCHID_M(value)) { + if (IOINST_SCHID_CSSID(value)) { + return -EINVAL; + } + *cssid = 0; + *m = 0; + } else { + *cssid = IOINST_SCHID_CSSID(value); + *m = 1; + } + *ssid = IOINST_SCHID_SSID(value); + *schid = IOINST_SCHID_NR(value); + return 0; +} diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h new file mode 100644 index 0000000000..037aabcada --- /dev/null +++ b/target-s390x/ioinst.h @@ -0,0 +1,207 @@ +/* + * S/390 channel I/O instructions + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. +*/ + +#ifndef IOINST_S390X_H +#define IOINST_S390X_H +/* + * Channel I/O related definitions, as defined in the Principles + * Of Operation (and taken from the Linux implementation). + */ + +/* subchannel status word (command mode only) */ +typedef struct SCSW { + uint16_t flags; + uint16_t ctrl; + uint32_t cpa; + uint8_t dstat; + uint8_t cstat; + uint16_t count; +} QEMU_PACKED SCSW; + +#define SCSW_FLAGS_MASK_KEY 0xf000 +#define SCSW_FLAGS_MASK_SCTL 0x0800 +#define SCSW_FLAGS_MASK_ESWF 0x0400 +#define SCSW_FLAGS_MASK_CC 0x0300 +#define SCSW_FLAGS_MASK_FMT 0x0080 +#define SCSW_FLAGS_MASK_PFCH 0x0040 +#define SCSW_FLAGS_MASK_ISIC 0x0020 +#define SCSW_FLAGS_MASK_ALCC 0x0010 +#define SCSW_FLAGS_MASK_SSI 0x0008 +#define SCSW_FLAGS_MASK_ZCC 0x0004 +#define SCSW_FLAGS_MASK_ECTL 0x0002 +#define SCSW_FLAGS_MASK_PNO 0x0001 + +#define SCSW_CTRL_MASK_FCTL 0x7000 +#define SCSW_CTRL_MASK_ACTL 0x0fe0 +#define SCSW_CTRL_MASK_STCTL 0x001f + +#define SCSW_FCTL_CLEAR_FUNC 0x1000 +#define SCSW_FCTL_HALT_FUNC 0x2000 +#define SCSW_FCTL_START_FUNC 0x4000 + +#define SCSW_ACTL_SUSP 0x0020 +#define SCSW_ACTL_DEVICE_ACTIVE 0x0040 +#define SCSW_ACTL_SUBCH_ACTIVE 0x0080 +#define SCSW_ACTL_CLEAR_PEND 0x0100 +#define SCSW_ACTL_HALT_PEND 0x0200 +#define SCSW_ACTL_START_PEND 0x0400 +#define SCSW_ACTL_RESUME_PEND 0x0800 + +#define SCSW_STCTL_STATUS_PEND 0x0001 +#define SCSW_STCTL_SECONDARY 0x0002 +#define SCSW_STCTL_PRIMARY 0x0004 +#define SCSW_STCTL_INTERMEDIATE 0x0008 +#define SCSW_STCTL_ALERT 0x0010 + +#define SCSW_DSTAT_ATTENTION 0x80 +#define SCSW_DSTAT_STAT_MOD 0x40 +#define SCSW_DSTAT_CU_END 0x20 +#define SCSW_DSTAT_BUSY 0x10 +#define SCSW_DSTAT_CHANNEL_END 0x08 +#define SCSW_DSTAT_DEVICE_END 0x04 +#define SCSW_DSTAT_UNIT_CHECK 0x02 +#define SCSW_DSTAT_UNIT_EXCEP 0x01 + +#define SCSW_CSTAT_PCI 0x80 +#define SCSW_CSTAT_INCORR_LEN 0x40 +#define SCSW_CSTAT_PROG_CHECK 0x20 +#define SCSW_CSTAT_PROT_CHECK 0x10 +#define SCSW_CSTAT_DATA_CHECK 0x08 +#define SCSW_CSTAT_CHN_CTRL_CHK 0x04 +#define SCSW_CSTAT_INTF_CTRL_CHK 0x02 +#define SCSW_CSTAT_CHAIN_CHECK 0x01 + +/* path management control word */ +typedef struct PMCW { + uint32_t intparm; + uint16_t flags; + uint16_t devno; + uint8_t lpm; + uint8_t pnom; + uint8_t lpum; + uint8_t pim; + uint16_t mbi; + uint8_t pom; + uint8_t pam; + uint8_t chpid[8]; + uint32_t chars; +} QEMU_PACKED PMCW; + +#define PMCW_FLAGS_MASK_QF 0x8000 +#define PMCW_FLAGS_MASK_W 0x4000 +#define PMCW_FLAGS_MASK_ISC 0x3800 +#define PMCW_FLAGS_MASK_ENA 0x0080 +#define PMCW_FLAGS_MASK_LM 0x0060 +#define PMCW_FLAGS_MASK_MME 0x0018 +#define PMCW_FLAGS_MASK_MP 0x0004 +#define PMCW_FLAGS_MASK_TF 0x0002 +#define PMCW_FLAGS_MASK_DNV 0x0001 +#define PMCW_FLAGS_MASK_INVALID 0x0700 + +#define PMCW_CHARS_MASK_ST 0x00e00000 +#define PMCW_CHARS_MASK_MBFC 0x00000004 +#define PMCW_CHARS_MASK_XMWME 0x00000002 +#define PMCW_CHARS_MASK_CSENSE 0x00000001 +#define PMCW_CHARS_MASK_INVALID 0xff1ffff8 + +/* subchannel information block */ +typedef struct SCHIB { + PMCW pmcw; + SCSW scsw; + uint64_t mba; + uint8_t mda[4]; +} QEMU_PACKED SCHIB; + +/* interruption response block */ +typedef struct IRB { + SCSW scsw; + uint32_t esw[5]; + uint32_t ecw[8]; + uint32_t emw[8]; +} QEMU_PACKED IRB; + +/* operation request block */ +typedef struct ORB { + uint32_t intparm; + uint16_t ctrl0; + uint8_t lpm; + uint8_t ctrl1; + uint32_t cpa; +} QEMU_PACKED ORB; + +#define ORB_CTRL0_MASK_KEY 0xf000 +#define ORB_CTRL0_MASK_SPND 0x0800 +#define ORB_CTRL0_MASK_STR 0x0400 +#define ORB_CTRL0_MASK_MOD 0x0200 +#define ORB_CTRL0_MASK_SYNC 0x0100 +#define ORB_CTRL0_MASK_FMT 0x0080 +#define ORB_CTRL0_MASK_PFCH 0x0040 +#define ORB_CTRL0_MASK_ISIC 0x0020 +#define ORB_CTRL0_MASK_ALCC 0x0010 +#define ORB_CTRL0_MASK_SSIC 0x0008 +#define ORB_CTRL0_MASK_C64 0x0002 +#define ORB_CTRL0_MASK_I2K 0x0001 +#define ORB_CTRL0_MASK_INVALID 0x0004 + +#define ORB_CTRL1_MASK_ILS 0x80 +#define ORB_CTRL1_MASK_MIDAW 0x40 +#define ORB_CTRL1_MASK_ORBX 0x01 +#define ORB_CTRL1_MASK_INVALID 0x3e + +/* channel command word (type 1) */ +typedef struct CCW1 { + uint8_t cmd_code; + uint8_t flags; + uint16_t count; + uint32_t cda; +} QEMU_PACKED CCW1; + +#define CCW_FLAG_DC 0x80 +#define CCW_FLAG_CC 0x40 +#define CCW_FLAG_SLI 0x20 +#define CCW_FLAG_SKIP 0x10 +#define CCW_FLAG_PCI 0x08 +#define CCW_FLAG_IDA 0x04 +#define CCW_FLAG_SUSPEND 0x02 + +#define CCW_CMD_NOOP 0x03 +#define CCW_CMD_BASIC_SENSE 0x04 +#define CCW_CMD_TIC 0x08 +#define CCW_CMD_SENSE_ID 0xe4 + +typedef struct CRW { + uint16_t flags; + uint16_t rsid; +} QEMU_PACKED CRW; + +#define CRW_FLAGS_MASK_S 0x4000 +#define CRW_FLAGS_MASK_R 0x2000 +#define CRW_FLAGS_MASK_C 0x1000 +#define CRW_FLAGS_MASK_RSC 0x0f00 +#define CRW_FLAGS_MASK_A 0x0080 +#define CRW_FLAGS_MASK_ERC 0x003f + +#define CRW_ERC_INIT 0x02 +#define CRW_ERC_IPI 0x04 + +#define CRW_RSC_SUBCH 0x3 +#define CRW_RSC_CHP 0x4 + +/* schid disintegration */ +#define IOINST_SCHID_ONE(_schid) ((_schid & 0x00010000) >> 16) +#define IOINST_SCHID_M(_schid) ((_schid & 0x00080000) >> 19) +#define IOINST_SCHID_CSSID(_schid) ((_schid & 0xff000000) >> 24) +#define IOINST_SCHID_SSID(_schid) ((_schid & 0x00060000) >> 17) +#define IOINST_SCHID_NR(_schid) (_schid & 0x0000ffff) + +int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, + int *schid); +#endif From 5d69c547d947798cba92d836d06f6e017ba2b19d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:04 +0000 Subject: [PATCH 0756/1634] s390: I/O interrupt and machine check injection. I/O interrupts are queued per isc. Only crw pending machine checks are supported. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 69 ++++++++++++++++++++- target-s390x/helper.c | 141 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index c1a00402fa..3e00d38567 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -50,6 +50,11 @@ #define MMU_USER_IDX 1 #define MAX_EXT_QUEUE 16 +#define MAX_IO_QUEUE 16 +#define MAX_MCHK_QUEUE 16 + +#define PSW_MCHK_MASK 0x0004000000000000 +#define PSW_IO_MASK 0x0200000000000000 typedef struct PSW { uint64_t mask; @@ -62,6 +67,17 @@ typedef struct ExtQueue { uint32_t param64; } ExtQueue; +typedef struct IOIntQueue { + uint16_t id; + uint16_t nr; + uint32_t parm; + uint32_t word; +} IOIntQueue; + +typedef struct MchkQueue { + uint16_t type; +} MchkQueue; + typedef struct CPUS390XState { uint64_t regs[16]; /* GP registers */ CPU_DoubleU fregs[16]; /* FP registers */ @@ -93,9 +109,17 @@ typedef struct CPUS390XState { uint64_t cregs[16]; /* control registers */ ExtQueue ext_queue[MAX_EXT_QUEUE]; - int pending_int; + IOIntQueue io_queue[MAX_IO_QUEUE][8]; + MchkQueue mchk_queue[MAX_MCHK_QUEUE]; + int pending_int; int ext_index; + int io_index[8]; + int mchk_index; + + uint64_t ckc; + uint64_t cputm; + uint32_t todpr; CPU_COMMON @@ -375,10 +399,14 @@ void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); #define EXCP_EXT 1 /* external interrupt */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_PGM 3 /* program interruption */ +#define EXCP_IO 7 /* I/O interrupt */ +#define EXCP_MCHK 8 /* machine check */ #define INTERRUPT_EXT (1 << 0) #define INTERRUPT_TOD (1 << 1) #define INTERRUPT_CPUTIMER (1 << 2) +#define INTERRUPT_IO (1 << 3) +#define INTERRUPT_MCHK (1 << 4) /* Program Status Word. */ #define S390_PSWM_REGNUM 0 @@ -841,6 +869,45 @@ static inline void cpu_inject_ext(CPUS390XState *env, uint32_t code, uint32_t pa cpu_interrupt(env, CPU_INTERRUPT_HARD); } +static inline void cpu_inject_io(CPUS390XState *env, uint16_t subchannel_id, + uint16_t subchannel_number, + uint32_t io_int_parm, uint32_t io_int_word) +{ + int isc = ffs(io_int_word << 2) - 1; + + if (env->io_index[isc] == MAX_IO_QUEUE - 1) { + /* ugh - can't queue anymore. Let's drop. */ + return; + } + + env->io_index[isc]++; + assert(env->io_index[isc] < MAX_IO_QUEUE); + + env->io_queue[env->io_index[isc]][isc].id = subchannel_id; + env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; + env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; + env->io_queue[env->io_index[isc]][isc].word = io_int_word; + + env->pending_int |= INTERRUPT_IO; + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} + +static inline void cpu_inject_crw_mchk(CPUS390XState *env) +{ + if (env->mchk_index == MAX_MCHK_QUEUE - 1) { + /* ugh - can't queue anymore. Let's drop. */ + return; + } + + env->mchk_index++; + assert(env->mchk_index < MAX_MCHK_QUEUE); + + env->mchk_queue[env->mchk_index].type = 1; + + env->pending_int |= INTERRUPT_MCHK; + cpu_interrupt(env, CPU_INTERRUPT_HARD); +} + static inline bool cpu_has_work(CPUState *cpu) { CPUS390XState *env = &S390_CPU(cpu)->env; diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 3109c77d98..857c89725c 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -614,12 +614,140 @@ static void do_ext_interrupt(CPUS390XState *env) load_psw(env, mask, addr); } +static void do_io_interrupt(CPUS390XState *env) +{ + uint64_t mask, addr; + LowCore *lowcore; + IOIntQueue *q; + uint8_t isc; + int disable = 1; + int found = 0; + + if (!(env->psw.mask & PSW_MASK_IO)) { + cpu_abort(env, "I/O int w/o I/O mask\n"); + } + + for (isc = 0; isc < ARRAY_SIZE(env->io_index); isc++) { + if (env->io_index[isc] < 0) { + continue; + } + if (env->io_index[isc] > MAX_IO_QUEUE) { + cpu_abort(env, "I/O queue overrun for isc %d: %d\n", + isc, env->io_index[isc]); + } + + q = &env->io_queue[env->io_index[isc]][isc]; + if (!(env->cregs[6] & q->word)) { + disable = 0; + continue; + } + found = 1; + lowcore = cpu_map_lowcore(env); + + lowcore->subchannel_id = cpu_to_be16(q->id); + lowcore->subchannel_nr = cpu_to_be16(q->nr); + lowcore->io_int_parm = cpu_to_be32(q->parm); + lowcore->io_int_word = cpu_to_be32(q->word); + lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr); + mask = be64_to_cpu(lowcore->io_new_psw.mask); + addr = be64_to_cpu(lowcore->io_new_psw.addr); + + cpu_unmap_lowcore(lowcore); + + env->io_index[isc]--; + if (env->io_index >= 0) { + disable = 0; + } + break; + } + + if (disable) { + env->pending_int &= ~INTERRUPT_IO; + } + + if (found) { + DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, + env->psw.mask, env->psw.addr); + load_psw(env, mask, addr); + } +} + +static void do_mchk_interrupt(CPUS390XState *env) +{ + uint64_t mask, addr; + LowCore *lowcore; + MchkQueue *q; + int i; + + if (!(env->psw.mask & PSW_MASK_MCHECK)) { + cpu_abort(env, "Machine check w/o mchk mask\n"); + } + + if (env->mchk_index < 0 || env->mchk_index > MAX_MCHK_QUEUE) { + cpu_abort(env, "Mchk queue overrun: %d\n", env->mchk_index); + } + + q = &env->mchk_queue[env->mchk_index]; + + if (q->type != 1) { + /* Don't know how to handle this... */ + cpu_abort(env, "Unknown machine check type %d\n", q->type); + } + if (!(env->cregs[14] & (1 << 28))) { + /* CRW machine checks disabled */ + return; + } + + lowcore = cpu_map_lowcore(env); + + for (i = 0; i < 16; i++) { + lowcore->floating_pt_save_area[i] = cpu_to_be64(env->fregs[i].ll); + lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]); + lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]); + lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]); + } + lowcore->prefixreg_save_area = cpu_to_be32(env->psa); + lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc); + lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr); + lowcore->cpu_timer_save_area[0] = cpu_to_be32(env->cputm >> 32); + lowcore->cpu_timer_save_area[1] = cpu_to_be32((uint32_t)env->cputm); + lowcore->clock_comp_save_area[0] = cpu_to_be32(env->ckc >> 32); + lowcore->clock_comp_save_area[1] = cpu_to_be32((uint32_t)env->ckc); + + lowcore->mcck_interruption_code[0] = cpu_to_be32(0x00400f1d); + lowcore->mcck_interruption_code[1] = cpu_to_be32(0x40330000); + lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr); + mask = be64_to_cpu(lowcore->mcck_new_psw.mask); + addr = be64_to_cpu(lowcore->mcck_new_psw.addr); + + cpu_unmap_lowcore(lowcore); + + env->mchk_index--; + if (env->mchk_index == -1) { + env->pending_int &= ~INTERRUPT_MCHK; + } + + DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, + env->psw.mask, env->psw.addr); + + load_psw(env, mask, addr); +} + void do_interrupt(CPUS390XState *env) { qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, env->psw.addr); s390_add_running_cpu(env); + /* handle machine checks */ + if ((env->psw.mask & PSW_MASK_MCHECK) && + (env->exception_index == -1)) { + if (env->pending_int & INTERRUPT_MCHK) { + env->exception_index = EXCP_MCHK; + } + } /* handle external interrupts */ if ((env->psw.mask & PSW_MASK_EXT) && env->exception_index == -1) { @@ -638,6 +766,13 @@ void do_interrupt(CPUS390XState *env) env->pending_int &= ~INTERRUPT_TOD; } } + /* handle I/O interrupts */ + if ((env->psw.mask & PSW_MASK_IO) && + (env->exception_index == -1)) { + if (env->pending_int & INTERRUPT_IO) { + env->exception_index = EXCP_IO; + } + } switch (env->exception_index) { case EXCP_PGM: @@ -649,6 +784,12 @@ void do_interrupt(CPUS390XState *env) case EXCP_EXT: do_ext_interrupt(env); break; + case EXCP_IO: + do_io_interrupt(env); + break; + case EXCP_MCHK: + do_mchk_interrupt(env); + break; } env->exception_index = -1; From 7b18aad543300de5da88efef8e4116a3ccbbf897 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:05 +0000 Subject: [PATCH 0757/1634] s390: Add channel I/O instructions. Provide handlers for (most) channel I/O instructions. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 100 ++++++ target-s390x/ioinst.c | 716 ++++++++++++++++++++++++++++++++++++++++++ target-s390x/ioinst.h | 16 + trace-events | 6 + 4 files changed, 838 insertions(+) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 3e00d38567..76a822c829 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -147,6 +147,9 @@ static inline void cpu_clone_regs(CPUS390XState *env, target_ulong newsp) } #endif +/* distinguish between 24 bit and 31 bit addressing */ +#define HIGH_ORDER_BIT 0x80000000 + /* Interrupt Codes */ /* Program Interrupts */ #define PGM_OPERATION 0x0001 @@ -331,6 +334,20 @@ void *s390_cpu_physical_memory_map(CPUS390XState *env, hwaddr addr, hwaddr *len, int is_write); void s390_cpu_physical_memory_unmap(CPUS390XState *env, void *addr, hwaddr len, int is_write); +static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb) +{ + hwaddr addr = 0; + uint8_t reg; + + reg = ipb >> 28; + if (reg > 0) { + addr = env->regs[reg]; + } + addr += (ipb >> 16) & 0xfff; + + return addr; +} + void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); @@ -380,6 +397,89 @@ static inline unsigned s390_del_running_cpu(CPUS390XState *env) void cpu_lock(void); void cpu_unlock(void); +typedef struct SubchDev SubchDev; + +static inline SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, + uint16_t schid) +{ + return NULL; +} +static inline bool css_subch_visible(SubchDev *sch) +{ + return false; +} +static inline void css_conditional_io_interrupt(SubchDev *sch) +{ +} +static inline int css_do_stsch(SubchDev *sch, SCHIB *schib) +{ + return -ENODEV; +} +static inline bool css_schid_final(uint8_t cssid, uint8_t ssid, uint16_t schid) +{ + return true; +} +static inline int css_do_msch(SubchDev *sch, SCHIB *schib) +{ + return -ENODEV; +} +static inline int css_do_xsch(SubchDev *sch) +{ + return -ENODEV; +} +static inline int css_do_csch(SubchDev *sch) +{ + return -ENODEV; +} +static inline int css_do_hsch(SubchDev *sch) +{ + return -ENODEV; +} +static inline int css_do_ssch(SubchDev *sch, ORB *orb) +{ + return -ENODEV; +} +static inline int css_do_tsch(SubchDev *sch, IRB *irb) +{ + return -ENODEV; +} +static inline int css_do_stcrw(CRW *crw) +{ + return 1; +} +static inline int css_do_tpi(uint64_t addr, int lowcore) +{ + return 0; +} +static inline int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, + int rfmt, uint8_t l_chpid, void *buf) +{ + return 0; +} +static inline void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo) +{ +} +static inline int css_enable_mss(void) +{ + return -EINVAL; +} +static inline int css_enable_mcsse(void) +{ + return -EINVAL; +} +static inline int css_do_rsch(SubchDev *sch) +{ + return -ENODEV; +} +static inline int css_do_rchp(uint8_t cssid, uint8_t chpid) +{ + return -ENODEV; +} +static inline bool css_present(uint8_t cssid) +{ + return false; +} + static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) { env->aregs[0] = newtls >> 32; diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index 06a16eec0a..4ef2d73a43 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -13,6 +13,7 @@ #include "cpu.h" #include "ioinst.h" +#include "trace.h" int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, int *schid) @@ -34,3 +35,718 @@ int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, *schid = IOINST_SCHID_NR(value); return 0; } + +int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + int ret = -ENODEV; + int cc; + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("xsch", cssid, ssid, schid); + sch = css_find_subch(m, cssid, ssid, schid); + if (sch && css_subch_visible(sch)) { + ret = css_do_xsch(sch); + } + switch (ret) { + case -ENODEV: + cc = 3; + break; + case -EBUSY: + cc = 2; + break; + case 0: + cc = 0; + break; + default: + cc = 1; + break; + } + + return cc; +} + +int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + int ret = -ENODEV; + int cc; + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("csch", cssid, ssid, schid); + sch = css_find_subch(m, cssid, ssid, schid); + if (sch && css_subch_visible(sch)) { + ret = css_do_csch(sch); + } + if (ret == -ENODEV) { + cc = 3; + } else { + cc = 0; + } + return cc; +} + +int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + int ret = -ENODEV; + int cc; + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("hsch", cssid, ssid, schid); + sch = css_find_subch(m, cssid, ssid, schid); + if (sch && css_subch_visible(sch)) { + ret = css_do_hsch(sch); + } + switch (ret) { + case -ENODEV: + cc = 3; + break; + case -EBUSY: + cc = 2; + break; + case 0: + cc = 0; + break; + default: + cc = 1; + break; + } + + return cc; +} + +static int ioinst_schib_valid(SCHIB *schib) +{ + if ((schib->pmcw.flags & PMCW_FLAGS_MASK_INVALID) || + (schib->pmcw.chars & PMCW_CHARS_MASK_INVALID)) { + return 0; + } + /* Disallow extended measurements for now. */ + if (schib->pmcw.chars & PMCW_CHARS_MASK_XMWME) { + return 0; + } + return 1; +} + +int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + SCHIB *schib; + uint64_t addr; + int ret = -ENODEV; + int cc; + hwaddr len = sizeof(*schib); + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("msch", cssid, ssid, schid); + addr = decode_basedisp_s(env, ipb); + schib = s390_cpu_physical_memory_map(env, addr, &len, 0); + if (!schib || len != sizeof(*schib)) { + program_interrupt(env, PGM_SPECIFICATION, 2); + cc = -EIO; + goto out; + } + if (!ioinst_schib_valid(schib)) { + program_interrupt(env, PGM_OPERAND, 2); + cc = -EIO; + goto out; + } + sch = css_find_subch(m, cssid, ssid, schid); + if (sch && css_subch_visible(sch)) { + ret = css_do_msch(sch, schib); + } + switch (ret) { + case -ENODEV: + cc = 3; + break; + case -EBUSY: + cc = 2; + break; + case 0: + cc = 0; + break; + default: + cc = 1; + break; + } +out: + s390_cpu_physical_memory_unmap(env, schib, len, 0); + return cc; +} + +static void copy_orb_from_guest(ORB *dest, const ORB *src) +{ + dest->intparm = be32_to_cpu(src->intparm); + dest->ctrl0 = be16_to_cpu(src->ctrl0); + dest->lpm = src->lpm; + dest->ctrl1 = src->ctrl1; + dest->cpa = be32_to_cpu(src->cpa); +} + +static int ioinst_orb_valid(ORB *orb) +{ + if ((orb->ctrl0 & ORB_CTRL0_MASK_INVALID) || + (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) { + return 0; + } + if ((orb->cpa & HIGH_ORDER_BIT) != 0) { + return 0; + } + return 1; +} + +int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + ORB *orig_orb, orb; + uint64_t addr; + int ret = -ENODEV; + int cc; + hwaddr len = sizeof(*orig_orb); + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("ssch", cssid, ssid, schid); + addr = decode_basedisp_s(env, ipb); + orig_orb = s390_cpu_physical_memory_map(env, addr, &len, 0); + if (!orig_orb || len != sizeof(*orig_orb)) { + program_interrupt(env, PGM_SPECIFICATION, 2); + cc = -EIO; + goto out; + } + copy_orb_from_guest(&orb, orig_orb); + if (!ioinst_orb_valid(&orb)) { + program_interrupt(env, PGM_OPERAND, 2); + cc = -EIO; + goto out; + } + sch = css_find_subch(m, cssid, ssid, schid); + if (sch && css_subch_visible(sch)) { + ret = css_do_ssch(sch, &orb); + } + switch (ret) { + case -ENODEV: + cc = 3; + break; + case -EBUSY: + cc = 2; + break; + case 0: + cc = 0; + break; + default: + cc = 1; + break; + } + +out: + s390_cpu_physical_memory_unmap(env, orig_orb, len, 0); + return cc; +} + +int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb) +{ + CRW *crw; + uint64_t addr; + int cc; + hwaddr len = sizeof(*crw); + + addr = decode_basedisp_s(env, ipb); + crw = s390_cpu_physical_memory_map(env, addr, &len, 1); + if (!crw || len != sizeof(*crw)) { + program_interrupt(env, PGM_SPECIFICATION, 2); + cc = -EIO; + goto out; + } + cc = css_do_stcrw(crw); + /* 0 - crw stored, 1 - zeroes stored */ +out: + s390_cpu_physical_memory_unmap(env, crw, len, 1); + return cc; +} + +int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + uint64_t addr; + int cc; + SCHIB *schib; + hwaddr len = sizeof(*schib); + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("stsch", cssid, ssid, schid); + addr = decode_basedisp_s(env, ipb); + schib = s390_cpu_physical_memory_map(env, addr, &len, 1); + if (!schib || len != sizeof(*schib)) { + program_interrupt(env, PGM_SPECIFICATION, 2); + cc = -EIO; + goto out; + } + sch = css_find_subch(m, cssid, ssid, schid); + if (sch) { + if (css_subch_visible(sch)) { + css_do_stsch(sch, schib); + cc = 0; + } else { + /* Indicate no more subchannels in this css/ss */ + cc = 3; + } + } else { + if (css_schid_final(cssid, ssid, schid)) { + cc = 3; /* No more subchannels in this css/ss */ + } else { + /* Store an empty schib. */ + memset(schib, 0, sizeof(*schib)); + cc = 0; + } + } +out: + s390_cpu_physical_memory_unmap(env, schib, len, 1); + return cc; +} + +int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + IRB *irb; + uint64_t addr; + int ret = -ENODEV; + int cc; + hwaddr len = sizeof(*irb); + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("tsch", cssid, ssid, schid); + addr = decode_basedisp_s(env, ipb); + irb = s390_cpu_physical_memory_map(env, addr, &len, 1); + if (!irb || len != sizeof(*irb)) { + program_interrupt(env, PGM_SPECIFICATION, 2); + cc = -EIO; + goto out; + } + sch = css_find_subch(m, cssid, ssid, schid); + if (sch && css_subch_visible(sch)) { + ret = css_do_tsch(sch, irb); + /* 0 - status pending, 1 - not status pending */ + cc = ret; + } else { + cc = 3; + } +out: + s390_cpu_physical_memory_unmap(env, irb, sizeof(*irb), 1); + return cc; +} + +typedef struct ChscReq { + uint16_t len; + uint16_t command; + uint32_t param0; + uint32_t param1; + uint32_t param2; +} QEMU_PACKED ChscReq; + +typedef struct ChscResp { + uint16_t len; + uint16_t code; + uint32_t param; + char data[0]; +} QEMU_PACKED ChscResp; + +#define CHSC_MIN_RESP_LEN 0x0008 + +#define CHSC_SCPD 0x0002 +#define CHSC_SCSC 0x0010 +#define CHSC_SDA 0x0031 + +#define CHSC_SCPD_0_M 0x20000000 +#define CHSC_SCPD_0_C 0x10000000 +#define CHSC_SCPD_0_FMT 0x0f000000 +#define CHSC_SCPD_0_CSSID 0x00ff0000 +#define CHSC_SCPD_0_RFMT 0x00000f00 +#define CHSC_SCPD_0_RES 0xc000f000 +#define CHSC_SCPD_1_RES 0xffffff00 +#define CHSC_SCPD_01_CHPID 0x000000ff +static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res) +{ + uint16_t len = be16_to_cpu(req->len); + uint32_t param0 = be32_to_cpu(req->param0); + uint32_t param1 = be32_to_cpu(req->param1); + uint16_t resp_code; + int rfmt; + uint16_t cssid; + uint8_t f_chpid, l_chpid; + int desc_size; + int m; + + rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8; + if ((rfmt == 0) || (rfmt == 1)) { + rfmt = !!(param0 & CHSC_SCPD_0_C); + } + if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) || + (param1 & CHSC_SCPD_1_RES) || req->param2) { + resp_code = 0x0003; + goto out_err; + } + if (param0 & CHSC_SCPD_0_FMT) { + resp_code = 0x0007; + goto out_err; + } + cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16; + m = param0 & CHSC_SCPD_0_M; + if (cssid != 0) { + if (!m || !css_present(cssid)) { + resp_code = 0x0008; + goto out_err; + } + } + f_chpid = param0 & CHSC_SCPD_01_CHPID; + l_chpid = param1 & CHSC_SCPD_01_CHPID; + if (l_chpid < f_chpid) { + resp_code = 0x0003; + goto out_err; + } + /* css_collect_chp_desc() is endian-aware */ + desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt, + &res->data); + res->code = cpu_to_be16(0x0001); + res->len = cpu_to_be16(8 + desc_size); + res->param = cpu_to_be32(rfmt); + return; + + out_err: + res->code = cpu_to_be16(resp_code); + res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); + res->param = cpu_to_be32(rfmt); +} + +#define CHSC_SCSC_0_M 0x20000000 +#define CHSC_SCSC_0_FMT 0x000f0000 +#define CHSC_SCSC_0_CSSID 0x0000ff00 +#define CHSC_SCSC_0_RES 0xdff000ff +static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res) +{ + uint16_t len = be16_to_cpu(req->len); + uint32_t param0 = be32_to_cpu(req->param0); + uint8_t cssid; + uint16_t resp_code; + uint32_t general_chars[510]; + uint32_t chsc_chars[508]; + + if (len != 0x0010) { + resp_code = 0x0003; + goto out_err; + } + + if (param0 & CHSC_SCSC_0_FMT) { + resp_code = 0x0007; + goto out_err; + } + cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8; + if (cssid != 0) { + if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) { + resp_code = 0x0008; + goto out_err; + } + } + if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) { + resp_code = 0x0003; + goto out_err; + } + res->code = cpu_to_be16(0x0001); + res->len = cpu_to_be16(4080); + res->param = 0; + + memset(general_chars, 0, sizeof(general_chars)); + memset(chsc_chars, 0, sizeof(chsc_chars)); + + general_chars[0] = cpu_to_be32(0x03000000); + general_chars[1] = cpu_to_be32(0x00059000); + + chsc_chars[0] = cpu_to_be32(0x40000000); + chsc_chars[3] = cpu_to_be32(0x00040000); + + memcpy(res->data, general_chars, sizeof(general_chars)); + memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars)); + return; + + out_err: + res->code = cpu_to_be16(resp_code); + res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); + res->param = 0; +} + +#define CHSC_SDA_0_FMT 0x0f000000 +#define CHSC_SDA_0_OC 0x0000ffff +#define CHSC_SDA_0_RES 0xf0ff0000 +#define CHSC_SDA_OC_MCSSE 0x0 +#define CHSC_SDA_OC_MSS 0x2 +static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res) +{ + uint16_t resp_code = 0x0001; + uint16_t len = be16_to_cpu(req->len); + uint32_t param0 = be32_to_cpu(req->param0); + uint16_t oc; + int ret; + + if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) { + resp_code = 0x0003; + goto out; + } + + if (param0 & CHSC_SDA_0_FMT) { + resp_code = 0x0007; + goto out; + } + + oc = param0 & CHSC_SDA_0_OC; + switch (oc) { + case CHSC_SDA_OC_MCSSE: + ret = css_enable_mcsse(); + if (ret == -EINVAL) { + resp_code = 0x0101; + goto out; + } + break; + case CHSC_SDA_OC_MSS: + ret = css_enable_mss(); + if (ret == -EINVAL) { + resp_code = 0x0101; + goto out; + } + break; + default: + resp_code = 0x0003; + goto out; + } + +out: + res->code = cpu_to_be16(resp_code); + res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); + res->param = 0; +} + +static void ioinst_handle_chsc_unimplemented(ChscResp *res) +{ + res->len = cpu_to_be16(CHSC_MIN_RESP_LEN); + res->code = cpu_to_be16(0x0004); + res->param = 0; +} + +int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb) +{ + ChscReq *req; + ChscResp *res; + uint64_t addr; + int reg; + uint16_t len; + uint16_t command; + hwaddr map_size = TARGET_PAGE_SIZE; + int ret = 0; + + trace_ioinst("chsc"); + reg = (ipb >> 20) & 0x00f; + addr = env->regs[reg]; + /* Page boundary? */ + if (addr & 0xfff) { + program_interrupt(env, PGM_SPECIFICATION, 2); + return -EIO; + } + req = s390_cpu_physical_memory_map(env, addr, &map_size, 1); + if (!req || map_size != TARGET_PAGE_SIZE) { + program_interrupt(env, PGM_SPECIFICATION, 2); + ret = -EIO; + goto out; + } + len = be16_to_cpu(req->len); + /* Length field valid? */ + if ((len < 16) || (len > 4088) || (len & 7)) { + program_interrupt(env, PGM_OPERAND, 2); + ret = -EIO; + goto out; + } + memset((char *)req + len, 0, TARGET_PAGE_SIZE - len); + res = (void *)((char *)req + len); + command = be16_to_cpu(req->command); + trace_ioinst_chsc_cmd(command, len); + switch (command) { + case CHSC_SCSC: + ioinst_handle_chsc_scsc(req, res); + break; + case CHSC_SCPD: + ioinst_handle_chsc_scpd(req, res); + break; + case CHSC_SDA: + ioinst_handle_chsc_sda(req, res); + break; + default: + ioinst_handle_chsc_unimplemented(res); + break; + } + +out: + s390_cpu_physical_memory_unmap(env, req, map_size, 1); + return ret; +} + +int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb) +{ + uint64_t addr; + int lowcore; + + trace_ioinst("tpi"); + addr = decode_basedisp_s(env, ipb); + lowcore = addr ? 0 : 1; + if (addr < 8192) { + addr += env->psa; + } else if ((env->psa <= addr) && (addr < env->psa + 8192)) { + addr -= env->psa; + } + return css_do_tpi(addr, lowcore); +} + +#define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc) +#define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28) +#define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1) +#define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001) + +int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2, + uint32_t ipb) +{ + uint8_t mbk; + int update; + int dct; + + trace_ioinst("schm"); + + if (SCHM_REG1_RES(reg1)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + + mbk = SCHM_REG1_MBK(reg1); + update = SCHM_REG1_UPD(reg1); + dct = SCHM_REG1_DCT(reg1); + + if (update && (reg2 & 0x0000000000000fff)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + + css_do_schm(mbk, update, dct, update ? reg2 : 0); + + return 0; +} + +int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1) +{ + int cssid, ssid, schid, m; + SubchDev *sch; + int ret = -ENODEV; + int cc; + + if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + trace_ioinst_sch_id("rsch", cssid, ssid, schid); + sch = css_find_subch(m, cssid, ssid, schid); + if (sch && css_subch_visible(sch)) { + ret = css_do_rsch(sch); + } + switch (ret) { + case -ENODEV: + cc = 3; + break; + case -EINVAL: + cc = 2; + break; + case 0: + cc = 0; + break; + default: + cc = 1; + break; + } + + return cc; + +} + +#define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00) +#define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16) +#define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff) +int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1) +{ + int cc; + uint8_t cssid; + uint8_t chpid; + int ret; + + if (RCHP_REG1_RES(reg1)) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + + cssid = RCHP_REG1_CSSID(reg1); + chpid = RCHP_REG1_CHPID(reg1); + + trace_ioinst_chp_id("rchp", cssid, chpid); + + ret = css_do_rchp(cssid, chpid); + + switch (ret) { + case -ENODEV: + cc = 3; + break; + case -EBUSY: + cc = 2; + break; + case 0: + cc = 0; + break; + default: + /* Invalid channel subsystem. */ + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + + return cc; +} + +#define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000) +int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1) +{ + /* We do not provide address limit checking, so let's suppress it. */ + if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) { + program_interrupt(env, PGM_OPERAND, 2); + return -EIO; + } + return 0; +} diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h index 037aabcada..a59742c3c6 100644 --- a/target-s390x/ioinst.h +++ b/target-s390x/ioinst.h @@ -204,4 +204,20 @@ typedef struct CRW { int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, int *schid); +int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1); +int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1); +int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1); +int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); +int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); +int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb); +int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); +int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb); +int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb); +int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb); +int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2, + uint32_t ipb); +int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1); +int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1); +int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1); + #endif diff --git a/trace-events b/trace-events index 2b28076e45..b680194d21 100644 --- a/trace-events +++ b/trace-events @@ -1072,3 +1072,9 @@ xics_ics_eoi(int nr) "ics_eoi: irq %#x" hbitmap_iter_skip_words(const void *hb, void *hbi, uint64_t pos, unsigned long cur) "hb %p hbi %p pos %"PRId64" cur 0x%lx" hbitmap_reset(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64 hbitmap_set(void *hb, uint64_t start, uint64_t count, uint64_t sbit, uint64_t ebit) "hb %p items %"PRIu64",%"PRIu64" bits %"PRIu64"..%"PRIu64 + +# target-s390x/ioinst.c +ioinst(const char *insn) "IOINST: %s" +ioinst_sch_id(const char *insn, int cssid, int ssid, int schid) "IOINST: %s (%x.%x.%04x)" +ioinst_chp_id(const char *insn, int cssid, int chpid) "IOINST: %s (%x.%02x)" +ioinst_chsc_cmd(uint16_t cmd, uint16_t len) "IOINST: chsc command %04x, len %04x" From df1fe5bb49241baddf1f319a6ecbe0885e875afa Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:06 +0000 Subject: [PATCH 0758/1634] s390: Virtual channel subsystem support. Provide a mechanism for qemu to provide fully virtual subchannels to the guest. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/Makefile.objs | 1 + hw/s390x/css.c | 1277 ++++++++++++++++++++++++++++++++++++++++ hw/s390x/css.h | 99 ++++ target-s390x/cpu.h | 62 ++ trace-events | 8 + 5 files changed, 1447 insertions(+) create mode 100644 hw/s390x/css.c create mode 100644 hw/s390x/css.h diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 1b40c2e66e..ab99da62d1 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -6,3 +6,4 @@ obj-y += sclp.o obj-y += event-facility.o obj-y += sclpquiesce.o sclpconsole.o obj-y += ipl.o +obj-y += css.o diff --git a/hw/s390x/css.c b/hw/s390x/css.c new file mode 100644 index 0000000000..113ac9a893 --- /dev/null +++ b/hw/s390x/css.c @@ -0,0 +1,1277 @@ +/* + * Channel subsystem base support. + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include +#include "qemu/bitops.h" +#include "cpu.h" +#include "ioinst.h" +#include "css.h" +#include "trace.h" + +typedef struct CrwContainer { + CRW crw; + QTAILQ_ENTRY(CrwContainer) sibling; +} CrwContainer; + +typedef struct ChpInfo { + uint8_t in_use; + uint8_t type; + uint8_t is_virtual; +} ChpInfo; + +typedef struct SubchSet { + SubchDev *sch[MAX_SCHID + 1]; + unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)]; + unsigned long devnos_used[BITS_TO_LONGS(MAX_SCHID + 1)]; +} SubchSet; + +typedef struct CssImage { + SubchSet *sch_set[MAX_SSID + 1]; + ChpInfo chpids[MAX_CHPID + 1]; +} CssImage; + +typedef struct ChannelSubSys { + QTAILQ_HEAD(, CrwContainer) pending_crws; + bool do_crw_mchk; + bool crws_lost; + uint8_t max_cssid; + uint8_t max_ssid; + bool chnmon_active; + uint64_t chnmon_area; + CssImage *css[MAX_CSSID + 1]; + uint8_t default_cssid; +} ChannelSubSys; + +static ChannelSubSys *channel_subsys; + +int css_create_css_image(uint8_t cssid, bool default_image) +{ + trace_css_new_image(cssid, default_image ? "(default)" : ""); + if (cssid > MAX_CSSID) { + return -EINVAL; + } + if (channel_subsys->css[cssid]) { + return -EBUSY; + } + channel_subsys->css[cssid] = g_malloc0(sizeof(CssImage)); + if (default_image) { + channel_subsys->default_cssid = cssid; + } + return 0; +} + +static uint16_t css_build_subchannel_id(SubchDev *sch) +{ + if (channel_subsys->max_cssid > 0) { + return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1; + } + return (sch->ssid << 1) | 1; +} + +static void css_inject_io_interrupt(SubchDev *sch) +{ + S390CPU *cpu = s390_cpu_addr2state(0); + uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; + + trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, + sch->curr_status.pmcw.intparm, isc, ""); + s390_io_interrupt(cpu, + css_build_subchannel_id(sch), + sch->schid, + sch->curr_status.pmcw.intparm, + (0x80 >> isc) << 24); +} + +void css_conditional_io_interrupt(SubchDev *sch) +{ + /* + * If the subchannel is not currently status pending, make it pending + * with alert status. + */ + if (!(sch->curr_status.scsw.ctrl & SCSW_STCTL_STATUS_PEND)) { + S390CPU *cpu = s390_cpu_addr2state(0); + uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; + + trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, + sch->curr_status.pmcw.intparm, isc, + "(unsolicited)"); + sch->curr_status.scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; + sch->curr_status.scsw.ctrl |= + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + /* Inject an I/O interrupt. */ + s390_io_interrupt(cpu, + css_build_subchannel_id(sch), + sch->schid, + sch->curr_status.pmcw.intparm, + (0x80 >> isc) << 24); + } +} + +static void sch_handle_clear_func(SubchDev *sch) +{ + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + int path; + + /* Path management: In our simple css, we always choose the only path. */ + path = 0x80; + + /* Reset values prior to 'issueing the clear signal'. */ + p->lpum = 0; + p->pom = 0xff; + s->flags &= ~SCSW_FLAGS_MASK_PNO; + + /* We always 'attempt to issue the clear signal', and we always succeed. */ + sch->orb = NULL; + sch->channel_prog = 0x0; + sch->last_cmd_valid = false; + s->ctrl &= ~SCSW_ACTL_CLEAR_PEND; + s->ctrl |= SCSW_STCTL_STATUS_PEND; + + s->dstat = 0; + s->cstat = 0; + p->lpum = path; + +} + +static void sch_handle_halt_func(SubchDev *sch) +{ + + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + int path; + + /* Path management: In our simple css, we always choose the only path. */ + path = 0x80; + + /* We always 'attempt to issue the halt signal', and we always succeed. */ + sch->orb = NULL; + sch->channel_prog = 0x0; + sch->last_cmd_valid = false; + s->ctrl &= ~SCSW_ACTL_HALT_PEND; + s->ctrl |= SCSW_STCTL_STATUS_PEND; + + if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) || + !((s->ctrl & SCSW_ACTL_START_PEND) || + (s->ctrl & SCSW_ACTL_SUSP))) { + s->dstat = SCSW_DSTAT_DEVICE_END; + } + s->cstat = 0; + p->lpum = path; + +} + +static void copy_sense_id_to_guest(SenseId *dest, SenseId *src) +{ + int i; + + dest->reserved = src->reserved; + dest->cu_type = cpu_to_be16(src->cu_type); + dest->cu_model = src->cu_model; + dest->dev_type = cpu_to_be16(src->dev_type); + dest->dev_model = src->dev_model; + dest->unused = src->unused; + for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) { + dest->ciw[i].type = src->ciw[i].type; + dest->ciw[i].command = src->ciw[i].command; + dest->ciw[i].count = cpu_to_be16(src->ciw[i].count); + } +} + +static CCW1 copy_ccw_from_guest(hwaddr addr) +{ + CCW1 tmp; + CCW1 ret; + + cpu_physical_memory_read(addr, &tmp, sizeof(tmp)); + ret.cmd_code = tmp.cmd_code; + ret.flags = tmp.flags; + ret.count = be16_to_cpu(tmp.count); + ret.cda = be32_to_cpu(tmp.cda); + + return ret; +} + +static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) +{ + int ret; + bool check_len; + int len; + CCW1 ccw; + + if (!ccw_addr) { + return -EIO; + } + + ccw = copy_ccw_from_guest(ccw_addr); + + /* Check for invalid command codes. */ + if ((ccw.cmd_code & 0x0f) == 0) { + return -EINVAL; + } + if (((ccw.cmd_code & 0x0f) == CCW_CMD_TIC) && + ((ccw.cmd_code & 0xf0) != 0)) { + return -EINVAL; + } + + if (ccw.flags & CCW_FLAG_SUSPEND) { + return -ERESTART; + } + + check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); + + /* Look at the command. */ + switch (ccw.cmd_code) { + case CCW_CMD_NOOP: + /* Nothing to do. */ + ret = 0; + break; + case CCW_CMD_BASIC_SENSE: + if (check_len) { + if (ccw.count != sizeof(sch->sense_data)) { + ret = -EINVAL; + break; + } + } + len = MIN(ccw.count, sizeof(sch->sense_data)); + cpu_physical_memory_write(ccw.cda, sch->sense_data, len); + sch->curr_status.scsw.count = ccw.count - len; + memset(sch->sense_data, 0, sizeof(sch->sense_data)); + ret = 0; + break; + case CCW_CMD_SENSE_ID: + { + SenseId sense_id; + + copy_sense_id_to_guest(&sense_id, &sch->id); + /* Sense ID information is device specific. */ + if (check_len) { + if (ccw.count != sizeof(sense_id)) { + ret = -EINVAL; + break; + } + } + len = MIN(ccw.count, sizeof(sense_id)); + /* + * Only indicate 0xff in the first sense byte if we actually + * have enough place to store at least bytes 0-3. + */ + if (len >= 4) { + sense_id.reserved = 0xff; + } else { + sense_id.reserved = 0; + } + cpu_physical_memory_write(ccw.cda, &sense_id, len); + sch->curr_status.scsw.count = ccw.count - len; + ret = 0; + break; + } + case CCW_CMD_TIC: + if (sch->last_cmd_valid && (sch->last_cmd.cmd_code == CCW_CMD_TIC)) { + ret = -EINVAL; + break; + } + if (ccw.flags & (CCW_FLAG_CC | CCW_FLAG_DC)) { + ret = -EINVAL; + break; + } + sch->channel_prog = ccw.cda; + ret = -EAGAIN; + break; + default: + if (sch->ccw_cb) { + /* Handle device specific commands. */ + ret = sch->ccw_cb(sch, ccw); + } else { + ret = -EOPNOTSUPP; + } + break; + } + sch->last_cmd = ccw; + sch->last_cmd_valid = true; + if (ret == 0) { + if (ccw.flags & CCW_FLAG_CC) { + sch->channel_prog += 8; + ret = -EAGAIN; + } + } + + return ret; +} + +static void sch_handle_start_func(SubchDev *sch) +{ + + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + ORB *orb = sch->orb; + int path; + int ret; + + /* Path management: In our simple css, we always choose the only path. */ + path = 0x80; + + if (!(s->ctrl & SCSW_ACTL_SUSP)) { + /* Look at the orb and try to execute the channel program. */ + p->intparm = orb->intparm; + if (!(orb->lpm & path)) { + /* Generate a deferred cc 3 condition. */ + s->flags |= SCSW_FLAGS_MASK_CC; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND); + return; + } + } else { + s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND); + } + sch->last_cmd_valid = false; + do { + ret = css_interpret_ccw(sch, sch->channel_prog); + switch (ret) { + case -EAGAIN: + /* ccw chain, continue processing */ + break; + case 0: + /* success */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_STATUS_PEND; + s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END; + break; + case -EOPNOTSUPP: + /* unsupported command, generate unit check (command reject) */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->dstat = SCSW_DSTAT_UNIT_CHECK; + /* Set sense bit 0 in ecw0. */ + sch->sense_data[0] = 0x80; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + break; + case -EFAULT: + /* memory problem, generate channel data check */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->cstat = SCSW_CSTAT_DATA_CHECK; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + break; + case -EBUSY: + /* subchannel busy, generate deferred cc 1 */ + s->flags &= ~SCSW_FLAGS_MASK_CC; + s->flags |= (1 << 8); + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + break; + case -ERESTART: + /* channel program has been suspended */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->ctrl |= SCSW_ACTL_SUSP; + break; + default: + /* error, generate channel program check */ + s->ctrl &= ~SCSW_ACTL_START_PEND; + s->cstat = SCSW_CSTAT_PROG_CHECK; + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; + break; + } + } while (ret == -EAGAIN); + +} + +/* + * On real machines, this would run asynchronously to the main vcpus. + * We might want to make some parts of the ssch handling (interpreting + * read/writes) asynchronous later on if we start supporting more than + * our current very simple devices. + */ +static void do_subchannel_work(SubchDev *sch) +{ + + SCSW *s = &sch->curr_status.scsw; + + if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) { + sch_handle_clear_func(sch); + } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { + sch_handle_halt_func(sch); + } else if (s->ctrl & SCSW_FCTL_START_FUNC) { + sch_handle_start_func(sch); + } else { + /* Cannot happen. */ + return; + } + css_inject_io_interrupt(sch); +} + +static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) +{ + int i; + + dest->intparm = cpu_to_be32(src->intparm); + dest->flags = cpu_to_be16(src->flags); + dest->devno = cpu_to_be16(src->devno); + dest->lpm = src->lpm; + dest->pnom = src->pnom; + dest->lpum = src->lpum; + dest->pim = src->pim; + dest->mbi = cpu_to_be16(src->mbi); + dest->pom = src->pom; + dest->pam = src->pam; + for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) { + dest->chpid[i] = src->chpid[i]; + } + dest->chars = cpu_to_be32(src->chars); +} + +static void copy_scsw_to_guest(SCSW *dest, const SCSW *src) +{ + dest->flags = cpu_to_be16(src->flags); + dest->ctrl = cpu_to_be16(src->ctrl); + dest->cpa = cpu_to_be32(src->cpa); + dest->dstat = src->dstat; + dest->cstat = src->cstat; + dest->count = cpu_to_be16(src->count); +} + +static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src) +{ + int i; + + copy_pmcw_to_guest(&dest->pmcw, &src->pmcw); + copy_scsw_to_guest(&dest->scsw, &src->scsw); + dest->mba = cpu_to_be64(src->mba); + for (i = 0; i < ARRAY_SIZE(dest->mda); i++) { + dest->mda[i] = src->mda[i]; + } +} + +int css_do_stsch(SubchDev *sch, SCHIB *schib) +{ + /* Use current status. */ + copy_schib_to_guest(schib, &sch->curr_status); + return 0; +} + +static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src) +{ + int i; + + dest->intparm = be32_to_cpu(src->intparm); + dest->flags = be16_to_cpu(src->flags); + dest->devno = be16_to_cpu(src->devno); + dest->lpm = src->lpm; + dest->pnom = src->pnom; + dest->lpum = src->lpum; + dest->pim = src->pim; + dest->mbi = be16_to_cpu(src->mbi); + dest->pom = src->pom; + dest->pam = src->pam; + for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) { + dest->chpid[i] = src->chpid[i]; + } + dest->chars = be32_to_cpu(src->chars); +} + +static void copy_scsw_from_guest(SCSW *dest, const SCSW *src) +{ + dest->flags = be16_to_cpu(src->flags); + dest->ctrl = be16_to_cpu(src->ctrl); + dest->cpa = be32_to_cpu(src->cpa); + dest->dstat = src->dstat; + dest->cstat = src->cstat; + dest->count = be16_to_cpu(src->count); +} + +static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src) +{ + int i; + + copy_pmcw_from_guest(&dest->pmcw, &src->pmcw); + copy_scsw_from_guest(&dest->scsw, &src->scsw); + dest->mba = be64_to_cpu(src->mba); + for (i = 0; i < ARRAY_SIZE(dest->mda); i++) { + dest->mda[i] = src->mda[i]; + } +} + +int css_do_msch(SubchDev *sch, SCHIB *orig_schib) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + int ret; + SCHIB schib; + + if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_DNV)) { + ret = 0; + goto out; + } + + if (s->ctrl & SCSW_STCTL_STATUS_PEND) { + ret = -EINPROGRESS; + goto out; + } + + if (s->ctrl & + (SCSW_FCTL_START_FUNC|SCSW_FCTL_HALT_FUNC|SCSW_FCTL_CLEAR_FUNC)) { + ret = -EBUSY; + goto out; + } + + copy_schib_from_guest(&schib, orig_schib); + /* Only update the program-modifiable fields. */ + p->intparm = schib.pmcw.intparm; + p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | + PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | + PMCW_FLAGS_MASK_MP); + p->flags |= schib.pmcw.flags & + (PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | + PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | + PMCW_FLAGS_MASK_MP); + p->lpm = schib.pmcw.lpm; + p->mbi = schib.pmcw.mbi; + p->pom = schib.pmcw.pom; + p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE); + p->chars |= schib.pmcw.chars & + (PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE); + sch->curr_status.mba = schib.mba; + + ret = 0; + +out: + return ret; +} + +int css_do_xsch(SubchDev *sch) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + int ret; + + if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + ret = -ENODEV; + goto out; + } + + if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) || + ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || + (!(s->ctrl & + (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) || + (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) { + ret = -EINPROGRESS; + goto out; + } + + if (s->ctrl & SCSW_CTRL_MASK_STCTL) { + ret = -EBUSY; + goto out; + } + + /* Cancel the current operation. */ + s->ctrl &= ~(SCSW_FCTL_START_FUNC | + SCSW_ACTL_RESUME_PEND | + SCSW_ACTL_START_PEND | + SCSW_ACTL_SUSP); + sch->channel_prog = 0x0; + sch->last_cmd_valid = false; + sch->orb = NULL; + s->dstat = 0; + s->cstat = 0; + ret = 0; + +out: + return ret; +} + +int css_do_csch(SubchDev *sch) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + int ret; + + if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + ret = -ENODEV; + goto out; + } + + /* Trigger the clear function. */ + s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL); + s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_CLEAR_FUNC; + + do_subchannel_work(sch); + ret = 0; + +out: + return ret; +} + +int css_do_hsch(SubchDev *sch) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + int ret; + + if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + ret = -ENODEV; + goto out; + } + + if (((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_STATUS_PEND) || + (s->ctrl & (SCSW_STCTL_PRIMARY | + SCSW_STCTL_SECONDARY | + SCSW_STCTL_ALERT))) { + ret = -EINPROGRESS; + goto out; + } + + if (s->ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + ret = -EBUSY; + goto out; + } + + /* Trigger the halt function. */ + s->ctrl |= SCSW_FCTL_HALT_FUNC; + s->ctrl &= ~SCSW_FCTL_START_FUNC; + if (((s->ctrl & SCSW_CTRL_MASK_ACTL) == + (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) && + ((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_INTERMEDIATE)) { + s->ctrl &= ~SCSW_STCTL_STATUS_PEND; + } + s->ctrl |= SCSW_ACTL_HALT_PEND; + + do_subchannel_work(sch); + ret = 0; + +out: + return ret; +} + +static void css_update_chnmon(SubchDev *sch) +{ + if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_MME)) { + /* Not active. */ + return; + } + /* The counter is conveniently located at the beginning of the struct. */ + if (sch->curr_status.pmcw.chars & PMCW_CHARS_MASK_MBFC) { + /* Format 1, per-subchannel area. */ + uint32_t count; + + count = ldl_phys(sch->curr_status.mba); + count++; + stl_phys(sch->curr_status.mba, count); + } else { + /* Format 0, global area. */ + uint32_t offset; + uint16_t count; + + offset = sch->curr_status.pmcw.mbi << 5; + count = lduw_phys(channel_subsys->chnmon_area + offset); + count++; + stw_phys(channel_subsys->chnmon_area + offset, count); + } +} + +int css_do_ssch(SubchDev *sch, ORB *orb) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + int ret; + + if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + ret = -ENODEV; + goto out; + } + + if (s->ctrl & SCSW_STCTL_STATUS_PEND) { + ret = -EINPROGRESS; + goto out; + } + + if (s->ctrl & (SCSW_FCTL_START_FUNC | + SCSW_FCTL_HALT_FUNC | + SCSW_FCTL_CLEAR_FUNC)) { + ret = -EBUSY; + goto out; + } + + /* If monitoring is active, update counter. */ + if (channel_subsys->chnmon_active) { + css_update_chnmon(sch); + } + sch->orb = orb; + sch->channel_prog = orb->cpa; + /* Trigger the start function. */ + s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); + s->flags &= ~SCSW_FLAGS_MASK_PNO; + + do_subchannel_work(sch); + ret = 0; + +out: + return ret; +} + +static void copy_irb_to_guest(IRB *dest, const IRB *src) +{ + int i; + + copy_scsw_to_guest(&dest->scsw, &src->scsw); + + for (i = 0; i < ARRAY_SIZE(dest->esw); i++) { + dest->esw[i] = cpu_to_be32(src->esw[i]); + } + for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) { + dest->ecw[i] = cpu_to_be32(src->ecw[i]); + } + for (i = 0; i < ARRAY_SIZE(dest->emw); i++) { + dest->emw[i] = cpu_to_be32(src->emw[i]); + } +} + +int css_do_tsch(SubchDev *sch, IRB *target_irb) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + uint16_t stctl; + uint16_t fctl; + uint16_t actl; + IRB irb; + int ret; + + if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + ret = 3; + goto out; + } + + stctl = s->ctrl & SCSW_CTRL_MASK_STCTL; + fctl = s->ctrl & SCSW_CTRL_MASK_FCTL; + actl = s->ctrl & SCSW_CTRL_MASK_ACTL; + + /* Prepare the irb for the guest. */ + memset(&irb, 0, sizeof(IRB)); + + /* Copy scsw from current status. */ + memcpy(&irb.scsw, s, sizeof(SCSW)); + if (stctl & SCSW_STCTL_STATUS_PEND) { + if (s->cstat & (SCSW_CSTAT_DATA_CHECK | + SCSW_CSTAT_CHN_CTRL_CHK | + SCSW_CSTAT_INTF_CTRL_CHK)) { + irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF; + irb.esw[0] = 0x04804000; + } else { + irb.esw[0] = 0x00800000; + } + /* If a unit check is pending, copy sense data. */ + if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) && + (p->chars & PMCW_CHARS_MASK_CSENSE)) { + irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL; + memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data)); + irb.esw[1] = 0x02000000 | (sizeof(sch->sense_data) << 8); + } + } + /* Store the irb to the guest. */ + copy_irb_to_guest(target_irb, &irb); + + /* Clear conditions on subchannel, if applicable. */ + if (stctl & SCSW_STCTL_STATUS_PEND) { + s->ctrl &= ~SCSW_CTRL_MASK_STCTL; + if ((stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) || + ((fctl & SCSW_FCTL_HALT_FUNC) && + (actl & SCSW_ACTL_SUSP))) { + s->ctrl &= ~SCSW_CTRL_MASK_FCTL; + } + if (stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) { + s->flags &= ~SCSW_FLAGS_MASK_PNO; + s->ctrl &= ~(SCSW_ACTL_RESUME_PEND | + SCSW_ACTL_START_PEND | + SCSW_ACTL_HALT_PEND | + SCSW_ACTL_CLEAR_PEND | + SCSW_ACTL_SUSP); + } else { + if ((actl & SCSW_ACTL_SUSP) && + (fctl & SCSW_FCTL_START_FUNC)) { + s->flags &= ~SCSW_FLAGS_MASK_PNO; + if (fctl & SCSW_FCTL_HALT_FUNC) { + s->ctrl &= ~(SCSW_ACTL_RESUME_PEND | + SCSW_ACTL_START_PEND | + SCSW_ACTL_HALT_PEND | + SCSW_ACTL_CLEAR_PEND | + SCSW_ACTL_SUSP); + } else { + s->ctrl &= ~SCSW_ACTL_RESUME_PEND; + } + } + } + /* Clear pending sense data. */ + if (p->chars & PMCW_CHARS_MASK_CSENSE) { + memset(sch->sense_data, 0 , sizeof(sch->sense_data)); + } + } + + ret = ((stctl & SCSW_STCTL_STATUS_PEND) == 0); + +out: + return ret; +} + +static void copy_crw_to_guest(CRW *dest, const CRW *src) +{ + dest->flags = cpu_to_be16(src->flags); + dest->rsid = cpu_to_be16(src->rsid); +} + +int css_do_stcrw(CRW *crw) +{ + CrwContainer *crw_cont; + int ret; + + crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws); + if (crw_cont) { + QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling); + copy_crw_to_guest(crw, &crw_cont->crw); + g_free(crw_cont); + ret = 0; + } else { + /* List was empty, turn crw machine checks on again. */ + memset(crw, 0, sizeof(*crw)); + channel_subsys->do_crw_mchk = true; + ret = 1; + } + + return ret; +} + +int css_do_tpi(uint64_t addr, int lowcore) +{ + /* No pending interrupts for !KVM. */ + return 0; + } + +int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, + int rfmt, void *buf) +{ + int i, desc_size; + uint32_t words[8]; + uint32_t chpid_type_word; + CssImage *css; + + if (!m && !cssid) { + css = channel_subsys->css[channel_subsys->default_cssid]; + } else { + css = channel_subsys->css[cssid]; + } + if (!css) { + return 0; + } + desc_size = 0; + for (i = f_chpid; i <= l_chpid; i++) { + if (css->chpids[i].in_use) { + chpid_type_word = 0x80000000 | (css->chpids[i].type << 8) | i; + if (rfmt == 0) { + words[0] = cpu_to_be32(chpid_type_word); + words[1] = 0; + memcpy(buf + desc_size, words, 8); + desc_size += 8; + } else if (rfmt == 1) { + words[0] = cpu_to_be32(chpid_type_word); + words[1] = 0; + words[2] = 0; + words[3] = 0; + words[4] = 0; + words[5] = 0; + words[6] = 0; + words[7] = 0; + memcpy(buf + desc_size, words, 32); + desc_size += 32; + } + } + } + return desc_size; +} + +void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo) +{ + /* dct is currently ignored (not really meaningful for our devices) */ + /* TODO: Don't ignore mbk. */ + if (update && !channel_subsys->chnmon_active) { + /* Enable measuring. */ + channel_subsys->chnmon_area = mbo; + channel_subsys->chnmon_active = true; + } + if (!update && channel_subsys->chnmon_active) { + /* Disable measuring. */ + channel_subsys->chnmon_area = 0; + channel_subsys->chnmon_active = false; + } +} + +int css_do_rsch(SubchDev *sch) +{ + SCSW *s = &sch->curr_status.scsw; + PMCW *p = &sch->curr_status.pmcw; + int ret; + + if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { + ret = -ENODEV; + goto out; + } + + if (s->ctrl & SCSW_STCTL_STATUS_PEND) { + ret = -EINPROGRESS; + goto out; + } + + if (((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || + (s->ctrl & SCSW_ACTL_RESUME_PEND) || + (!(s->ctrl & SCSW_ACTL_SUSP))) { + ret = -EINVAL; + goto out; + } + + /* If monitoring is active, update counter. */ + if (channel_subsys->chnmon_active) { + css_update_chnmon(sch); + } + + s->ctrl |= SCSW_ACTL_RESUME_PEND; + do_subchannel_work(sch); + ret = 0; + +out: + return ret; +} + +int css_do_rchp(uint8_t cssid, uint8_t chpid) +{ + uint8_t real_cssid; + + if (cssid > channel_subsys->max_cssid) { + return -EINVAL; + } + if (channel_subsys->max_cssid == 0) { + real_cssid = channel_subsys->default_cssid; + } else { + real_cssid = cssid; + } + if (!channel_subsys->css[real_cssid]) { + return -EINVAL; + } + + if (!channel_subsys->css[real_cssid]->chpids[chpid].in_use) { + return -ENODEV; + } + + if (!channel_subsys->css[real_cssid]->chpids[chpid].is_virtual) { + fprintf(stderr, + "rchp unsupported for non-virtual chpid %x.%02x!\n", + real_cssid, chpid); + return -ENODEV; + } + + /* We don't really use a channel path, so we're done here. */ + css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, + channel_subsys->max_cssid > 0 ? 1 : 0, chpid); + if (channel_subsys->max_cssid > 0) { + css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 0, real_cssid << 8); + } + return 0; +} + +bool css_schid_final(uint8_t cssid, uint8_t ssid, uint16_t schid) +{ + SubchSet *set; + + if (cssid > MAX_CSSID || ssid > MAX_SSID || !channel_subsys->css[cssid] || + !channel_subsys->css[cssid]->sch_set[ssid]) { + return true; + } + set = channel_subsys->css[cssid]->sch_set[ssid]; + return schid > find_last_bit(set->schids_used, + (MAX_SCHID + 1) / sizeof(unsigned long)); +} + +static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) +{ + CssImage *css; + + trace_css_chpid_add(cssid, chpid, type); + if (cssid > MAX_CSSID) { + return -EINVAL; + } + css = channel_subsys->css[cssid]; + if (!css) { + return -EINVAL; + } + if (css->chpids[chpid].in_use) { + return -EEXIST; + } + css->chpids[chpid].in_use = 1; + css->chpids[chpid].type = type; + css->chpids[chpid].is_virtual = 1; + + css_generate_chp_crws(cssid, chpid); + + return 0; +} + +void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type) +{ + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + int i; + CssImage *css = channel_subsys->css[sch->cssid]; + + assert(css != NULL); + memset(p, 0, sizeof(PMCW)); + p->flags |= PMCW_FLAGS_MASK_DNV; + p->devno = sch->devno; + /* single path */ + p->pim = 0x80; + p->pom = 0xff; + p->pam = 0x80; + p->chpid[0] = chpid; + if (!css->chpids[chpid].in_use) { + css_add_virtual_chpid(sch->cssid, chpid, type); + } + + memset(s, 0, sizeof(SCSW)); + sch->curr_status.mba = 0; + for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) { + sch->curr_status.mda[i] = 0; + } +} + +SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid) +{ + uint8_t real_cssid; + + real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid; + + if (!channel_subsys->css[real_cssid]) { + return NULL; + } + + if (!channel_subsys->css[real_cssid]->sch_set[ssid]) { + return NULL; + } + + return channel_subsys->css[real_cssid]->sch_set[ssid]->sch[schid]; +} + +bool css_subch_visible(SubchDev *sch) +{ + if (sch->ssid > channel_subsys->max_ssid) { + return false; + } + + if (sch->cssid != channel_subsys->default_cssid) { + return (channel_subsys->max_cssid > 0); + } + + return true; +} + +bool css_present(uint8_t cssid) +{ + return (channel_subsys->css[cssid] != NULL); +} + +bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno) +{ + if (!channel_subsys->css[cssid]) { + return false; + } + if (!channel_subsys->css[cssid]->sch_set[ssid]) { + return false; + } + + return !!test_bit(devno, + channel_subsys->css[cssid]->sch_set[ssid]->devnos_used); +} + +void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, + uint16_t devno, SubchDev *sch) +{ + CssImage *css; + SubchSet *s_set; + + trace_css_assign_subch(sch ? "assign" : "deassign", cssid, ssid, schid, + devno); + if (!channel_subsys->css[cssid]) { + fprintf(stderr, + "Suspicious call to %s (%x.%x.%04x) for non-existing css!\n", + __func__, cssid, ssid, schid); + return; + } + css = channel_subsys->css[cssid]; + + if (!css->sch_set[ssid]) { + css->sch_set[ssid] = g_malloc0(sizeof(SubchSet)); + } + s_set = css->sch_set[ssid]; + + s_set->sch[schid] = sch; + if (sch) { + set_bit(schid, s_set->schids_used); + set_bit(devno, s_set->devnos_used); + } else { + clear_bit(schid, s_set->schids_used); + clear_bit(devno, s_set->devnos_used); + } +} + +void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid) +{ + CrwContainer *crw_cont; + + trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : ""); + /* TODO: Maybe use a static crw pool? */ + crw_cont = g_try_malloc0(sizeof(CrwContainer)); + if (!crw_cont) { + channel_subsys->crws_lost = true; + return; + } + crw_cont->crw.flags = (rsc << 8) | erc; + if (chain) { + crw_cont->crw.flags |= CRW_FLAGS_MASK_C; + } + crw_cont->crw.rsid = rsid; + if (channel_subsys->crws_lost) { + crw_cont->crw.flags |= CRW_FLAGS_MASK_R; + channel_subsys->crws_lost = false; + } + + QTAILQ_INSERT_TAIL(&channel_subsys->pending_crws, crw_cont, sibling); + + if (channel_subsys->do_crw_mchk) { + S390CPU *cpu = s390_cpu_addr2state(0); + + channel_subsys->do_crw_mchk = false; + /* Inject crw pending machine check. */ + s390_crw_mchk(cpu); + } +} + +void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, + int hotplugged, int add) +{ + uint8_t guest_cssid; + bool chain_crw; + + if (add && !hotplugged) { + return; + } + if (channel_subsys->max_cssid == 0) { + /* Default cssid shows up as 0. */ + guest_cssid = (cssid == channel_subsys->default_cssid) ? 0 : cssid; + } else { + /* Show real cssid to the guest. */ + guest_cssid = cssid; + } + /* + * Only notify for higher subchannel sets/channel subsystems if the + * guest has enabled it. + */ + if ((ssid > channel_subsys->max_ssid) || + (guest_cssid > channel_subsys->max_cssid) || + ((channel_subsys->max_cssid == 0) && + (cssid != channel_subsys->default_cssid))) { + return; + } + chain_crw = (channel_subsys->max_ssid > 0) || + (channel_subsys->max_cssid > 0); + css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, chain_crw ? 1 : 0, schid); + if (chain_crw) { + css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0, + (guest_cssid << 8) | (ssid << 4)); + } +} + +void css_generate_chp_crws(uint8_t cssid, uint8_t chpid) +{ + /* TODO */ +} + +int css_enable_mcsse(void) +{ + trace_css_enable_facility("mcsse"); + channel_subsys->max_cssid = MAX_CSSID; + return 0; +} + +int css_enable_mss(void) +{ + trace_css_enable_facility("mss"); + channel_subsys->max_ssid = MAX_SSID; + return 0; +} + +static void css_init(void) +{ + channel_subsys = g_malloc0(sizeof(*channel_subsys)); + QTAILQ_INIT(&channel_subsys->pending_crws); + channel_subsys->do_crw_mchk = true; + channel_subsys->crws_lost = false; + channel_subsys->chnmon_active = false; +} +machine_init(css_init); + +void css_reset_sch(SubchDev *sch) +{ + PMCW *p = &sch->curr_status.pmcw; + + p->intparm = 0; + p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | + PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | + PMCW_FLAGS_MASK_MP | PMCW_FLAGS_MASK_TF); + p->flags |= PMCW_FLAGS_MASK_DNV; + p->devno = sch->devno; + p->pim = 0x80; + p->lpm = p->pim; + p->pnom = 0; + p->lpum = 0; + p->mbi = 0; + p->pom = 0xff; + p->pam = 0x80; + p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_XMWME | + PMCW_CHARS_MASK_CSENSE); + + memset(&sch->curr_status.scsw, 0, sizeof(sch->curr_status.scsw)); + sch->curr_status.mba = 0; + + sch->channel_prog = 0x0; + sch->last_cmd_valid = false; + sch->orb = NULL; +} + +void css_reset(void) +{ + CrwContainer *crw_cont; + + /* Clean up monitoring. */ + channel_subsys->chnmon_active = false; + channel_subsys->chnmon_area = 0; + + /* Clear pending CRWs. */ + while ((crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws))) { + QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling); + g_free(crw_cont); + } + channel_subsys->do_crw_mchk = true; + channel_subsys->crws_lost = false; + + /* Reset maximum ids. */ + channel_subsys->max_cssid = 0; + channel_subsys->max_ssid = 0; +} diff --git a/hw/s390x/css.h b/hw/s390x/css.h new file mode 100644 index 0000000000..85ed05d0f5 --- /dev/null +++ b/hw/s390x/css.h @@ -0,0 +1,99 @@ +/* + * Channel subsystem structures and definitions. + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef CSS_H +#define CSS_H + +#include "ioinst.h" + +/* Channel subsystem constants. */ +#define MAX_SCHID 65535 +#define MAX_SSID 3 +#define MAX_CSSID 254 /* 255 is reserved */ +#define MAX_CHPID 255 + +#define MAX_CIWS 62 + +typedef struct CIW { + uint8_t type; + uint8_t command; + uint16_t count; +} QEMU_PACKED CIW; + +typedef struct SenseId { + /* common part */ + uint8_t reserved; /* always 0x'FF' */ + uint16_t cu_type; /* control unit type */ + uint8_t cu_model; /* control unit model */ + uint16_t dev_type; /* device type */ + uint8_t dev_model; /* device model */ + uint8_t unused; /* padding byte */ + /* extended part */ + CIW ciw[MAX_CIWS]; /* variable # of CIWs */ +} QEMU_PACKED SenseId; + +/* Channel measurements, from linux/drivers/s390/cio/cmf.c. */ +typedef struct CMB { + uint16_t ssch_rsch_count; + uint16_t sample_count; + uint32_t device_connect_time; + uint32_t function_pending_time; + uint32_t device_disconnect_time; + uint32_t control_unit_queuing_time; + uint32_t device_active_only_time; + uint32_t reserved[2]; +} QEMU_PACKED CMB; + +typedef struct CMBE { + uint32_t ssch_rsch_count; + uint32_t sample_count; + uint32_t device_connect_time; + uint32_t function_pending_time; + uint32_t device_disconnect_time; + uint32_t control_unit_queuing_time; + uint32_t device_active_only_time; + uint32_t device_busy_time; + uint32_t initial_command_response_time; + uint32_t reserved[7]; +} QEMU_PACKED CMBE; + +struct SubchDev { + /* channel-subsystem related things: */ + uint8_t cssid; + uint8_t ssid; + uint16_t schid; + uint16_t devno; + SCHIB curr_status; + uint8_t sense_data[32]; + hwaddr channel_prog; + CCW1 last_cmd; + bool last_cmd_valid; + ORB *orb; + /* transport-provided data: */ + int (*ccw_cb) (SubchDev *, CCW1); + SenseId id; + void *driver_data; +}; + +typedef SubchDev *(*css_subch_cb_func)(uint8_t m, uint8_t cssid, uint8_t ssid, + uint16_t schid); +int css_create_css_image(uint8_t cssid, bool default_image); +bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); +void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, + uint16_t devno, SubchDev *sch); +void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type); +void css_reset(void); +void css_reset_sch(SubchDev *sch); +void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid); +void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, + int hotplugged, int add); +void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); +#endif diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 76a822c829..778065c0bc 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -399,6 +399,30 @@ void cpu_unlock(void); typedef struct SubchDev SubchDev; +#ifndef CONFIG_USER_ONLY +SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, + uint16_t schid); +bool css_subch_visible(SubchDev *sch); +void css_conditional_io_interrupt(SubchDev *sch); +int css_do_stsch(SubchDev *sch, SCHIB *schib); +bool css_schid_final(uint8_t cssid, uint8_t ssid, uint16_t schid); +int css_do_msch(SubchDev *sch, SCHIB *schib); +int css_do_xsch(SubchDev *sch); +int css_do_csch(SubchDev *sch); +int css_do_hsch(SubchDev *sch); +int css_do_ssch(SubchDev *sch, ORB *orb); +int css_do_tsch(SubchDev *sch, IRB *irb); +int css_do_stcrw(CRW *crw); +int css_do_tpi(uint64_t addr, int lowcore); +int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, + int rfmt, void *buf); +void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo); +int css_enable_mcsse(void); +int css_enable_mss(void); +int css_do_rsch(SubchDev *sch); +int css_do_rchp(uint8_t cssid, uint8_t chpid); +bool css_present(uint8_t cssid); +#else static inline SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid) { @@ -479,6 +503,7 @@ static inline bool css_present(uint8_t cssid) { return false; } +#endif static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls) { @@ -1031,4 +1056,41 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, uintptr_t retaddr); +#include + +static inline void kvm_s390_io_interrupt(S390CPU *cpu, + uint16_t subchannel_id, + uint16_t subchannel_nr, + uint32_t io_int_parm, + uint32_t io_int_word) +{ +} +static inline void kvm_s390_crw_mchk(S390CPU *cpu) +{ +} + +static inline void s390_io_interrupt(S390CPU *cpu, + uint16_t subchannel_id, + uint16_t subchannel_nr, + uint32_t io_int_parm, + uint32_t io_int_word) +{ + if (kvm_enabled()) { + kvm_s390_io_interrupt(cpu, subchannel_id, subchannel_nr, io_int_parm, + io_int_word); + } else { + cpu_inject_io(&cpu->env, subchannel_id, subchannel_nr, io_int_parm, + io_int_word); + } +} + +static inline void s390_crw_mchk(S390CPU *cpu) +{ + if (kvm_enabled()) { + kvm_s390_crw_mchk(cpu); + } else { + cpu_inject_crw_mchk(&cpu->env); + } +} + #endif diff --git a/trace-events b/trace-events index b680194d21..71a1111901 100644 --- a/trace-events +++ b/trace-events @@ -1078,3 +1078,11 @@ ioinst(const char *insn) "IOINST: %s" ioinst_sch_id(const char *insn, int cssid, int ssid, int schid) "IOINST: %s (%x.%x.%04x)" ioinst_chp_id(const char *insn, int cssid, int chpid) "IOINST: %s (%x.%02x)" ioinst_chsc_cmd(uint16_t cmd, uint16_t len) "IOINST: chsc command %04x, len %04x" + +# hw/s390x/css.c +css_enable_facility(const char *facility) "CSS: enable %s" +css_crw(uint8_t rsc, uint8_t erc, uint16_t rsid, const char *chained) "CSS: queueing crw: rsc=%x, erc=%x, rsid=%x %s" +css_chpid_add(uint8_t cssid, uint8_t chpid, uint8_t type) "CSS: add chpid %x.%02x (type %02x)" +css_new_image(uint8_t cssid, const char *default_cssid) "CSS: add css image %02x %s" +css_assign_subch(const char *do_assign, uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno) "CSS: %s %x.%x.%04x (devno %04x)" +css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, const char *conditional) "CSS: I/O interrupt on sch %x.%x.%04x (intparm %08x, isc %x) %s" From 09b998782978f95f626236b39f0be99c02a014a9 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:07 +0000 Subject: [PATCH 0759/1634] s390: Wire up channel I/O in kvm. Trigger the code for our virtual css in case of instruction intercepts for I/O instructions. Handle the tsch exit for the subchannel-related part of tsch. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 11 +++ target-s390x/kvm.c | 239 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 237 insertions(+), 13 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 778065c0bc..ce12fa46bc 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1058,6 +1058,13 @@ void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, #include +#ifdef CONFIG_KVM +void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, + uint16_t subchannel_nr, uint32_t io_int_parm, + uint32_t io_int_word); +void kvm_s390_crw_mchk(S390CPU *cpu); +void kvm_s390_enable_css_support(S390CPU *cpu); +#else static inline void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, uint16_t subchannel_nr, @@ -1068,6 +1075,10 @@ static inline void kvm_s390_io_interrupt(S390CPU *cpu, static inline void kvm_s390_crw_mchk(S390CPU *cpu) { } +static inline void kvm_s390_enable_css_support(S390CPU *cpu) +{ +} +#endif static inline void s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 99deddf96d..2c24182001 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -47,9 +47,29 @@ #define IPA0_DIAG 0x8300 #define IPA0_SIGP 0xae00 -#define IPA0_PRIV 0xb200 +#define IPA0_B2 0xb200 +#define IPA0_B9 0xb900 +#define IPA0_EB 0xeb00 #define PRIV_SCLP_CALL 0x20 +#define PRIV_CSCH 0x30 +#define PRIV_HSCH 0x31 +#define PRIV_MSCH 0x32 +#define PRIV_SSCH 0x33 +#define PRIV_STSCH 0x34 +#define PRIV_TSCH 0x35 +#define PRIV_TPI 0x36 +#define PRIV_SAL 0x37 +#define PRIV_RSCH 0x38 +#define PRIV_STCRW 0x39 +#define PRIV_STCPS 0x3a +#define PRIV_RCHP 0x3b +#define PRIV_SCHM 0x3c +#define PRIV_CHSC 0x5f +#define PRIV_SIGA 0x74 +#define PRIV_XSCH 0x76 +#define PRIV_SQBS 0x8a +#define PRIV_EQBS 0x9c #define DIAG_KVM_HYPERCALL 0x500 #define DIAG_KVM_BREAKPOINT 0x501 @@ -380,10 +400,123 @@ static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, return 0; } -static int handle_priv(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) +static int kvm_handle_css_inst(S390CPU *cpu, struct kvm_run *run, + uint8_t ipa0, uint8_t ipa1, uint8_t ipb) +{ + int r = 0; + int no_cc = 0; + CPUS390XState *env = &cpu->env; + + if (ipa0 != 0xb2) { + /* Not handled for now. */ + return -1; + } + cpu_synchronize_state(env); + switch (ipa1) { + case PRIV_XSCH: + r = ioinst_handle_xsch(env, env->regs[1]); + break; + case PRIV_CSCH: + r = ioinst_handle_csch(env, env->regs[1]); + break; + case PRIV_HSCH: + r = ioinst_handle_hsch(env, env->regs[1]); + break; + case PRIV_MSCH: + r = ioinst_handle_msch(env, env->regs[1], run->s390_sieic.ipb); + break; + case PRIV_SSCH: + r = ioinst_handle_ssch(env, env->regs[1], run->s390_sieic.ipb); + break; + case PRIV_STCRW: + r = ioinst_handle_stcrw(env, run->s390_sieic.ipb); + break; + case PRIV_STSCH: + r = ioinst_handle_stsch(env, env->regs[1], run->s390_sieic.ipb); + break; + case PRIV_TSCH: + /* We should only get tsch via KVM_EXIT_S390_TSCH. */ + fprintf(stderr, "Spurious tsch intercept\n"); + break; + case PRIV_CHSC: + r = ioinst_handle_chsc(env, run->s390_sieic.ipb); + break; + case PRIV_TPI: + /* This should have been handled by kvm already. */ + fprintf(stderr, "Spurious tpi intercept\n"); + break; + case PRIV_SCHM: + no_cc = 1; + r = ioinst_handle_schm(env, env->regs[1], env->regs[2], + run->s390_sieic.ipb); + break; + case PRIV_RSCH: + r = ioinst_handle_rsch(env, env->regs[1]); + break; + case PRIV_RCHP: + r = ioinst_handle_rchp(env, env->regs[1]); + break; + case PRIV_STCPS: + /* We do not provide this instruction, it is suppressed. */ + no_cc = 1; + r = 0; + break; + case PRIV_SAL: + no_cc = 1; + r = ioinst_handle_sal(env, env->regs[1]); + break; + default: + r = -1; + break; + } + + if (r >= 0) { + if (!no_cc) { + setcc(cpu, r); + } + r = 0; + } else if (r < -1) { + r = 0; + } + return r; +} + +static int is_ioinst(uint8_t ipa0, uint8_t ipa1, uint8_t ipb) +{ + int ret = 0; + uint16_t ipa = (ipa0 << 8) | ipa1; + + switch (ipa) { + case IPA0_B2 | PRIV_CSCH: + case IPA0_B2 | PRIV_HSCH: + case IPA0_B2 | PRIV_MSCH: + case IPA0_B2 | PRIV_SSCH: + case IPA0_B2 | PRIV_STSCH: + case IPA0_B2 | PRIV_TPI: + case IPA0_B2 | PRIV_SAL: + case IPA0_B2 | PRIV_RSCH: + case IPA0_B2 | PRIV_STCRW: + case IPA0_B2 | PRIV_STCPS: + case IPA0_B2 | PRIV_RCHP: + case IPA0_B2 | PRIV_SCHM: + case IPA0_B2 | PRIV_CHSC: + case IPA0_B2 | PRIV_SIGA: + case IPA0_B2 | PRIV_XSCH: + case IPA0_B9 | PRIV_EQBS: + case IPA0_EB | PRIV_SQBS: + ret = 1; + break; + } + + return ret; +} + +static int handle_priv(S390CPU *cpu, struct kvm_run *run, + uint8_t ipa0, uint8_t ipa1) { int r = 0; uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16; + uint8_t ipb = run->s390_sieic.ipb & 0xff; dprintf("KVM: PRIV: %d\n", ipa1); switch (ipa1) { @@ -391,8 +524,16 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) r = kvm_sclp_service_call(cpu, run, ipbh0); break; default: - dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); - r = -1; + if (is_ioinst(ipa0, ipa1, ipb)) { + r = kvm_handle_css_inst(cpu, run, ipa0, ipa1, ipb); + if (r == -1) { + setcc(cpu, 3); + r = 0; + } + } else { + dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); + r = -1; + } break; } @@ -533,15 +674,17 @@ static int handle_instruction(S390CPU *cpu, struct kvm_run *run) dprintf("handle_instruction 0x%x 0x%x\n", run->s390_sieic.ipa, run->s390_sieic.ipb); switch (ipa0) { - case IPA0_PRIV: - r = handle_priv(cpu, run, ipa1); - break; - case IPA0_DIAG: - r = handle_diag(env, run, ipb_code); - break; - case IPA0_SIGP: - r = handle_sigp(cpu, run, ipa1); - break; + case IPA0_B2: + case IPA0_B9: + case IPA0_EB: + r = handle_priv(cpu, run, ipa0 >> 8, ipa1); + break; + case IPA0_DIAG: + r = handle_diag(env, run, ipb_code); + break; + case IPA0_SIGP: + r = handle_sigp(cpu, run, ipa1); + break; } if (r < 0) { @@ -600,6 +743,43 @@ static int handle_intercept(S390CPU *cpu) return r; } +static int handle_tsch(S390CPU *cpu) +{ + CPUS390XState *env = &cpu->env; + CPUState *cs = CPU(cpu); + struct kvm_run *run = cs->kvm_run; + int ret; + + cpu_synchronize_state(env); + ret = ioinst_handle_tsch(env, env->regs[1], run->s390_tsch.ipb); + if (ret >= 0) { + /* Success; set condition code. */ + setcc(cpu, ret); + ret = 0; + } else if (ret < -1) { + /* + * Failure. + * If an I/O interrupt had been dequeued, we have to reinject it. + */ + if (run->s390_tsch.dequeued) { + uint16_t subchannel_id = run->s390_tsch.subchannel_id; + uint16_t subchannel_nr = run->s390_tsch.subchannel_nr; + uint32_t io_int_parm = run->s390_tsch.io_int_parm; + uint32_t io_int_word = run->s390_tsch.io_int_word; + uint32_t type = ((subchannel_id & 0xff00) << 24) | + ((subchannel_id & 0x00060) << 22) | (subchannel_nr << 16); + + kvm_s390_interrupt_internal(cpu, type, + ((uint32_t)subchannel_id << 16) + | subchannel_nr, + ((uint64_t)io_int_parm << 32) + | io_int_word, 1); + } + ret = 0; + } + return ret; +} + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { S390CPU *cpu = S390_CPU(cs); @@ -612,6 +792,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) case KVM_EXIT_S390_RESET: qemu_system_reset_request(); break; + case KVM_EXIT_S390_TSCH: + ret = handle_tsch(cpu); + break; default: fprintf(stderr, "Unknown KVM exit: %d\n", run->exit_reason); break; @@ -637,3 +820,33 @@ int kvm_arch_on_sigbus(int code, void *addr) { return 1; } + +void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, + uint16_t subchannel_nr, uint32_t io_int_parm, + uint32_t io_int_word) +{ + uint32_t type; + + type = ((subchannel_id & 0xff00) << 24) | + ((subchannel_id & 0x00060) << 22) | (subchannel_nr << 16); + kvm_s390_interrupt_internal(cpu, type, + ((uint32_t)subchannel_id << 16) | subchannel_nr, + ((uint64_t)io_int_parm << 32) | io_int_word, 1); +} + +void kvm_s390_crw_mchk(S390CPU *cpu) +{ + kvm_s390_interrupt_internal(cpu, KVM_S390_MCHK, 1 << 28, + 0x00400f1d40330000, 1); +} + +void kvm_s390_enable_css_support(S390CPU *cpu) +{ + struct kvm_enable_cap cap = {}; + int r; + + /* Activate host kernel channel subsystem support. */ + cap.cap = KVM_CAP_S390_CSS_SUPPORT; + r = kvm_vcpu_ioctl(CPU(cpu), KVM_ENABLE_CAP, &cap); + assert(r == 0); +} From fad37673f53ac8a2e0575c084a26e5f6bb59957d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 02:28:09 +0000 Subject: [PATCH 0760/1634] s390-virtio: Factor out some initialization code. Some of the machine initialization for s390-virtio will be reused by virtio-ccw. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390-virtio.c | 118 +++++++++++++++++++++++++++-------------------- hw/s390-virtio.h | 5 ++ 2 files changed, 72 insertions(+), 51 deletions(-) diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 5edaabb7c4..6e0f53bd80 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -147,13 +147,73 @@ unsigned s390_del_running_cpu(CPUS390XState *env) return s390_running_cpus; } +void s390_init_ipl_dev(const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "s390-ipl"); + if (kernel_filename) { + qdev_prop_set_string(dev, "kernel", kernel_filename); + } + if (initrd_filename) { + qdev_prop_set_string(dev, "initrd", initrd_filename); + } + qdev_prop_set_string(dev, "cmdline", kernel_cmdline); + qdev_init_nofail(dev); +} + +void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys) +{ + int i; + + if (cpu_model == NULL) { + cpu_model = "host"; + } + + ipi_states = g_malloc(sizeof(S390CPU *) * smp_cpus); + + for (i = 0; i < smp_cpus; i++) { + S390CPU *cpu; + + cpu = cpu_s390x_init(cpu_model); + + ipi_states[i] = cpu; + cpu->env.halted = 1; + cpu->env.exception_index = EXCP_HLT; + cpu->env.storage_keys = storage_keys; + } +} + + +void s390_create_virtio_net(BusState *bus, const char *name) +{ + int i; + + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + DeviceState *dev; + + if (!nd->model) { + nd->model = g_strdup("virtio"); + } + + if (strcmp(nd->model, "virtio")) { + fprintf(stderr, "S390 only supports VirtIO nics\n"); + exit(1); + } + + dev = qdev_create(bus, name); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + } +} + /* PC hardware initialisation */ static void s390_init(QEMUMachineInitArgs *args) { ram_addr_t my_ram_size = args->ram_size; - const char *cpu_model = args->cpu_model; - CPUS390XState *env = NULL; - DeviceState *dev; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); int shift = 0; @@ -161,7 +221,6 @@ static void s390_init(QEMUMachineInitArgs *args) void *virtio_region; hwaddr virtio_region_len; hwaddr virtio_region_start; - int i; /* s390x ram size detection needs a 16bit multiplier + an increment. So guests > 64GB can be specified in 2MB steps etc. */ @@ -176,15 +235,8 @@ static void s390_init(QEMUMachineInitArgs *args) /* get a BUS */ s390_bus = s390_virtio_bus_init(&my_ram_size); s390_sclp_init(); - dev = qdev_create(NULL, "s390-ipl"); - if (args->kernel_filename) { - qdev_prop_set_string(dev, "kernel", args->kernel_filename); - } - if (args->initrd_filename) { - qdev_prop_set_string(dev, "initrd", args->initrd_filename); - } - qdev_prop_set_string(dev, "cmdline", args->kernel_cmdline); - qdev_init_nofail(dev); + s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline, + args->initrd_filename); /* register hypercalls */ s390_virtio_register_hcalls(); @@ -207,46 +259,10 @@ static void s390_init(QEMUMachineInitArgs *args) storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE); /* init CPUs */ - if (cpu_model == NULL) { - cpu_model = "host"; - } - - ipi_states = g_malloc(sizeof(S390CPU *) * smp_cpus); - - for (i = 0; i < smp_cpus; i++) { - S390CPU *cpu; - CPUS390XState *tmp_env; - - cpu = cpu_s390x_init(cpu_model); - tmp_env = &cpu->env; - if (!env) { - env = tmp_env; - } - ipi_states[i] = cpu; - tmp_env->halted = 1; - tmp_env->exception_index = EXCP_HLT; - tmp_env->storage_keys = storage_keys; - } - + s390_init_cpus(args->cpu_model, storage_keys); /* Create VirtIO network adapters */ - for(i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - DeviceState *dev; - - if (!nd->model) { - nd->model = g_strdup("virtio"); - } - - if (strcmp(nd->model, "virtio")) { - fprintf(stderr, "S390 only supports VirtIO nics\n"); - exit(1); - } - - dev = qdev_create((BusState *)s390_bus, "virtio-net-s390"); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - } + s390_create_virtio_net((BusState *)s390_bus, "virtio-net-s390"); } static QEMUMachine s390_machine = { diff --git a/hw/s390-virtio.h b/hw/s390-virtio.h index 25bb610fd8..67bfd20646 100644 --- a/hw/s390-virtio.h +++ b/hw/s390-virtio.h @@ -19,4 +19,9 @@ typedef int (*s390_virtio_fn)(const uint64_t *args); void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); +void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys); +void s390_init_ipl_dev(const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename); +void s390_create_virtio_net(BusState *bus, const char *name); #endif From a5cf2bb4e3827732b1b6740bddd022eb19988e0a Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 06:08:55 +0000 Subject: [PATCH 0761/1634] s390: Add new channel I/O based virtio transport. Add a new virtio transport that uses channel commands to perform virtio operations. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/Makefile.objs | 1 + hw/s390x/virtio-ccw.c | 960 +++++++++++++++++++++++++++++++++++++++++ hw/s390x/virtio-ccw.h | 98 +++++ trace-events | 4 + 4 files changed, 1063 insertions(+) create mode 100644 hw/s390x/virtio-ccw.c create mode 100644 hw/s390x/virtio-ccw.h diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index ab99da62d1..f6b461b6b3 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -7,3 +7,4 @@ obj-y += event-facility.o obj-y += sclpquiesce.o sclpconsole.o obj-y += ipl.o obj-y += css.o +obj-y += virtio-ccw.o diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c new file mode 100644 index 0000000000..8c9b7452f5 --- /dev/null +++ b/hw/s390x/virtio-ccw.c @@ -0,0 +1,960 @@ +/* + * virtio ccw target implementation + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "hw/hw.h" +#include "block/block.h" +#include "sysemu/blockdev.h" +#include "sysemu/sysemu.h" +#include "net/net.h" +#include "monitor/monitor.h" +#include "hw/virtio.h" +#include "hw/virtio-serial.h" +#include "hw/virtio-net.h" +#include "hw/sysbus.h" +#include "qemu/bitops.h" +#include "hw/virtio-bus.h" + +#include "ioinst.h" +#include "css.h" +#include "virtio-ccw.h" +#include "trace.h" + +static int virtual_css_bus_reset(BusState *qbus) +{ + /* This should actually be modelled via the generic css */ + css_reset(); + + /* we dont traverse ourself, return 0 */ + return 0; +} + + +static void virtual_css_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->reset = virtual_css_bus_reset; +} + +static const TypeInfo virtual_css_bus_info = { + .name = TYPE_VIRTUAL_CSS_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(VirtualCssBus), + .class_init = virtual_css_bus_class_init, +}; + +static const VirtIOBindings virtio_ccw_bindings; + +VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) +{ + VirtIODevice *vdev = NULL; + + if (sch->driver_data) { + vdev = ((VirtioCcwDevice *)sch->driver_data)->vdev; + } + return vdev; +} + +VirtualCssBus *virtual_css_bus_init(void) +{ + VirtualCssBus *cbus; + BusState *bus; + DeviceState *dev; + + /* Create bridge device */ + dev = qdev_create(NULL, "virtual-css-bridge"); + qdev_init_nofail(dev); + + /* Create bus on bridge device */ + bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); + cbus = VIRTUAL_CSS_BUS(bus); + + /* Enable hotplugging */ + bus->allow_hotplug = 1; + + return cbus; +} + +/* Communication blocks used by several channel commands. */ +typedef struct VqInfoBlock { + uint64_t queue; + uint32_t align; + uint16_t index; + uint16_t num; +} QEMU_PACKED VqInfoBlock; + +typedef struct VqConfigBlock { + uint16_t index; + uint16_t num_max; +} QEMU_PACKED VqConfigBlock; + +typedef struct VirtioFeatDesc { + uint32_t features; + uint8_t index; +} QEMU_PACKED VirtioFeatDesc; + +/* Specify where the virtqueues for the subchannel are in guest memory. */ +static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align, + uint16_t index, uint16_t num) +{ + VirtioCcwDevice *dev = sch->driver_data; + + if (index > VIRTIO_PCI_QUEUE_MAX) { + return -EINVAL; + } + + /* Current code in virtio.c relies on 4K alignment. */ + if (addr && (align != 4096)) { + return -EINVAL; + } + + if (!dev) { + return -EINVAL; + } + + virtio_queue_set_addr(dev->vdev, index, addr); + if (!addr) { + virtio_queue_set_vector(dev->vdev, index, 0); + } else { + /* Fail if we don't have a big enough queue. */ + /* TODO: Add interface to handle vring.num changing */ + if (virtio_queue_get_num(dev->vdev, index) > num) { + return -EINVAL; + } + virtio_queue_set_vector(dev->vdev, index, index); + } + /* tell notify handler in case of config change */ + dev->vdev->config_vector = VIRTIO_PCI_QUEUE_MAX; + return 0; +} + +static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) +{ + int ret; + VqInfoBlock info; + uint8_t status; + VirtioFeatDesc features; + void *config; + hwaddr indicators; + VqConfigBlock vq_config; + VirtioCcwDevice *dev = sch->driver_data; + bool check_len; + int len; + hwaddr hw_len; + + if (!dev) { + return -EINVAL; + } + + trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid, + ccw.cmd_code); + check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); + + /* Look at the command. */ + switch (ccw.cmd_code) { + case CCW_CMD_SET_VQ: + if (check_len) { + if (ccw.count != sizeof(info)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(info)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + if (!ccw.cda) { + ret = -EFAULT; + } else { + info.queue = ldq_phys(ccw.cda); + info.align = ldl_phys(ccw.cda + sizeof(info.queue)); + info.index = lduw_phys(ccw.cda + sizeof(info.queue) + + sizeof(info.align)); + info.num = lduw_phys(ccw.cda + sizeof(info.queue) + + sizeof(info.align) + + sizeof(info.index)); + ret = virtio_ccw_set_vqs(sch, info.queue, info.align, info.index, + info.num); + sch->curr_status.scsw.count = 0; + } + break; + case CCW_CMD_VDEV_RESET: + virtio_reset(dev->vdev); + ret = 0; + break; + case CCW_CMD_READ_FEAT: + if (check_len) { + if (ccw.count != sizeof(features)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(features)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + if (!ccw.cda) { + ret = -EFAULT; + } else { + features.index = ldub_phys(ccw.cda + sizeof(features.features)); + if (features.index < ARRAY_SIZE(dev->host_features)) { + features.features = dev->host_features[features.index]; + } else { + /* Return zeroes if the guest supports more feature bits. */ + features.features = 0; + } + stl_le_phys(ccw.cda, features.features); + sch->curr_status.scsw.count = ccw.count - sizeof(features); + ret = 0; + } + break; + case CCW_CMD_WRITE_FEAT: + if (check_len) { + if (ccw.count != sizeof(features)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(features)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + if (!ccw.cda) { + ret = -EFAULT; + } else { + features.index = ldub_phys(ccw.cda + sizeof(features.features)); + features.features = ldl_le_phys(ccw.cda); + if (features.index < ARRAY_SIZE(dev->host_features)) { + if (dev->vdev->set_features) { + dev->vdev->set_features(dev->vdev, features.features); + } + dev->vdev->guest_features = features.features; + } else { + /* + * If the guest supports more feature bits, assert that it + * passes us zeroes for those we don't support. + */ + if (features.features) { + fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n", + features.index, features.features); + /* XXX: do a unit check here? */ + } + } + sch->curr_status.scsw.count = ccw.count - sizeof(features); + ret = 0; + } + break; + case CCW_CMD_READ_CONF: + if (check_len) { + if (ccw.count > dev->vdev->config_len) { + ret = -EINVAL; + break; + } + } + len = MIN(ccw.count, dev->vdev->config_len); + if (!ccw.cda) { + ret = -EFAULT; + } else { + dev->vdev->get_config(dev->vdev, dev->vdev->config); + /* XXX config space endianness */ + cpu_physical_memory_write(ccw.cda, dev->vdev->config, len); + sch->curr_status.scsw.count = ccw.count - len; + ret = 0; + } + break; + case CCW_CMD_WRITE_CONF: + if (check_len) { + if (ccw.count > dev->vdev->config_len) { + ret = -EINVAL; + break; + } + } + len = MIN(ccw.count, dev->vdev->config_len); + hw_len = len; + if (!ccw.cda) { + ret = -EFAULT; + } else { + config = cpu_physical_memory_map(ccw.cda, &hw_len, 0); + if (!config) { + ret = -EFAULT; + } else { + len = hw_len; + /* XXX config space endianness */ + memcpy(dev->vdev->config, config, len); + cpu_physical_memory_unmap(config, hw_len, 0, hw_len); + if (dev->vdev->set_config) { + dev->vdev->set_config(dev->vdev, dev->vdev->config); + } + sch->curr_status.scsw.count = ccw.count - len; + ret = 0; + } + } + break; + case CCW_CMD_WRITE_STATUS: + if (check_len) { + if (ccw.count != sizeof(status)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(status)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + if (!ccw.cda) { + ret = -EFAULT; + } else { + status = ldub_phys(ccw.cda); + virtio_set_status(dev->vdev, status); + if (dev->vdev->status == 0) { + virtio_reset(dev->vdev); + } + sch->curr_status.scsw.count = ccw.count - sizeof(status); + ret = 0; + } + break; + case CCW_CMD_SET_IND: + if (check_len) { + if (ccw.count != sizeof(indicators)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(indicators)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + indicators = ldq_phys(ccw.cda); + if (!indicators) { + ret = -EFAULT; + } else { + dev->indicators = indicators; + sch->curr_status.scsw.count = ccw.count - sizeof(indicators); + ret = 0; + } + break; + case CCW_CMD_SET_CONF_IND: + if (check_len) { + if (ccw.count != sizeof(indicators)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(indicators)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + indicators = ldq_phys(ccw.cda); + if (!indicators) { + ret = -EFAULT; + } else { + dev->indicators2 = indicators; + sch->curr_status.scsw.count = ccw.count - sizeof(indicators); + ret = 0; + } + break; + case CCW_CMD_READ_VQ_CONF: + if (check_len) { + if (ccw.count != sizeof(vq_config)) { + ret = -EINVAL; + break; + } + } else if (ccw.count < sizeof(vq_config)) { + /* Can't execute command. */ + ret = -EINVAL; + break; + } + if (!ccw.cda) { + ret = -EFAULT; + } else { + vq_config.index = lduw_phys(ccw.cda); + vq_config.num_max = virtio_queue_get_num(dev->vdev, + vq_config.index); + stw_phys(ccw.cda + sizeof(vq_config.index), vq_config.num_max); + sch->curr_status.scsw.count = ccw.count - sizeof(vq_config); + ret = 0; + } + break; + default: + ret = -EOPNOTSUPP; + break; + } + return ret; +} + +static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) +{ + unsigned int cssid = 0; + unsigned int ssid = 0; + unsigned int schid; + unsigned int devno; + bool have_devno = false; + bool found = false; + SubchDev *sch; + int ret; + int num; + DeviceState *parent = DEVICE(dev); + + sch = g_malloc0(sizeof(SubchDev)); + + sch->driver_data = dev; + dev->sch = sch; + + dev->vdev = vdev; + dev->indicators = 0; + + /* Initialize subchannel structure. */ + sch->channel_prog = 0x0; + sch->last_cmd_valid = false; + sch->orb = NULL; + /* + * Use a device number if provided. Otherwise, fall back to subchannel + * number. + */ + if (dev->bus_id) { + num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno); + if (num == 3) { + if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) { + ret = -EINVAL; + error_report("Invalid cssid or ssid: cssid %x, ssid %x", + cssid, ssid); + goto out_err; + } + /* Enforce use of virtual cssid. */ + if (cssid != VIRTUAL_CSSID) { + ret = -EINVAL; + error_report("cssid %x not valid for virtio devices", cssid); + goto out_err; + } + if (css_devno_used(cssid, ssid, devno)) { + ret = -EEXIST; + error_report("Device %x.%x.%04x already exists", cssid, ssid, + devno); + goto out_err; + } + sch->cssid = cssid; + sch->ssid = ssid; + sch->devno = devno; + have_devno = true; + } else { + ret = -EINVAL; + error_report("Malformed devno parameter '%s'", dev->bus_id); + goto out_err; + } + } + + /* Find the next free id. */ + if (have_devno) { + for (schid = 0; schid <= MAX_SCHID; schid++) { + if (!css_find_subch(1, cssid, ssid, schid)) { + sch->schid = schid; + css_subch_assign(cssid, ssid, schid, devno, sch); + found = true; + break; + } + } + if (!found) { + ret = -ENODEV; + error_report("No free subchannel found for %x.%x.%04x", cssid, ssid, + devno); + goto out_err; + } + trace_virtio_ccw_new_device(cssid, ssid, schid, devno, + "user-configured"); + } else { + cssid = VIRTUAL_CSSID; + for (ssid = 0; ssid <= MAX_SSID; ssid++) { + for (schid = 0; schid <= MAX_SCHID; schid++) { + if (!css_find_subch(1, cssid, ssid, schid)) { + sch->cssid = cssid; + sch->ssid = ssid; + sch->schid = schid; + devno = schid; + /* + * If the devno is already taken, look further in this + * subchannel set. + */ + while (css_devno_used(cssid, ssid, devno)) { + if (devno == MAX_SCHID) { + devno = 0; + } else if (devno == schid - 1) { + ret = -ENODEV; + error_report("No free devno found"); + goto out_err; + } else { + devno++; + } + } + sch->devno = devno; + css_subch_assign(cssid, ssid, schid, devno, sch); + found = true; + break; + } + } + if (found) { + break; + } + } + if (!found) { + ret = -ENODEV; + error_report("Virtual channel subsystem is full!"); + goto out_err; + } + trace_virtio_ccw_new_device(cssid, ssid, schid, devno, + "auto-configured"); + } + + /* Build initial schib. */ + css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE); + + sch->ccw_cb = virtio_ccw_cb; + + /* Build senseid data. */ + memset(&sch->id, 0, sizeof(SenseId)); + sch->id.reserved = 0xff; + sch->id.cu_type = VIRTIO_CCW_CU_TYPE; + sch->id.cu_model = dev->vdev->device_id; + + virtio_bind_device(vdev, &virtio_ccw_bindings, DEVICE(dev)); + /* Only the first 32 feature bits are used. */ + dev->host_features[0] = vdev->get_features(vdev, dev->host_features[0]); + dev->host_features[0] |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY; + dev->host_features[0] |= 0x1 << VIRTIO_F_BAD_FEATURE; + + css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, + parent->hotplugged, 1); + return 0; + +out_err: + dev->sch = NULL; + g_free(sch); + return ret; +} + +static int virtio_ccw_exit(VirtioCcwDevice *dev) +{ + SubchDev *sch = dev->sch; + + if (sch) { + css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); + g_free(sch); + } + dev->indicators = 0; + return 0; +} + +static int virtio_ccw_net_init(VirtioCcwDevice *dev) +{ + VirtIODevice *vdev; + + vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net); + if (!vdev) { + return -1; + } + + return virtio_ccw_device_init(dev, vdev); +} + +static int virtio_ccw_net_exit(VirtioCcwDevice *dev) +{ + virtio_net_exit(dev->vdev); + return virtio_ccw_exit(dev); +} + +static int virtio_ccw_blk_init(VirtioCcwDevice *dev) +{ + VirtIODevice *vdev; + + vdev = virtio_blk_init((DeviceState *)dev, &dev->blk); + if (!vdev) { + return -1; + } + + return virtio_ccw_device_init(dev, vdev); +} + +static int virtio_ccw_blk_exit(VirtioCcwDevice *dev) +{ + virtio_blk_exit(dev->vdev); + blockdev_mark_auto_del(dev->blk.conf.bs); + return virtio_ccw_exit(dev); +} + +static int virtio_ccw_serial_init(VirtioCcwDevice *dev) +{ + VirtIODevice *vdev; + + vdev = virtio_serial_init((DeviceState *)dev, &dev->serial); + if (!vdev) { + return -1; + } + + return virtio_ccw_device_init(dev, vdev); +} + +static int virtio_ccw_serial_exit(VirtioCcwDevice *dev) +{ + virtio_serial_exit(dev->vdev); + return virtio_ccw_exit(dev); +} + +static int virtio_ccw_balloon_init(VirtioCcwDevice *dev) +{ + VirtIODevice *vdev; + + vdev = virtio_balloon_init((DeviceState *)dev); + if (!vdev) { + return -1; + } + + return virtio_ccw_device_init(dev, vdev); +} + +static int virtio_ccw_balloon_exit(VirtioCcwDevice *dev) +{ + virtio_balloon_exit(dev->vdev); + return virtio_ccw_exit(dev); +} + +static int virtio_ccw_scsi_init(VirtioCcwDevice *dev) +{ + VirtIODevice *vdev; + + vdev = virtio_scsi_init((DeviceState *)dev, &dev->scsi); + if (!vdev) { + return -1; + } + + return virtio_ccw_device_init(dev, vdev); +} + +static int virtio_ccw_scsi_exit(VirtioCcwDevice *dev) +{ + virtio_scsi_exit(dev->vdev); + return virtio_ccw_exit(dev); +} + +/* DeviceState to VirtioCcwDevice. Note: used on datapath, + * be careful and test performance if you change this. + */ +static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) +{ + return container_of(d, VirtioCcwDevice, parent_obj); +} + +static void virtio_ccw_notify(DeviceState *d, uint16_t vector) +{ + VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d); + SubchDev *sch = dev->sch; + uint64_t indicators; + + if (vector >= 128) { + return; + } + + if (vector < VIRTIO_PCI_QUEUE_MAX) { + indicators = ldq_phys(dev->indicators); + set_bit(vector, &indicators); + stq_phys(dev->indicators, indicators); + } else { + vector = 0; + indicators = ldq_phys(dev->indicators2); + set_bit(vector, &indicators); + stq_phys(dev->indicators2, indicators); + } + + css_conditional_io_interrupt(sch); + +} + +static unsigned virtio_ccw_get_features(DeviceState *d) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + + /* Only the first 32 feature bits are used. */ + return dev->host_features[0]; +} + +static void virtio_ccw_reset(DeviceState *d) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + + virtio_reset(dev->vdev); + css_reset_sch(dev->sch); +} + +/**************** Virtio-ccw Bus Device Descriptions *******************/ + +static const VirtIOBindings virtio_ccw_bindings = { + .notify = virtio_ccw_notify, + .get_features = virtio_ccw_get_features, +}; + +static Property virtio_ccw_net_properties[] = { + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), + DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]), + DEFINE_NIC_PROPERTIES(VirtioCcwDevice, nic), + DEFINE_PROP_UINT32("x-txtimer", VirtioCcwDevice, + net.txtimer, TX_TIMER_INTERVAL), + DEFINE_PROP_INT32("x-txburst", VirtioCcwDevice, + net.txburst, TX_BURST), + DEFINE_PROP_STRING("tx", VirtioCcwDevice, net.tx), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_net_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->init = virtio_ccw_net_init; + k->exit = virtio_ccw_net_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_net_properties; +} + +static const TypeInfo virtio_ccw_net = { + .name = "virtio-net-ccw", + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtioCcwDevice), + .class_init = virtio_ccw_net_class_init, +}; + +static Property virtio_ccw_blk_properties[] = { + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), + DEFINE_BLOCK_PROPERTIES(VirtioCcwDevice, blk.conf), + DEFINE_PROP_STRING("serial", VirtioCcwDevice, blk.serial), +#ifdef __linux__ + DEFINE_PROP_BIT("scsi", VirtioCcwDevice, blk.scsi, 0, true), +#endif + DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->init = virtio_ccw_blk_init; + k->exit = virtio_ccw_blk_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_blk_properties; +} + +static const TypeInfo virtio_ccw_blk = { + .name = "virtio-blk-ccw", + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtioCcwDevice), + .class_init = virtio_ccw_blk_class_init, +}; + +static Property virtio_ccw_serial_properties[] = { + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), + DEFINE_PROP_UINT32("max_ports", VirtioCcwDevice, + serial.max_virtserial_ports, 31), + DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->init = virtio_ccw_serial_init; + k->exit = virtio_ccw_serial_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_serial_properties; +} + +static const TypeInfo virtio_ccw_serial = { + .name = "virtio-serial-ccw", + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtioCcwDevice), + .class_init = virtio_ccw_serial_class_init, +}; + +static Property virtio_ccw_balloon_properties[] = { + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), + DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->init = virtio_ccw_balloon_init; + k->exit = virtio_ccw_balloon_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_balloon_properties; +} + +static const TypeInfo virtio_ccw_balloon = { + .name = "virtio-balloon-ccw", + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtioCcwDevice), + .class_init = virtio_ccw_balloon_class_init, +}; + +static Property virtio_ccw_scsi_properties[] = { + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), + DEFINE_VIRTIO_SCSI_PROPERTIES(VirtioCcwDevice, host_features[0], scsi), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->init = virtio_ccw_scsi_init; + k->exit = virtio_ccw_scsi_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_scsi_properties; +} + +static const TypeInfo virtio_ccw_scsi = { + .name = "virtio-scsi-ccw", + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtioCcwDevice), + .class_init = virtio_ccw_scsi_class_init, +}; + +static int virtio_ccw_busdev_init(DeviceState *dev) +{ + VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; + VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev); + + virtio_ccw_bus_new(&_dev->bus, _dev); + + return _info->init(_dev); +} + +static int virtio_ccw_busdev_exit(DeviceState *dev) +{ + VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; + VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev); + + return _info->exit(_dev); +} + +static int virtio_ccw_busdev_unplug(DeviceState *dev) +{ + VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; + SubchDev *sch = _dev->sch; + + /* + * We should arrive here only for device_del, since we don't support + * direct hot(un)plug of channels, but only through virtio. + */ + assert(sch != NULL); + /* Subchannel is now disabled and no longer valid. */ + sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | + PMCW_FLAGS_MASK_DNV); + + css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); + + object_unparent(OBJECT(dev)); + qdev_free(dev); + return 0; +} + +static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->init = virtio_ccw_busdev_init; + dc->exit = virtio_ccw_busdev_exit; + dc->unplug = virtio_ccw_busdev_unplug; + dc->bus_type = TYPE_VIRTUAL_CSS_BUS; + +} + +static const TypeInfo virtio_ccw_device_info = { + .name = TYPE_VIRTIO_CCW_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtioCcwDevice), + .class_init = virtio_ccw_device_class_init, + .class_size = sizeof(VirtIOCCWDeviceClass), + .abstract = true, +}; + +/***************** Virtual-css Bus Bridge Device ********************/ +/* Only required to have the virtio bus as child in the system bus */ + +static int virtual_css_bridge_init(SysBusDevice *dev) +{ + /* nothing */ + return 0; +} + +static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = virtual_css_bridge_init; + dc->no_user = 1; +} + +static const TypeInfo virtual_css_bridge_info = { + .name = "virtual-css-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = virtual_css_bridge_class_init, +}; + +/* virtio-ccw-bus */ + +void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev) +{ + DeviceState *qdev = DEVICE(dev); + BusState *qbus; + + qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_CCW_BUS, qdev, NULL); + qbus = BUS(bus); + qbus->allow_hotplug = 0; +} + +static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) +{ + VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); + BusClass *bus_class = BUS_CLASS(klass); + + bus_class->max_dev = 1; + k->notify = virtio_ccw_notify; + k->get_features = virtio_ccw_get_features; +} + +static const TypeInfo virtio_ccw_bus_info = { + .name = TYPE_VIRTIO_CCW_BUS, + .parent = TYPE_VIRTIO_BUS, + .instance_size = sizeof(VirtioCcwBusState), + .class_init = virtio_ccw_bus_class_init, +}; + +static void virtio_ccw_register(void) +{ + type_register_static(&virtio_ccw_bus_info); + type_register_static(&virtual_css_bus_info); + type_register_static(&virtio_ccw_device_info); + type_register_static(&virtio_ccw_serial); + type_register_static(&virtio_ccw_blk); + type_register_static(&virtio_ccw_net); + type_register_static(&virtio_ccw_balloon); + type_register_static(&virtio_ccw_scsi); + type_register_static(&virtual_css_bridge_info); +} + +type_init(virtio_ccw_register) diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h new file mode 100644 index 0000000000..48474b31ab --- /dev/null +++ b/hw/s390x/virtio-ccw.h @@ -0,0 +1,98 @@ +/* + * virtio ccw target definitions + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef HW_S390X_VIRTIO_CCW_H +#define HW_S390X_VIRTIO_CCW_H + +#include +#include +#include +#include +#include + +#define VIRTUAL_CSSID 0xfe + +#define VIRTIO_CCW_CU_TYPE 0x3832 +#define VIRTIO_CCW_CHPID_TYPE 0x32 + +#define CCW_CMD_SET_VQ 0x13 +#define CCW_CMD_VDEV_RESET 0x33 +#define CCW_CMD_READ_FEAT 0x12 +#define CCW_CMD_WRITE_FEAT 0x11 +#define CCW_CMD_READ_CONF 0x22 +#define CCW_CMD_WRITE_CONF 0x21 +#define CCW_CMD_WRITE_STATUS 0x31 +#define CCW_CMD_SET_IND 0x43 +#define CCW_CMD_SET_CONF_IND 0x53 +#define CCW_CMD_READ_VQ_CONF 0x32 + +#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device" +#define VIRTIO_CCW_DEVICE(obj) \ + OBJECT_CHECK(VirtioCcwDevice, (obj), TYPE_VIRTIO_CCW_DEVICE) +#define VIRTIO_CCW_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtIOCCWDeviceClass, (klass), TYPE_VIRTIO_CCW_DEVICE) +#define VIRTIO_CCW_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtIOCCWDeviceClass, (obj), TYPE_VIRTIO_CCW_DEVICE) + +typedef struct VirtioBusState VirtioCcwBusState; +typedef struct VirtioBusClass VirtioCcwBusClass; + +#define TYPE_VIRTIO_CCW_BUS "virtio-ccw-bus" +#define VIRTIO_CCW_BUS(obj) \ + OBJECT_CHECK(VirtioCcwBus, (obj), TYPE_VIRTIO_CCW_BUS) +#define VIRTIO_CCW_BUS_GET_CLASS(obj) \ + OBJECT_CHECK(VirtioCcwBusState, (obj), TYPE_VIRTIO_CCW_BUS) +#define VIRTIO_CCW_BUS_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtioCcwBusClass, klass, TYPE_VIRTIO_CCW_BUS) + +typedef struct VirtioCcwDevice VirtioCcwDevice; + +void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev); + +typedef struct VirtIOCCWDeviceClass { + DeviceClass parent_class; + int (*init)(VirtioCcwDevice *dev); + int (*exit)(VirtioCcwDevice *dev); +} VirtIOCCWDeviceClass; + +/* Change here if we want to support more feature bits. */ +#define VIRTIO_CCW_FEATURE_SIZE 1 + +struct VirtioCcwDevice { + DeviceState parent_obj; + SubchDev *sch; + VirtIODevice *vdev; + char *bus_id; + VirtIOBlkConf blk; + NICConf nic; + uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE]; + virtio_serial_conf serial; + virtio_net_conf net; + VirtIOSCSIConf scsi; + VirtioBusState bus; + /* Guest provided values: */ + hwaddr indicators; + hwaddr indicators2; +}; + +/* virtual css bus type */ +typedef struct VirtualCssBus { + BusState parent_obj; +} VirtualCssBus; + +#define TYPE_VIRTUAL_CSS_BUS "virtual-css-bus" +#define VIRTUAL_CSS_BUS(obj) \ + OBJECT_CHECK(VirtualCssBus, (obj), TYPE_VIRTUAL_CSS_BUS) + +VirtualCssBus *virtual_css_bus_init(void); +void virtio_ccw_device_update_status(SubchDev *sch); +VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch); +#endif diff --git a/trace-events b/trace-events index 71a1111901..1011f27676 100644 --- a/trace-events +++ b/trace-events @@ -1086,3 +1086,7 @@ css_chpid_add(uint8_t cssid, uint8_t chpid, uint8_t type) "CSS: add chpid %x.%02 css_new_image(uint8_t cssid, const char *default_cssid) "CSS: add css image %02x %s" css_assign_subch(const char *do_assign, uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno) "CSS: %s %x.%x.%04x (devno %04x)" css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, const char *conditional) "CSS: I/O interrupt on sch %x.%x.%04x (intparm %08x, isc %x) %s" + +# hw/s390x/virtio-ccw.c +virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x" +virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)" From 49973ebc039f644fce3e73ff8019efaa795bd83b Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 24 Jan 2013 19:11:26 +0100 Subject: [PATCH 0762/1634] s390: Make typeinfo const All TypeInfo definitions should be const. Signed-off-by: Alexander Graf --- hw/s390x/ipl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 7cbbf99fde..86e84153ad 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -159,7 +159,7 @@ static void s390_ipl_class_init(ObjectClass *klass, void *data) dc->no_user = 1; } -static TypeInfo s390_ipl_info = { +static const TypeInfo s390_ipl_info = { .class_init = s390_ipl_class_init, .parent = TYPE_SYS_BUS_DEVICE, .name = "s390-ipl", From 93726cb31982f5d930a4d5838215307390636d9b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Jan 2013 04:40:25 +0000 Subject: [PATCH 0763/1634] virtio-s390: add a reset function to virtio-s390 devices virtio-s390 devices are not being reset when their bus is. To fix this, add a reset method that forwards to virtio_reset. This is only needed because of the "strange" modeling of virtio devices; the ->vdev link is being handled manually rather than through qdev. Signed-off-by: Paolo Bonzini Signed-off-by: Alexander Graf --- hw/s390-virtio-bus.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index b5d1f2be16..6858db0895 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -508,6 +508,13 @@ static int s390_virtio_busdev_init(DeviceState *dev) return _info->init(_dev); } +static void s390_virtio_busdev_reset(DeviceState *dev) +{ + VirtIOS390Device *_dev = (VirtIOS390Device *)dev; + + virtio_reset(_dev->vdev); +} + static void virtio_s390_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -515,6 +522,7 @@ static void virtio_s390_device_class_init(ObjectClass *klass, void *data) dc->init = s390_virtio_busdev_init; dc->bus_type = TYPE_S390_VIRTIO_BUS; dc->unplug = qdev_simple_unplug_cb; + dc->reset = s390_virtio_busdev_reset; } static const TypeInfo virtio_s390_device_info = { From b73d35311098585dbdb375fdf8369b16c8222e12 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 25 Jan 2013 01:16:39 +0100 Subject: [PATCH 0764/1634] s390: Move hw files to hw/s390x This moves all files only used by s390 system emulation to hw/s390x. Signed-off-by: Alexander Graf Acked-by: Christian Borntraeger --- hw/s390x/Makefile.objs | 2 -- hw/{ => s390x}/s390-virtio-bus.c | 8 ++++---- hw/{ => s390x}/s390-virtio-bus.h | 12 ++++++------ hw/s390x/s390-virtio-hcall.c | 2 +- hw/{ => s390x}/s390-virtio.c | 10 +++++----- hw/{ => s390x}/s390-virtio.h | 0 6 files changed, 16 insertions(+), 18 deletions(-) rename hw/{ => s390x}/s390-virtio-bus.c (99%) rename hw/{ => s390x}/s390-virtio-bus.h (95%) rename hw/{ => s390x}/s390-virtio.c (98%) rename hw/{ => s390x}/s390-virtio.h (100%) diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index f6b461b6b3..e4ee456fd4 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -1,6 +1,4 @@ obj-y = s390-virtio-bus.o s390-virtio.o - -obj-y := $(addprefix ../,$(obj-y)) obj-y += s390-virtio-hcall.o obj-y += sclp.o obj-y += event-facility.o diff --git a/hw/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c similarity index 99% rename from hw/s390-virtio-bus.c rename to hw/s390x/s390-virtio-bus.c index 6858db0895..32f63b07ea 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -17,12 +17,12 @@ * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "block/block.h" #include "sysemu/sysemu.h" -#include "boards.h" +#include "hw/boards.h" #include "monitor/monitor.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" #include "hw/virtio.h" #include "hw/virtio-rng.h" @@ -31,7 +31,7 @@ #include "hw/sysbus.h" #include "sysemu/kvm.h" -#include "hw/s390-virtio-bus.h" +#include "hw/s390x/s390-virtio-bus.h" #include "hw/virtio-bus.h" /* #define DEBUG_S390 */ diff --git a/hw/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h similarity index 95% rename from hw/s390-virtio-bus.h rename to hw/s390x/s390-virtio-bus.h index 438b37fd82..4aacf83998 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390x/s390-virtio-bus.h @@ -19,12 +19,12 @@ #ifndef HW_S390_VIRTIO_BUS_H #define HW_S390_VIRTIO_BUS_H 1 -#include "virtio-blk.h" -#include "virtio-net.h" -#include "virtio-rng.h" -#include "virtio-serial.h" -#include "virtio-scsi.h" -#include "virtio-bus.h" +#include "hw/virtio-blk.h" +#include "hw/virtio-net.h" +#include "hw/virtio-rng.h" +#include "hw/virtio-serial.h" +#include "hw/virtio-scsi.h" +#include "hw/virtio-bus.h" #define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */ #define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */ diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c index d7938c0734..ee626493c6 100644 --- a/hw/s390x/s390-virtio-hcall.c +++ b/hw/s390x/s390-virtio-hcall.c @@ -10,7 +10,7 @@ */ #include "cpu.h" -#include "hw/s390-virtio.h" +#include "hw/s390x/s390-virtio.h" #define MAX_DIAG_SUBCODES 255 diff --git a/hw/s390-virtio.c b/hw/s390x/s390-virtio.c similarity index 98% rename from hw/s390-virtio.c rename to hw/s390x/s390-virtio.c index 6e0f53bd80..a8a489dc3e 100644 --- a/hw/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -21,22 +21,22 @@ * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "block/block.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" #include "net/net.h" -#include "boards.h" +#include "hw/boards.h" #include "monitor/monitor.h" -#include "loader.h" +#include "hw/loader.h" #include "hw/virtio.h" #include "hw/sysbus.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" -#include "hw/s390-virtio-bus.h" +#include "hw/s390x/s390-virtio-bus.h" #include "hw/s390x/sclp.h" -#include "hw/s390-virtio.h" +#include "hw/s390x/s390-virtio.h" //#define DEBUG_S390 diff --git a/hw/s390-virtio.h b/hw/s390x/s390-virtio.h similarity index 100% rename from hw/s390-virtio.h rename to hw/s390x/s390-virtio.h From ab290630fad0df42ee94a81b20c48d0da2dc6f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 22 Jan 2013 23:24:08 +0000 Subject: [PATCH 0765/1634] s390-virtio: Check for NULL device in reset hypercall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s390_virtio_bus_find_mem() may return a NULL VirtIOS390Device. If called with, e.g., args[0] == 0, this leads to a segfault. Fix this by adding error handling as done for other hypercalls. Present since baf0b55a9e57b909b1f8b0f732c0b10242867418 (Implement virtio reset). Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/s390x/s390-virtio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index a8a489dc3e..2a1d9ac2da 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -86,6 +86,9 @@ static int s390_virtio_hcall_reset(const uint64_t *args) VirtIOS390Device *dev; dev = s390_virtio_bus_find_mem(s390_bus, mem); + if (dev == NULL) { + return -EINVAL; + } virtio_reset(dev->vdev); stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0); s390_virtio_device_sync(dev); From a5c95808bac7d995378b3835e10011775c7c2d0b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 24 Jan 2013 06:08:56 +0000 Subject: [PATCH 0766/1634] s390: Add s390-ccw-virtio machine. Add a new machine type, s390-ccw-virtio, making use of the virtio-ccw transport to present virtio devices as channel devices. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/Makefile.objs | 1 + hw/s390x/s390-virtio-ccw.c | 134 +++++++++++++++++++++++++++++++++++++ hw/s390x/s390-virtio.h | 1 + 3 files changed, 136 insertions(+) create mode 100644 hw/s390x/s390-virtio-ccw.c diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index e4ee456fd4..9f2f41989c 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -5,4 +5,5 @@ obj-y += event-facility.o obj-y += sclpquiesce.o sclpconsole.o obj-y += ipl.o obj-y += css.o +obj-y += s390-virtio-ccw.o obj-y += virtio-ccw.o diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c new file mode 100644 index 0000000000..6549211820 --- /dev/null +++ b/hw/s390x/s390-virtio-ccw.c @@ -0,0 +1,134 @@ +/* + * virtio ccw machine + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include "hw/boards.h" +#include "exec/address-spaces.h" +#include "s390-virtio.h" +#include "sclp.h" +#include "ioinst.h" +#include "css.h" +#include "virtio-ccw.h" + +static int virtio_ccw_hcall_notify(const uint64_t *args) +{ + uint64_t subch_id = args[0]; + uint64_t queue = args[1]; + SubchDev *sch; + int cssid, ssid, schid, m; + + if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) { + return -EINVAL; + } + sch = css_find_subch(m, cssid, ssid, schid); + if (!sch || !css_subch_visible(sch)) { + return -EINVAL; + } + virtio_queue_notify(virtio_ccw_get_vdev(sch), queue); + return 0; + +} + +static int virtio_ccw_hcall_early_printk(const uint64_t *args) +{ + uint64_t mem = args[0]; + + if (mem < ram_size) { + /* Early printk */ + return 0; + } + return -EINVAL; +} + +static void virtio_ccw_register_hcalls(void) +{ + s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, + virtio_ccw_hcall_notify); + /* Tolerate early printk. */ + s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY, + virtio_ccw_hcall_early_printk); +} + +static void ccw_init(QEMUMachineInitArgs *args) +{ + ram_addr_t my_ram_size = args->ram_size; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + int shift = 0; + uint8_t *storage_keys; + int ret; + VirtualCssBus *css_bus; + + /* s390x ram size detection needs a 16bit multiplier + an increment. So + guests > 64GB can be specified in 2MB steps etc. */ + while ((my_ram_size >> (20 + shift)) > 65535) { + shift++; + } + my_ram_size = my_ram_size >> (20 + shift) << (20 + shift); + + /* lets propagate the changed ram size into the global variable. */ + ram_size = my_ram_size; + + /* get a BUS */ + css_bus = virtual_css_bus_init(); + s390_sclp_init(); + s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline, + args->initrd_filename); + + /* register hypercalls */ + virtio_ccw_register_hcalls(); + + /* allocate RAM */ + memory_region_init_ram(ram, "s390.ram", my_ram_size); + vmstate_register_ram_global(ram); + memory_region_add_subregion(sysmem, 0, ram); + + /* allocate storage keys */ + storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE); + + /* init CPUs */ + s390_init_cpus(args->cpu_model, storage_keys); + + if (kvm_enabled()) { + kvm_s390_enable_css_support(s390_cpu_addr2state(0)); + } + /* + * Create virtual css and set it as default so that non mcss-e + * enabled guests only see virtio devices. + */ + ret = css_create_css_image(VIRTUAL_CSSID, true); + assert(ret == 0); + + /* Create VirtIO network adapters */ + s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); +} + +static QEMUMachine ccw_machine = { + .name = "s390-ccw-virtio", + .alias = "s390-ccw", + .desc = "VirtIO-ccw based S390 machine", + .init = ccw_init, + .block_default_type = IF_VIRTIO, + .no_cdrom = 1, + .no_floppy = 1, + .no_serial = 1, + .no_parallel = 1, + .no_sdcard = 1, + .use_sclp = 1, + .max_cpus = 255, + DEFAULT_MACHINE_OPTIONS, +}; + +static void ccw_machine_init(void) +{ + qemu_register_machine(&ccw_machine); +} + +machine_init(ccw_machine_init) diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h index 67bfd20646..a6c4c19895 100644 --- a/hw/s390x/s390-virtio.h +++ b/hw/s390x/s390-virtio.h @@ -15,6 +15,7 @@ #define KVM_S390_VIRTIO_NOTIFY 0 #define KVM_S390_VIRTIO_RESET 1 #define KVM_S390_VIRTIO_SET_STATUS 2 +#define KVM_S390_VIRTIO_CCW_NOTIFY 3 typedef int (*s390_virtio_fn)(const uint64_t *args); void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); From 2e788490d83a4de5bea00207c8695edd5d487e4a Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 25 Jan 2013 06:00:19 +0000 Subject: [PATCH 0767/1634] sclpconsole: Don't instantiate sclpconsole with -nodefaults libvirt specifies nodefaults and creates an sclp console with special parameters. Let qemu follow nodefaults and don't create an sclp console if nodefaults is specified. Signed-off-by: Christian Borntraeger Signed-off-by: Alexander Graf --- vl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vl.c b/vl.c index 8b0961ef01..910abb6526 100644 --- a/vl.c +++ b/vl.c @@ -3652,6 +3652,7 @@ int main(int argc, char **argv, char **envp) default_serial = 0; default_parallel = 0; default_virtcon = 0; + default_sclp = 0; default_monitor = 0; default_net = 0; default_floppy = 0; From 50c8d9bfc6d9ca48b978c6201f97bd850bd0dc83 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Sun, 27 Jan 2013 23:59:26 +0000 Subject: [PATCH 0768/1634] s390: Use s390_cpu_physical_memory_map for tpi. Map the I/O interruption code before calling into css. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/css.c | 2 +- target-s390x/cpu.h | 4 ++-- target-s390x/ioinst.c | 19 ++++++++++++++----- target-s390x/ioinst.h | 7 +++++++ 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 113ac9a893..84efd4ad87 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -852,7 +852,7 @@ int css_do_stcrw(CRW *crw) return ret; } -int css_do_tpi(uint64_t addr, int lowcore) +int css_do_tpi(IOIntCode *int_code, int lowcore) { /* No pending interrupts for !KVM. */ return 0; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index ce12fa46bc..9be4a475a3 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -413,7 +413,7 @@ int css_do_hsch(SubchDev *sch); int css_do_ssch(SubchDev *sch, ORB *orb); int css_do_tsch(SubchDev *sch, IRB *irb); int css_do_stcrw(CRW *crw); -int css_do_tpi(uint64_t addr, int lowcore); +int css_do_tpi(IOIntCode *int_code, int lowcore); int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, int rfmt, void *buf); void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo); @@ -471,7 +471,7 @@ static inline int css_do_stcrw(CRW *crw) { return 1; } -static inline int css_do_tpi(uint64_t addr, int lowcore) +static inline int css_do_tpi(IOIntCode *int_code, int lowcore) { return 0; } diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index 4ef2d73a43..e3531f365e 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -619,16 +619,25 @@ int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb) { uint64_t addr; int lowcore; + IOIntCode *int_code; + hwaddr len, orig_len; + int ret; trace_ioinst("tpi"); addr = decode_basedisp_s(env, ipb); lowcore = addr ? 0 : 1; - if (addr < 8192) { - addr += env->psa; - } else if ((env->psa <= addr) && (addr < env->psa + 8192)) { - addr -= env->psa; + len = lowcore ? 8 /* two words */ : 12 /* three words */; + orig_len = len; + int_code = s390_cpu_physical_memory_map(env, addr, &len, 1); + if (!int_code || (len != orig_len)) { + program_interrupt(env, PGM_SPECIFICATION, 2); + ret = -EIO; + goto out; } - return css_do_tpi(addr, lowcore); + ret = css_do_tpi(int_code, lowcore); +out: + s390_cpu_physical_memory_unmap(env, int_code, len, 1); + return ret; } #define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc) diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h index a59742c3c6..d5a43f4a71 100644 --- a/target-s390x/ioinst.h +++ b/target-s390x/ioinst.h @@ -195,6 +195,13 @@ typedef struct CRW { #define CRW_RSC_SUBCH 0x3 #define CRW_RSC_CHP 0x4 +/* I/O interruption code */ +typedef struct IOIntCode { + uint32_t subsys_id; + uint32_t intparm; + uint32_t interrupt_id; +} QEMU_PACKED IOIntCode; + /* schid disintegration */ #define IOINST_SCHID_ONE(_schid) ((_schid & 0x00010000) >> 16) #define IOINST_SCHID_M(_schid) ((_schid & 0x00080000) >> 19) From 8d034a6fad4c580be3ed4a15f24e0bf47aa92d15 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 28 Jan 2013 17:01:30 +0100 Subject: [PATCH 0769/1634] s390: css error codes. Changed error codes in the channel subsystem / virtio-ccw code (-EOPNOTSUPP -> -ENOSYS, -ERESTART -> -EINPROGRESS). This should hopefully fix building on mingw32. Signed-off-by: Cornelia Huck Reviewed-by: Stefan Weil Signed-off-by: Alexander Graf --- hw/s390x/css.c | 8 ++++---- hw/s390x/virtio-ccw.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 84efd4ad87..3244201fc7 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -223,7 +223,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) } if (ccw.flags & CCW_FLAG_SUSPEND) { - return -ERESTART; + return -EINPROGRESS; } check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); @@ -291,7 +291,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) /* Handle device specific commands. */ ret = sch->ccw_cb(sch, ccw); } else { - ret = -EOPNOTSUPP; + ret = -ENOSYS; } break; } @@ -347,7 +347,7 @@ static void sch_handle_start_func(SubchDev *sch) SCSW_STCTL_STATUS_PEND; s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END; break; - case -EOPNOTSUPP: + case -ENOSYS: /* unsupported command, generate unit check (command reject) */ s->ctrl &= ~SCSW_ACTL_START_PEND; s->dstat = SCSW_DSTAT_UNIT_CHECK; @@ -372,7 +372,7 @@ static void sch_handle_start_func(SubchDev *sch) s->ctrl &= ~SCSW_CTRL_MASK_STCTL; s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; break; - case -ERESTART: + case -EINPROGRESS: /* channel program has been suspended */ s->ctrl &= ~SCSW_ACTL_START_PEND; s->ctrl |= SCSW_ACTL_SUSP; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 8c9b7452f5..7d7f33637f 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -384,7 +384,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } break; default: - ret = -EOPNOTSUPP; + ret = -ENOSYS; break; } return ret; From 19380b1bf587fd962a60fb40cc4927ba999cf17b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 29 Jan 2013 16:33:04 +0100 Subject: [PATCH 0770/1634] s390: Drop set_bit usage in virtio_ccw. set_bit on indicators doesn't go well on 32 bit targets: note: expected 'long unsigned int *' but argument is of type 'uint64_t *' Switch to bit shifts instead. Signed-off-by: Cornelia Huck [agraf: use 1ULL instead] Signed-off-by: Alexander Graf --- hw/s390x/virtio-ccw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 7d7f33637f..231f81e48c 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -662,12 +662,12 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector) if (vector < VIRTIO_PCI_QUEUE_MAX) { indicators = ldq_phys(dev->indicators); - set_bit(vector, &indicators); + indicators |= 1ULL << vector; stq_phys(dev->indicators, indicators); } else { vector = 0; indicators = ldq_phys(dev->indicators2); - set_bit(vector, &indicators); + indicators |= 1ULL << vector; stq_phys(dev->indicators2, indicators); } From a52a8841038638afe54ffb00e0aca48de0b1539a Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 9 Jan 2013 23:50:00 +0200 Subject: [PATCH 0771/1634] e1000: document ICS read behaviour Add code comment to clarify the reason we set ICS with ICR: the reason was previously undocumented and git log confused rather than clarified the comments. Signed-off-by: Michael S. Tsirkin --- hw/e1000.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/e1000.c b/hw/e1000.c index ef06ca1894..ee85c53d38 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -237,7 +237,17 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val) val |= E1000_ICR_INT_ASSERTED; } s->mac_reg[ICR] = val; + + /* + * Make sure ICR and ICS registers have the same value. + * The spec says that the ICS register is write-only. However in practice, + * on real hardware ICS is readable, and for reads it has the same value as + * ICR (except that ICS does not have the clear on read behaviour of ICR). + * + * The VxWorks PRO/1000 driver uses this behaviour. + */ s->mac_reg[ICS] = val; + qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0); } From 4b25966ab976f3a7fd9008193b2defcc82f8f04d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 15 Jan 2013 13:12:35 +0200 Subject: [PATCH 0772/1634] rules.mak: cleanup config generation rules This addresses two issues with config generation 1. rule generating timestamp has side effect. Thus cleanup on error does not work. 2. rule for handling timestamp is too generic. It can create any missing .h file. As a result when .h file is removed, build might try to create it using this rule which results in build errors. Signed-off-by: Michael S. Tsirkin --- rules.mak | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rules.mak b/rules.mak index 6d82c0d5a0..d11a5b4f00 100644 --- a/rules.mak +++ b/rules.mak @@ -82,12 +82,11 @@ TRACETOOL=$(PYTHON) $(SRC_PATH)/scripts/tracetool.py # Generate timestamp files for .h include files -%.h: %.h-timestamp - @test -f $@ || cp $< $@ +config-%.h: config-%.h-timestamp + @cmp $< $@ >/dev/null 2>&1 || cp $< $@ -%.h-timestamp: %.mak - $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $(TARGET_DIR)$*.h") - @cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h +config-%.h-timestamp: config-%.mak + $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $(TARGET_DIR)config-$*.h") # will delete the target of a rule if commands exit with a nonzero exit status .DELETE_ON_ERROR: From 6f329a55305c3b14da3c7b35f19379bae745e728 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 15 Jan 2013 14:47:33 +0200 Subject: [PATCH 0773/1634] Makefile: clean timestamp generation rule create timestamp by rule without sideeffects. Signed-off-by: Michael S. Tsirkin --- trace/Makefile.objs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trace/Makefile.objs b/trace/Makefile.objs index 27fe26b5c2..dde9d5784e 100644 --- a/trace/Makefile.objs +++ b/trace/Makefile.objs @@ -4,24 +4,24 @@ # Auto-generated header for tracing routines $(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp + @cmp -s $< $@ || cp $< $@ $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=h \ --backend=$(TRACE_BACKEND) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") - @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) ###################################################################### # Auto-generated tracing routines (non-DTrace) ifneq ($(TRACE_BACKEND),dtrace) $(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp + @cmp -s $< $@ || cp $< $@ $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak $(call quiet-command,$(TRACETOOL) \ --format=c \ --backend=$(TRACE_BACKEND) \ < $< > $@," GEN $(patsubst %-timestamp,%,$@)") - @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@) $(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h endif From 7586317bc0db3b993446b21eec914f5b66645ee4 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 15 Jan 2013 13:27:54 +0200 Subject: [PATCH 0774/1634] rules/mak: make clean should blow away timestamp files Using a global pattern makes it easier to clean out old generated files. Signed-off-by: Michael S. Tsirkin --- rules.mak | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rules.mak b/rules.mak index d11a5b4f00..edc2552f08 100644 --- a/rules.mak +++ b/rules.mak @@ -88,6 +88,11 @@ config-%.h: config-%.h-timestamp config-%.h-timestamp: config-%.mak $(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $(TARGET_DIR)config-$*.h") +.PHONY: clean-timestamp +clean-timestamp: + rm -f *.timestamp +clean: clean-timestamp + # will delete the target of a rule if commands exit with a nonzero exit status .DELETE_ON_ERROR: From 41dc8a67c7dcecdf7ae1cd25db3c46f2b42a221f Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 16 Jan 2013 11:37:40 +0200 Subject: [PATCH 0775/1634] virtio-net: revert mac on reset Once guest overrides virtio net primary mac, it retains the value set until qemu exit. This is inconsistent with standard nic behaviour. To fix, revert the mac to the original value on reset. Signed-off-by: Michael S. Tsirkin --- hw/virtio-net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 3bb01b1037..4d80a25744 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -199,6 +199,7 @@ static void virtio_net_reset(VirtIODevice *vdev) n->mac_table.multi_overflow = 0; n->mac_table.uni_overflow = 0; memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); + memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac)); memset(n->vlans, 0, MAX_VLAN >> 3); } From 921ac5d0f3a0df869db5ce4edf752f51d8b1596a Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 22 Jan 2013 23:44:44 +0800 Subject: [PATCH 0776/1634] virtio-net: remove layout assumptions for ctrl vq Virtio-net code makes assumption about virtqueue descriptor layout (e.g. sg[0] is the header, sg[1] is the data buffer). This patch makes code not rely on the layout of descriptors. Signed-off-by: Michael S. Tsirkin Signed-off-by: Amos Kong Signed-off-by: Michael S. Tsirkin --- hw/virtio-net.c | 133 ++++++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 56 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 4d80a25744..9ea987562f 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -316,44 +316,44 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) } static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, - VirtQueueElement *elem) + struct iovec *iov, unsigned int iov_cnt) { uint8_t on; + size_t s; - if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) { - error_report("virtio-net ctrl invalid rx mode command"); - exit(1); + s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on)); + if (s != sizeof(on)) { + return VIRTIO_NET_ERR; } - on = ldub_p(elem->out_sg[1].iov_base); - - if (cmd == VIRTIO_NET_CTRL_RX_MODE_PROMISC) + if (cmd == VIRTIO_NET_CTRL_RX_MODE_PROMISC) { n->promisc = on; - else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) + } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) { n->allmulti = on; - else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI) + } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI) { n->alluni = on; - else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI) + } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI) { n->nomulti = on; - else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI) + } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI) { n->nouni = on; - else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST) + } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST) { n->nobcast = on; - else + } else { return VIRTIO_NET_ERR; + } return VIRTIO_NET_OK; } static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, - VirtQueueElement *elem) + struct iovec *iov, unsigned int iov_cnt) { struct virtio_net_ctrl_mac mac_data; + size_t s; - if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET || elem->out_num != 3 || - elem->out_sg[1].iov_len < sizeof(mac_data) || - elem->out_sg[2].iov_len < sizeof(mac_data)) + if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) { return VIRTIO_NET_ERR; + } n->mac_table.in_use = 0; n->mac_table.first_multi = 0; @@ -361,54 +361,72 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, n->mac_table.multi_overflow = 0; memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); - mac_data.entries = ldl_p(elem->out_sg[1].iov_base); - - if (sizeof(mac_data.entries) + - (mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len) + s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, + sizeof(mac_data.entries)); + mac_data.entries = ldl_p(&mac_data.entries); + if (s != sizeof(mac_data.entries)) { return VIRTIO_NET_ERR; + } + iov_discard_front(&iov, &iov_cnt, s); + + if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) { + return VIRTIO_NET_ERR; + } if (mac_data.entries <= MAC_TABLE_ENTRIES) { - memcpy(n->mac_table.macs, elem->out_sg[1].iov_base + sizeof(mac_data), - mac_data.entries * ETH_ALEN); + s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs, + mac_data.entries * ETH_ALEN); + if (s != mac_data.entries * ETH_ALEN) { + return VIRTIO_NET_ERR; + } n->mac_table.in_use += mac_data.entries; } else { n->mac_table.uni_overflow = 1; } + iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN); + n->mac_table.first_multi = n->mac_table.in_use; - mac_data.entries = ldl_p(elem->out_sg[2].iov_base); - - if (sizeof(mac_data.entries) + - (mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len) + s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries, + sizeof(mac_data.entries)); + mac_data.entries = ldl_p(&mac_data.entries); + if (s != sizeof(mac_data.entries)) { return VIRTIO_NET_ERR; + } - if (mac_data.entries) { - if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) { - memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN), - elem->out_sg[2].iov_base + sizeof(mac_data), - mac_data.entries * ETH_ALEN); - n->mac_table.in_use += mac_data.entries; - } else { - n->mac_table.multi_overflow = 1; + iov_discard_front(&iov, &iov_cnt, s); + + if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) { + return VIRTIO_NET_ERR; + } + + if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) { + s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs, + mac_data.entries * ETH_ALEN); + if (s != mac_data.entries * ETH_ALEN) { + return VIRTIO_NET_ERR; } + n->mac_table.in_use += mac_data.entries; + } else { + n->mac_table.multi_overflow = 1; } return VIRTIO_NET_OK; } static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, - VirtQueueElement *elem) + struct iovec *iov, unsigned int iov_cnt) { uint16_t vid; + size_t s; - if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) { - error_report("virtio-net ctrl invalid vlan command"); + s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid)); + vid = lduw_p(&vid); + if (s != sizeof(vid)) { return VIRTIO_NET_ERR; } - vid = lduw_p(elem->out_sg[1].iov_base); - if (vid >= MAX_VLAN) return VIRTIO_NET_ERR; @@ -428,30 +446,33 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) struct virtio_net_ctrl_hdr ctrl; virtio_net_ctrl_ack status = VIRTIO_NET_ERR; VirtQueueElement elem; + size_t s; + struct iovec *iov; + unsigned int iov_cnt; while (virtqueue_pop(vq, &elem)) { - if ((elem.in_num < 1) || (elem.out_num < 1)) { + if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) || + iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) { error_report("virtio-net ctrl missing headers"); exit(1); } - if (elem.out_sg[0].iov_len < sizeof(ctrl) || - elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) { - error_report("virtio-net ctrl header not in correct element"); - exit(1); + iov = elem.out_sg; + iov_cnt = elem.out_num; + s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); + iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); + if (s != sizeof(ctrl)) { + status = VIRTIO_NET_ERR; + } else if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE) { + status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); + } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { + status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); + } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { + status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); } - ctrl.class = ldub_p(elem.out_sg[0].iov_base); - ctrl.cmd = ldub_p(elem.out_sg[0].iov_base + sizeof(ctrl.class)); - - if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE) - status = virtio_net_handle_rx_mode(n, ctrl.cmd, &elem); - else if (ctrl.class == VIRTIO_NET_CTRL_MAC) - status = virtio_net_handle_mac(n, ctrl.cmd, &elem); - else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) - status = virtio_net_handle_vlan_table(n, ctrl.cmd, &elem); - - stb_p(elem.in_sg[elem.in_num - 1].iov_base, status); + s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status)); + assert(s == sizeof(status)); virtqueue_push(vq, &elem, sizeof(status)); virtio_notify(vdev, vq); From c1943a3f3774ee1aad51e8cc5b8cd24e66e198a5 Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Tue, 22 Jan 2013 23:44:45 +0800 Subject: [PATCH 0777/1634] virtio-net: introduce a new macaddr control In virtio-net guest driver, currently we write MAC address to pci config space byte by byte, this means that we have an intermediate step where mac is wrong. This patch introduced a new control command to set MAC address, it's atomic. VIRTIO_NET_F_CTRL_MAC_ADDR is a new feature bit for compatibility. "mac" field will be set to read-only when VIRTIO_NET_F_CTRL_MAC_ADDR is acked. Signed-off-by: Amos Kong Signed-off-by: Michael S. Tsirkin --- hw/pc_piix.c | 4 ++++ hw/virtio-net.c | 13 ++++++++++++- hw/virtio-net.h | 12 ++++++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index b9a9b2efe1..ba09714d6c 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -309,6 +309,10 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { .driver = "usb-tablet",\ .property = "usb_version",\ .value = stringify(1),\ + },{\ + .driver = "virtio-net-pci",\ + .property = "ctrl_mac_addr",\ + .value = "off", \ } static QEMUMachine pc_machine_v1_3 = { diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 9ea987562f..04834e99a7 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -93,7 +93,8 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) memcpy(&netcfg, config, sizeof(netcfg)); - if (memcmp(netcfg.mac, n->mac, ETH_ALEN)) { + if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) && + memcmp(netcfg.mac, n->mac, ETH_ALEN)) { memcpy(n->mac, netcfg.mac, ETH_ALEN); qemu_format_nic_info_str(&n->nic->nc, n->mac); } @@ -351,6 +352,16 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, struct virtio_net_ctrl_mac mac_data; size_t s; + if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) { + if (iov_size(iov, iov_cnt) != sizeof(n->mac)) { + return VIRTIO_NET_ERR; + } + s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac)); + assert(s == sizeof(n->mac)); + qemu_format_nic_info_str(&n->nic->nc, n->mac); + return VIRTIO_NET_OK; + } + if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) { return VIRTIO_NET_ERR; } diff --git a/hw/virtio-net.h b/hw/virtio-net.h index d46fb9840f..1ec632f2f3 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -44,6 +44,8 @@ #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ #define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */ +#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ + #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ #define TX_TIMER_INTERVAL 150000 /* 150 us */ @@ -106,7 +108,7 @@ typedef uint8_t virtio_net_ctrl_ack; #define VIRTIO_NET_CTRL_RX_MODE_NOBCAST 5 /* - * Control the MAC filter table. + * Control the MAC * * The MAC filter table is managed by the hypervisor, the guest should * assume the size is infinite. Filtering should be considered @@ -119,6 +121,10 @@ typedef uint8_t virtio_net_ctrl_ack; * first sg list contains unicast addresses, the second is for multicast. * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature * is available. + * + * The ADDR_SET command requests one out scatterlist, it contains a + * 6 bytes MAC address. This functionality is present if the + * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available. */ struct virtio_net_ctrl_mac { uint32_t entries; @@ -126,6 +132,7 @@ struct virtio_net_ctrl_mac { }; #define VIRTIO_NET_CTRL_MAC 1 #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 + #define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 /* * Control VLAN filtering @@ -158,5 +165,6 @@ struct virtio_net_ctrl_mac { DEFINE_PROP_BIT("ctrl_vq", _state, _field, VIRTIO_NET_F_CTRL_VQ, true), \ DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \ DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \ - DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true) + DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true), \ + DEFINE_PROP_BIT("ctrl_mac_addr", _state, _field, VIRTIO_NET_F_CTRL_MAC_ADDR, true) #endif From dd23454ba2c83168b453155365671e67723b881f Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Tue, 22 Jan 2013 23:44:46 +0800 Subject: [PATCH 0778/1634] virtio-net: rename ctrl rx commands This patch makes rx commands consistent with specification. Signed-off-by: Amos Kong Signed-off-by: Michael S. Tsirkin --- hw/virtio-net.c | 14 +++++++------- hw/virtio-net.h | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 04834e99a7..dfb9687d2f 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -327,17 +327,17 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; } - if (cmd == VIRTIO_NET_CTRL_RX_MODE_PROMISC) { + if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) { n->promisc = on; - } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) { + } else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) { n->allmulti = on; - } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI) { + } else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) { n->alluni = on; - } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI) { + } else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) { n->nomulti = on; - } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI) { + } else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) { n->nouni = on; - } else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST) { + } else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) { n->nobcast = on; } else { return VIRTIO_NET_ERR; @@ -474,7 +474,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) iov_discard_front(&iov, &iov_cnt, sizeof(ctrl)); if (s != sizeof(ctrl)) { status = VIRTIO_NET_ERR; - } else if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE) { + } else if (ctrl.class == VIRTIO_NET_CTRL_RX) { status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt); } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) { status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 1ec632f2f3..c0bb284df2 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -99,13 +99,13 @@ typedef uint8_t virtio_net_ctrl_ack; * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature. * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA. */ -#define VIRTIO_NET_CTRL_RX_MODE 0 - #define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0 - #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1 - #define VIRTIO_NET_CTRL_RX_MODE_ALLUNI 2 - #define VIRTIO_NET_CTRL_RX_MODE_NOMULTI 3 - #define VIRTIO_NET_CTRL_RX_MODE_NOUNI 4 - #define VIRTIO_NET_CTRL_RX_MODE_NOBCAST 5 +#define VIRTIO_NET_CTRL_RX 0 + #define VIRTIO_NET_CTRL_RX_PROMISC 0 + #define VIRTIO_NET_CTRL_RX_ALLMULTI 1 + #define VIRTIO_NET_CTRL_RX_ALLUNI 2 + #define VIRTIO_NET_CTRL_RX_NOMULTI 3 + #define VIRTIO_NET_CTRL_RX_NOUNI 4 + #define VIRTIO_NET_CTRL_RX_NOBCAST 5 /* * Control the MAC From 91c3f2f00810a9ba5e4404c9611197efd8f694c8 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Tue, 22 Jan 2013 19:11:37 -0700 Subject: [PATCH 0779/1634] ich9: add support for pci assignment Fills out support for the pci assignment API. Added: PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin) Add calls to pci_bus_fire_intx_routing_notifier() when routing changes are made. Signed-off-by: Jason Baron Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/ich9.h | 1 + hw/lpc_ich9.c | 33 +++++++++++++++++++++++++++++++++ hw/pc_q35.c | 1 + 3 files changed, 35 insertions(+) diff --git a/hw/ich9.h b/hw/ich9.h index b8d8e6d3df..d4509bb606 100644 --- a/hw/ich9.h +++ b/hw/ich9.h @@ -18,6 +18,7 @@ void ich9_lpc_set_irq(void *opaque, int irq_num, int level); int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); +PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin); void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3); PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus); i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base); diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index 16843d76bc..e25689bf87 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -158,6 +158,7 @@ static void ich9_cc_write(void *opaque, hwaddr addr, ich9_cc_addr_len(&addr, &len); memcpy(lpc->chip_config + addr, &val, len); + pci_bus_fire_intx_routing_notifier(lpc->d.bus); ich9_cc_update(lpc); } @@ -286,6 +287,32 @@ int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx) return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx]; } +PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin) +{ + ICH9LPCState *lpc = opaque; + PCIINTxRoute route; + int pic_irq; + int pic_dis; + + assert(0 <= pirq_pin); + assert(pirq_pin < ICH9_LPC_NB_PIRQS); + + route.mode = PCI_INTX_ENABLED; + ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis); + if (!pic_dis) { + if (pic_irq < ICH9_LPC_PIC_NUM_PINS) { + route.irq = pic_irq; + } else { + route.mode = PCI_INTX_DISABLED; + route.irq = -1; + } + } else { + route.irq = ich9_pirq_to_gsi(pirq_pin); + } + + return route; +} + static int ich9_lpc_sci_irq(ICH9LPCState *lpc) { switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] & @@ -405,6 +432,12 @@ static void ich9_lpc_config_write(PCIDevice *d, if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) { ich9_lpc_rcba_update(lpc, rbca_old); } + if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) { + pci_bus_fire_intx_routing_notifier(lpc->d.bus); + } + if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) { + pci_bus_fire_intx_routing_notifier(lpc->d.bus); + } } static void ich9_lpc_reset(DeviceState *qdev) diff --git a/hw/pc_q35.c b/hw/pc_q35.c index d82353e84f..6f5ff8dcae 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -147,6 +147,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) ich9_lpc->ioapic = gsi_state->ioapic_irq; pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc, ICH9_LPC_NB_PIRQS); + pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq); isa_bus = ich9_lpc->isa_bus; /*end early*/ From 1ec4ba741630699665a6334f3959271da3effec7 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 24 Jan 2013 10:31:20 +0100 Subject: [PATCH 0780/1634] PIIX3: reset the VM when the Reset Control Register's RCPU bit gets set Traditional PCI config space access is achieved by writing a 32 bit value to io port 0xcf8 to identify the bus, device, function and config register. Port 0xcfc then contains the register in question. But if you write the appropriate pair of magic values to 0xcf9, the machine will reboot. Spectacular! And not standardised in any way (certainly not part of the PCI spec), so different chipsets may have different requirements. Booo. In the PIIX3 spec, IO port 0xcf9 is specified as the Reset Control Register. Bit 1 (System Reset, SRST) would normally differentiate between soft reset and hard reset, but we ignore the difference beyond allowing the guest to read it back. RHBZ reference: 890459 This patch introduces the following overlap between the preexistent "pci-conf-idx" region and the "piix3-reset-control" region just being added. Partial output from "info mtree": I/O 0000000000000000-000000000000ffff (prio 0, RW): io 0000000000000cf8-0000000000000cfb (prio 0, RW): pci-conf-idx 0000000000000cf9-0000000000000cf9 (prio 1, RW): piix3-reset-control I sanity-checked the patch by booting a RHEL-6.3 guest and found no problems. I summoned gdb and set a breakpoint on rcr_write() in order to gather a bit more confidence. Relevant frames of the stack: kvm_handle_io (port=3321, data=0x7f3f5f3de000, direction=1, size=1, count=1) [kvm-all.c:1422] cpu_outb (addr=3321, val=6 '\006') [ioport.c:289] ioport_write (index=0, address=3321, data=6) [ioport.c:83] ioport_writeb_thunk (opaque=0x7f3f622c4680, addr=3321, data=6) [ioport.c:212] memory_region_iorange_write (iorange=0x7f3f622c4680, offset=0, width=1, data=6) [memory.c:439] access_with_adjusted_size (addr=0, value=0x7f3f531fbac0, size=1, access_size_min=1, access_size_max=4, access=0x7f3f5f6e0f90 , opaque=0x7f3f6227b668) [memory.c:364] memory_region_write_accessor (opaque=0x7f3f6227b668, addr=0, value=0x7f3f531fbac0, size=1, shift=0, mask=255) [memory.c:334] rcr_write (opaque=0x7f3f6227afb0, addr=0, val=6, len=1) [hw/piix_pci.c:498] The dispatch happens in ioport_write(); "index=0" means byte-wide access: static void ioport_write(int index, uint32_t address, uint32_t data) { static IOPortWriteFunc * const default_func[3] = { default_ioport_writeb, default_ioport_writew, default_ioport_writel }; IOPortWriteFunc *func = ioport_write_table[index][address]; if (!func) func = default_func[index]; func(ioport_opaque[address], address, data); } The "ioport_write_table" and "ioport_opaque" arrays describe the flattened IO port space. The first array is less interesting (it selects a thunk function). The "ioport_opaque" array is interesting because it decides how writing to the port is implemented ultimately. 4-byte wide access to 0xcf8 (pci-conf-idx): (gdb) print ioport_write_table[2][0xcf8] $1 = (IOPortWriteFunc *) 0x7f3f5f6d99ba (gdb) print \ ((struct MemoryRegionIORange*)ioport_opaque[0xcf8])->mr->ops.write $2 = (void (*)(void *, hwaddr, uint64_t, unsigned int)) 0x7f3f5f5575cb 1-byte wide access to 0xcf9 (piix3-reset-control): (gdb) print ioport_write_table[0][0xcf9] $3 = (IOPortWriteFunc *) 0x7f3f5f6d98d0 (gdb) print \ ((struct MemoryRegionIORange*)ioport_opaque[0xcf9])->mr->ops.write $4 = (void (*)(void *, hwaddr, uint64_t, unsigned int)) 0x7f3f5f6b42f1 The higher priority of "piix3-reset-control" ensures that the 0xcf9 entries in ioport_write_table / ioport_opaque will always belong to it, independently of its relative registration order versus "pci-conf-idx". Signed-off-by: Laszlo Ersek Signed-off-by: Michael S. Tsirkin --- hw/piix_pci.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 3d79c73fda..6c77e493e4 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -31,6 +31,7 @@ #include "qemu/range.h" #include "xen.h" #include "pam.h" +#include "sysemu/sysemu.h" /* * I440FX chipset data sheet. @@ -46,6 +47,12 @@ typedef struct I440FXState { #define XEN_PIIX_NUM_PIRQS 128ULL #define PIIX_PIRQC 0x60 +/* + * Reset Control Register: PCI-accessible ISA-Compatible Register at address + * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000). + */ +#define RCR_IOPORT 0xcf9 + typedef struct PIIX3State { PCIDevice dev; @@ -67,6 +74,12 @@ typedef struct PIIX3State { /* This member isn't used. Just for save/load compatibility */ int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; + + /* Reset Control Register contents */ + uint8_t rcr; + + /* IO memory region for Reset Control Register (RCR_IOPORT) */ + MemoryRegion rcr_mem; } PIIX3State; struct PCII440FXState { @@ -442,6 +455,7 @@ static void piix3_reset(void *opaque) pci_conf[0xae] = 0x00; d->pic_levels = 0; + d->rcr = 0; } static int piix3_post_load(void *opaque, int version_id) @@ -462,6 +476,23 @@ static void piix3_pre_save(void *opaque) } } +static bool piix3_rcr_needed(void *opaque) +{ + PIIX3State *piix3 = opaque; + + return (piix3->rcr != 0); +} + +static const VMStateDescription vmstate_piix3_rcr = { + .name = "PIIX3/rcr", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) { + VMSTATE_UINT8(rcr, PIIX3State), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_piix3 = { .name = "PIIX3", .version_id = 3, @@ -469,19 +500,56 @@ static const VMStateDescription vmstate_piix3 = { .minimum_version_id_old = 2, .post_load = piix3_post_load, .pre_save = piix3_pre_save, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, PIIX3State), VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State, PIIX_NUM_PIRQS, 3), VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &vmstate_piix3_rcr, + .needed = piix3_rcr_needed, + }, + { 0 } } }; + +static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len) +{ + PIIX3State *d = opaque; + + if (val & 4) { + qemu_system_reset_request(); + return; + } + d->rcr = val & 2; /* keep System Reset type only */ +} + +static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len) +{ + PIIX3State *d = opaque; + + return d->rcr; +} + +static const MemoryRegionOps rcr_ops = { + .read = rcr_read, + .write = rcr_write, + .endianness = DEVICE_LITTLE_ENDIAN +}; + static int piix3_initfn(PCIDevice *dev) { PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev); isa_bus_new(&d->dev.qdev, pci_address_space_io(dev)); + + memory_region_init_io(&d->rcr_mem, &rcr_ops, d, "piix3-reset-control", 1); + memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT, + &d->rcr_mem, 1); + qemu_register_reset(piix3_reset, d); return 0; } From 6a659bbff991b0033d1bf1ff71b7d550e0367d99 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 23 Jan 2013 17:46:13 -0700 Subject: [PATCH 0781/1634] vfio-pci: Enable PCIe extended config space We don't know pre-init time whether the device we're exposing is PCIe or legacy PCI. We could ask for it to be specified via a device option, but that seems like too much to ask of the user. Instead we can assume everything will be PCIe, which makes PCI-core allocate enough config space. Removing the flag during init leaves the space allocated, but allows legacy PCI devices to report the real device config space size to rest of Qemu. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/vfio_pci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index c51ae6761b..66537b7eb5 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -1899,6 +1899,9 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) (unsigned long)reg_info.flags); vdev->config_size = reg_info.size; + if (vdev->config_size == PCI_CONFIG_SPACE_SIZE) { + vdev->pdev.cap_present &= ~QEMU_PCI_CAP_EXPRESS; + } vdev->config_offset = reg_info.offset; error: @@ -2121,6 +2124,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) pdc->exit = vfio_exitfn; pdc->config_read = vfio_pci_read_config; pdc->config_write = vfio_pci_write_config; + pdc->is_express = 1; /* We might be */ } static const TypeInfo vfio_pci_dev_info = { From cfba8e6f92d45a2374622c3dc57499e42a1c07e1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 25 Jan 2013 10:31:16 +0100 Subject: [PATCH 0782/1634] vnc: Clean up vncws_send_handshake_response() Use appropriate types, drop superfluous casts, use sizeof, don't exploit that this particular call of gnutls_fingerprint() doesn't change its last argument. Signed-off-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- ui/vnc-ws.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index 9ccdc1971c..3e3020916c 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -120,10 +120,11 @@ static char *vncws_extract_handshake_entry(const char *handshake, static void vncws_send_handshake_response(VncState *vs, const char* key) { char combined_key[WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1]; - char hash[SHA1_DIGEST_LEN]; - size_t hash_size = SHA1_DIGEST_LEN; + unsigned char hash[SHA1_DIGEST_LEN]; + size_t hash_size = sizeof(hash); char *accept = NULL, *response = NULL; gnutls_datum_t in; + int ret; g_strlcpy(combined_key, key, WS_CLIENT_KEY_LEN + 1); g_strlcat(combined_key, WS_GUID, WS_CLIENT_KEY_LEN + WS_GUID_LEN + 1); @@ -131,9 +132,9 @@ static void vncws_send_handshake_response(VncState *vs, const char* key) /* hash and encode it */ in.data = (void *)combined_key; in.size = WS_CLIENT_KEY_LEN + WS_GUID_LEN; - if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &in, hash, &hash_size) - == GNUTLS_E_SUCCESS) { - accept = g_base64_encode((guchar *)hash, SHA1_DIGEST_LEN); + ret = gnutls_fingerprint(GNUTLS_DIG_SHA1, &in, hash, &hash_size); + if (ret == GNUTLS_E_SUCCESS && hash_size <= SHA1_DIGEST_LEN) { + accept = g_base64_encode(hash, hash_size); } if (accept == NULL) { VNC_DEBUG("Hashing Websocket combined key failed\n"); From c69544130f50536c61686a9ec6734327b6174ee0 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Sat, 26 Jan 2013 12:54:33 -0800 Subject: [PATCH 0783/1634] cadence_ttc: Debug mode compile fixes Some printfs are throwing warnings when debug mode is enabled. Fixed. Signed-off-by: Peter Crosthwaite Signed-off-by: Stefan Hajnoczi --- hw/cadence_ttc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index 2a8fadd810..67028a3f75 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -302,7 +302,7 @@ static uint64_t cadence_ttc_read(void *opaque, hwaddr offset, { uint32_t ret = cadence_ttc_read_imp(opaque, offset); - DB_PRINT("addr: %08x data: %08x\n", offset, ret); + DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret); return ret; } @@ -311,7 +311,7 @@ static void cadence_ttc_write(void *opaque, hwaddr offset, { CadenceTimerState *s = cadence_timer_from_addr(opaque, offset); - DB_PRINT("addr: %08x data %08x\n", offset, (unsigned)value); + DB_PRINT("addr: %08x data %08x\n", (unsigned)offset, (unsigned)value); cadence_timer_sync(s); From 080251a46493e4e4cb6cbd6e2878d31c7cf023c5 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Sat, 26 Jan 2013 12:54:34 -0800 Subject: [PATCH 0784/1634] cadence_gem: Debug mode compile fixes Some printfs are throwing warnings when debug mode is enabled. Fixed. Signed-off-by: Peter Crosthwaite Signed-off-by: Stefan Hajnoczi --- hw/cadence_gem.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 0d834422df..b77423d449 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -687,14 +687,15 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) packet_desc_addr = s->rx_desc_addr; while (1) { - DB_PRINT("read descriptor 0x%x\n", packet_desc_addr); + DB_PRINT("read descriptor 0x%x\n", (unsigned)packet_desc_addr); /* read current descriptor */ cpu_physical_memory_read(packet_desc_addr, (uint8_t *)&desc[0], sizeof(desc)); /* Descriptor owned by software ? */ if (rx_desc_get_ownership(desc) == 1) { - DB_PRINT("descriptor 0x%x owned by sw.\n", packet_desc_addr); + DB_PRINT("descriptor 0x%x owned by sw.\n", + (unsigned)packet_desc_addr); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; /* Handle interrupt consequences */ gem_update_int_status(s); @@ -709,7 +710,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) */ if (rx_desc_get_buffer(desc) == 0) { DB_PRINT("Invalid RX buffer (NULL) for descriptor 0x%x\n", - packet_desc_addr); + (unsigned)packet_desc_addr); break; } @@ -749,7 +750,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) s->rx_desc_addr += 8; } - DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", packet_desc_addr); + DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", (unsigned)packet_desc_addr); /* Count it */ gem_receive_updatestats(s, buf, size); @@ -861,7 +862,8 @@ static void gem_transmit(GemState *s) */ if ((tx_desc_get_buffer(desc) == 0) || (tx_desc_get_length(desc) == 0)) { - DB_PRINT("Invalid TX descriptor @ 0x%x\n", packet_desc_addr); + DB_PRINT("Invalid TX descriptor @ 0x%x\n", + (unsigned)packet_desc_addr); break; } @@ -1031,10 +1033,11 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) offset >>= 2; retval = s->regs[offset]; - DB_PRINT("offset: 0x%04x read: 0x%08x\n", offset*4, retval); + DB_PRINT("offset: 0x%04x read: 0x%08x\n", (unsigned)offset*4, retval); switch (offset) { case GEM_ISR: + DB_PRINT("lowering irq on ISR read\n"); qemu_set_irq(s->irq, 0); break; case GEM_PHYMNTNC: @@ -1073,7 +1076,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, GemState *s = (GemState *)opaque; uint32_t readonly; - DB_PRINT("offset: 0x%04x write: 0x%08x ", offset, (unsigned)val); + DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val); offset >>= 2; /* Squash bits which are read only in write value */ From 74cef80c473fe4ce195d5280a34bb2af8492aabb Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Sat, 26 Jan 2013 12:54:35 -0800 Subject: [PATCH 0785/1634] xilinx_axidma: Fix debug mode compile messages Missing cast one one of the conditionally compiled printfs. Signed-off-by: Peter Crosthwaite Signed-off-by: Stefan Hajnoczi --- hw/xilinx_axidma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index d0ee566a28..cc51584dfc 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -444,7 +444,7 @@ static void axidma_write(void *opaque, hwaddr addr, break; default: D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n", - __func__, sid, addr * 4, value)); + __func__, sid, addr * 4, (unsigned)value)); s->regs[addr] = value; break; } From 75610155562bd480356a7a5018e5de4c44ec7884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 26 Jan 2013 20:41:58 +0100 Subject: [PATCH 0786/1634] prep: Move PReP machine to hw/ppc/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber --- MAINTAINERS | 2 +- hw/ppc/Makefile.objs | 3 ++- hw/{ppc_prep.c => ppc/prep.c} | 28 ++++++++++++++-------------- 3 files changed, 17 insertions(+), 16 deletions(-) rename hw/{ppc_prep.c => ppc/prep.c} (98%) diff --git a/MAINTAINERS b/MAINTAINERS index 9dd4c20798..21043e4b4a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -395,7 +395,7 @@ PReP M: Andreas Färber L: qemu-ppc@nongnu.org S: Odd Fixes -F: hw/ppc_prep.c +F: hw/ppc/prep.c F: hw/prep_pci.[hc] F: hw/pc87312.[hc] diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 462146b0b0..f7620509a9 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -2,7 +2,6 @@ obj-y = ppc.o ppc_booke.o # PREP target obj-y += mc146818rtc.o -obj-y += ppc_prep.o # IBM pSeries (sPAPR) obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o @@ -24,6 +23,8 @@ obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) +# PReP +obj-y += prep.o # OldWorld PowerMac obj-y += mac_oldworld.o # NewWorld PowerMac diff --git a/hw/ppc_prep.c b/hw/ppc/prep.c similarity index 98% rename from hw/ppc_prep.c rename to hw/ppc/prep.c index a35fbedbdc..e06dded003 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc/prep.c @@ -21,23 +21,23 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "nvram.h" -#include "pc.h" -#include "serial.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/nvram.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/fdc.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "isa.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "ppc.h" -#include "boards.h" +#include "hw/isa.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/ppc.h" +#include "hw/boards.h" #include "qemu/log.h" -#include "ide.h" -#include "loader.h" -#include "mc146818rtc.h" -#include "pc87312.h" +#include "hw/ide.h" +#include "hw/loader.h" +#include "hw/mc146818rtc.h" +#include "hw/pc87312.h" #include "sysemu/blockdev.h" #include "sysemu/arch_init.h" #include "exec/address-spaces.h" From 6528499fa4c3ceaec01ad29d8090ef55918ebfb3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:07:56 +0100 Subject: [PATCH 0787/1634] g_malloc(0) and g_malloc0(0) return NULL; simplify Once upon a time, it was decided that qemu_malloc(0) should abort. Switching to glib retired that bright idea. Some code that was added to cope with it (e.g. in commits 702ef63, b76b6e9) is still around. Bury it. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- block/qcow2-refcount.c | 6 +----- block/vdi.c | 4 +--- hw/9pfs/virtio-9p.c | 6 +----- hw/vhost.c | 7 ++----- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 6a95aa6c92..bc1784c30e 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -737,11 +737,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, * l1_table_offset when it is the current s->l1_table_offset! Be careful * when changing this! */ if (l1_table_offset != s->l1_table_offset) { - if (l1_size2 != 0) { - l1_table = g_malloc0(align_offset(l1_size2, 512)); - } else { - l1_table = NULL; - } + l1_table = g_malloc0(align_offset(l1_size2, 512)); l1_allocated = 1; if (bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2) != l1_size2) diff --git a/block/vdi.c b/block/vdi.c index 257a592ea9..87c691b504 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -443,9 +443,7 @@ static int vdi_open(BlockDriverState *bs, int flags) bmap_size = header.blocks_in_image * sizeof(uint32_t); bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE; - if (bmap_size > 0) { - s->bmap = g_malloc(bmap_size * SECTOR_SIZE); - } + s->bmap = g_malloc(bmap_size * SECTOR_SIZE); ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size); if (ret < 0) { goto fail_free_bmap; diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 0aaf0d2de0..b795839620 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -3101,11 +3101,7 @@ static void v9fs_xattrcreate(void *opaque) xattr_fidp->fs.xattr.flags = flags; v9fs_string_init(&xattr_fidp->fs.xattr.name); v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name); - if (size) { - xattr_fidp->fs.xattr.value = g_malloc(size); - } else { - xattr_fidp->fs.xattr.value = NULL; - } + xattr_fidp->fs.xattr.value = g_malloc(size); err = offset; put_fid(pdu, file_fidp); out_nofid: diff --git a/hw/vhost.c b/hw/vhost.c index cee8aad4a1..0dd2a9aa40 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -269,11 +269,8 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) vhost_log_chunk_t *log; uint64_t log_base; int r, i; - if (size) { - log = g_malloc0(size * sizeof *log); - } else { - log = NULL; - } + + log = g_malloc0(size * sizeof *log); log_base = (uint64_t)(unsigned long)log; r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base); assert(r >= 0); From c64f50d1e250879611e6f328e2c4fb18c8a4ab0c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:07:57 +0100 Subject: [PATCH 0788/1634] g_strdup(NULL) returns NULL; simplify Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- hw/9pfs/virtio-9p-device.c | 6 +----- hw/block-common.c | 4 +--- net/net.c | 4 +--- slirp/slirp.c | 8 ++------ util/qemu-option.c | 8 ++------ 5 files changed, 7 insertions(+), 23 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 6f427dfc5d..6eab7f7fa1 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -85,11 +85,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) } s->ctx.export_flags = fse->export_flags; - if (fse->path) { - s->ctx.fs_root = g_strdup(fse->path); - } else { - s->ctx.fs_root = NULL; - } + s->ctx.fs_root = g_strdup(fse->path); s->ctx.exops.get_st_gen = NULL; len = strlen(conf->tag); if (len > MAX_TAG_LEN - 1) { diff --git a/hw/block-common.c b/hw/block-common.c index 0f1b64ec95..d21ec3ada1 100644 --- a/hw/block-common.c +++ b/hw/block-common.c @@ -18,9 +18,7 @@ void blkconf_serial(BlockConf *conf, char **serial) if (!*serial) { /* try to fall back to value set with legacy -drive serial=... */ dinfo = drive_get_by_blockdev(conf->bs); - if (dinfo->serial) { - *serial = g_strdup(dinfo->serial); - } + *serial = g_strdup(dinfo->serial); } } diff --git a/net/net.c b/net/net.c index cdd9b04989..2f0ab3a121 100644 --- a/net/net.c +++ b/net/net.c @@ -566,9 +566,7 @@ static int net_init_nic(const NetClientOptions *opts, const char *name, assert(peer); nd->netdev = peer; } - if (name) { - nd->name = g_strdup(name); - } + nd->name = g_strdup(name); if (nic->has_model) { nd->model = g_strdup(nic->model); } diff --git a/slirp/slirp.c b/slirp/slirp.c index e93b578832..0e6e232789 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -225,12 +225,8 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname), vhostname); } - if (tftp_path) { - slirp->tftp_prefix = g_strdup(tftp_path); - } - if (bootfile) { - slirp->bootp_filename = g_strdup(bootfile); - } + slirp->tftp_prefix = g_strdup(tftp_path); + slirp->bootp_filename = g_strdup(bootfile); slirp->vdhcp_startaddr = vdhcp_start; slirp->vnameserver_addr = vnameserver; diff --git a/util/qemu-option.c b/util/qemu-option.c index f532b765a0..c12e7245ef 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -643,9 +643,7 @@ static void opt_set(QemuOpts *opts, const char *name, const char *value, QTAILQ_INSERT_TAIL(&opts->head, opt, next); } opt->desc = desc; - if (value) { - opt->str = g_strdup(value); - } + opt->str = g_strdup(value); qemu_opt_parse(opt, &local_err); if (error_is_set(&local_err)) { error_propagate(errp, local_err); @@ -792,9 +790,7 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, } } opts = g_malloc0(sizeof(*opts)); - if (id) { - opts->id = g_strdup(id); - } + opts->id = g_strdup(id); opts->list = list; loc_save(&opts->loc); QTAILQ_INIT(&opts->head); From d3f8e138c23ba082f87c96634d06b978473c1e9b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:07:58 +0100 Subject: [PATCH 0789/1634] hw/9pfs: Fix unchecked strdup() by converting to g_strdup() Note: the allocation in virtio_9p_init() is still leaked. To be fixed in a followup commit. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- hw/9pfs/virtio-9p-device.c | 2 +- hw/9pfs/virtio-9p-local.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 6eab7f7fa1..74155fb61e 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -94,7 +94,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) exit(1); } - s->tag = strdup(conf->tag); + s->tag = g_strdup(conf->tag); s->ctx.uid = -1; s->ops = fse->ops; diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 113602144c..f1b1c83a22 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -46,7 +46,7 @@ static const char *local_mapped_attr_path(FsContext *ctx, const char *path, char *buffer) { char *dir_name; - char *tmp_path = strdup(path); + char *tmp_path = g_strdup(path); char *base_name = basename(tmp_path); /* NULL terminate the directory */ @@ -55,7 +55,7 @@ static const char *local_mapped_attr_path(FsContext *ctx, snprintf(buffer, PATH_MAX, "%s/%s/%s/%s", ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name); - free(tmp_path); + g_free(tmp_path); return buffer; } @@ -130,7 +130,7 @@ static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) { int err; char attr_dir[PATH_MAX]; - char *tmp_path = strdup(path); + char *tmp_path = g_strdup(path); snprintf(attr_dir, PATH_MAX, "%s/%s/%s", ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR); @@ -139,7 +139,7 @@ static int local_create_mapped_attr_dir(FsContext *ctx, const char *path) if (err < 0 && errno == EEXIST) { err = 0; } - free(tmp_path); + g_free(tmp_path); return err; } From c3baa5f9e4f84bbc9ed9c3fe590835ecc8b0bf4a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:07:59 +0100 Subject: [PATCH 0790/1634] readline: Fix unchecked strdup() by converting to g_strdup() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- readline.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readline.c b/readline.c index a0c9638e4d..d6e04d4796 100644 --- a/readline.c +++ b/readline.c @@ -247,14 +247,14 @@ static void readline_hist_add(ReadLineState *rs, const char *cmdline) } if (idx == READLINE_MAX_CMDS) { /* Need to get one free slot */ - free(rs->history[0]); + g_free(rs->history[0]); memmove(rs->history, &rs->history[1], (READLINE_MAX_CMDS - 1) * sizeof(char *)); rs->history[READLINE_MAX_CMDS - 1] = NULL; idx = READLINE_MAX_CMDS - 1; } if (new_entry == NULL) - new_entry = strdup(cmdline); + new_entry = g_strdup(cmdline); rs->history[idx] = new_entry; rs->hist_entry = -1; } From fd3bea3f44500bbd361e617a4316df073b112eec Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:08:00 +0100 Subject: [PATCH 0791/1634] spice: Fix unchecked strdup() by converting to g_strdup() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- ui/spice-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 3f2c5650cd..bcc4199e7a 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -848,8 +848,8 @@ static int qemu_spice_set_ticket(bool fail_if_conn, bool disconnect_if_conn) int qemu_spice_set_passwd(const char *passwd, bool fail_if_conn, bool disconnect_if_conn) { - free(auth_passwd); - auth_passwd = strdup(passwd); + g_free(auth_passwd); + auth_passwd = g_strdup(passwd); return qemu_spice_set_ticket(fail_if_conn, disconnect_if_conn); } From 606017de2f254f847a009af770f8babc9a9fcadc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:08:01 +0100 Subject: [PATCH 0792/1634] virtfs-proxy-helper: Fix unchecked strdup() by conv. to g_strdup() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- fsdev/virtfs-proxy-helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index 6b9afd32d5..36f66163b2 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -1039,7 +1039,7 @@ int main(int argc, char **argv) } switch (c) { case 'p': - rpath = strdup(optarg); + rpath = g_strdup(optarg); break; case 'n': is_daemon = false; @@ -1048,7 +1048,7 @@ int main(int argc, char **argv) sock = atoi(optarg); break; case 's': - sock_name = strdup(optarg); + sock_name = g_strdup(optarg); break; case 'u': own_u = atoi(optarg); From 636e0f27c6675839dc43d4c7613dfefc222234eb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:08:02 +0100 Subject: [PATCH 0793/1634] qemu-log: Fix unchecked strdup() by converting to g_strdup() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- qemu-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-log.c b/qemu-log.c index b655b305ea..64a1b886dc 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -84,7 +84,7 @@ void qemu_set_log(int log_flags, bool use_own_buffers) void cpu_set_log_filename(const char *filename) { - logfilename = strdup(filename); + logfilename = g_strdup(filename); if (qemu_logfile) { fclose(qemu_logfile); qemu_logfile = NULL; From 40a50b0a73d185c85cf62023f07e3091861081bb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:08:03 +0100 Subject: [PATCH 0794/1634] qemu-log: Plug trivial memory leak in cpu_set_log_filename() Signed-off-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- qemu-log.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/qemu-log.c b/qemu-log.c index 64a1b886dc..30c9ab01bd 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -21,10 +21,12 @@ #include "qemu/log.h" #ifdef WIN32 -static const char *logfilename = "qemu.log"; +#define DEFAULT_LOGFILENAME "qemu.log" #else -static const char *logfilename = "/tmp/qemu.log"; +#define DEFAULT_LOGFILENAME "/tmp/qemu.log" #endif + +static char *logfilename; FILE *qemu_logfile; int qemu_loglevel; static int log_append = 0; @@ -54,11 +56,13 @@ void qemu_log_mask(int mask, const char *fmt, ...) /* enable or disable low levels log */ void qemu_set_log(int log_flags, bool use_own_buffers) { + const char *fname = logfilename ?: DEFAULT_LOGFILENAME; + qemu_loglevel = log_flags; if (qemu_loglevel && !qemu_logfile) { - qemu_logfile = fopen(logfilename, log_append ? "a" : "w"); + qemu_logfile = fopen(fname, log_append ? "a" : "w"); if (!qemu_logfile) { - perror(logfilename); + perror(fname); _exit(1); } /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ @@ -84,6 +88,7 @@ void qemu_set_log(int log_flags, bool use_own_buffers) void cpu_set_log_filename(const char *filename) { + g_free(logfilename); logfilename = g_strdup(filename); if (qemu_logfile) { fclose(qemu_logfile); From be168af860109a1ecc8526c5bbe0ace1536448b8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:08:04 +0100 Subject: [PATCH 0795/1634] libcacard: Fix unchecked strdup() by converting to g_strdup() Note that we already free with g_free(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- libcacard/vcard_emul_nss.c | 4 ++-- libcacard/vreader.c | 2 +- libcacard/vscclient.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index 5f565e0b4a..df79476db8 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -454,7 +454,7 @@ vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params) new_reader_emul->slot = PK11_ReferenceSlot(slot); new_reader_emul->default_type = type; - new_reader_emul->type_params = strdup(params); + new_reader_emul->type_params = g_strdup(params); new_reader_emul->present = PR_FALSE; new_reader_emul->series = 0; new_reader_emul->saved_vcard = NULL; @@ -997,7 +997,7 @@ vcard_emul_init(const VCardEmulOptions *options) /* We should control this with options. For now we mirror out any * removable hardware slot */ default_card_type = options->hw_card_type; - default_type_params = strdup(options->hw_type_params); + default_type_params = g_strdup(options->hw_type_params); SECMOD_GetReadLock(module_lock); for (mlp = module_list; mlp; mlp = mlp->next) { diff --git a/libcacard/vreader.c b/libcacard/vreader.c index 313349b656..f3efc270a2 100644 --- a/libcacard/vreader.c +++ b/libcacard/vreader.c @@ -49,7 +49,7 @@ vreader_new(const char *name, VReaderEmul *private, reader = (VReader *)g_malloc(sizeof(VReader)); qemu_mutex_init(&reader->lock); reader->reference_count = 1; - reader->name = name ? strdup(name) : NULL; + reader->name = g_strdup(name); reader->card = NULL; reader->id = (vreader_id_t)-1; reader->reader_private = private; diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 2fce52bed5..9b744f249c 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -503,8 +503,8 @@ main( command_line_options = vcard_emul_options(emul_args); } - qemu_host = strdup(argv[argc - 2]); - qemu_port = strdup(argv[argc - 1]); + qemu_host = g_strdup(argv[argc - 2]); + qemu_port = g_strdup(argv[argc - 1]); sock = connect_to_qemu(qemu_host, qemu_port); if (sock == -1) { fprintf(stderr, "error opening socket, exiting.\n"); From 13b10e05e4b89418a78500da05b25164f786d7e4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:08:05 +0100 Subject: [PATCH 0796/1634] qapi: Fix unchecked strdup() by converting to g_strdup() Note that we already free with g_free(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Luiz Capitulino Signed-off-by: Stefan Hajnoczi --- qapi/qmp-registry.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 70cdbca470..28bbbe849e 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -92,7 +92,7 @@ char **qmp_get_command_list(void) list_head = list = g_malloc0(count * sizeof(char *)); QTAILQ_FOREACH(cmd, &qmp_commands, node) { - *list = strdup(cmd->name); + *list = g_strdup(cmd->name); list++; } From 24a53049537886cf93273c01e3d7727444321afc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 22 Jan 2013 11:08:06 +0100 Subject: [PATCH 0797/1634] qemu-ga: Fix unchecked strdup() by converting to g_strdup() I figure it's freed somewhere deep down in QAPI, with g_free(). Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Luiz Capitulino Signed-off-by: Stefan Hajnoczi --- qga/commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/commands.c b/qga/commands.c index 7ffb35e4af..528b082fa8 100644 --- a/qga/commands.c +++ b/qga/commands.c @@ -61,7 +61,7 @@ struct GuestAgentInfo *qmp_guest_info(Error **err) while (*cmd_list) { cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo)); - cmd_info->name = strdup(*cmd_list); + cmd_info->name = g_strdup(*cmd_list); cmd_info->enabled = qmp_command_is_enabled(cmd_info->name); cmd_info_list = g_malloc0(sizeof(GuestAgentCommandInfoList)); From 0b0878611c64f027ca5d15ba641f423cc04ead3f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 21 Jan 2013 12:03:47 +0000 Subject: [PATCH 0798/1634] qemu-pixman.h: Avoid mutual inclusion loop with console.h Remove an unnecessary mutual inclusion loop between qemu-pixman.h and console.h, since the former was only including the latter for 'PixelFormat*', which can be provided by typedefs.h. This requires a minor adjustment to the files which included qemu-pixman.h, since they were relying on it implicitly dragging in all of console.h. Signed-off-by: Peter Maydell Acked-by: Gerd Hoffmann Signed-off-by: Stefan Hajnoczi --- include/ui/qemu-pixman.h | 2 +- include/ui/spice-display.h | 1 + ui/qemu-pixman.c | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 016fd87726..b032f529aa 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -15,7 +15,7 @@ #pragma GCC diagnostic error "-Wredundant-decls" #endif -#include "console.h" +#include "qemu/typedefs.h" /* * pixman image formats are defined to be native endian, diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 8b192e9613..46f9530fe3 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -21,6 +21,7 @@ #include "qemu/thread.h" #include "ui/qemu-pixman.h" +#include "ui/console.h" #include "sysemu/sysemu.h" #define NUM_MEMSLOTS 8 diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 609335ab11..6dcbe90546 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -3,7 +3,8 @@ * See the COPYING file in the top-level directory. */ -#include "ui/qemu-pixman.h" +#include "qemu-common.h" +#include "ui/console.h" int qemu_pixman_get_type(int rshift, int gshift, int bshift) { From a05ddd9216b6c5e9c48eac3433ff6fa4a282fc17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 26 Jan 2013 15:27:59 +0100 Subject: [PATCH 0799/1634] tests: Fix {rtc, m48t59}-test build on illumos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Struct tm does not have tm_gmtoff field on illumos. Fix the build by not zero-initializing these fields on Solaris. Cc: qemu-stable@nongnu.org Signed-off-by: Andreas Färber Signed-off-by: Stefan Hajnoczi --- tests/m48t59-test.c | 2 ++ tests/rtc-test.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c index d79f55472d..77d69b330d 100644 --- a/tests/m48t59-test.c +++ b/tests/m48t59-test.c @@ -142,7 +142,9 @@ static void cmos_get_date_time(struct tm *date) date->tm_mday = mday; date->tm_mon = mon - 1; date->tm_year = base_year + year - 1900; +#ifndef __sun__ date->tm_gmtoff = 0; +#endif ts = mktime(date); } diff --git a/tests/rtc-test.c b/tests/rtc-test.c index e7123cafbc..203c0fc363 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -115,7 +115,9 @@ static void cmos_get_date_time(struct tm *date) date->tm_mday = mday; date->tm_mon = mon - 1; date->tm_year = base_year + year - 1900; +#ifndef __sun__ date->tm_gmtoff = 0; +#endif ts = mktime(date); } From 99f4280854514b22972bd257fe5facc439222d2e Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Tue, 29 Jan 2013 17:58:41 +0100 Subject: [PATCH 0800/1634] qmp-commands.hx: s/tray-open/tray_open/ to match qapi schema Currently, we are using 'tray_open' in QMP and 'tray-open' in HMP. However, the QMP documentation was mistakenly using the HMP version. Signed-off-by: Michal Privoznik Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- qmp-commands.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmp-commands.hx b/qmp-commands.hx index f58a8411ea..f90efe590c 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1659,7 +1659,7 @@ Each json-object contain the following: - Possible values: "unknown" - "removable": true if the device is removable, false otherwise (json-bool) - "locked": true if the device is locked, false otherwise (json-bool) -- "tray-open": only present if removable, true if the device has a tray, +- "tray_open": only present if removable, true if the device has a tray, and it is open (json-bool) - "inserted": only present if the device is inserted, it is a json-object containing the following: From 79dd77de124c47263f54e5f686273487e0016a8f Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 20 Dec 2012 11:00:11 +0000 Subject: [PATCH 0801/1634] linux-user: correct msgrcv() All parameters must be swapped before the call of do_msgrcv(). Allow faked (debian fakeroot daemon) to work properly. WITHOUT this patch: $ faked-sysv --foreground --debug using 1723744788 as msg key msg_key=1723744788 1723744788:431 FAKEROOT: msg=131072, key=1723744788 FAKEROOT: r=-1, received message type=-150996052, message=-160219330 FAKEROOT, get_msg: Bad address r=14, EINTR=4 fakeroot: clearing up message queues and semaphores, signal=-1 fakeroot: database save FAILED WITH this patch: $ faked-sysv --foreground --debug using 1569385744 as msg key msg_key=1569385744 1569385744:424 FAKEROOT: msg=0, key=1569385744 ^C fakeroot: clearing up message queues and semaphores, signal=2 fakeroot: database save FAILED Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 693e66fc4f..a6f42718c8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2897,7 +2897,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp, return -TARGET_EFAULT; host_mb = g_malloc(msgsz+sizeof(long)); - ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg)); + ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg)); if (ret > 0) { abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong); @@ -3189,7 +3189,7 @@ static abi_long do_ipc(unsigned int call, int first, break; } - ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third); + ret = do_msgrcv(first, tswapal(tmp->msgp), second, tswapal(tmp->msgtyp), third); unlock_user_struct(tmp, ptr, 0); break; From 910ee4e5f4a1df5b1bd144dfca1ae466e2a86a78 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 31 Dec 2012 09:45:06 +0000 Subject: [PATCH 0802/1634] linux-user: correct print_timeval() swap tv_sec and tv_usec Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/strace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 6ec90e8974..4e91a6eb9c 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -682,7 +682,7 @@ print_timeval(abi_ulong tv_addr, int last) if (!tv) return; gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}%s", - tv->tv_sec, tv->tv_usec, get_comma(last)); + tswapal(tv->tv_sec), tswapal(tv->tv_usec), get_comma(last)); unlock_user(tv, tv_addr, 0); } else gemu_log("NULL%s", get_comma(last)); From 1b09aeb90827c1d91383a9eae42ce8f25909857b Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 1 Jan 2013 08:24:11 +0000 Subject: [PATCH 0803/1634] linux-user: correct setsockopt() SO_SNDTIMEO and SO_RCVTIMEO take a struct timeval, not an int To test this, you can use : QEMU_STRACE= ping localhost 2>&1 |grep TIMEO 568 setsockopt(3,SOL_SOCKET,SO_SNDTIMEO,{1,0},8) = 0 568 setsockopt(3,SOL_SOCKET,SO_RCVTIMEO,{1,0},8) = 0 Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/syscall.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a6f42718c8..151f4f3272 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1489,6 +1489,28 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, break; case TARGET_SOL_SOCKET: switch (optname) { + case TARGET_SO_RCVTIMEO: + { + struct timeval tv; + + optname = SO_RCVTIMEO; + +set_timeout: + if (optlen != sizeof(struct target_timeval)) { + return -TARGET_EINVAL; + } + + if (copy_from_user_timeval(&tv, optval_addr)) { + return -TARGET_EFAULT; + } + + ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, + &tv, sizeof(tv))); + return ret; + } + case TARGET_SO_SNDTIMEO: + optname = SO_SNDTIMEO; + goto set_timeout; /* Options with 'int' argument. */ case TARGET_SO_DEBUG: optname = SO_DEBUG; @@ -1540,12 +1562,6 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, case TARGET_SO_RCVLOWAT: optname = SO_RCVLOWAT; break; - case TARGET_SO_RCVTIMEO: - optname = SO_RCVTIMEO; - break; - case TARGET_SO_SNDTIMEO: - optname = SO_SNDTIMEO; - break; break; default: goto unimplemented; From c07ecc6866f8c5eb2e0b23ba20214000310355e0 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 7 Jan 2013 11:40:06 +0000 Subject: [PATCH 0804/1634] linux-user: correct reboot() According to man reboot(2), the 4th argument is only used with LINUX_REBOOT_CMD_RESTART2. In other cases, trying to convert the value can generate EFAULT. Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell --- linux-user/syscall.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 151f4f3272..08538fc35c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -101,6 +101,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include +#include #include "linux_loop.h" #include "cpu-uname.h" @@ -6451,10 +6452,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif case TARGET_NR_reboot: - if (!(p = lock_user_string(arg4))) - goto efault; - ret = reboot(arg1, arg2, arg3, p); - unlock_user(p, arg4, 0); + if (arg3 == LINUX_REBOOT_CMD_RESTART2) { + /* arg4 must be ignored in all other cases */ + p = lock_user_string(arg4); + if (!p) { + goto efault; + } + ret = get_errno(reboot(arg1, arg2, arg3, p)); + unlock_user(p, arg4, 0); + } else { + ret = get_errno(reboot(arg1, arg2, arg3, NULL)); + } break; #ifdef TARGET_NR_readdir case TARGET_NR_readdir: From 706872a56630a206897742b70c69ff99727672d3 Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Wed, 30 Jan 2013 15:39:01 +0000 Subject: [PATCH 0805/1634] hw/arm_sysctl: Clear sysctl cfgctrl start bit The start bit should only be set to indicate that a function call is underway, right now. When done with function, clear it. Signed-off-by: Christoffer Dall Signed-off-by: Peter Maydell --- hw/arm_sysctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index da36f8a435..7ecb7da54b 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -334,6 +334,7 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, default: s->sys_cfgstat |= 2; /* error */ } + s->sys_cfgctrl &= ~(1 << 31); return; case 0xa8: /* SYS_CFGSTAT */ if (board_id(s) != BOARD_ID_VEXPRESS) { From f61850bffbd0bb8b15aa55ebc3470bf1f8ce8664 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 30 Jan 2013 15:39:02 +0000 Subject: [PATCH 0806/1634] hw/vexpress: Use correct HBI (board model number) for vexpress-a15 The vexpress-a15 QEMU model is supposed to be a V2P-CA15; the HBI (a kind of board model number) for this coretile is 237, not 217. Signed-off-by: Peter Maydell --- hw/vexpress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/vexpress.c b/hw/vexpress.c index 7f0897c773..741b044f1d 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -271,7 +271,7 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, cpu_model = "cortex-a15"; } - *proc_id = 0x14000217; + *proc_id = 0x14000237; for (n = 0; n < smp_cpus; n++) { ARMCPU *cpu; From e4c1cfa5cb8f8bfbbfd949f2fabbe2be35e60c99 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 30 Jan 2013 16:01:56 +0000 Subject: [PATCH 0807/1634] target-arm: Fix TCG temp leaks for WI and UNDEF VFP sysreg writes Fix a leak of a TCG temporary in code paths for VFP system register writes for cases which UNDEF or are write-ignored. Signed-off-by: Peter Maydell --- target-arm/translate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 724e00f7cf..a8893f767f 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2737,7 +2737,6 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn) } } else { /* arm->vfp */ - tmp = load_reg(s, rd); if (insn & (1 << 21)) { rn >>= 1; /* system register */ @@ -2748,6 +2747,7 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn) /* Writes are ignored. */ break; case ARM_VFP_FPSCR: + tmp = load_reg(s, rd); gen_helper_vfp_set_fpscr(cpu_env, tmp); tcg_temp_free_i32(tmp); gen_lookup_tb(s); @@ -2757,18 +2757,21 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn) return 1; /* TODO: VFP subarchitecture support. * For now, keep the EN bit only */ + tmp = load_reg(s, rd); tcg_gen_andi_i32(tmp, tmp, 1 << 30); store_cpu_field(tmp, vfp.xregs[rn]); gen_lookup_tb(s); break; case ARM_VFP_FPINST: case ARM_VFP_FPINST2: + tmp = load_reg(s, rd); store_cpu_field(tmp, vfp.xregs[rn]); break; default: return 1; } } else { + tmp = load_reg(s, rd); gen_vfp_msr(tmp); gen_mov_vreg_F0(0, rn); } From 51492fd1a99099308d8c20ab7134ffb54abbf374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 17:30:10 +0100 Subject: [PATCH 0808/1634] target-arm: Rename CPU types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the initial conversion of CPU models to QOM types, model names were mapped 1:1 to type names. As a side effect this gained us a type "any", which is now a device. To avoid "-device any" silliness and to pave the way for compiling multiple targets into one executable, adopt a --cpu scheme. This leads to names like arm926-arm-cpu but is easiest to handle. No functional changes for -cpu arguments or -cpu ? output. Suggested-by: Eduardo Habkost Signed-off-by: Andreas Färber Signed-off-by: Andreas Färber Signed-off-by: Peter Maydell --- target-arm/cpu.c | 8 ++++++-- target-arm/helper.c | 11 ++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index d1a4c82680..1c6a628df4 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -204,12 +204,15 @@ void arm_cpu_realize(ARMCPU *cpu) static ObjectClass *arm_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; + char *typename; if (!cpu_model) { return NULL; } - oc = object_class_by_name(cpu_model); + typename = g_strdup_printf("%s-" TYPE_ARM_CPU, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); if (!oc || !object_class_dynamic_cast(oc, TYPE_ARM_CPU) || object_class_is_abstract(oc)) { return NULL; @@ -789,14 +792,15 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) static void cpu_register(const ARMCPUInfo *info) { TypeInfo type_info = { - .name = info->name, .parent = TYPE_ARM_CPU, .instance_size = sizeof(ARMCPU), .instance_init = info->initfn, .class_size = sizeof(ARMCPUClass), }; + type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); type_register(&type_info); + g_free((void *)type_info.name); } static const TypeInfo arm_cpu_type_info = { diff --git a/target-arm/helper.c b/target-arm/helper.c index 7a10fddf25..eb7b2910c3 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1303,9 +1303,9 @@ static gint arm_cpu_list_compare(gconstpointer a, gconstpointer b) name_a = object_class_get_name(class_a); name_b = object_class_get_name(class_b); - if (strcmp(name_a, "any") == 0) { + if (strcmp(name_a, "any-" TYPE_ARM_CPU) == 0) { return 1; - } else if (strcmp(name_b, "any") == 0) { + } else if (strcmp(name_b, "any-" TYPE_ARM_CPU) == 0) { return -1; } else { return strcmp(name_a, name_b); @@ -1316,9 +1316,14 @@ static void arm_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; CPUListState *s = user_data; + const char *typename; + char *name; + typename = object_class_get_name(oc); + name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_ARM_CPU)); (*s->cpu_fprintf)(s->file, " %s\n", - object_class_get_name(oc)); + name); + g_free(name); } void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf) From 477a3877fdc3125f309133ce511236f39f58c16e Mon Sep 17 00:00:00 2001 From: Henry Harrington Date: Tue, 27 Nov 2012 08:59:41 +0000 Subject: [PATCH 0809/1634] cocoa: Fix VBE function Set Display Start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register a dpy_gfx_setdata callback so that the Cocoa code is notified whenever the screen start address changes. Commit 1d3323d has a similar fix for the VNC UI. Signed-off-by: Henry Harrington Cc: qemu-stable@nongnu.org (1.3.x) Signed-off-by: Andreas Färber --- ui/cocoa.m | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ui/cocoa.m b/ui/cocoa.m index 3bf1c6e890..fbd7386295 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -265,6 +265,7 @@ static int cocoa_keycode_to_qemu(int keycode) BOOL isTabletEnabled; } - (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds; +- (void) updateDataOffset:(DisplayState *)ds; - (void) grabMouse; - (void) ungrabMouse; - (void) toggleFullScreen:(id)sender; @@ -429,6 +430,20 @@ QemuCocoaView *cocoaView; [self setFrame:NSMakeRect(cx, cy, cw, ch)]; } +- (void) updateDataOffset:(DisplayState *)ds +{ + COCOA_DEBUG("QemuCocoaView: UpdateDataOffset\n"); + + // update screenBuffer + if (dataProviderRef) { + CGDataProviderRelease(dataProviderRef); + } + + size_t size = ds_get_width(ds) * 4 * ds_get_height(ds); + dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), + size, NULL); +} + - (void) toggleFullScreen:(id)sender { COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n"); @@ -1004,6 +1019,11 @@ static void cocoa_refresh(DisplayState *ds) vga_hw_update(); } +static void cocoa_setdata(DisplayState *ds) +{ + [cocoaView updateDataOffset:ds]; +} + static void cocoa_cleanup(void) { COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n"); @@ -1020,6 +1040,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen) dcl->dpy_gfx_update = cocoa_update; dcl->dpy_gfx_resize = cocoa_resize; dcl->dpy_refresh = cocoa_refresh; + dcl->dpy_gfx_setdata = cocoa_setdata; register_displaychangelistener(ds, dcl); From 7e02dc63b8f16372107434d44269e21cdff5d19d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 16 Jan 2013 07:38:40 +0000 Subject: [PATCH 0810/1634] cocoa: Replace non-portable asprintf() by g_strdup_printf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Weil Signed-off-by: Andreas Färber --- ui/cocoa.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index fbd7386295..ca42413b34 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -828,9 +828,9 @@ QemuCocoaView *cocoaView; [sheet close]; - asprintf(&argv[0], "%s", bin); - asprintf(&argv[1], "-hda"); - asprintf(&argv[2], "%s", img); + argv[0] = g_strdup_printf("%s", bin); + argv[1] = g_strdup_printf("-hda"); + argv[2] = g_strdup_printf("%s", img); printf("Using argc %d argv %s -hda %s\n", 3, bin, img); From f7d2072e25d3592acec4657dae8862facf298e9f Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:22 +0100 Subject: [PATCH 0811/1634] target-mips: fix DSP loads with rd = 0 When rd is 0, which still need to do the actually load to possibly generate a TLB exception. Reviewed-by: Eric Johnson Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 206ba83401..a9368294f3 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12657,11 +12657,6 @@ static void gen_mipsdsp_ld(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, const char *opn = "ldx"; TCGv t0; - if (rd == 0) { - MIPS_DEBUG("NOP"); - return; - } - check_dsp(ctx); t0 = tcg_temp_new(); From d75c135e6b6255787dfc01ce997862d820ed1d36 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:22 +0100 Subject: [PATCH 0812/1634] target-mips: copy insn_flags in DisasContext Copy insn_flags in DisasContext to avoid passing a CPUMIPSState pointer to subroutines, as suggested by Richard Henderson. Change subroutines to use this new field and remove the first argument. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 762 ++++++++++++++++++++-------------------- 1 file changed, 381 insertions(+), 381 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index a9368294f3..aad5ae4b14 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1066,6 +1066,7 @@ typedef struct DisasContext { target_ulong pc, saved_pc; uint32_t opcode; int singlestep_enabled; + int insn_flags; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; @@ -1406,10 +1407,11 @@ static inline void check_dspr2(DisasContext *ctx) /* This code generates a "reserved instruction" exception if the CPU does not support the instruction set corresponding to flags. */ -static inline void check_insn(CPUMIPSState *env, DisasContext *ctx, int flags) +static inline void check_insn(DisasContext *ctx, int flags) { - if (unlikely(!(env->insn_flags & flags))) + if (unlikely(!(ctx->insn_flags & flags))) { generate_exception(ctx, EXCP_RI); + } } /* This code generates a "reserved instruction" exception if 64-bit @@ -1576,13 +1578,13 @@ static target_ulong pc_relative_pc (DisasContext *ctx) } /* Load */ -static void gen_ld (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, - int rt, int base, int16_t offset) +static void gen_ld(DisasContext *ctx, uint32_t opc, + int rt, int base, int16_t offset) { const char *opn = "ld"; TCGv t0, t1, t2; - if (rt == 0 && env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) { + if (rt == 0 && ctx->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F)) { /* Loongson CPU uses a load to zero register for prefetch. We emulate it as a NOP. On other CPU we must perform the actual memory access. */ @@ -1921,8 +1923,8 @@ static void gen_cop1_ldst(CPUMIPSState *env, DisasContext *ctx, } /* Arithmetic with immediate operand */ -static void gen_arith_imm (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, - int rt, int rs, int16_t imm) +static void gen_arith_imm(DisasContext *ctx, uint32_t opc, + int rt, int rs, int16_t imm) { target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ const char *opn = "imm arith"; @@ -2009,7 +2011,7 @@ static void gen_arith_imm (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Logic with immediate operand */ -static void gen_logic_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, +static void gen_logic_imm(DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { target_ulong uimm; @@ -2057,7 +2059,7 @@ static void gen_logic_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Set on less than with immediate operand */ -static void gen_slt_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, +static void gen_slt_imm(DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ @@ -2087,7 +2089,7 @@ static void gen_slt_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Shifts with immediate operand */ -static void gen_shift_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, +static void gen_shift_imm(DisasContext *ctx, uint32_t opc, int rt, int rs, int16_t imm) { target_ulong uimm = ((uint16_t)imm) & 0x1f; @@ -2179,8 +2181,8 @@ static void gen_shift_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Arithmetic */ -static void gen_arith (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, - int rd, int rs, int rt) +static void gen_arith(DisasContext *ctx, uint32_t opc, + int rd, int rs, int rt) { const char *opn = "arith"; @@ -2359,7 +2361,7 @@ static void gen_arith (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Conditional move */ -static void gen_cond_move(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, +static void gen_cond_move(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { const char *opn = "cond move"; @@ -2395,7 +2397,7 @@ static void gen_cond_move(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Logic */ -static void gen_logic(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, +static void gen_logic(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { const char *opn = "logic"; @@ -2457,7 +2459,7 @@ static void gen_logic(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Set on lower than */ -static void gen_slt(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, +static void gen_slt(DisasContext *ctx, uint32_t opc, int rd, int rs, int rt) { const char *opn = "slt"; @@ -2490,8 +2492,8 @@ static void gen_slt(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, } /* Shifts */ -static void gen_shift (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, - int rd, int rs, int rt) +static void gen_shift(DisasContext *ctx, uint32_t opc, + int rd, int rs, int rt) { const char *opn = "shifts"; TCGv t0, t1; @@ -4097,12 +4099,12 @@ static inline void gen_mtc0_store64 (TCGv arg, target_ulong off) tcg_gen_st_tl(arg, cpu_env, off); } -static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel) +static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); switch (reg) { case 0: @@ -4112,17 +4114,17 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Index"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_mvpcontrol(arg, cpu_env); rn = "MVPControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_mvpconf0(arg, cpu_env); rn = "MVPConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_mvpconf1(arg, cpu_env); rn = "MVPConf1"; break; @@ -4137,37 +4139,37 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Random"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_YQMask)); rn = "YQMask"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt)); rn = "VPEOpt"; break; @@ -4183,37 +4185,37 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "EntryLo0"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tcstatus(arg, cpu_env); rn = "TCStatus"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tcbind(arg, cpu_env); rn = "TCBind"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tcrestart(arg, cpu_env); rn = "TCRestart"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tchalt(arg, cpu_env); rn = "TCHalt"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tccontext(arg, cpu_env); rn = "TCContext"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tcschedule(arg, cpu_env); rn = "TCSchedule"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tcschefback(arg, cpu_env); rn = "TCScheFBack"; break; @@ -4254,7 +4256,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "PageMask"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain)); rn = "PageGrain"; break; @@ -4269,27 +4271,27 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Wired"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0)); rn = "SRSConf0"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1)); rn = "SRSConf1"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2)); rn = "SRSConf2"; break; case 4: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3)); rn = "SRSConf3"; break; case 5: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4)); rn = "SRSConf4"; break; @@ -4300,7 +4302,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i case 7: switch (sel) { case 0: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna)); rn = "HWREna"; break; @@ -4368,17 +4370,17 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Status"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl)); rn = "IntCtl"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl)); rn = "SRSCtl"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); rn = "SRSMap"; break; @@ -4414,7 +4416,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "PRid"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_EBase)); rn = "EBase"; break; @@ -4488,7 +4490,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i switch (sel) { case 0: #if defined(TARGET_MIPS64) - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext)); tcg_gen_ext32s_tl(arg, arg); rn = "XContext"; @@ -4677,12 +4679,12 @@ die: generate_exception(ctx, EXCP_RI); } -static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel) +static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); if (use_icount) gen_io_start(); @@ -4695,17 +4697,17 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Index"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_mvpcontrol(cpu_env, arg); rn = "MVPControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); /* ignored */ rn = "MVPConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); /* ignored */ rn = "MVPConf1"; break; @@ -4720,37 +4722,37 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Random"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpecontrol(cpu_env, arg); rn = "VPEControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpeconf0(cpu_env, arg); rn = "VPEConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpeconf1(cpu_env, arg); rn = "VPEConf1"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_yqmask(cpu_env, arg); rn = "YQMask"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mtc0_store64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpeopt(cpu_env, arg); rn = "VPEOpt"; break; @@ -4765,37 +4767,37 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "EntryLo0"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcstatus(cpu_env, arg); rn = "TCStatus"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcbind(cpu_env, arg); rn = "TCBind"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcrestart(cpu_env, arg); rn = "TCRestart"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tchalt(cpu_env, arg); rn = "TCHalt"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tccontext(cpu_env, arg); rn = "TCContext"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcschedule(cpu_env, arg); rn = "TCSchedule"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcschefback(cpu_env, arg); rn = "TCScheFBack"; break; @@ -4834,7 +4836,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "PageMask"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_pagegrain(cpu_env, arg); rn = "PageGrain"; break; @@ -4849,27 +4851,27 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Wired"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf0(cpu_env, arg); rn = "SRSConf0"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf1(cpu_env, arg); rn = "SRSConf1"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf2(cpu_env, arg); rn = "SRSConf2"; break; case 4: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf3(cpu_env, arg); rn = "SRSConf3"; break; case 5: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf4(cpu_env, arg); rn = "SRSConf4"; break; @@ -4880,7 +4882,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i case 7: switch (sel) { case 0: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); rn = "HWREna"; break; @@ -4935,21 +4937,21 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "Status"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_intctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -4987,7 +4989,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i rn = "PRid"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_ebase(cpu_env, arg); rn = "EBase"; break; @@ -5066,7 +5068,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i switch (sel) { case 0: #if defined(TARGET_MIPS64) - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); gen_helper_mtc0_xcontext(cpu_env, arg); rn = "XContext"; break; @@ -5274,12 +5276,12 @@ die: } #if defined(TARGET_MIPS64) -static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel) +static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) - check_insn(env, ctx, ISA_MIPS64); + check_insn(ctx, ISA_MIPS64); switch (reg) { case 0: @@ -5289,17 +5291,17 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Index"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_mvpcontrol(arg, cpu_env); rn = "MVPControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_mvpconf0(arg, cpu_env); rn = "MVPConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_mvpconf1(arg, cpu_env); rn = "MVPConf1"; break; @@ -5314,37 +5316,37 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Random"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl)); rn = "VPEControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0)); rn = "VPEConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1)); rn = "VPEConf1"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask)); rn = "YQMask"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt)); rn = "VPEOpt"; break; @@ -5359,37 +5361,37 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "EntryLo0"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tcstatus(arg, cpu_env); rn = "TCStatus"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mfc0_tcbind(arg, cpu_env); rn = "TCBind"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_dmfc0_tcrestart(arg, cpu_env); rn = "TCRestart"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_dmfc0_tchalt(arg, cpu_env); rn = "TCHalt"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_dmfc0_tccontext(arg, cpu_env); rn = "TCContext"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_dmfc0_tcschedule(arg, cpu_env); rn = "TCSchedule"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_dmfc0_tcschefback(arg, cpu_env); rn = "TCScheFBack"; break; @@ -5428,7 +5430,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "PageMask"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain)); rn = "PageGrain"; break; @@ -5443,27 +5445,27 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Wired"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0)); rn = "SRSConf0"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1)); rn = "SRSConf1"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2)); rn = "SRSConf2"; break; case 4: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3)); rn = "SRSConf3"; break; case 5: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4)); rn = "SRSConf4"; break; @@ -5474,7 +5476,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, case 7: switch (sel) { case 0: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna)); rn = "HWREna"; break; @@ -5540,17 +5542,17 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Status"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl)); rn = "IntCtl"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl)); rn = "SRSCtl"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); rn = "SRSMap"; break; @@ -5585,7 +5587,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "PRid"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_EBase)); rn = "EBase"; break; @@ -5657,7 +5659,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, case 20: switch (sel) { case 0: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext)); rn = "XContext"; break; @@ -5843,12 +5845,12 @@ die: generate_exception(ctx, EXCP_RI); } -static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, int sel) +static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) { const char *rn = "invalid"; if (sel != 0) - check_insn(env, ctx, ISA_MIPS64); + check_insn(ctx, ISA_MIPS64); if (use_icount) gen_io_start(); @@ -5861,17 +5863,17 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Index"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_mvpcontrol(cpu_env, arg); rn = "MVPControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); /* ignored */ rn = "MVPConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); /* ignored */ rn = "MVPConf1"; break; @@ -5886,37 +5888,37 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Random"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpecontrol(cpu_env, arg); rn = "VPEControl"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpeconf0(cpu_env, arg); rn = "VPEConf0"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpeconf1(cpu_env, arg); rn = "VPEConf1"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_yqmask(cpu_env, arg); rn = "YQMask"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); rn = "VPESchedule"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); rn = "VPEScheFBack"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_vpeopt(cpu_env, arg); rn = "VPEOpt"; break; @@ -5931,37 +5933,37 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "EntryLo0"; break; case 1: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcstatus(cpu_env, arg); rn = "TCStatus"; break; case 2: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcbind(cpu_env, arg); rn = "TCBind"; break; case 3: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcrestart(cpu_env, arg); rn = "TCRestart"; break; case 4: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tchalt(cpu_env, arg); rn = "TCHalt"; break; case 5: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tccontext(cpu_env, arg); rn = "TCContext"; break; case 6: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcschedule(cpu_env, arg); rn = "TCSchedule"; break; case 7: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_mtc0_tcschefback(cpu_env, arg); rn = "TCScheFBack"; break; @@ -6000,7 +6002,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "PageMask"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_pagegrain(cpu_env, arg); rn = "PageGrain"; break; @@ -6015,27 +6017,27 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Wired"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf0(cpu_env, arg); rn = "SRSConf0"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf1(cpu_env, arg); rn = "SRSConf1"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf2(cpu_env, arg); rn = "SRSConf2"; break; case 4: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf3(cpu_env, arg); rn = "SRSConf3"; break; case 5: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsconf4(cpu_env, arg); rn = "SRSConf4"; break; @@ -6046,7 +6048,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, case 7: switch (sel) { case 0: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); rn = "HWREna"; break; @@ -6105,21 +6107,21 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "Status"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_intctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "IntCtl"; break; case 2: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_srsctl(cpu_env, arg); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; rn = "SRSCtl"; break; case 3: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap)); /* Stop translation as we may have switched the execution mode */ ctx->bstate = BS_STOP; @@ -6167,7 +6169,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, rn = "PRid"; break; case 1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_ebase(cpu_env, arg); rn = "EBase"; break; @@ -6236,7 +6238,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, case 20: switch (sel) { case 0: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); gen_helper_mtc0_xcontext(cpu_env, arg); rn = "XContext"; break; @@ -6493,7 +6495,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, gen_helper_mftc0_tcschefback(t0, cpu_env); break; default: - gen_mfc0(env, ctx, t0, rt, sel); + gen_mfc0(ctx, t0, rt, sel); break; } break; @@ -6503,7 +6505,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, gen_helper_mftc0_entryhi(t0, cpu_env); break; default: - gen_mfc0(env, ctx, t0, rt, sel); + gen_mfc0(ctx, t0, rt, sel); break; } case 12: @@ -6512,7 +6514,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, gen_helper_mftc0_status(t0, cpu_env); break; default: - gen_mfc0(env, ctx, t0, rt, sel); + gen_mfc0(ctx, t0, rt, sel); break; } case 13: @@ -6561,12 +6563,12 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, gen_helper_mftc0_debug(t0, cpu_env); break; default: - gen_mfc0(env, ctx, t0, rt, sel); + gen_mfc0(ctx, t0, rt, sel); break; } break; default: - gen_mfc0(env, ctx, t0, rt, sel); + gen_mfc0(ctx, t0, rt, sel); } } else switch (sel) { /* GPR registers. */ @@ -6711,7 +6713,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, gen_helper_mttc0_tcschefback(cpu_env, t0); break; default: - gen_mtc0(env, ctx, t0, rd, sel); + gen_mtc0(ctx, t0, rd, sel); break; } break; @@ -6721,7 +6723,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, gen_helper_mttc0_entryhi(cpu_env, t0); break; default: - gen_mtc0(env, ctx, t0, rd, sel); + gen_mtc0(ctx, t0, rd, sel); break; } case 12: @@ -6730,7 +6732,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, gen_helper_mttc0_status(cpu_env, t0); break; default: - gen_mtc0(env, ctx, t0, rd, sel); + gen_mtc0(ctx, t0, rd, sel); break; } case 13: @@ -6759,12 +6761,12 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, gen_helper_mttc0_debug(cpu_env, t0); break; default: - gen_mtc0(env, ctx, t0, rd, sel); + gen_mtc0(ctx, t0, rd, sel); break; } break; default: - gen_mtc0(env, ctx, t0, rd, sel); + gen_mtc0(ctx, t0, rd, sel); } } else switch (sel) { /* GPR registers. */ @@ -6866,7 +6868,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, /* Treat as NOP. */ return; } - gen_mfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); + gen_mfc0(ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); opn = "mfc0"; break; case OPC_MTC0: @@ -6874,35 +6876,35 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, TCGv t0 = tcg_temp_new(); gen_load_gpr(t0, rt); - gen_mtc0(env, ctx, t0, rd, ctx->opcode & 0x7); + gen_mtc0(ctx, t0, rd, ctx->opcode & 0x7); tcg_temp_free(t0); } opn = "mtc0"; break; #if defined(TARGET_MIPS64) case OPC_DMFC0: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); if (rt == 0) { /* Treat as NOP. */ return; } - gen_dmfc0(env, ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); + gen_dmfc0(ctx, cpu_gpr[rt], rd, ctx->opcode & 0x7); opn = "dmfc0"; break; case OPC_DMTC0: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); { TCGv t0 = tcg_temp_new(); gen_load_gpr(t0, rt); - gen_dmtc0(env, ctx, t0, rd, ctx->opcode & 0x7); + gen_dmtc0(ctx, t0, rd, ctx->opcode & 0x7); tcg_temp_free(t0); } opn = "dmtc0"; break; #endif case OPC_MFTR: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); if (rd == 0) { /* Treat as NOP. */ return; @@ -6912,7 +6914,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, opn = "mftr"; break; case OPC_MTTR: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_mttr(env, ctx, rd, rt, (ctx->opcode >> 5) & 1, ctx->opcode & 0x7, (ctx->opcode >> 4) & 1); opn = "mttr"; @@ -6943,13 +6945,13 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, break; case OPC_ERET: opn = "eret"; - check_insn(env, ctx, ISA_MIPS2); + check_insn(ctx, ISA_MIPS2); gen_helper_eret(cpu_env); ctx->bstate = BS_EXCP; break; case OPC_DERET: opn = "deret"; - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); if (!(ctx->hflags & MIPS_HFLAG_DM)) { MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); @@ -6960,7 +6962,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, break; case OPC_WAIT: opn = "wait"; - check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32); + check_insn(ctx, ISA_MIPS3 | ISA_MIPS32); /* If we get an exception, we want to restart at next instruction */ ctx->pc += 4; save_cpu_state(ctx, 1); @@ -6980,15 +6982,15 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, #endif /* !CONFIG_USER_ONLY */ /* CP1 Branches (before delay slot) */ -static void gen_compute_branch1 (CPUMIPSState *env, DisasContext *ctx, uint32_t op, - int32_t cc, int32_t offset) +static void gen_compute_branch1(DisasContext *ctx, uint32_t op, + int32_t cc, int32_t offset) { target_ulong btarget; const char *opn = "cp1 cond branch"; TCGv_i32 t0 = tcg_temp_new_i32(); if (cc != 0) - check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); btarget = ctx->pc + 4 + offset; @@ -9032,15 +9034,14 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, fregnames[fs], fregnames[ft]); } -static void -gen_rdhwr (CPUMIPSState *env, DisasContext *ctx, int rt, int rd) +static void gen_rdhwr(DisasContext *ctx, int rt, int rd) { TCGv t0; #if !defined(CONFIG_USER_ONLY) /* The Linux kernel will emulate rdhwr if it's not supported natively. Therefore only check the ISA in system mode. */ - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); #endif t0 = tcg_temp_new(); @@ -9082,8 +9083,7 @@ gen_rdhwr (CPUMIPSState *env, DisasContext *ctx, int rt, int rd) tcg_temp_free(t0); } -static void handle_delay_slot (CPUMIPSState *env, DisasContext *ctx, - int insn_bytes) +static void handle_delay_slot(DisasContext *ctx, int insn_bytes) { if (ctx->hflags & MIPS_HFLAG_BMASK) { int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK; @@ -9121,7 +9121,7 @@ static void handle_delay_slot (CPUMIPSState *env, DisasContext *ctx, case MIPS_HFLAG_BR: /* unconditional branch to register */ MIPS_DEBUG("branch to register"); - if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) { + if (ctx->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) { TCGv t0 = tcg_temp_new(); TCGv_i32 t1 = tcg_temp_new_i32(); @@ -9548,7 +9548,7 @@ static void gen_addiupc (DisasContext *ctx, int rx, int imm, } #if defined(TARGET_MIPS64) -static void decode_i64_mips16 (CPUMIPSState *env, DisasContext *ctx, +static void decode_i64_mips16 (DisasContext *ctx, int ry, int funct, int16_t offset, int extended) { @@ -9556,7 +9556,7 @@ static void decode_i64_mips16 (CPUMIPSState *env, DisasContext *ctx, case I64_LDSP: check_mips_64(ctx); offset = extended ? offset : offset << 3; - gen_ld(env, ctx, OPC_LD, ry, 29, offset); + gen_ld(ctx, OPC_LD, ry, 29, offset); break; case I64_SDSP: check_mips_64(ctx); @@ -9571,20 +9571,20 @@ static void decode_i64_mips16 (CPUMIPSState *env, DisasContext *ctx, case I64_DADJSP: check_mips_64(ctx); offset = extended ? offset : ((int8_t)ctx->opcode) << 3; - gen_arith_imm(env, ctx, OPC_DADDIU, 29, 29, offset); + gen_arith_imm(ctx, OPC_DADDIU, 29, 29, offset); break; case I64_LDPC: if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) { generate_exception(ctx, EXCP_RI); } else { offset = extended ? offset : offset << 3; - gen_ld(env, ctx, OPC_LDPC, ry, 0, offset); + gen_ld(ctx, OPC_LDPC, ry, 0, offset); } break; case I64_DADDIU5: check_mips_64(ctx); offset = extended ? offset : ((int8_t)(offset << 3)) >> 3; - gen_arith_imm(env, ctx, OPC_DADDIU, ry, ry, offset); + gen_arith_imm(ctx, OPC_DADDIU, ry, ry, offset); break; case I64_DADDIUPC: check_mips_64(ctx); @@ -9594,7 +9594,7 @@ static void decode_i64_mips16 (CPUMIPSState *env, DisasContext *ctx, case I64_DADDIUSP: check_mips_64(ctx); offset = extended ? offset : offset << 2; - gen_arith_imm(env, ctx, OPC_DADDIU, ry, 29, offset); + gen_arith_imm(ctx, OPC_DADDIU, ry, 29, offset); break; } } @@ -9621,7 +9621,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, counterparts. */ switch (op) { case M16_OPC_ADDIUSP: - gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm); + gen_arith_imm(ctx, OPC_ADDIU, rx, 29, imm); break; case M16_OPC_ADDIUPC: gen_addiupc(ctx, rx, imm, 0, 1); @@ -9641,28 +9641,28 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, case M16_OPC_SHIFT: switch (ctx->opcode & 0x3) { case 0x0: - gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa); + gen_shift_imm(ctx, OPC_SLL, rx, ry, sa); break; case 0x1: #if defined(TARGET_MIPS64) check_mips_64(ctx); - gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa); + gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); #else generate_exception(ctx, EXCP_RI); #endif break; case 0x2: - gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa); + gen_shift_imm(ctx, OPC_SRL, rx, ry, sa); break; case 0x3: - gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa); + gen_shift_imm(ctx, OPC_SRA, rx, ry, sa); break; } break; #if defined(TARGET_MIPS64) case M16_OPC_LD: check_mips_64(ctx); - gen_ld(env, ctx, OPC_LD, ry, rx, offset); + gen_ld(ctx, OPC_LD, ry, rx, offset); break; #endif case M16_OPC_RRIA: @@ -9673,22 +9673,22 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, if ((ctx->opcode >> 4) & 0x1) { #if defined(TARGET_MIPS64) check_mips_64(ctx); - gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm); + gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); #else generate_exception(ctx, EXCP_RI); #endif } else { - gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm); + gen_arith_imm(ctx, OPC_ADDIU, ry, rx, imm); } break; case M16_OPC_ADDIU8: - gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm); + gen_arith_imm(ctx, OPC_ADDIU, rx, rx, imm); break; case M16_OPC_SLTI: - gen_slt_imm(env, ctx, OPC_SLTI, 24, rx, imm); + gen_slt_imm(ctx, OPC_SLTI, 24, rx, imm); break; case M16_OPC_SLTIU: - gen_slt_imm(env, ctx, OPC_SLTIU, 24, rx, imm); + gen_slt_imm(ctx, OPC_SLTIU, 24, rx, imm); break; case M16_OPC_I8: switch (funct) { @@ -9702,7 +9702,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, gen_st(ctx, OPC_SW, 31, 29, imm); break; case I8_ADJSP: - gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm); break; case I8_SVRS: { @@ -9742,29 +9742,29 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, break; #endif case M16_OPC_LB: - gen_ld(env, ctx, OPC_LB, ry, rx, offset); + gen_ld(ctx, OPC_LB, ry, rx, offset); break; case M16_OPC_LH: - gen_ld(env, ctx, OPC_LH, ry, rx, offset); + gen_ld(ctx, OPC_LH, ry, rx, offset); break; case M16_OPC_LWSP: - gen_ld(env, ctx, OPC_LW, rx, 29, offset); + gen_ld(ctx, OPC_LW, rx, 29, offset); break; case M16_OPC_LW: - gen_ld(env, ctx, OPC_LW, ry, rx, offset); + gen_ld(ctx, OPC_LW, ry, rx, offset); break; case M16_OPC_LBU: - gen_ld(env, ctx, OPC_LBU, ry, rx, offset); + gen_ld(ctx, OPC_LBU, ry, rx, offset); break; case M16_OPC_LHU: - gen_ld(env, ctx, OPC_LHU, ry, rx, offset); + gen_ld(ctx, OPC_LHU, ry, rx, offset); break; case M16_OPC_LWPC: - gen_ld(env, ctx, OPC_LWPC, rx, 0, offset); + gen_ld(ctx, OPC_LWPC, rx, 0, offset); break; #if defined(TARGET_MIPS64) case M16_OPC_LWU: - gen_ld(env, ctx, OPC_LWU, ry, rx, offset); + gen_ld(ctx, OPC_LWU, ry, rx, offset); break; #endif case M16_OPC_SB: @@ -9781,7 +9781,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, break; #if defined(TARGET_MIPS64) case M16_OPC_I64: - decode_i64_mips16(env, ctx, ry, funct, offset, 1); + decode_i64_mips16(ctx, ry, funct, offset, 1); break; #endif default: @@ -9816,7 +9816,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, { int16_t imm = ((uint8_t) ctx->opcode) << 2; - gen_arith_imm(env, ctx, OPC_ADDIU, rx, 29, imm); + gen_arith_imm(ctx, OPC_ADDIU, rx, 29, imm); } break; case M16_OPC_ADDIUPC: @@ -9849,28 +9849,28 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, case M16_OPC_SHIFT: switch (ctx->opcode & 0x3) { case 0x0: - gen_shift_imm(env, ctx, OPC_SLL, rx, ry, sa); + gen_shift_imm(ctx, OPC_SLL, rx, ry, sa); break; case 0x1: #if defined(TARGET_MIPS64) check_mips_64(ctx); - gen_shift_imm(env, ctx, OPC_DSLL, rx, ry, sa); + gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); #else generate_exception(ctx, EXCP_RI); #endif break; case 0x2: - gen_shift_imm(env, ctx, OPC_SRL, rx, ry, sa); + gen_shift_imm(ctx, OPC_SRL, rx, ry, sa); break; case 0x3: - gen_shift_imm(env, ctx, OPC_SRA, rx, ry, sa); + gen_shift_imm(ctx, OPC_SRA, rx, ry, sa); break; } break; #if defined(TARGET_MIPS64) case M16_OPC_LD: check_mips_64(ctx); - gen_ld(env, ctx, OPC_LD, ry, rx, offset << 3); + gen_ld(ctx, OPC_LD, ry, rx, offset << 3); break; #endif case M16_OPC_RRIA: @@ -9880,12 +9880,12 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, if ((ctx->opcode >> 4) & 1) { #if defined(TARGET_MIPS64) check_mips_64(ctx); - gen_arith_imm(env, ctx, OPC_DADDIU, ry, rx, imm); + gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); #else generate_exception(ctx, EXCP_RI); #endif } else { - gen_arith_imm(env, ctx, OPC_ADDIU, ry, rx, imm); + gen_arith_imm(ctx, OPC_ADDIU, ry, rx, imm); } } break; @@ -9893,19 +9893,19 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, { int16_t imm = (int8_t) ctx->opcode; - gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm); + gen_arith_imm(ctx, OPC_ADDIU, rx, rx, imm); } break; case M16_OPC_SLTI: { int16_t imm = (uint8_t) ctx->opcode; - gen_slt_imm(env, ctx, OPC_SLTI, 24, rx, imm); + gen_slt_imm(ctx, OPC_SLTI, 24, rx, imm); } break; case M16_OPC_SLTIU: { int16_t imm = (uint8_t) ctx->opcode; - gen_slt_imm(env, ctx, OPC_SLTIU, 24, rx, imm); + gen_slt_imm(ctx, OPC_SLTIU, 24, rx, imm); } break; case M16_OPC_I8: @@ -9926,7 +9926,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); break; case I8_ADJSP: - gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, ((int8_t)ctx->opcode) << 3); break; case I8_SVRS: @@ -9957,12 +9957,12 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, reg32 = (((ctx->opcode >> 3) & 0x3) << 3) | ((ctx->opcode >> 5) & 0x7); - gen_arith(env, ctx, OPC_ADDU, reg32, rz, 0); + gen_arith(ctx, OPC_ADDU, reg32, rz, 0); } break; case I8_MOVR32: reg32 = ctx->opcode & 0x1f; - gen_arith(env, ctx, OPC_ADDU, ry, reg32, 0); + gen_arith(ctx, OPC_ADDU, ry, reg32, 0); break; default: generate_exception(ctx, EXCP_RI); @@ -9974,13 +9974,13 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, { int16_t imm = (uint8_t) ctx->opcode; - gen_arith_imm(env, ctx, OPC_ADDIU, rx, 0, imm); + gen_arith_imm(ctx, OPC_ADDIU, rx, 0, imm); } break; case M16_OPC_CMPI: { int16_t imm = (uint8_t) ctx->opcode; - gen_logic_imm(env, ctx, OPC_XORI, 24, rx, imm); + gen_logic_imm(ctx, OPC_XORI, 24, rx, imm); } break; #if defined(TARGET_MIPS64) @@ -9990,30 +9990,30 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, break; #endif case M16_OPC_LB: - gen_ld(env, ctx, OPC_LB, ry, rx, offset); + gen_ld(ctx, OPC_LB, ry, rx, offset); break; case M16_OPC_LH: - gen_ld(env, ctx, OPC_LH, ry, rx, offset << 1); + gen_ld(ctx, OPC_LH, ry, rx, offset << 1); break; case M16_OPC_LWSP: - gen_ld(env, ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2); + gen_ld(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2); break; case M16_OPC_LW: - gen_ld(env, ctx, OPC_LW, ry, rx, offset << 2); + gen_ld(ctx, OPC_LW, ry, rx, offset << 2); break; case M16_OPC_LBU: - gen_ld(env, ctx, OPC_LBU, ry, rx, offset); + gen_ld(ctx, OPC_LBU, ry, rx, offset); break; case M16_OPC_LHU: - gen_ld(env, ctx, OPC_LHU, ry, rx, offset << 1); + gen_ld(ctx, OPC_LHU, ry, rx, offset << 1); break; case M16_OPC_LWPC: - gen_ld(env, ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2); + gen_ld(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2); break; #if defined (TARGET_MIPS64) case M16_OPC_LWU: check_mips_64(ctx); - gen_ld(env, ctx, OPC_LWU, ry, rx, offset << 2); + gen_ld(ctx, OPC_LWU, ry, rx, offset << 2); break; #endif case M16_OPC_SB: @@ -10055,7 +10055,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, goto done; } - gen_arith(env, ctx, mips32_op, rz, rx, ry); + gen_arith(ctx, mips32_op, rz, rx, ry); done: ; } @@ -10084,7 +10084,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, /* XXX: not clear which exception should be raised * when in debug mode... */ - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); if (!(ctx->hflags & MIPS_HFLAG_DM)) { generate_exception(ctx, EXCP_DBp); } else { @@ -10092,46 +10092,46 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, } break; case RR_SLT: - gen_slt(env, ctx, OPC_SLT, 24, rx, ry); + gen_slt(ctx, OPC_SLT, 24, rx, ry); break; case RR_SLTU: - gen_slt(env, ctx, OPC_SLTU, 24, rx, ry); + gen_slt(ctx, OPC_SLTU, 24, rx, ry); break; case RR_BREAK: generate_exception(ctx, EXCP_BREAK); break; case RR_SLLV: - gen_shift(env, ctx, OPC_SLLV, ry, rx, ry); + gen_shift(ctx, OPC_SLLV, ry, rx, ry); break; case RR_SRLV: - gen_shift(env, ctx, OPC_SRLV, ry, rx, ry); + gen_shift(ctx, OPC_SRLV, ry, rx, ry); break; case RR_SRAV: - gen_shift(env, ctx, OPC_SRAV, ry, rx, ry); + gen_shift(ctx, OPC_SRAV, ry, rx, ry); break; #if defined (TARGET_MIPS64) case RR_DSRL: check_mips_64(ctx); - gen_shift_imm(env, ctx, OPC_DSRL, ry, ry, sa); + gen_shift_imm(ctx, OPC_DSRL, ry, ry, sa); break; #endif case RR_CMP: - gen_logic(env, ctx, OPC_XOR, 24, rx, ry); + gen_logic(ctx, OPC_XOR, 24, rx, ry); break; case RR_NEG: - gen_arith(env, ctx, OPC_SUBU, rx, 0, ry); + gen_arith(ctx, OPC_SUBU, rx, 0, ry); break; case RR_AND: - gen_logic(env, ctx, OPC_AND, rx, rx, ry); + gen_logic(ctx, OPC_AND, rx, rx, ry); break; case RR_OR: - gen_logic(env, ctx, OPC_OR, rx, rx, ry); + gen_logic(ctx, OPC_OR, rx, rx, ry); break; case RR_XOR: - gen_logic(env, ctx, OPC_XOR, rx, rx, ry); + gen_logic(ctx, OPC_XOR, rx, rx, ry); break; case RR_NOT: - gen_logic(env, ctx, OPC_NOR, rx, ry, 0); + gen_logic(ctx, OPC_NOR, rx, ry, 0); break; case RR_MFHI: gen_HILO(ctx, OPC_MFHI, rx); @@ -10171,19 +10171,19 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, #if defined (TARGET_MIPS64) case RR_DSRA: check_mips_64(ctx); - gen_shift_imm(env, ctx, OPC_DSRA, ry, ry, sa); + gen_shift_imm(ctx, OPC_DSRA, ry, ry, sa); break; case RR_DSLLV: check_mips_64(ctx); - gen_shift(env, ctx, OPC_DSLLV, ry, rx, ry); + gen_shift(ctx, OPC_DSLLV, ry, rx, ry); break; case RR_DSRLV: check_mips_64(ctx); - gen_shift(env, ctx, OPC_DSRLV, ry, rx, ry); + gen_shift(ctx, OPC_DSRLV, ry, rx, ry); break; case RR_DSRAV: check_mips_64(ctx); - gen_shift(env, ctx, OPC_DSRAV, ry, rx, ry); + gen_shift(ctx, OPC_DSRAV, ry, rx, ry); break; #endif case RR_MULT: @@ -10228,7 +10228,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, #if defined(TARGET_MIPS64) case M16_OPC_I64: funct = (ctx->opcode >> 8) & 0x7; - decode_i64_mips16(env, ctx, ry, funct, offset, 0); + decode_i64_mips16(ctx, ry, funct, offset, 0); break; #endif default: @@ -10730,23 +10730,23 @@ static int mmreg2 (int r) /* Zero-extended immediate */ #define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32-width))) -static void gen_addiur1sp (CPUMIPSState *env, DisasContext *ctx) +static void gen_addiur1sp(DisasContext *ctx) { int rd = mmreg(uMIPS_RD(ctx->opcode)); - gen_arith_imm(env, ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2); + gen_arith_imm(ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2); } -static void gen_addiur2 (CPUMIPSState *env, DisasContext *ctx) +static void gen_addiur2(DisasContext *ctx) { static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 }; int rd = mmreg(uMIPS_RD(ctx->opcode)); int rs = mmreg(uMIPS_RS(ctx->opcode)); - gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]); + gen_arith_imm(ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]); } -static void gen_addiusp (CPUMIPSState *env, DisasContext *ctx) +static void gen_addiusp(DisasContext *ctx) { int encoded = ZIMM(ctx->opcode, 1, 9); int decoded; @@ -10761,18 +10761,18 @@ static void gen_addiusp (CPUMIPSState *env, DisasContext *ctx) decoded = encoded - 768; } - gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, decoded << 2); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, decoded << 2); } -static void gen_addius5 (CPUMIPSState *env, DisasContext *ctx) +static void gen_addius5(DisasContext *ctx) { int imm = SIMM(ctx->opcode, 1, 4); int rd = (ctx->opcode >> 5) & 0x1f; - gen_arith_imm(env, ctx, OPC_ADDIU, rd, rd, imm); + gen_arith_imm(ctx, OPC_ADDIU, rd, rd, imm); } -static void gen_andi16 (CPUMIPSState *env, DisasContext *ctx) +static void gen_andi16(DisasContext *ctx) { static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 255, 32768, 65535 }; @@ -10780,7 +10780,7 @@ static void gen_andi16 (CPUMIPSState *env, DisasContext *ctx) int rs = mmreg(uMIPS_RS(ctx->opcode)); int encoded = ZIMM(ctx->opcode, 0, 4); - gen_logic_imm(env, ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); + gen_logic_imm(ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); } static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, @@ -10831,7 +10831,7 @@ static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, } -static void gen_pool16c_insn (CPUMIPSState *env, DisasContext *ctx, int *is_branch) +static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) { int rd = mmreg((ctx->opcode >> 3) & 0x7); int rs = mmreg(ctx->opcode & 0x7); @@ -10842,25 +10842,25 @@ static void gen_pool16c_insn (CPUMIPSState *env, DisasContext *ctx, int *is_bran case NOT16 + 1: case NOT16 + 2: case NOT16 + 3: - gen_logic(env, ctx, OPC_NOR, rd, rs, 0); + gen_logic(ctx, OPC_NOR, rd, rs, 0); break; case XOR16 + 0: case XOR16 + 1: case XOR16 + 2: case XOR16 + 3: - gen_logic(env, ctx, OPC_XOR, rd, rd, rs); + gen_logic(ctx, OPC_XOR, rd, rd, rs); break; case AND16 + 0: case AND16 + 1: case AND16 + 2: case AND16 + 3: - gen_logic(env, ctx, OPC_AND, rd, rd, rs); + gen_logic(ctx, OPC_AND, rd, rd, rs); break; case OR16 + 0: case OR16 + 1: case OR16 + 2: case OR16 + 3: - gen_logic(env, ctx, OPC_OR, rd, rd, rs); + gen_logic(ctx, OPC_OR, rd, rd, rs); break; case LWM16 + 0: case LWM16 + 1: @@ -10935,7 +10935,7 @@ static void gen_pool16c_insn (CPUMIPSState *env, DisasContext *ctx, int *is_bran /* XXX: not clear which exception should be raised * when in debug mode... */ - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); if (!(ctx->hflags & MIPS_HFLAG_DM)) { generate_exception(ctx, EXCP_DBp); } else { @@ -10948,7 +10948,7 @@ static void gen_pool16c_insn (CPUMIPSState *env, DisasContext *ctx, int *is_bran int imm = ZIMM(ctx->opcode, 0, 5); gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0); - gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm << 2); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); /* Let normal delay slot handling in our caller take us to the branch target. */ } @@ -11085,7 +11085,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, /* Treat as NOP. */ break; } - gen_mfc0(env, ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7); + gen_mfc0(ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7); break; case MTC0: case MTC0 + 32: @@ -11094,7 +11094,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, TCGv t0 = tcg_temp_new(); gen_load_gpr(t0, rt); - gen_mtc0(env, ctx, t0, rs, (ctx->opcode >> 11) & 0x7); + gen_mtc0(ctx, t0, rs, (ctx->opcode >> 11) & 0x7); tcg_temp_free(t0); } break; @@ -11113,11 +11113,11 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, case CLZ: mips32_op = OPC_CLZ; do_cl: - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); gen_cl(ctx, mips32_op, rt, rs); break; case RDHWR: - gen_rdhwr(env, ctx, rt, rs); + gen_rdhwr(ctx, rt, rs); break; case WSBH: gen_bshfl(ctx, OPC_WSBH, rs, rt); @@ -11146,7 +11146,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, case MSUBU: mips32_op = OPC_MSUBU; do_muldiv: - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); gen_muldiv(ctx, mips32_op, rs, rt); break; default: @@ -11187,12 +11187,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, switch (minor) { case RDPGPR: check_cp0_enabled(ctx); - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_load_srsgpr(rt, rs); break; case WRPGPR: check_cp0_enabled(ctx); - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_store_srsgpr(rt, rs); break; default: @@ -11272,7 +11272,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, ctx->bstate = BS_STOP; break; case SDBBP: - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); if (!(ctx->hflags & MIPS_HFLAG_DM)) { generate_exception(ctx, EXCP_DBp); } else { @@ -11329,7 +11329,7 @@ enum { FMT_DWL_L = 2 }; -static void gen_pool32fxf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) +static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) { int extension = (ctx->opcode >> 6) & 0x3ff; uint32_t mips32_op; @@ -11614,7 +11614,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case ROTR: mips32_op = OPC_ROTR; do_shifti: - gen_shift_imm(env, ctx, mips32_op, rt, rs, rd); + gen_shift_imm(ctx, mips32_op, rt, rs, rd); break; default: goto pool32a_invalid; @@ -11639,7 +11639,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case MUL: mips32_op = OPC_MUL; do_arith: - gen_arith(env, ctx, mips32_op, rd, rs, rt); + gen_arith(ctx, mips32_op, rd, rs, rt); break; /* Shifts */ case SLLV: @@ -11654,7 +11654,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case ROTRV: mips32_op = OPC_ROTRV; do_shift: - gen_shift(env, ctx, mips32_op, rd, rs, rt); + gen_shift(ctx, mips32_op, rd, rs, rt); break; /* Logical operations */ case AND: @@ -11669,7 +11669,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case XOR32: mips32_op = OPC_XOR; do_logic: - gen_logic(env, ctx, mips32_op, rd, rs, rt); + gen_logic(ctx, mips32_op, rd, rs, rt); break; /* Set less than */ case SLT: @@ -11678,7 +11678,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case SLTU: mips32_op = OPC_SLTU; do_slt: - gen_slt(env, ctx, mips32_op, rd, rs, rt); + gen_slt(ctx, mips32_op, rd, rs, rt); break; default: goto pool32a_invalid; @@ -11694,7 +11694,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case MOVZ: mips32_op = OPC_MOVZ; do_cmov: - gen_cond_move(env, ctx, mips32_op, rd, rs, rt); + gen_cond_move(ctx, mips32_op, rd, rs, rt); break; case LWXS: gen_ldxs(ctx, rs, rt, rd); @@ -11839,7 +11839,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, } break; case POOL32FXF: - gen_pool32fxf(env, ctx, rt, rs); + gen_pool32fxf(ctx, rt, rs); break; case 0x00: /* PLL foo */ @@ -12107,7 +12107,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, target. */ break; case LUI: - gen_logic_imm(env, ctx, OPC_LUI, rs, -1, imm); + gen_logic_imm(ctx, OPC_LUI, rs, -1, imm); break; case SYNCI: break; @@ -12129,10 +12129,10 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, mips32_op = OPC_BC1TANY4; do_cp1mips3d: check_cop1x(ctx); - check_insn(env, ctx, ASE_MIPS3D); + check_insn(ctx, ASE_MIPS3D); /* Fall through */ do_cp1branch: - gen_compute_branch1(env, ctx, mips32_op, + gen_compute_branch1(ctx, mips32_op, (ctx->opcode >> 18) & 0x7, imm << 1); *is_branch = 1; break; @@ -12185,7 +12185,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, mips32_op = OPC_LL; goto do_ld_lr; do_ld_lr: - gen_ld(env, ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12)); + gen_ld(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12)); break; do_st_lr: gen_st(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12)); @@ -12213,7 +12213,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case ADDIU32: mips32_op = OPC_ADDIU; do_addi: - gen_arith_imm(env, ctx, mips32_op, rt, rs, imm); + gen_arith_imm(ctx, mips32_op, rt, rs, imm); break; /* Logical operations */ @@ -12226,7 +12226,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case ANDI32: mips32_op = OPC_ANDI; do_logici: - gen_logic_imm(env, ctx, mips32_op, rt, rs, imm); + gen_logic_imm(ctx, mips32_op, rt, rs, imm); break; /* Set less than immediate */ @@ -12236,7 +12236,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case SLTIU32: mips32_op = OPC_SLTIU; do_slti: - gen_slt_imm(env, ctx, mips32_op, rt, rs, imm); + gen_slt_imm(ctx, mips32_op, rt, rs, imm); break; case JALX32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; @@ -12323,7 +12323,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, mips32_op = OPC_SW; goto do_st; do_ld: - gen_ld(env, ctx, mips32_op, rt, rs, imm); + gen_ld(ctx, mips32_op, rt, rs, imm); break; do_st: gen_st(ctx, mips32_op, rt, rs, imm); @@ -12443,7 +12443,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b break; } - gen_arith(env, ctx, opc, rd, rs1, rs2); + gen_arith(ctx, opc, rd, rs1, rs2); } break; case POOL16B: @@ -12463,11 +12463,11 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b break; } - gen_shift_imm(env, ctx, opc, rd, rs, amount); + gen_shift_imm(ctx, opc, rd, rs, amount); } break; case POOL16C: - gen_pool16c_insn(env, ctx, is_branch); + gen_pool16c_insn(ctx, is_branch); break; case LWGP16: { @@ -12475,7 +12475,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b int rb = 28; /* GP */ int16_t offset = SIMM(ctx->opcode, 0, 7) << 2; - gen_ld(env, ctx, OPC_LW, rd, rb, offset); + gen_ld(ctx, OPC_LW, rd, rb, offset); } break; case POOL16F: @@ -12496,8 +12496,8 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b rs = rs_rt_enc[enc_rs]; rt = rs_rt_enc[enc_rt]; - gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0); - gen_arith_imm(env, ctx, OPC_ADDIU, re, rt, 0); + gen_arith_imm(ctx, OPC_ADDIU, rd, rs, 0); + gen_arith_imm(ctx, OPC_ADDIU, re, rt, 0); } break; case LBU16: @@ -12507,7 +12507,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b int16_t offset = ZIMM(ctx->opcode, 0, 4); offset = (offset == 0xf ? -1 : offset); - gen_ld(env, ctx, OPC_LBU, rd, rb, offset); + gen_ld(ctx, OPC_LBU, rd, rb, offset); } break; case LHU16: @@ -12516,7 +12516,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b int rb = mmreg(uMIPS_RS(ctx->opcode)); int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; - gen_ld(env, ctx, OPC_LHU, rd, rb, offset); + gen_ld(ctx, OPC_LHU, rd, rb, offset); } break; case LWSP16: @@ -12525,7 +12525,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b int rb = 29; /* SP */ int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; - gen_ld(env, ctx, OPC_LW, rd, rb, offset); + gen_ld(ctx, OPC_LW, rd, rb, offset); } break; case LW16: @@ -12534,7 +12534,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b int rb = mmreg(uMIPS_RS(ctx->opcode)); int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; - gen_ld(env, ctx, OPC_LW, rd, rb, offset); + gen_ld(ctx, OPC_LW, rd, rb, offset); } break; case SB16: @@ -12578,29 +12578,29 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b int rd = uMIPS_RD5(ctx->opcode); int rs = uMIPS_RS5(ctx->opcode); - gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0); + gen_arith_imm(ctx, OPC_ADDIU, rd, rs, 0); } break; case ANDI16: - gen_andi16(env, ctx); + gen_andi16(ctx); break; case POOL16D: switch (ctx->opcode & 0x1) { case ADDIUS5: - gen_addius5(env, ctx); + gen_addius5(ctx); break; case ADDIUSP: - gen_addiusp(env, ctx); + gen_addiusp(ctx); break; } break; case POOL16E: switch (ctx->opcode & 0x1) { case ADDIUR2: - gen_addiur2(env, ctx); + gen_addiur2(ctx); break; case ADDIUR1SP: - gen_addiur1sp(env, ctx); + gen_addiur1sp(ctx); break; } break; @@ -12651,7 +12651,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int *is_b #endif /* MIPSDSP functions. */ -static void gen_mipsdsp_ld(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, +static void gen_mipsdsp_ld(DisasContext *ctx, uint32_t opc, int rd, int base, int offset) { const char *opn = "ldx"; @@ -13712,8 +13712,7 @@ static void gen_mipsdsp_multiply(DisasContext *ctx, uint32_t op1, uint32_t op2, } -static void gen_mipsdsp_bitinsn(CPUMIPSState *env, DisasContext *ctx, - uint32_t op1, uint32_t op2, +static void gen_mipsdsp_bitinsn(DisasContext *ctx, uint32_t op1, uint32_t op2, int ret, int val) { const char *opn = "mipsdsp Bit/ Manipulation"; @@ -14367,18 +14366,18 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) switch (op1) { case OPC_SLL: /* Shift with immediate */ case OPC_SRA: - gen_shift_imm(env, ctx, op1, rd, rt, sa); + gen_shift_imm(ctx, op1, rd, rt, sa); break; case OPC_SRL: switch ((ctx->opcode >> 21) & 0x1f) { case 1: /* rotr is decoded as srl on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { + if (ctx->insn_flags & ISA_MIPS32R2) { op1 = OPC_ROTR; } /* Fallthrough */ case 0: - gen_shift_imm(env, ctx, op1, rd, rt, sa); + gen_shift_imm(ctx, op1, rd, rt, sa); break; default: generate_exception(ctx, EXCP_RI); @@ -14387,27 +14386,27 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_MOVN: /* Conditional move */ case OPC_MOVZ: - check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32 | + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32 | INSN_LOONGSON2E | INSN_LOONGSON2F); - gen_cond_move(env, ctx, op1, rd, rs, rt); + gen_cond_move(ctx, op1, rd, rs, rt); break; case OPC_ADD ... OPC_SUBU: - gen_arith(env, ctx, op1, rd, rs, rt); + gen_arith(ctx, op1, rd, rs, rt); break; case OPC_SLLV: /* Shifts */ case OPC_SRAV: - gen_shift(env, ctx, op1, rd, rs, rt); + gen_shift(ctx, op1, rd, rs, rt); break; case OPC_SRLV: switch ((ctx->opcode >> 6) & 0x1f) { case 1: /* rotrv is decoded as srlv on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { + if (ctx->insn_flags & ISA_MIPS32R2) { op1 = OPC_ROTRV; } /* Fallthrough */ case 0: - gen_shift(env, ctx, op1, rd, rs, rt); + gen_shift(ctx, op1, rd, rs, rt); break; default: generate_exception(ctx, EXCP_RI); @@ -14416,17 +14415,17 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_SLT: /* Set on less than */ case OPC_SLTU: - gen_slt(env, ctx, op1, rd, rs, rt); + gen_slt(ctx, op1, rd, rs, rt); break; case OPC_AND: /* Logic*/ case OPC_OR: case OPC_NOR: case OPC_XOR: - gen_logic(env, ctx, op1, rd, rs, rt); + gen_logic(ctx, op1, rd, rs, rt); break; case OPC_MULT ... OPC_DIVU: if (sa) { - check_insn(env, ctx, INSN_VR54XX); + check_insn(ctx, INSN_VR54XX); op1 = MASK_MUL_VR54XX(ctx->opcode); gen_mul_vr54xx(ctx, op1, rd, rs, rt); } else @@ -14478,7 +14477,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_MOVCI: - check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); if (env->CP0_Config1 & (1 << CP0C1_FP)) { check_cp1_enabled(ctx); gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7, @@ -14494,22 +14493,22 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_DSRA: case OPC_DSLL32: case OPC_DSRA32: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_shift_imm(env, ctx, op1, rd, rt, sa); + gen_shift_imm(ctx, op1, rd, rt, sa); break; case OPC_DSRL: switch ((ctx->opcode >> 21) & 0x1f) { case 1: /* drotr is decoded as dsrl on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { + if (ctx->insn_flags & ISA_MIPS32R2) { op1 = OPC_DROTR; } /* Fallthrough */ case 0: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_shift_imm(env, ctx, op1, rd, rt, sa); + gen_shift_imm(ctx, op1, rd, rt, sa); break; default: generate_exception(ctx, EXCP_RI); @@ -14520,14 +14519,14 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) switch ((ctx->opcode >> 21) & 0x1f) { case 1: /* drotr32 is decoded as dsrl32 on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { + if (ctx->insn_flags & ISA_MIPS32R2) { op1 = OPC_DROTR32; } /* Fallthrough */ case 0: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_shift_imm(env, ctx, op1, rd, rt, sa); + gen_shift_imm(ctx, op1, rd, rt, sa); break; default: generate_exception(ctx, EXCP_RI); @@ -14535,28 +14534,28 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) } break; case OPC_DADD ... OPC_DSUBU: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_arith(env, ctx, op1, rd, rs, rt); + gen_arith(ctx, op1, rd, rs, rt); break; case OPC_DSLLV: case OPC_DSRAV: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_shift(env, ctx, op1, rd, rs, rt); + gen_shift(ctx, op1, rd, rs, rt); break; case OPC_DSRLV: switch ((ctx->opcode >> 6) & 0x1f) { case 1: /* drotrv is decoded as dsrlv on non-R2 CPUs */ - if (env->insn_flags & ISA_MIPS32R2) { + if (ctx->insn_flags & ISA_MIPS32R2) { op1 = OPC_DROTRV; } /* Fallthrough */ case 0: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_shift(env, ctx, op1, rd, rs, rt); + gen_shift(ctx, op1, rd, rs, rt); break; default: generate_exception(ctx, EXCP_RI); @@ -14564,7 +14563,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) } break; case OPC_DMULT ... OPC_DDIVU: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, op1, rs, rt); break; @@ -14580,22 +14579,22 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) switch (op1) { case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ case OPC_MSUB ... OPC_MSUBU: - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); gen_muldiv(ctx, op1, rs, rt); break; case OPC_MUL: - gen_arith(env, ctx, op1, rd, rs, rt); + gen_arith(ctx, op1, rd, rs, rt); break; case OPC_CLO: case OPC_CLZ: - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); gen_cl(ctx, op1, rd, rs); break; case OPC_SDBBP: /* XXX: not clear which exception should be raised * when in debug mode... */ - check_insn(env, ctx, ISA_MIPS32); + check_insn(ctx, ISA_MIPS32); if (!(ctx->hflags & MIPS_HFLAG_DM)) { generate_exception(ctx, EXCP_DBp); } else { @@ -14609,13 +14608,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_MULTU_G_2F: case OPC_MOD_G_2F: case OPC_MODU_G_2F: - check_insn(env, ctx, INSN_LOONGSON2F); + check_insn(ctx, INSN_LOONGSON2F); gen_loongson_integer(ctx, op1, rd, rs, rt); break; #if defined(TARGET_MIPS64) case OPC_DCLO: case OPC_DCLZ: - check_insn(env, ctx, ISA_MIPS64); + check_insn(ctx, ISA_MIPS64); check_mips_64(ctx); gen_cl(ctx, op1, rd, rs); break; @@ -14625,7 +14624,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_DDIVU_G_2F: case OPC_DMOD_G_2F: case OPC_DMODU_G_2F: - check_insn(env, ctx, INSN_LOONGSON2F); + check_insn(ctx, INSN_LOONGSON2F); gen_loongson_integer(ctx, op1, rd, rs, rt); break; #endif @@ -14640,19 +14639,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) switch (op1) { case OPC_EXT: case OPC_INS: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_BSHFL: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); op2 = MASK_BSHFL(ctx->opcode); gen_bshfl(ctx, op2, rt, rd); break; case OPC_RDHWR: - gen_rdhwr(env, ctx, rt, rd); + gen_rdhwr(ctx, rt, rd); break; case OPC_FORK: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -14665,7 +14664,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) } break; case OPC_YIELD: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); { TCGv t0 = tcg_temp_new(); @@ -14681,7 +14680,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_MULT_G_2E ... OPC_MULTU_G_2E: /* OPC_MULT_G_2E, OPC_ADDUH_QB_DSP, OPC_MUL_PH_DSP have * the same mask and op1. */ - if ((env->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) { + if ((ctx->insn_flags & ASE_DSPR2) && (op1 == OPC_MULT_G_2E)) { op2 = MASK_ADDUH_QB(ctx->opcode); switch (op2) { case OPC_ADDUH_QB: @@ -14709,7 +14708,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) generate_exception(ctx, EXCP_RI); break; } - } else if (env->insn_flags & INSN_LOONGSON2E) { + } else if (ctx->insn_flags & INSN_LOONGSON2E) { gen_loongson_integer(ctx, op1, rd, rs, rt); } else { generate_exception(ctx, EXCP_RI); @@ -14724,7 +14723,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_LBUX: case OPC_LHX: case OPC_LWX: - gen_mipsdsp_ld(env, ctx, op2, rd, rs, rt); + gen_mipsdsp_ld(ctx, op2, rd, rs, rt); break; default: /* Invalid */ MIPS_INVAL("MASK LX"); @@ -14755,7 +14754,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_REPLV_QB: case OPC_REPL_PH: case OPC_REPLV_PH: - gen_mipsdsp_bitinsn(env, ctx, op1, op2, rd, rt); + gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt); break; default: MIPS_INVAL("MASK ABSQ_S.PH"); @@ -14947,12 +14946,12 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) #if defined(TARGET_MIPS64) case OPC_DEXTM ... OPC_DEXT: case OPC_DINSM ... OPC_DINS: - check_insn(env, ctx, ISA_MIPS64R2); + check_insn(ctx, ISA_MIPS64R2); check_mips_64(ctx); gen_bitops(ctx, op1, rt, rs, sa, rd); break; case OPC_DBSHFL: - check_insn(env, ctx, ISA_MIPS64R2); + check_insn(ctx, ISA_MIPS64R2); check_mips_64(ctx); op2 = MASK_DBSHFL(ctx->opcode); gen_bshfl(ctx, op2, rt, rd); @@ -14960,7 +14959,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_DDIV_G_2E ... OPC_DDIVU_G_2E: case OPC_DMULT_G_2E ... OPC_DMULTU_G_2E: case OPC_DMOD_G_2E ... OPC_DMODU_G_2E: - check_insn(env, ctx, INSN_LOONGSON2E); + check_insn(ctx, INSN_LOONGSON2E); gen_loongson_integer(ctx, op1, rd, rs, rt); break; case OPC_ABSQ_S_QH_DSP: @@ -14991,7 +14990,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_REPLV_OB: case OPC_REPLV_PW: case OPC_REPLV_QH: - gen_mipsdsp_bitinsn(env, ctx, op1, op2, rd, rt); + gen_mipsdsp_bitinsn(ctx, op1, op2, rd, rt); break; default: /* Invalid */ MIPS_INVAL("MASK ABSQ_S.QH"); @@ -15212,7 +15211,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) gen_trap(ctx, op1, rs, -1, imm); break; case OPC_SYNCI: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); /* Treat as NOP. */ break; case OPC_BPOSGE32: /* MIPS DSP branch */ @@ -15258,27 +15257,27 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) op2 = MASK_MFMC0(ctx->opcode); switch (op2) { case OPC_DMT: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_dmt(t0); gen_store_gpr(t0, rt); break; case OPC_EMT: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_emt(t0); gen_store_gpr(t0, rt); break; case OPC_DVPE: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_dvpe(t0, cpu_env); gen_store_gpr(t0, rt); break; case OPC_EVPE: - check_insn(env, ctx, ASE_MT); + check_insn(ctx, ASE_MT); gen_helper_evpe(t0, cpu_env); gen_store_gpr(t0, rt); break; case OPC_DI: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); save_cpu_state(ctx, 1); gen_helper_di(t0, cpu_env); gen_store_gpr(t0, rt); @@ -15286,7 +15285,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) ctx->bstate = BS_STOP; break; case OPC_EI: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); save_cpu_state(ctx, 1); gen_helper_ei(t0, cpu_env); gen_store_gpr(t0, rt); @@ -15303,11 +15302,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) #endif /* !CONFIG_USER_ONLY */ break; case OPC_RDPGPR: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_load_srsgpr(rt, rd); break; case OPC_WRPGPR: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); gen_store_srsgpr(rt, rd); break; default: @@ -15318,17 +15317,17 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_ADDI: /* Arithmetic with immediate opcode */ case OPC_ADDIU: - gen_arith_imm(env, ctx, op, rt, rs, imm); + gen_arith_imm(ctx, op, rt, rs, imm); break; case OPC_SLTI: /* Set on less than with immediate opcode */ case OPC_SLTIU: - gen_slt_imm(env, ctx, op, rt, rs, imm); + gen_slt_imm(ctx, op, rt, rs, imm); break; case OPC_ANDI: /* Arithmetic with immediate opcode */ case OPC_LUI: case OPC_ORI: case OPC_XORI: - gen_logic_imm(env, ctx, op, rt, rs, imm); + gen_logic_imm(ctx, op, rt, rs, imm); break; case OPC_J ... OPC_JAL: /* Jump */ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; @@ -15342,7 +15341,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_LB ... OPC_LWR: /* Load and stores */ case OPC_LL: - gen_ld(env, ctx, op, rt, rs, imm); + gen_ld(ctx, op, rt, rs, imm); break; case OPC_SB ... OPC_SW: case OPC_SWR: @@ -15353,11 +15352,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_CACHE: check_cp0_enabled(ctx); - check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32); + check_insn(ctx, ISA_MIPS3 | ISA_MIPS32); /* Treat as NOP. */ break; case OPC_PREF: - check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32); + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); /* Treat as NOP. */ break; @@ -15376,7 +15375,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) switch (op1) { case OPC_MFHC1: case OPC_MTHC1: - check_insn(env, ctx, ISA_MIPS32R2); + check_insn(ctx, ISA_MIPS32R2); case OPC_MFC1: case OPC_CFC1: case OPC_MTC1: @@ -15386,17 +15385,17 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) #if defined(TARGET_MIPS64) case OPC_DMFC1: case OPC_DMTC1: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); gen_cp1(ctx, op1, rt, rd); break; #endif case OPC_BC1ANY2: case OPC_BC1ANY4: check_cop1x(ctx); - check_insn(env, ctx, ASE_MIPS3D); + check_insn(ctx, ASE_MIPS3D); /* fall through */ case OPC_BC1: - gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode), + gen_compute_branch1(ctx, MASK_BC1(ctx->opcode), (rt >> 2) & 0x7, imm << 2); *is_branch = 1; break; @@ -15427,7 +15426,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) generate_exception_err(ctx, EXCP_CpU, 2); break; case OPC_CP2: - check_insn(env, ctx, INSN_LOONGSON2F); + check_insn(ctx, INSN_LOONGSON2F); /* Note that these instructions use different fields. */ gen_loongson_multimedia(ctx, sa, rd, rt); break; @@ -15479,36 +15478,36 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_LDL ... OPC_LDR: case OPC_LLD: case OPC_LD: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_ld(env, ctx, op, rt, rs, imm); + gen_ld(ctx, op, rt, rs, imm); break; case OPC_SDL ... OPC_SDR: case OPC_SD: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_st(ctx, op, rt, rs, imm); break; case OPC_SCD: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_st_cond(ctx, op, rt, rs, imm); break; case OPC_DADDI: case OPC_DADDIU: - check_insn(env, ctx, ISA_MIPS3); + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_arith_imm(env, ctx, op, rt, rs, imm); + gen_arith_imm(ctx, op, rt, rs, imm); break; #endif case OPC_JALX: - check_insn(env, ctx, ASE_MIPS16 | ASE_MICROMIPS); + check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; gen_compute_branch(ctx, op, 4, rs, rt, offset); *is_branch = 1; break; case OPC_MDMX: - check_insn(env, ctx, ASE_MDMX); + check_insn(ctx, ASE_MDMX); /* MDMX: Not implemented. */ default: /* Invalid */ MIPS_INVAL("major opcode"); @@ -15539,6 +15538,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, ctx.pc = pc_start; ctx.saved_pc = -1; ctx.singlestep_enabled = env->singlestep_enabled; + ctx.insn_flags = env->insn_flags; ctx.tb = tb; ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ @@ -15591,10 +15591,10 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; decode_opc(env, &ctx, &is_branch); - } else if (env->insn_flags & ASE_MICROMIPS) { + } else if (ctx.insn_flags & ASE_MICROMIPS) { ctx.opcode = cpu_lduw_code(env, ctx.pc); insn_bytes = decode_micromips_opc(env, &ctx, &is_branch); - } else if (env->insn_flags & ASE_MIPS16) { + } else if (ctx.insn_flags & ASE_MIPS16) { ctx.opcode = cpu_lduw_code(env, ctx.pc); insn_bytes = decode_mips16_opc(env, &ctx, &is_branch); } else { @@ -15603,7 +15603,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, break; } if (!is_branch) { - handle_delay_slot(env, &ctx, insn_bytes); + handle_delay_slot(&ctx, insn_bytes); } ctx.pc += insn_bytes; From ad153f153da08f5e08bc8e433c0070af53e34e0a Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:23 +0100 Subject: [PATCH 0813/1634] target-mips: generate a reserved instruction exception on CPU without DSP On CPU without DSP ASE support, a reserved instruction exception (instead of a DSP ASE sate disabled) should be generated. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index aad5ae4b14..99f3492de2 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1394,14 +1394,22 @@ static inline void check_cp1_registers(DisasContext *ctx, int regs) static inline void check_dsp(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_DSP))) { - generate_exception(ctx, EXCP_DSPDIS); + if (ctx->insn_flags & ASE_DSP) { + generate_exception(ctx, EXCP_DSPDIS); + } else { + generate_exception(ctx, EXCP_RI); + } } } static inline void check_dspr2(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_DSPR2))) { - generate_exception(ctx, EXCP_DSPDIS); + if (ctx->insn_flags & ASE_DSP) { + generate_exception(ctx, EXCP_DSPDIS); + } else { + generate_exception(ctx, EXCP_RI); + } } } From 652613ab5ae4559b481c612010b407e1c2216f36 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:23 +0100 Subject: [PATCH 0814/1634] target-mips: add unions to access DSP elements Instead of playing with bit shifting, add two unions (one for 32-bit values, one for 64-bit ones) to access all the DSP elements with the correct type. This make the code easier to read and less error prone, and allow GCC to vectorize the code in some cases. Reviewed-by: Eric Johnson Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 4870e3dbbc..aed4c637c3 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -20,6 +20,28 @@ #include "cpu.h" #include "helper.h" +/* As the byte ordering doesn't matter, i.e. all columns are treated + identically, these unions can be used directly. */ +typedef union { + uint8_t ub[4]; + int8_t sb[4]; + uint16_t uh[2]; + int16_t sh[2]; + uint32_t uw[1]; + int32_t sw[1]; +} DSP32Value; + +typedef union { + uint8_t ub[8]; + int8_t sb[8]; + uint16_t uh[4]; + int16_t sh[4]; + uint32_t uw[2]; + int32_t sw[2]; + uint64_t ul[1]; + int64_t sl[1]; +} DSP64Value; + /*** MIPS DSP internal functions begin ***/ #define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x) #define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d))) From 6de0e6c13e275a59de7fcf5dee26c5a88e3a2ebe Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:23 +0100 Subject: [PATCH 0815/1634] target-mips: use DSP unions for binary DSP operators This allow to reduce the number of macros. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 374 ++++++++++++--------------------------- 1 file changed, 111 insertions(+), 263 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index aed4c637c3..37dbeaa48f 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -1078,7 +1078,6 @@ static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b) b = num & MIPSDSP_LO; \ } while (0) -#define MIPSDSP_RETURN32(a) ((target_long)(int32_t)a) #define MIPSDSP_RETURN32_8(a, b, c, d) ((target_long)(int32_t) \ (((uint32_t)a << 24) | \ (((uint32_t)b << 16) | \ @@ -1111,119 +1110,127 @@ static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b) #endif /** DSP Arithmetic Sub-class insns **/ -#define ARITH_PH(name, func) \ -target_ulong helper_##name##_ph(target_ulong rs, target_ulong rt) \ -{ \ - uint16_t rsh, rsl, rth, rtl, temph, templ; \ - \ - MIPSDSP_SPLIT32_16(rs, rsh, rsl); \ - MIPSDSP_SPLIT32_16(rt, rth, rtl); \ - \ - temph = mipsdsp_##func(rsh, rth); \ - templ = mipsdsp_##func(rsl, rtl); \ - \ - return MIPSDSP_RETURN32_16(temph, templ); \ +#define MIPSDSP32_BINOP(name, func, element) \ +target_ulong helper_##name(target_ulong rs, target_ulong rt) \ +{ \ + DSP32Value ds, dt; \ + unsigned int i, n; \ + \ + n = sizeof(DSP32Value) / sizeof(ds.element[0]); \ + ds.sw[0] = rs; \ + dt.sw[0] = rt; \ + \ + for (i = 0; i < n; i++) { \ + ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i]); \ + } \ + \ + return (target_long)ds.sw[0]; \ } +MIPSDSP32_BINOP(addqh_ph, rshift1_add_q16, sh); +MIPSDSP32_BINOP(addqh_r_ph, rrshift1_add_q16, sh); +MIPSDSP32_BINOP(addqh_r_w, rrshift1_add_q32, sw); +MIPSDSP32_BINOP(addqh_w, rshift1_add_q32, sw); +MIPSDSP32_BINOP(adduh_qb, rshift1_add_u8, ub); +MIPSDSP32_BINOP(adduh_r_qb, rrshift1_add_u8, ub); +MIPSDSP32_BINOP(subqh_ph, rshift1_sub_q16, sh); +MIPSDSP32_BINOP(subqh_r_ph, rrshift1_sub_q16, sh); +MIPSDSP32_BINOP(subqh_r_w, rrshift1_sub_q32, sw); +MIPSDSP32_BINOP(subqh_w, rshift1_sub_q32, sw); +#undef MIPSDSP32_BINOP -#define ARITH_PH_ENV(name, func) \ -target_ulong helper_##name##_ph(target_ulong rs, target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - uint16_t rsh, rsl, rth, rtl, temph, templ; \ - \ - MIPSDSP_SPLIT32_16(rs, rsh, rsl); \ - MIPSDSP_SPLIT32_16(rt, rth, rtl); \ - \ - temph = mipsdsp_##func(rsh, rth, env); \ - templ = mipsdsp_##func(rsl, rtl, env); \ - \ - return MIPSDSP_RETURN32_16(temph, templ); \ +#define MIPSDSP32_BINOP_ENV(name, func, element) \ +target_ulong helper_##name(target_ulong rs, target_ulong rt, \ + CPUMIPSState *env) \ +{ \ + DSP32Value ds, dt; \ + unsigned int i, n; \ + \ + n = sizeof(DSP32Value) / sizeof(ds.element[0]); \ + ds.sw[0] = rs; \ + dt.sw[0] = rt; \ + \ + for (i = 0 ; i < n ; i++) { \ + ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i], env); \ + } \ + \ + return (target_long)ds.sw[0]; \ } - - -ARITH_PH_ENV(addq, add_i16); -ARITH_PH_ENV(addq_s, sat_add_i16); -ARITH_PH_ENV(addu, add_u16); -ARITH_PH_ENV(addu_s, sat_add_u16); - -ARITH_PH(addqh, rshift1_add_q16); -ARITH_PH(addqh_r, rrshift1_add_q16); - -ARITH_PH_ENV(subq, sub_i16); -ARITH_PH_ENV(subq_s, sat16_sub); -ARITH_PH_ENV(subu, sub_u16_u16); -ARITH_PH_ENV(subu_s, satu16_sub_u16_u16); - -ARITH_PH(subqh, rshift1_sub_q16); -ARITH_PH(subqh_r, rrshift1_sub_q16); - -#undef ARITH_PH -#undef ARITH_PH_ENV +MIPSDSP32_BINOP_ENV(addq_ph, add_i16, sh) +MIPSDSP32_BINOP_ENV(addq_s_ph, sat_add_i16, sh) +MIPSDSP32_BINOP_ENV(addq_s_w, sat_add_i32, sw); +MIPSDSP32_BINOP_ENV(addu_ph, add_u16, sh) +MIPSDSP32_BINOP_ENV(addu_qb, add_u8, ub); +MIPSDSP32_BINOP_ENV(addu_s_ph, sat_add_u16, sh) +MIPSDSP32_BINOP_ENV(addu_s_qb, sat_add_u8, ub); +MIPSDSP32_BINOP_ENV(subq_ph, sub_i16, sh); +MIPSDSP32_BINOP_ENV(subq_s_ph, sat16_sub, sh); +MIPSDSP32_BINOP_ENV(subq_s_w, sat32_sub, sw); +MIPSDSP32_BINOP_ENV(subu_ph, sub_u16_u16, sh); +MIPSDSP32_BINOP_ENV(subu_qb, sub_u8, ub); +MIPSDSP32_BINOP_ENV(subu_s_ph, satu16_sub_u16_u16, sh); +MIPSDSP32_BINOP_ENV(subu_s_qb, satu8_sub, ub); +#undef MIPSDSP32_BINOP_ENV #ifdef TARGET_MIPS64 -#define ARITH_QH_ENV(name, func) \ -target_ulong helper_##name##_qh(target_ulong rs, target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - uint16_t rs3, rs2, rs1, rs0; \ - uint16_t rt3, rt2, rt1, rt0; \ - uint16_t tempD, tempC, tempB, tempA; \ - \ - MIPSDSP_SPLIT64_16(rs, rs3, rs2, rs1, rs0); \ - MIPSDSP_SPLIT64_16(rt, rt3, rt2, rt1, rt0); \ - \ - tempD = mipsdsp_##func(rs3, rt3, env); \ - tempC = mipsdsp_##func(rs2, rt2, env); \ - tempB = mipsdsp_##func(rs1, rt1, env); \ - tempA = mipsdsp_##func(rs0, rt0, env); \ - \ - return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA); \ +#define MIPSDSP64_BINOP(name, func, element) \ +target_ulong helper_##name(target_ulong rs, target_ulong rt) \ +{ \ + DSP64Value ds, dt; \ + unsigned int i, n; \ + \ + n = sizeof(DSP64Value) / sizeof(ds.element[0]); \ + ds.sl[0] = rs; \ + dt.sl[0] = rt; \ + \ + for (i = 0 ; i < n ; i++) { \ + ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i]); \ + } \ + \ + return ds.sl[0]; \ } +MIPSDSP64_BINOP(adduh_ob, rshift1_add_u8, ub); +MIPSDSP64_BINOP(adduh_r_ob, rrshift1_add_u8, ub); +MIPSDSP64_BINOP(subuh_ob, rshift1_sub_u8, ub); +MIPSDSP64_BINOP(subuh_r_ob, rrshift1_sub_u8, ub); +#undef MIPSDSP64_BINOP -ARITH_QH_ENV(addq, add_i16); -ARITH_QH_ENV(addq_s, sat_add_i16); -ARITH_QH_ENV(addu, add_u16); -ARITH_QH_ENV(addu_s, sat_add_u16); - -ARITH_QH_ENV(subq, sub_i16); -ARITH_QH_ENV(subq_s, sat16_sub); -ARITH_QH_ENV(subu, sub_u16_u16); -ARITH_QH_ENV(subu_s, satu16_sub_u16_u16); - -#undef ARITH_QH_ENV +#define MIPSDSP64_BINOP_ENV(name, func, element) \ +target_ulong helper_##name(target_ulong rs, target_ulong rt, \ + CPUMIPSState *env) \ +{ \ + DSP64Value ds, dt; \ + unsigned int i, n; \ + \ + n = sizeof(DSP64Value) / sizeof(ds.element[0]); \ + ds.sl[0] = rs; \ + dt.sl[0] = rt; \ + \ + for (i = 0 ; i < n ; i++) { \ + ds.element[i] = mipsdsp_##func(ds.element[i], dt.element[i], env); \ + } \ + \ + return ds.sl[0]; \ +} +MIPSDSP64_BINOP_ENV(addq_pw, add_i32, sw); +MIPSDSP64_BINOP_ENV(addq_qh, add_i16, sh); +MIPSDSP64_BINOP_ENV(addq_s_pw, sat_add_i32, sw); +MIPSDSP64_BINOP_ENV(addq_s_qh, sat_add_i16, sh); +MIPSDSP64_BINOP_ENV(addu_ob, add_u8, uh); +MIPSDSP64_BINOP_ENV(addu_qh, add_u16, uh); +MIPSDSP64_BINOP_ENV(addu_s_ob, sat_add_u8, uh); +MIPSDSP64_BINOP_ENV(addu_s_qh, sat_add_u16, uh); +MIPSDSP64_BINOP_ENV(subq_pw, sub32, sw); +MIPSDSP64_BINOP_ENV(subq_qh, sub_i16, sh); +MIPSDSP64_BINOP_ENV(subq_s_pw, sat32_sub, sw); +MIPSDSP64_BINOP_ENV(subq_s_qh, sat16_sub, sh); +MIPSDSP64_BINOP_ENV(subu_ob, sub_u8, uh); +MIPSDSP64_BINOP_ENV(subu_qh, sub_u16_u16, uh); +MIPSDSP64_BINOP_ENV(subu_s_ob, satu8_sub, uh); +MIPSDSP64_BINOP_ENV(subu_s_qh, satu16_sub_u16_u16, uh); +#undef MIPSDSP64_BINOP_ENV #endif -#define ARITH_W(name, func) \ -target_ulong helper_##name##_w(target_ulong rs, target_ulong rt) \ -{ \ - uint32_t rd; \ - rd = mipsdsp_##func(rs, rt); \ - return MIPSDSP_RETURN32(rd); \ -} - -#define ARITH_W_ENV(name, func) \ -target_ulong helper_##name##_w(target_ulong rs, target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - uint32_t rd; \ - rd = mipsdsp_##func(rs, rt, env); \ - return MIPSDSP_RETURN32(rd); \ -} - -ARITH_W_ENV(addq_s, sat_add_i32); - -ARITH_W(addqh, rshift1_add_q32); -ARITH_W(addqh_r, rrshift1_add_q32); - -ARITH_W_ENV(subq_s, sat32_sub); - -ARITH_W(subqh, rshift1_sub_q32); -ARITH_W(subqh_r, rrshift1_sub_q32); - -#undef ARITH_W -#undef ARITH_W_ENV - target_ulong helper_absq_s_w(target_ulong rt, CPUMIPSState *env) { uint32_t rd; @@ -1234,164 +1241,6 @@ target_ulong helper_absq_s_w(target_ulong rt, CPUMIPSState *env) } -#if defined(TARGET_MIPS64) - -#define ARITH_PW_ENV(name, func) \ -target_ulong helper_##name##_pw(target_ulong rs, target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - uint32_t rs1, rs0; \ - uint32_t rt1, rt0; \ - uint32_t tempB, tempA; \ - \ - MIPSDSP_SPLIT64_32(rs, rs1, rs0); \ - MIPSDSP_SPLIT64_32(rt, rt1, rt0); \ - \ - tempB = mipsdsp_##func(rs1, rt1, env); \ - tempA = mipsdsp_##func(rs0, rt0, env); \ - \ - return MIPSDSP_RETURN64_32(tempB, tempA); \ -} - -ARITH_PW_ENV(addq, add_i32); -ARITH_PW_ENV(addq_s, sat_add_i32); -ARITH_PW_ENV(subq, sub32); -ARITH_PW_ENV(subq_s, sat32_sub); - -#undef ARITH_PW_ENV - -#endif - -#define ARITH_QB(name, func) \ -target_ulong helper_##name##_qb(target_ulong rs, target_ulong rt) \ -{ \ - uint8_t rs0, rs1, rs2, rs3; \ - uint8_t rt0, rt1, rt2, rt3; \ - uint8_t temp0, temp1, temp2, temp3; \ - \ - MIPSDSP_SPLIT32_8(rs, rs3, rs2, rs1, rs0); \ - MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0); \ - \ - temp0 = mipsdsp_##func(rs0, rt0); \ - temp1 = mipsdsp_##func(rs1, rt1); \ - temp2 = mipsdsp_##func(rs2, rt2); \ - temp3 = mipsdsp_##func(rs3, rt3); \ - \ - return MIPSDSP_RETURN32_8(temp3, temp2, temp1, temp0); \ -} - -#define ARITH_QB_ENV(name, func) \ -target_ulong helper_##name##_qb(target_ulong rs, target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - uint8_t rs0, rs1, rs2, rs3; \ - uint8_t rt0, rt1, rt2, rt3; \ - uint8_t temp0, temp1, temp2, temp3; \ - \ - MIPSDSP_SPLIT32_8(rs, rs3, rs2, rs1, rs0); \ - MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0); \ - \ - temp0 = mipsdsp_##func(rs0, rt0, env); \ - temp1 = mipsdsp_##func(rs1, rt1, env); \ - temp2 = mipsdsp_##func(rs2, rt2, env); \ - temp3 = mipsdsp_##func(rs3, rt3, env); \ - \ - return MIPSDSP_RETURN32_8(temp3, temp2, temp1, temp0); \ -} - -ARITH_QB(adduh, rshift1_add_u8); -ARITH_QB(adduh_r, rrshift1_add_u8); - -ARITH_QB_ENV(addu, add_u8); -ARITH_QB_ENV(addu_s, sat_add_u8); - -#undef ADDU_QB -#undef ADDU_QB_ENV - -#if defined(TARGET_MIPS64) -#define ARITH_OB(name, func) \ -target_ulong helper_##name##_ob(target_ulong rs, target_ulong rt) \ -{ \ - int i; \ - uint8_t rs_t[8], rt_t[8]; \ - uint8_t temp[8]; \ - uint64_t result; \ - \ - result = 0; \ - \ - for (i = 0; i < 8; i++) { \ - rs_t[i] = (rs >> (8 * i)) & MIPSDSP_Q0; \ - rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0; \ - temp[i] = mipsdsp_##func(rs_t[i], rt_t[i]); \ - result |= (uint64_t)temp[i] << (8 * i); \ - } \ - \ - return result; \ -} - -#define ARITH_OB_ENV(name, func) \ -target_ulong helper_##name##_ob(target_ulong rs, target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - int i; \ - uint8_t rs_t[8], rt_t[8]; \ - uint8_t temp[8]; \ - uint64_t result; \ - \ - result = 0; \ - \ - for (i = 0; i < 8; i++) { \ - rs_t[i] = (rs >> (8 * i)) & MIPSDSP_Q0; \ - rt_t[i] = (rt >> (8 * i)) & MIPSDSP_Q0; \ - temp[i] = mipsdsp_##func(rs_t[i], rt_t[i], env); \ - result |= (uint64_t)temp[i] << (8 * i); \ - } \ - \ - return result; \ -} - -ARITH_OB_ENV(addu, add_u8); -ARITH_OB_ENV(addu_s, sat_add_u8); - -ARITH_OB(adduh, rshift1_add_u8); -ARITH_OB(adduh_r, rrshift1_add_u8); - -ARITH_OB_ENV(subu, sub_u8); -ARITH_OB_ENV(subu_s, satu8_sub); - -ARITH_OB(subuh, rshift1_sub_u8); -ARITH_OB(subuh_r, rrshift1_sub_u8); - -#undef ARITH_OB -#undef ARITH_OB_ENV - -#endif - -#define SUBU_QB(name, func) \ -target_ulong helper_##name##_qb(target_ulong rs, \ - target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - uint8_t rs3, rs2, rs1, rs0; \ - uint8_t rt3, rt2, rt1, rt0; \ - uint8_t tempD, tempC, tempB, tempA; \ - \ - MIPSDSP_SPLIT32_8(rs, rs3, rs2, rs1, rs0); \ - MIPSDSP_SPLIT32_8(rt, rt3, rt2, rt1, rt0); \ - \ - tempD = mipsdsp_##func(rs3, rt3, env); \ - tempC = mipsdsp_##func(rs2, rt2, env); \ - tempB = mipsdsp_##func(rs1, rt1, env); \ - tempA = mipsdsp_##func(rs0, rt0, env); \ - \ - return MIPSDSP_RETURN32_8(tempD, tempC, tempB, tempA); \ -} - -SUBU_QB(subu, sub_u8); -SUBU_QB(subu_s, satu8_sub); - -#undef SUBU_QB - #define SUBUH_QB(name, var) \ target_ulong helper_##name##_qb(target_ulong rs, target_ulong rt) \ { \ @@ -4027,7 +3876,6 @@ target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env) #undef MIPSDSP_SPLIT32_8 #undef MIPSDSP_SPLIT32_16 -#undef MIPSDSP_RETURN32 #undef MIPSDSP_RETURN32_8 #undef MIPSDSP_RETURN32_16 From 75d012ac7f5c92ac5ee2c1dee8c7a7fbeb724e3c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:23 +0100 Subject: [PATCH 0816/1634] target-mips: use DSP unions for unary DSP operators This allow to reduce the number of macros. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 124 +++++++++++++-------------------------- 1 file changed, 42 insertions(+), 82 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 37dbeaa48f..bcc3885601 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -1110,6 +1110,48 @@ static inline int32_t mipsdsp_cmpu_lt(uint32_t a, uint32_t b) #endif /** DSP Arithmetic Sub-class insns **/ +#define MIPSDSP32_UNOP_ENV(name, func, element) \ +target_ulong helper_##name(target_ulong rt, CPUMIPSState *env) \ +{ \ + DSP32Value dt; \ + unsigned int i, n; \ + \ + n = sizeof(DSP32Value) / sizeof(dt.element[0]); \ + dt.sw[0] = rt; \ + \ + for (i = 0; i < n; i++) { \ + dt.element[i] = mipsdsp_##func(dt.element[i], env); \ + } \ + \ + return (target_long)dt.sw[0]; \ +} +MIPSDSP32_UNOP_ENV(absq_s_ph, sat_abs16, sh) +MIPSDSP32_UNOP_ENV(absq_s_qb, sat_abs8, sb) +MIPSDSP32_UNOP_ENV(absq_s_w, sat_abs32, sw) +#undef MIPSDSP32_UNOP_ENV + +#if defined(TARGET_MIPS64) +#define MIPSDSP64_UNOP_ENV(name, func, element) \ +target_ulong helper_##name(target_ulong rt, CPUMIPSState *env) \ +{ \ + DSP64Value dt; \ + unsigned int i, n; \ + \ + n = sizeof(DSP64Value) / sizeof(dt.element[0]); \ + dt.sl[0] = rt; \ + \ + for (i = 0; i < n; i++) { \ + dt.element[i] = mipsdsp_##func(dt.element[i], env); \ + } \ + \ + return dt.sl[0]; \ +} +MIPSDSP64_UNOP_ENV(absq_s_ob, sat_abs8, sb) +MIPSDSP64_UNOP_ENV(absq_s_qh, sat_abs16, sh) +MIPSDSP64_UNOP_ENV(absq_s_pw, sat_abs32, sw) +#undef MIPSDSP64_UNOP_ENV +#endif + #define MIPSDSP32_BINOP(name, func, element) \ target_ulong helper_##name(target_ulong rs, target_ulong rt) \ { \ @@ -1231,16 +1273,6 @@ MIPSDSP64_BINOP_ENV(subu_s_qh, satu16_sub_u16_u16, uh); #endif -target_ulong helper_absq_s_w(target_ulong rt, CPUMIPSState *env) -{ - uint32_t rd; - - rd = mipsdsp_sat_abs32(rt, env); - - return (target_ulong)rd; -} - - #define SUBUH_QB(name, var) \ target_ulong helper_##name##_qb(target_ulong rs, target_ulong rt) \ { \ @@ -1348,78 +1380,6 @@ target_ulong helper_raddu_l_ob(target_ulong rs) } #endif -target_ulong helper_absq_s_qb(target_ulong rt, CPUMIPSState *env) -{ - uint8_t tempD, tempC, tempB, tempA; - - MIPSDSP_SPLIT32_8(rt, tempD, tempC, tempB, tempA); - - tempD = mipsdsp_sat_abs8(tempD, env); - tempC = mipsdsp_sat_abs8(tempC, env); - tempB = mipsdsp_sat_abs8(tempB, env); - tempA = mipsdsp_sat_abs8(tempA, env); - - return MIPSDSP_RETURN32_8(tempD, tempC, tempB, tempA); -} - -target_ulong helper_absq_s_ph(target_ulong rt, CPUMIPSState *env) -{ - uint16_t tempB, tempA; - - MIPSDSP_SPLIT32_16(rt, tempB, tempA); - - tempB = mipsdsp_sat_abs16 (tempB, env); - tempA = mipsdsp_sat_abs16 (tempA, env); - - return MIPSDSP_RETURN32_16(tempB, tempA); -} - -#if defined(TARGET_MIPS64) -target_ulong helper_absq_s_ob(target_ulong rt, CPUMIPSState *env) -{ - int i; - int8_t temp[8]; - uint64_t result; - - for (i = 0; i < 8; i++) { - temp[i] = (rt >> (8 * i)) & MIPSDSP_Q0; - temp[i] = mipsdsp_sat_abs8(temp[i], env); - } - - for (i = 0; i < 8; i++) { - result = (uint64_t)(uint8_t)temp[i] << (8 * i); - } - - return result; -} - -target_ulong helper_absq_s_qh(target_ulong rt, CPUMIPSState *env) -{ - int16_t tempD, tempC, tempB, tempA; - - MIPSDSP_SPLIT64_16(rt, tempD, tempC, tempB, tempA); - - tempD = mipsdsp_sat_abs16(tempD, env); - tempC = mipsdsp_sat_abs16(tempC, env); - tempB = mipsdsp_sat_abs16(tempB, env); - tempA = mipsdsp_sat_abs16(tempA, env); - - return MIPSDSP_RETURN64_16(tempD, tempC, tempB, tempA); -} - -target_ulong helper_absq_s_pw(target_ulong rt, CPUMIPSState *env) -{ - int32_t tempB, tempA; - - MIPSDSP_SPLIT64_32(rt, tempB, tempA); - - tempB = mipsdsp_sat_abs32(tempB, env); - tempA = mipsdsp_sat_abs32(tempA, env); - - return MIPSDSP_RETURN64_32(tempB, tempA); -} -#endif - #define PRECR_QB_PH(name, a, b)\ target_ulong helper_##name##_qb_ph(target_ulong rs, target_ulong rt) \ { \ From 0a16c79cc4087838ae5f2bc9554d91db2cbb2503 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:23 +0100 Subject: [PATCH 0817/1634] target-mips: use DSP unions for reduction add instructions Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index bcc3885601..f5de2ca8e5 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -1352,31 +1352,29 @@ target_ulong helper_modsub(target_ulong rs, target_ulong rt) target_ulong helper_raddu_w_qb(target_ulong rs) { - uint8_t rs3, rs2, rs1, rs0; - uint16_t temp; + target_ulong ret = 0; + DSP32Value ds; + unsigned int i; - MIPSDSP_SPLIT32_8(rs, rs3, rs2, rs1, rs0); - - temp = (uint16_t)rs3 + (uint16_t)rs2 + (uint16_t)rs1 + (uint16_t)rs0; - - return (target_ulong)temp; + ds.uw[0] = rs; + for (i = 0; i < 4; i++) { + ret += ds.ub[i]; + } + return ret; } #if defined(TARGET_MIPS64) target_ulong helper_raddu_l_ob(target_ulong rs) { - int i; - uint16_t rs_t[8]; - uint64_t temp; - - temp = 0; + target_ulong ret = 0; + DSP64Value ds; + unsigned int i; + ds.ul[0] = rs; for (i = 0; i < 8; i++) { - rs_t[i] = (rs >> (8 * i)) & MIPSDSP_Q0; - temp += (uint64_t)rs_t[i]; + ret += ds.ub[i]; } - - return temp; + return ret; } #endif From df6126a7f21a1a032e41b15899ca29777399d5a2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 1 Jan 2013 18:02:24 +0100 Subject: [PATCH 0818/1634] target-mips: implement DSP (d)append sub-class with TCG DSP instruction from the (d)append sub-class can be implemented with TCG. Use a different function for these instructions are they are quite different from compare-pick sub-class. Fix BALIGN instruction for negative value, where the value should be zero-extended before being shift to the right. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 67 -------------------- target-mips/helper.h | 13 ---- target-mips/translate.c | 133 +++++++++++++++++++++++++-------------- 3 files changed, 87 insertions(+), 126 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index f5de2ca8e5..96cb0447e2 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -3111,73 +3111,6 @@ PICK_INSN(pick_pw, 2, MIPSDSP_LLO, 32, 0); #endif #undef PICK_INSN -#define APPEND_INSN(name, ret_32) \ -target_ulong helper_##name(target_ulong rt, target_ulong rs, uint32_t sa) \ -{ \ - target_ulong temp; \ - \ - if (ret_32) { \ - temp = ((rt & MIPSDSP_LLO) << sa) | \ - ((rs & MIPSDSP_LLO) & ((0x01 << sa) - 1)); \ - temp = (target_long)(int32_t)(temp & MIPSDSP_LLO); \ - } else { \ - temp = (rt << sa) | (rs & ((0x01 << sa) - 1)); \ - } \ - \ - return temp; \ -} - -APPEND_INSN(append, 1); -#ifdef TARGET_MIPS64 -APPEND_INSN(dappend, 0); -#endif -#undef APPEND_INSN - -#define PREPEND_INSN(name, or_val, ret_32) \ -target_ulong helper_##name(target_ulong rs, target_ulong rt, \ - uint32_t sa) \ -{ \ - sa |= or_val; \ - \ - if (1) { \ - return (target_long)(int32_t)(uint32_t) \ - (((rs & MIPSDSP_LLO) << (32 - sa)) | \ - ((rt & MIPSDSP_LLO) >> sa)); \ - } else { \ - return (rs << (64 - sa)) | (rt >> sa); \ - } \ -} - -PREPEND_INSN(prepend, 0, 1); -#ifdef TARGET_MIPS64 -PREPEND_INSN(prependw, 0, 0); -PREPEND_INSN(prependd, 0x20, 0); -#endif -#undef PREPEND_INSN - -#define BALIGN_INSN(name, filter, ret32) \ -target_ulong helper_##name(target_ulong rs, target_ulong rt, uint32_t bp) \ -{ \ - bp = bp & 0x03; \ - \ - if ((bp & 1) == 0) { \ - return rt; \ - } else { \ - if (ret32) { \ - return (target_long)(int32_t)((rt << (8 * bp)) | \ - (rs >> (8 * (4 - bp)))); \ - } else { \ - return (rt << (8 * bp)) | (rs >> (8 * (8 - bp))); \ - } \ - } \ -} - -BALIGN_INSN(balign, 0x03, 1); -#if defined(TARGET_MIPS64) -BALIGN_INSN(dbalign, 0x07, 0); -#endif -#undef BALIGN_INSN - target_ulong helper_packrl_ph(target_ulong rs, target_ulong rt) { uint32_t rsl, rth; diff --git a/target-mips/helper.h b/target-mips/helper.h index 9ea60ec1bb..cd48738ff9 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -654,19 +654,6 @@ DEF_HELPER_FLAGS_3(pick_ob, 0, tl, tl, tl, env) DEF_HELPER_FLAGS_3(pick_qh, 0, tl, tl, tl, env) DEF_HELPER_FLAGS_3(pick_pw, 0, tl, tl, tl, env) #endif -DEF_HELPER_FLAGS_3(append, TCG_CALL_NO_RWG_SE, tl, tl, tl, i32) -#if defined(TARGET_MIPS64) -DEF_HELPER_FLAGS_3(dappend, TCG_CALL_NO_RWG_SE, tl, tl, tl, i32) -#endif -DEF_HELPER_FLAGS_3(prepend, TCG_CALL_NO_RWG_SE, tl, tl, tl, i32) -#if defined(TARGET_MIPS64) -DEF_HELPER_FLAGS_3(prependd, TCG_CALL_NO_RWG_SE, tl, tl, tl, i32) -DEF_HELPER_FLAGS_3(prependw, TCG_CALL_NO_RWG_SE, tl, tl, tl, i32) -#endif -DEF_HELPER_FLAGS_3(balign, TCG_CALL_NO_RWG_SE, tl, tl, tl, i32) -#if defined(TARGET_MIPS64) -DEF_HELPER_FLAGS_3(dbalign, TCG_CALL_NO_RWG_SE, tl, tl, tl, i32) -#endif DEF_HELPER_FLAGS_2(packrl_ph, TCG_CALL_NO_RWG_SE, tl, tl, tl) #if defined(TARGET_MIPS64) DEF_HELPER_FLAGS_2(packrl_pw, TCG_CALL_NO_RWG_SE, tl, tl, tl) diff --git a/target-mips/translate.c b/target-mips/translate.c index 99f3492de2..8722638678 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -336,7 +336,7 @@ enum { /* DSP Bit/Manipulation Sub-class */ OPC_INSV_DSP = 0x0C | OPC_SPECIAL3, OPC_DINSV_DSP = 0x0D | OPC_SPECIAL3, - /* MIPS DSP Compare-Pick Sub-class */ + /* MIPS DSP Append Sub-class */ OPC_APPEND_DSP = 0x31 | OPC_SPECIAL3, OPC_DAPPEND_DSP = 0x35 | OPC_SPECIAL3, /* MIPS DSP Accumulator and DSPControl Access Sub-class */ @@ -543,7 +543,7 @@ enum { #define MASK_APPEND(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) enum { - /* MIPS DSP Compare-Pick Sub-class */ + /* MIPS DSP Append Sub-class */ OPC_APPEND = (0x00 << 6) | OPC_APPEND_DSP, OPC_PREPEND = (0x01 << 6) | OPC_APPEND_DSP, OPC_BALIGN = (0x10 << 6) | OPC_APPEND_DSP, @@ -667,7 +667,7 @@ enum { #define MASK_DAPPEND(op) (MASK_SPECIAL3(op) | (op & (0x1F << 6))) enum { - /* DSP Compare-Pick Sub-class */ + /* DSP Append Sub-class */ OPC_DAPPEND = (0x00 << 6) | OPC_DAPPEND_DSP, OPC_PREPENDD = (0x03 << 6) | OPC_DAPPEND_DSP, OPC_PREPENDW = (0x01 << 6) | OPC_DAPPEND_DSP, @@ -13868,7 +13868,6 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, int ret, int v1, int v2, int check_ret) { const char *opn = "mipsdsp add compare pick"; - TCGv_i32 t0; TCGv t1; TCGv v1_t; TCGv v2_t; @@ -13879,7 +13878,6 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, return; } - t0 = tcg_temp_new_i32(); t1 = tcg_temp_new(); v1_t = tcg_temp_new(); v2_t = tcg_temp_new(); @@ -13888,26 +13886,6 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, gen_load_gpr(v2_t, v2); switch (op1) { - case OPC_APPEND_DSP: - switch (op2) { - case OPC_APPEND: - tcg_gen_movi_i32(t0, v2); - gen_helper_append(cpu_gpr[ret], cpu_gpr[ret], v1_t, t0); - break; - case OPC_PREPEND: - tcg_gen_movi_i32(t0, v2); - gen_helper_prepend(cpu_gpr[ret], v1_t, cpu_gpr[ret], t0); - break; - case OPC_BALIGN: - tcg_gen_movi_i32(t0, v2); - gen_helper_balign(cpu_gpr[ret], v1_t, cpu_gpr[ret], t0); - break; - default: /* Invid */ - MIPS_INVAL("MASK APPEND"); - generate_exception(ctx, EXCP_RI); - break; - } - break; case OPC_CMPU_EQ_QB_DSP: switch (op2) { case OPC_CMPU_EQ_QB: @@ -14065,23 +14043,95 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, break; } break; +#endif + } + + tcg_temp_free(t1); + tcg_temp_free(v1_t); + tcg_temp_free(v2_t); + + (void)opn; /* avoid a compiler warning */ + MIPS_DEBUG("%s", opn); +} + +static void gen_mipsdsp_append(CPUMIPSState *env, DisasContext *ctx, + uint32_t op1, int rt, int rs, int sa) +{ + const char *opn = "mipsdsp append/dappend"; + TCGv t0; + + check_dspr2(ctx); + + if (rt == 0) { + /* Treat as NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, rs); + + switch (op1) { + case OPC_APPEND_DSP: + switch (MASK_APPEND(ctx->opcode)) { + case OPC_APPEND: + if (sa != 0) { + tcg_gen_deposit_tl(cpu_gpr[rt], t0, cpu_gpr[rt], sa, 32 - sa); + } + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + break; + case OPC_PREPEND: + if (sa != 0) { + tcg_gen_ext32u_tl(cpu_gpr[rt], cpu_gpr[rt]); + tcg_gen_shri_tl(cpu_gpr[rt], cpu_gpr[rt], sa); + tcg_gen_shli_tl(t0, t0, 32 - sa); + tcg_gen_or_tl(cpu_gpr[rt], cpu_gpr[rt], t0); + } + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + break; + case OPC_BALIGN: + sa &= 3; + if (sa != 0 && sa != 2) { + tcg_gen_shli_tl(cpu_gpr[rt], cpu_gpr[rt], 8 * sa); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_shri_tl(t0, t0, 8 * (4 - sa)); + tcg_gen_or_tl(cpu_gpr[rt], cpu_gpr[rt], t0); + } + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + break; + default: /* Invalid */ + MIPS_INVAL("MASK APPEND"); + generate_exception(ctx, EXCP_RI); + break; + } + break; +#ifdef TARGET_MIPS64 case OPC_DAPPEND_DSP: - switch (op2) { + switch (MASK_DAPPEND(ctx->opcode)) { case OPC_DAPPEND: - tcg_gen_movi_i32(t0, v2); - gen_helper_dappend(cpu_gpr[ret], v1_t, cpu_gpr[ret], t0); + if (sa != 0) { + tcg_gen_deposit_tl(cpu_gpr[rt], t0, cpu_gpr[rt], sa, 64 - sa); + } break; case OPC_PREPENDD: - tcg_gen_movi_i32(t0, v2); - gen_helper_prependd(cpu_gpr[ret], v1_t, cpu_gpr[ret], t0); + tcg_gen_shri_tl(cpu_gpr[rt], cpu_gpr[rt], 0x20 | sa); + tcg_gen_shli_tl(t0, t0, 64 - (0x20 | sa)); + tcg_gen_or_tl(cpu_gpr[rt], t0, t0); break; case OPC_PREPENDW: - tcg_gen_movi_i32(t0, v2); - gen_helper_prependw(cpu_gpr[ret], v1_t, cpu_gpr[ret], t0); + if (sa != 0) { + tcg_gen_shri_tl(cpu_gpr[rt], cpu_gpr[rt], sa); + tcg_gen_shli_tl(t0, t0, 64 - sa); + tcg_gen_or_tl(cpu_gpr[rt], cpu_gpr[rt], t0); + } break; case OPC_DBALIGN: - tcg_gen_movi_i32(t0, v2); - gen_helper_dbalign(cpu_gpr[ret], v1_t, cpu_gpr[ret], t0); + sa &= 7; + if (sa != 0 && sa != 2 && sa != 4) { + tcg_gen_shli_tl(cpu_gpr[rt], cpu_gpr[rt], 8 * sa); + tcg_gen_shri_tl(t0, t0, 8 * (8 - sa)); + tcg_gen_or_tl(cpu_gpr[rt], cpu_gpr[rt], t0); + } break; default: /* Invalid */ MIPS_INVAL("MASK DAPPEND"); @@ -14091,12 +14141,7 @@ static void gen_mipsdsp_add_cmp_pick(DisasContext *ctx, break; #endif } - - tcg_temp_free_i32(t0); - tcg_temp_free(t1); - tcg_temp_free(v1_t); - tcg_temp_free(v2_t); - + tcg_temp_free(t0); (void)opn; /* avoid a compiler warning */ MIPS_DEBUG("%s", opn); } @@ -14915,9 +14960,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) } break; case OPC_APPEND_DSP: - check_dspr2(ctx); - op2 = MASK_APPEND(ctx->opcode); - gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1); + gen_mipsdsp_append(env, ctx, op1, rt, rs, rd); break; case OPC_EXTR_W_DSP: op2 = MASK_EXTR_W(ctx->opcode); @@ -15091,9 +15134,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) } break; case OPC_DAPPEND_DSP: - check_dspr2(ctx); - op2 = MASK_DAPPEND(ctx->opcode); - gen_mipsdsp_add_cmp_pick(ctx, op1, op2, rt, rs, rd, 1); + gen_mipsdsp_append(env, ctx, op1, rt, rs, rd); break; case OPC_DEXTR_W_DSP: op2 = MASK_DEXTR_W(ctx->opcode); From 17e8fef1af2db3a13613a311db2ec2f7a69645a1 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sun, 20 Jan 2013 19:28:48 +0000 Subject: [PATCH 0819/1634] target-mips: Fix signedness of loads in MIPS16 RESTOREs Make RESTORE use sign-extending rather than zero-extending loads. Signed-off-by: Richard Sandiford Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8722638678..8520d28519 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -9446,7 +9446,7 @@ static void gen_mips16_restore (DisasContext *ctx, #define DECR_AND_LOAD(reg) do { \ tcg_gen_subi_tl(t0, t0, 4); \ - tcg_gen_qemu_ld32u(t1, t0, ctx->mem_idx); \ + tcg_gen_qemu_ld32s(t1, t0, ctx->mem_idx); \ gen_store_gpr(t1, reg); \ } while (0) From c728154bbbc1a86465a0fd6bfc839bc9710ac374 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sun, 20 Jan 2013 19:30:54 +0000 Subject: [PATCH 0820/1634] target-mips: Sign-extend the result of LWR Sign-extend the result of LWR, as is already done for LWL. This is necessary in the case where LWR loads the full word (i.e. the address is actually aligned). In the other cases, it is implementation defined whether the upper 32 bits of the result are unchanged or a copy of bit 31. The latter seems easier to implement. Previously the code used: (oldval & (0xfffffffe << (31 - bitshift))) | (newval >> bitshift) which zeroed the upper bits of the register, losing any previous sign extension in the unaligned cases. Signed-off-by: Richard Sandiford Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index 8520d28519..e58d916b04 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1745,6 +1745,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, tcg_temp_free(t2); tcg_gen_or_tl(t0, t0, t1); tcg_temp_free(t1); + tcg_gen_ext32s_tl(t0, t0); gen_store_gpr(t0, rt); opn = "lwr"; break; From f54c35d1ea287beb26f6e929e2362cbc9dcfec07 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 22 Jan 2013 17:16:00 +0000 Subject: [PATCH 0821/1634] target-mips: Unfuse {,N}M{ADD,SUB}.fmt Turn MADD.fmt, MSUB.fmt, NMADD.fmt and NMSUB.fmt from fused to unfused operations, so that they behave in the same way as a separate multiplication and addition. The instructions were only fused in early MIPS IV processors. Signed-off-by: Richard Sandiford Signed-off-by: Aurelien Jarno --- target-mips/op_helper.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 1bca4a159e..526f84f136 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2878,14 +2878,26 @@ FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP +#define UNFUSED_FMA(prefix, a, b, c, flags) \ +{ \ + a = prefix##_mul(a, b, &env->active_fpu.fp_status); \ + if ((flags) & float_muladd_negate_c) { \ + a = prefix##_sub(a, c, &env->active_fpu.fp_status); \ + } else { \ + a = prefix##_add(a, c, &env->active_fpu.fp_status); \ + } \ + if ((flags) & float_muladd_negate_result) { \ + a = prefix##_chs(a); \ + } \ +} + /* FMA based operations */ #define FLOAT_FMA(name, type) \ uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ uint64_t fdt0, uint64_t fdt1, \ uint64_t fdt2) \ { \ - fdt0 = float64_muladd(fdt0, fdt1, fdt2, type, \ - &env->active_fpu.fp_status); \ + UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \ update_fcr31(env, GETPC()); \ return fdt0; \ } \ @@ -2894,8 +2906,7 @@ uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ uint32_t fst0, uint32_t fst1, \ uint32_t fst2) \ { \ - fst0 = float32_muladd(fst0, fst1, fst2, type, \ - &env->active_fpu.fp_status); \ + UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ update_fcr31(env, GETPC()); \ return fst0; \ } \ @@ -2911,10 +2922,8 @@ uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ uint32_t fsth2 = fdt2 >> 32; \ \ - fst0 = float32_muladd(fst0, fst1, fst2, type, \ - &env->active_fpu.fp_status); \ - fsth0 = float32_muladd(fsth0, fsth1, fsth2, type, \ - &env->active_fpu.fp_status); \ + UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ + UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \ update_fcr31(env, GETPC()); \ return ((uint64_t)fsth0 << 32) | fst0; \ } From 6f0af30449b4780c65723d0d45d0f956af5e8c4e Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Wed, 23 Jan 2013 03:57:02 +0100 Subject: [PATCH 0822/1634] target-mips: enable access to DSP ASE if implemented compute_hflags() will reset DSP h-flags, so MX bit should be initially set for usermode in cpu_state_reset() if DSP ASE is implemented. This change will bring back user-mode support for DSP ASE, since one of the recent changes broke it. Signed-off-by: Petar Jovanovic Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index e58d916b04..3b77b53b93 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15978,10 +15978,8 @@ void cpu_state_reset(CPUMIPSState *env) if (env->CP0_Config1 & (1 << CP0C1_FP)) { env->CP0_Status |= (1 << CP0St_CU1); } - if (env->cpu_model->insn_flags & ASE_DSPR2) { - env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2; - } else if (env->cpu_model->insn_flags & ASE_DSP) { - env->hflags |= MIPS_HFLAG_DSP; + if (env->CP0_Config3 & (1 << CP0C3_DSPP)) { + env->CP0_Status |= (1 << CP0St_MX); } #else if (env->hflags & MIPS_HFLAG_BMASK) { From e62a214cd49f836339fe3fd8126fc81d66c3c917 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Wed, 23 Jan 2013 04:17:41 +0100 Subject: [PATCH 0823/1634] target-mips: fix incorrect test for MTHLIP The pos field in the DSPControl register is not correctly initialized. Per documentation, the result of MTHLIP is unpredictable if the value of the pos field before the execution is greater than 32. Signed-off-by: Petar Jovanovic Signed-off-by: Aurelien Jarno --- tests/tcg/mips/mips32-dsp/mthlip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/mips/mips32-dsp/mthlip.c b/tests/tcg/mips/mips32-dsp/mthlip.c index 9549aae36a..85f94d8450 100644 --- a/tests/tcg/mips/mips32-dsp/mthlip.c +++ b/tests/tcg/mips/mips32-dsp/mthlip.c @@ -30,7 +30,7 @@ int main() assert(ach == resulth); assert(acl == resultl); - dsp = 0x3f; + dsp = 0x1f; ach = 0x05; acl = 0xB4CB; rs = 0x00FFBBAA; From 6b2578d678497dbce44ed7999d269fc973ae6e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 1 Feb 2013 00:13:41 +0100 Subject: [PATCH 0824/1634] ide/mmio: QOM'ify MMIO IDE for R2D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was not qdev'ified before, so turn it into a SysBusDevice. Keep mmio_ide_init_drives() around to attach the hard drive. Signed-off-by: Andreas Färberr Cc: Markus Armbruster Signed-off-by: Aurelien Jarno --- hw/ide.h | 5 +-- hw/ide/mmio.c | 92 ++++++++++++++++++++++++++++++++++++++++----------- hw/r2d.c | 10 ++++-- 3 files changed, 82 insertions(+), 25 deletions(-) diff --git a/hw/ide.h b/hw/ide.h index 9b357c05a5..0eb3a74467 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -20,10 +20,7 @@ PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); /* ide-mmio.c */ -void mmio_ide_init (hwaddr membase, hwaddr membase2, - MemoryRegion *address_space, - qemu_irq irq, int shift, - DriveInfo *hd0, DriveInfo *hd1); +void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1); int ide_get_geometry(BusState *bus, int unit, int16_t *cyls, int8_t *heads, int8_t *secs); diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index eb59976eda..ce88c3a651 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -22,7 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include +#include "hw/hw.h" +#include "hw/sysbus.h" #include "block/block.h" #include "sysemu/dma.h" @@ -34,15 +35,24 @@ * dedicated ide controller, which is often seen on embedded boards. */ -typedef struct { +#define TYPE_MMIO_IDE "mmio-ide" +#define MMIO_IDE(obj) OBJECT_CHECK(MMIOState, (obj), TYPE_MMIO_IDE) + +typedef struct MMIOIDEState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + IDEBus bus; - int shift; + + uint32_t shift; + qemu_irq irq; MemoryRegion iomem1, iomem2; } MMIOState; -static void mmio_ide_reset(void *opaque) +static void mmio_ide_reset(DeviceState *dev) { - MMIOState *s = opaque; + MMIOState *s = MMIO_IDE(dev); ide_bus_reset(&s->bus); } @@ -107,24 +117,68 @@ static const VMStateDescription vmstate_ide_mmio = { } }; -void mmio_ide_init (hwaddr membase, hwaddr membase2, - MemoryRegion *address_space, - qemu_irq irq, int shift, - DriveInfo *hd0, DriveInfo *hd1) +static void mmio_ide_realizefn(DeviceState *dev, Error **errp) { - MMIOState *s = g_malloc0(sizeof(MMIOState)); + SysBusDevice *d = SYS_BUS_DEVICE(dev); + MMIOState *s = MMIO_IDE(dev); - ide_init2_with_non_qdev_drives(&s->bus, hd0, hd1, irq); - - s->shift = shift; + ide_init2(&s->bus, s->irq); memory_region_init_io(&s->iomem1, &mmio_ide_ops, s, - "ide-mmio.1", 16 << shift); + "ide-mmio.1", 16 << s->shift); memory_region_init_io(&s->iomem2, &mmio_ide_cs_ops, s, - "ide-mmio.2", 2 << shift); - memory_region_add_subregion(address_space, membase, &s->iomem1); - memory_region_add_subregion(address_space, membase2, &s->iomem2); - vmstate_register(NULL, 0, &vmstate_ide_mmio, s); - qemu_register_reset(mmio_ide_reset, s); + "ide-mmio.2", 2 << s->shift); + sysbus_init_mmio(d, &s->iomem1); + sysbus_init_mmio(d, &s->iomem2); } +static void mmio_ide_initfn(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + MMIOState *s = MMIO_IDE(obj); + + ide_bus_new(&s->bus, DEVICE(obj), 0); + sysbus_init_irq(d, &s->irq); +} + +static Property mmio_ide_properties[] = { + DEFINE_PROP_UINT32("shift", MMIOState, shift, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void mmio_ide_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = mmio_ide_realizefn; + dc->reset = mmio_ide_reset; + dc->props = mmio_ide_properties; + dc->vmsd = &vmstate_ide_mmio; +} + +static const TypeInfo mmio_ide_type_info = { + .name = TYPE_MMIO_IDE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MMIOState), + .instance_init = mmio_ide_initfn, + .class_init = mmio_ide_class_init, +}; + +static void mmio_ide_register_types(void) +{ + type_register_static(&mmio_ide_type_info); +} + +void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1) +{ + MMIOState *s = MMIO_IDE(dev); + + if (hd0 != NULL) { + ide_create_drive(&s->bus, 0, hd0); + } + if (hd1 != NULL) { + ide_create_drive(&s->bus, 1, hd1); + } +} + +type_init(mmio_ide_register_types) diff --git a/hw/r2d.c b/hw/r2d.c index a2e3b6fe1c..2d0dd1ffba 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -276,8 +276,14 @@ static void r2d_init(QEMUMachineInitArgs *args) /* onboard CF (True IDE mode, Master only). */ dinfo = drive_get(IF_IDE, 0, 0); - mmio_ide_init(0x14001000, 0x1400080c, address_space_mem, irq[CF_IDE], 1, - dinfo, NULL); + dev = qdev_create(NULL, "mmio-ide"); + busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, irq[CF_IDE]); + qdev_prop_set_uint32(dev, "shift", 1); + qdev_init_nofail(dev); + sysbus_mmio_map(busdev, 0, 0x14001000); + sysbus_mmio_map(busdev, 1, 0x1400080c); + mmio_ide_init_drives(dev, dinfo, NULL); /* onboard flash memory */ dinfo = drive_get(IF_PFLASH, 0, 0); From 88e28512efd8d36476e50a78acb1dca8b41a3cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 11:43:30 +0100 Subject: [PATCH 0825/1634] target-unicore32: Mark as unmigratable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPU_SAVE_VERSION 2 was bogus as both save and load would just throw a hw_error(). Therefore we can without problems suppress registration of "cpu_common" VMState by dropping CPU_SAVE_VERSION define and provide an unmigratable "cpu" VMStateDescription for UniCore32CPU at device level instead, where we can attach this the QOM way. Signed-off-by: Juan Quintela Signed-off-by: Andreas Färber Reviewed-by: Juan Quintela --- target-unicore32/Makefile.objs | 2 +- target-unicore32/cpu.c | 8 ++++++++ target-unicore32/cpu.h | 2 -- target-unicore32/machine.c | 23 ----------------------- 4 files changed, 9 insertions(+), 26 deletions(-) delete mode 100644 target-unicore32/machine.c diff --git a/target-unicore32/Makefile.objs b/target-unicore32/Makefile.objs index 8e143da937..6b41b1e9ef 100644 --- a/target-unicore32/Makefile.objs +++ b/target-unicore32/Makefile.objs @@ -1,4 +1,4 @@ obj-y += translate.o op_helper.o helper.o cpu.o obj-y += ucf64_helper.o -obj-$(CONFIG_SOFTMMU) += machine.o softmmu.o +obj-$(CONFIG_SOFTMMU) += softmmu.o diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index c120440653..18ef1c5dad 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -14,6 +14,7 @@ #include "cpu.h" #include "qemu-common.h" +#include "migration/vmstate.h" static inline void set_feature(CPUUniCore32State *env, int feature) { @@ -96,11 +97,18 @@ static void uc32_cpu_initfn(Object *obj) tlb_flush(env, 1); } +static const VMStateDescription vmstate_uc32_cpu = { + .name = "cpu", + .unmigratable = 1, +}; + static void uc32_cpu_class_init(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); cc->class_by_name = uc32_cpu_class_by_name; + dc->vmsd = &vmstate_uc32_cpu; } static void uc32_register_cpu_type(const UniCore32CPUInfo *info) diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h index 509ce7c69d..ae9a9d623d 100644 --- a/target-unicore32/cpu.h +++ b/target-unicore32/cpu.h @@ -133,8 +133,6 @@ int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc); int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address, int rw, int mmu_idx); -#define CPU_SAVE_VERSION 2 - /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel #define MMU_MODE1_SUFFIX _user diff --git a/target-unicore32/machine.c b/target-unicore32/machine.c deleted file mode 100644 index 60b2ec1771..0000000000 --- a/target-unicore32/machine.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Generic machine functions for UniCore32 ISA - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ -#include "hw/hw.h" - -void cpu_save(QEMUFile *f, void *opaque) -{ - hw_error("%s not supported yet.\n", __func__); -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - hw_error("%s not supported yet.\n", __func__); - - return 0; -} From 3ce8b2bcbff6445f84db53ef38dbc4e5dd102676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 19:03:32 +0100 Subject: [PATCH 0826/1634] target-microblaze: Mark as unmigratable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cpu_{save,load} were no-ops, so de facto it is unmigratable and no backwards compatibility to keep. Therefore mark the MicroBlazeCPU as unmigratable at device level the QOM way and suppress "cpu_common" VMState registration by dropping CPU_SAVE_VERSION. Signed-off-by: Juan Quintela Signed-off-by: Andreas Färber Reviewed-by: Juan Quintela --- target-microblaze/Makefile.objs | 2 +- target-microblaze/cpu.c | 9 +++++++++ target-microblaze/cpu.h | 2 -- target-microblaze/machine.c | 11 ----------- 4 files changed, 10 insertions(+), 14 deletions(-) delete mode 100644 target-microblaze/machine.c diff --git a/target-microblaze/Makefile.objs b/target-microblaze/Makefile.objs index afb87bcc80..985330eac5 100644 --- a/target-microblaze/Makefile.objs +++ b/target-microblaze/Makefile.objs @@ -1,2 +1,2 @@ obj-y += translate.o op_helper.o helper.o cpu.o -obj-$(CONFIG_SOFTMMU) += mmu.o machine.o +obj-$(CONFIG_SOFTMMU) += mmu.o diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 0f858fd869..39230fddcc 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "qemu-common.h" +#include "migration/vmstate.h" /* CPUClass::reset() */ @@ -94,13 +95,21 @@ static void mb_cpu_initfn(Object *obj) set_float_rounding_mode(float_round_nearest_even, &env->fp_status); } +static const VMStateDescription vmstate_mb_cpu = { + .name = "cpu", + .unmigratable = 1, +}; + static void mb_cpu_class_init(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_CLASS(oc); mcc->parent_reset = cc->reset; cc->reset = mb_cpu_reset; + + dc->vmsd = &vmstate_mb_cpu; } static const TypeInfo mb_cpu_type_info = { diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 5621068d82..41480e71e1 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -307,8 +307,6 @@ static inline CPUMBState *cpu_init(const char *cpu_model) #define cpu_gen_code cpu_mb_gen_code #define cpu_signal_handler cpu_mb_signal_handler -#define CPU_SAVE_VERSION 1 - /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _nommu #define MMU_MODE1_SUFFIX _kernel diff --git a/target-microblaze/machine.c b/target-microblaze/machine.c deleted file mode 100644 index 1be1c351b2..0000000000 --- a/target-microblaze/machine.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "hw/hw.h" -#include "hw/boards.h" - -void cpu_save(QEMUFile *f, void *opaque) -{ -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - return 0; -} From 004a569057492784e4922f2f8cb396fb55affe71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 19:22:41 +0100 Subject: [PATCH 0827/1634] target-xtensa: Mark as unmigratable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was no CPU_SAVE_VERSION defined, so neither "cpu_common" VMState nor cpu_{save,load}() were registered. Their implementation was no-op. Therefore there is no backwards compatibility to keep, so mark XtensaCPU as unmigratable at device level. Signed-off-by: Andreas Färber Reviewed-by: Juan Quintela --- target-xtensa/Makefile.objs | 1 - target-xtensa/cpu.c | 9 +++++++++ target-xtensa/machine.c | 38 ------------------------------------- 3 files changed, 9 insertions(+), 39 deletions(-) delete mode 100644 target-xtensa/machine.c diff --git a/target-xtensa/Makefile.objs b/target-xtensa/Makefile.objs index b30e5a8466..644b7f99bb 100644 --- a/target-xtensa/Makefile.objs +++ b/target-xtensa/Makefile.objs @@ -3,4 +3,3 @@ obj-y += core-dc232b.o obj-y += core-dc233c.o obj-y += core-fsf.o obj-y += translate.o op_helper.o helper.o cpu.o -obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 035b07c1c5..ebc7e9979b 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -30,6 +30,7 @@ #include "cpu.h" #include "qemu-common.h" +#include "migration/vmstate.h" /* CPUClass::reset() */ @@ -64,13 +65,21 @@ static void xtensa_cpu_initfn(Object *obj) cpu_exec_init(env); } +static const VMStateDescription vmstate_xtensa_cpu = { + .name = "cpu", + .unmigratable = 1, +}; + static void xtensa_cpu_class_init(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc); xcc->parent_reset = cc->reset; cc->reset = xtensa_cpu_reset; + + dc->vmsd = &vmstate_xtensa_cpu; } static const TypeInfo xtensa_cpu_type_info = { diff --git a/target-xtensa/machine.c b/target-xtensa/machine.c deleted file mode 100644 index ddeffb2da4..0000000000 --- a/target-xtensa/machine.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the Open Source and Linux Lab nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "hw/hw.h" -#include "hw/boards.h" - -void cpu_save(QEMUFile *f, void *opaque) -{ -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - return 0; -} From 1e45d31b04b1e3ccad2bfb3b4a90a75317ada16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 19:32:33 +0100 Subject: [PATCH 0828/1634] target-sh4: Mark as unmigratable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It neither defined CPU_SAVE_VERSION nor implemented cpu{save,load}(). Mark it as unmigratable at device level. Signed-off-by: Andreas Färber Reviewed-by: Juan Quintela --- target-sh4/Makefile.objs | 1 - target-sh4/cpu.c | 9 +++++++++ target-sh4/machine.c | 0 3 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 target-sh4/machine.c diff --git a/target-sh4/Makefile.objs b/target-sh4/Makefile.objs index ca20f21443..cb448a840f 100644 --- a/target-sh4/Makefile.objs +++ b/target-sh4/Makefile.objs @@ -1,2 +1 @@ obj-y += translate.o op_helper.o helper.o cpu.o -obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index e4858a03ed..d2831226b9 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -21,6 +21,7 @@ #include "cpu.h" #include "qemu-common.h" +#include "migration/vmstate.h" /* CPUClass::reset() */ @@ -63,13 +64,21 @@ static void superh_cpu_initfn(Object *obj) env->movcal_backup_tail = &(env->movcal_backup); } +static const VMStateDescription vmstate_sh_cpu = { + .name = "cpu", + .unmigratable = 1, +}; + static void superh_cpu_class_init(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); scc->parent_reset = cc->reset; cc->reset = superh_cpu_reset; + + dc->vmsd = &vmstate_sh_cpu; } static const TypeInfo superh_cpu_type_info = { diff --git a/target-sh4/machine.c b/target-sh4/machine.c deleted file mode 100644 index e69de29bb2..0000000000 From c7396bbb2597577b1463fc997a73e67b8a067880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 19:41:06 +0100 Subject: [PATCH 0829/1634] target-s390x: Mark as unmigratable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPU_SAVE_VERSION was undefined, so "cpu_common" VMState and cpu_{save,load}() were not registered. They were no-ops. Therefore there is no backwards compatibility to keep, so we can mark S390CPU as unmigratable at device level. Signed-off-by: Andreas Färber Acked-by: Alexander Graf Reviewed-by: Juan Quintela --- target-s390x/Makefile.objs | 2 +- target-s390x/cpu.c | 10 +++++++++- target-s390x/machine.c | 30 ------------------------------ 3 files changed, 10 insertions(+), 32 deletions(-) delete mode 100644 target-s390x/machine.c diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 3afb0b71f9..4e634173a4 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,4 +1,4 @@ obj-y += translate.o helper.o cpu.o interrupt.o obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o -obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o +obj-$(CONFIG_SOFTMMU) += ioinst.o obj-$(CONFIG_KVM) += kvm.o diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 0b68db8305..a0c4479f39 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -26,8 +26,8 @@ #include "cpu.h" #include "qemu-common.h" #include "qemu/timer.h" -#ifndef CONFIG_USER_ONLY #include "hw/hw.h" +#ifndef CONFIG_USER_ONLY #include "sysemu/arch_init.h" #endif @@ -135,13 +135,21 @@ static void s390_cpu_finalize(Object *obj) #endif } +static const VMStateDescription vmstate_s390_cpu = { + .name = "cpu", + .unmigratable = 1, +}; + static void s390_cpu_class_init(ObjectClass *oc, void *data) { S390CPUClass *scc = S390_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(scc); + DeviceClass *dc = DEVICE_CLASS(oc); scc->parent_reset = cc->reset; cc->reset = s390_cpu_reset; + + dc->vmsd = &vmstate_s390_cpu; } static const TypeInfo s390_cpu_type_info = { diff --git a/target-s390x/machine.c b/target-s390x/machine.c deleted file mode 100644 index 3e79be6d56..0000000000 --- a/target-s390x/machine.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * QEMU S390x machine definitions - * - * Copyright (c) 2009 Alexander Graf - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "hw/hw.h" -#include "hw/boards.h" - -void cpu_save(QEMUFile *f, void *opaque) -{ -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - return 0; -} From 087fe4f824e88d5924bf6887cb59985510a790b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 19:53:28 +0100 Subject: [PATCH 0830/1634] target-m68k: Mark as unmigratable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It neither defined CPU_SAVE_VERSION nor implemented cpu_{save,load}(). Mark M68kCPU as unmigratable at device level. Signed-off-by: Andreas Färber Reviewed-by: Juan Quintela --- target-m68k/Makefile.objs | 1 - target-m68k/cpu.c | 8 ++++++++ target-m68k/machine.c | 0 3 files changed, 8 insertions(+), 1 deletion(-) delete mode 100644 target-m68k/machine.c diff --git a/target-m68k/Makefile.objs b/target-m68k/Makefile.objs index 7eccfab0e4..2e2b85044d 100644 --- a/target-m68k/Makefile.objs +++ b/target-m68k/Makefile.objs @@ -1,3 +1,2 @@ obj-y += m68k-semi.o obj-y += translate.o op_helper.o helper.o cpu.o -obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 5c7803181d..c911b8fa97 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "qemu-common.h" +#include "migration/vmstate.h" static void m68k_set_feature(CPUM68KState *env, int feature) @@ -143,15 +144,22 @@ static void m68k_cpu_initfn(Object *obj) cpu_exec_init(env); } +static const VMStateDescription vmstate_m68k_cpu = { + .name = "cpu", + .unmigratable = 1, +}; + static void m68k_cpu_class_init(ObjectClass *c, void *data) { M68kCPUClass *mcc = M68K_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); + DeviceClass *dc = DEVICE_CLASS(c); mcc->parent_reset = cc->reset; cc->reset = m68k_cpu_reset; cc->class_by_name = m68k_cpu_class_by_name; + dc->vmsd = &vmstate_m68k_cpu; } static void register_cpu_type(const M68kCPUInfo *info) diff --git a/target-m68k/machine.c b/target-m68k/machine.c deleted file mode 100644 index e69de29bb2..0000000000 From 7a9f812b381639b96a020bdb1f4783f11f886754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 20:16:17 +0100 Subject: [PATCH 0831/1634] target-m68k: Rename CPU subtypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the initial conversion of CPU models to QOM types, model names were mapped 1:1 to type names. As a side effect this gained us a type "any", which is now a device. To avoid "-device any" silliness and to pave the way for compiling multiple targets into one executable, adopt a --cpu scheme. No functional changes for -cpu arguments or -cpu ? output. Signed-off-by: Andreas Färber --- target-m68k/cpu.c | 8 ++++++-- target-m68k/helper.c | 11 ++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index c911b8fa97..c71f715174 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -59,12 +59,15 @@ static void m68k_cpu_reset(CPUState *s) static ObjectClass *m68k_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; + char *typename; if (cpu_model == NULL) { return NULL; } - oc = object_class_by_name(cpu_model); + typename = g_strdup_printf("%s-" TYPE_M68K_CPU, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); if (oc != NULL && (object_class_dynamic_cast(oc, TYPE_M68K_CPU) == NULL || object_class_is_abstract(oc))) { return NULL; @@ -165,12 +168,13 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) static void register_cpu_type(const M68kCPUInfo *info) { TypeInfo type_info = { - .name = info->name, .parent = TYPE_M68K_CPU, .instance_init = info->instance_init, }; + type_info.name = g_strdup_printf("%s-" TYPE_M68K_CPU, info->name); type_register(&type_info); + g_free((void *)type_info.name); } static const TypeInfo m68k_cpu_type_info = { diff --git a/target-m68k/helper.c b/target-m68k/helper.c index f66e12b6ba..5ddcd707fd 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -34,9 +34,9 @@ static gint m68k_cpu_list_compare(gconstpointer a, gconstpointer b) name_a = object_class_get_name(class_a); name_b = object_class_get_name(class_b); - if (strcmp(name_a, "any") == 0) { + if (strcmp(name_a, "any-" TYPE_M68K_CPU) == 0) { return 1; - } else if (strcmp(name_b, "any") == 0) { + } else if (strcmp(name_b, "any-" TYPE_M68K_CPU) == 0) { return -1; } else { return strcasecmp(name_a, name_b); @@ -47,9 +47,14 @@ static void m68k_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *c = data; CPUListState *s = user_data; + const char *typename; + char *name; + typename = object_class_get_name(c); + name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_M68K_CPU)); (*s->cpu_fprintf)(s->file, "%s\n", - object_class_get_name(c)); + name); + g_free(name); } void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf) From bc755a00b1fd58ac9bfa316237134958489f0145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 22:27:17 +0100 Subject: [PATCH 0832/1634] target-openrisc: TYPE_OPENRISC_CPU should be abstract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A basic assumption of CPU subtypes is that only specific models get instantiated. A user is not supposed to instantiate an -cpu. Suppress it via abstract = true, which also drops or32-cpu from -cpu ? output. Cc: qemu-stable@nongnu.org Cc: Jia Liu Signed-off-by: Andreas Färber --- target-openrisc/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 54876d904b..14f2cbe18e 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -159,7 +159,7 @@ static const TypeInfo openrisc_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(OpenRISCCPU), .instance_init = openrisc_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(OpenRISCCPUClass), .class_init = openrisc_cpu_class_init, }; From 478032a93d908e59085c1ac56f10979942e7dc4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 22:50:35 +0100 Subject: [PATCH 0833/1634] target-openrisc: Rename CPU subtypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model names were mapped 1:1 to type names. As a side effect this registered a type "any", which is now a device. To avoid "-device any" silliness and to pave the way for compiling multiple targets into one executable, adopt a --cpu scheme. No functional changes for -cpu arguments or -cpu ? output. Signed-off-by: Andreas Färber --- target-openrisc/cpu.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 14f2cbe18e..a7a8de8a37 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -144,14 +144,15 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) static void cpu_register(const OpenRISCCPUInfo *info) { TypeInfo type_info = { - .name = info->name, .parent = TYPE_OPENRISC_CPU, .instance_size = sizeof(OpenRISCCPU), .instance_init = info->initfn, .class_size = sizeof(OpenRISCCPUClass), }; + type_info.name = g_strdup_printf("%s-" TYPE_OPENRISC_CPU, info->name); type_register(&type_info); + g_free((void *)type_info.name); } static const TypeInfo openrisc_cpu_type_info = { @@ -200,9 +201,9 @@ static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b) name_a = object_class_get_name(class_a); name_b = object_class_get_name(class_b); - if (strcmp(name_a, "any") == 0) { + if (strcmp(name_a, "any-" TYPE_OPENRISC_CPU) == 0) { return 1; - } else if (strcmp(name_b, "any") == 0) { + } else if (strcmp(name_b, "any-" TYPE_OPENRISC_CPU) == 0) { return -1; } else { return strcmp(name_a, name_b); @@ -213,9 +214,15 @@ static void openrisc_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; CPUListState *s = user_data; + const char *typename; + char *name; + typename = object_class_get_name(oc); + name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_OPENRISC_CPU)); (*s->cpu_fprintf)(s->file, " %s\n", - object_class_get_name(oc)); + name); + g_free(name); } void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf) From eeb266ded886185d1d3b0d8bc089ec72df1a2bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 23:25:25 +0100 Subject: [PATCH 0834/1634] target-unicore32: Rename CPU subtypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the initial conversion of CPU models to QOM types, model names were mapped 1:1 to type names. As a side effect this gained us a type "any", which is now a device. To avoid "-device any" silliness and to pave the way for compiling multiple targets into one executable, adopt a --cpu scheme. No functional changes for -cpu arguments. Signed-off-by: Andreas Färber --- target-unicore32/cpu.c | 9 ++++++--- target-unicore32/helper.c | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 18ef1c5dad..4e4177fc57 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -26,12 +26,15 @@ static inline void set_feature(CPUUniCore32State *env, int feature) static ObjectClass *uc32_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; + char *typename; if (cpu_model == NULL) { return NULL; } - oc = object_class_by_name(cpu_model); + typename = g_strdup_printf("%s-" TYPE_UNICORE32_CPU, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU) || object_class_is_abstract(oc))) { oc = NULL; @@ -84,7 +87,6 @@ static void uc32_cpu_initfn(Object *obj) CPUUniCore32State *env = &cpu->env; cpu_exec_init(env); - env->cpu_model_str = object_get_typename(obj); #ifdef CONFIG_USER_ONLY env->uncached_asr = ASR_MODE_USER; @@ -114,12 +116,13 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data) static void uc32_register_cpu_type(const UniCore32CPUInfo *info) { TypeInfo type_info = { - .name = info->name, .parent = TYPE_UNICORE32_CPU, .instance_init = info->instance_init, }; + type_info.name = g_strdup_printf("%s-" TYPE_UNICORE32_CPU, info->name); type_register(&type_info); + g_free((void *)type_info.name); } static const TypeInfo uc32_cpu_type_info = { diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index 183b5b3577..3a92232de5 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -38,6 +38,7 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model) } cpu = UNICORE32_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; + env->cpu_model_str = cpu_model; if (inited) { inited = 0; From cc36a7a2c7e281d7d715ac73d31bbccc0d2d2670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 15:19:06 +0100 Subject: [PATCH 0835/1634] target-i386: Pass X86CPU to cpu_x86_set_a20() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares for cpu_interrupt() changing argument to CPUState. While touching it, rename to x86_cpu_...() now that it takes an X86CPU. Signed-off-by: Andreas Färber Reviewed-by: Eduardo Habkost --- hw/pc.c | 7 ++++--- target-i386/cpu.h | 2 +- target-i386/helper.c | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 34b6dff686..53cc173eb2 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -527,11 +527,11 @@ type_init(port92_register_types) static void handle_a20_line_change(void *opaque, int irq, int level) { - CPUX86State *cpu = opaque; + X86CPU *cpu = opaque; /* XXX: send to all CPUs ? */ /* XXX: add logic to handle multiple A20 line sources */ - cpu_x86_set_a20(cpu, level); + x86_cpu_set_a20(cpu, level); } int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) @@ -1085,7 +1085,8 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, } } - a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); + a20_line = qemu_allocate_irqs(handle_a20_line_change, + x86_env_get_cpu(first_cpu), 2); i8042 = isa_create_simple(isa_bus, "i8042"); i8042_setup_a20_line(i8042, &a20_line[0]); if (!no_vmport) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 62508dc688..9e6e1a652f 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1011,7 +1011,7 @@ void host_cpuid(uint32_t function, uint32_t count, int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int is_write, int mmu_idx); #define cpu_handle_mmu_fault cpu_x86_handle_mmu_fault -void cpu_x86_set_a20(CPUX86State *env, int a20_state); +void x86_cpu_set_a20(X86CPU *cpu, int a20_state); static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) { diff --git a/target-i386/helper.c b/target-i386/helper.c index 547c25ee9d..bdf83084ff 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -366,8 +366,10 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, /* x86 mmu */ /* XXX: add PGE support */ -void cpu_x86_set_a20(CPUX86State *env, int a20_state) +void x86_cpu_set_a20(X86CPU *cpu, int a20_state) { + CPUX86State *env = &cpu->env; + a20_state = (a20_state != 0); if (a20_state != ((env->a20_mask >> 20) & 1)) { #if defined(DEBUG_MMU) From 77868120cfe93ad7816dfac6546684e5a6c6e256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 05:34:10 +0100 Subject: [PATCH 0836/1634] linux-user: bsd-user: Don't reset X86CPU twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 65dee38052597b6285eb208125369f01b29ba6c1 (target-i386: move cpu_reset and reset callback to cpu.c) the x86 CPU is reset through cpu_init() but was still reset immediately after in linux-user and bsd-user. Clean this up. Similarly in linux-user/syscall.c it is also reset after cpu_copy(). But that's a bug of its own, fixing which poses a semantic change. Signed-off-by: Andreas Färber Reviewed-by: Igor Mammedov --- bsd-user/main.c | 2 +- linux-user/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 1dc033046b..ae24723710 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -917,7 +917,7 @@ int main(int argc, char **argv) fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } -#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) +#if defined(TARGET_SPARC) || defined(TARGET_PPC) cpu_reset(ENV_GET_CPU(env)); #endif thread_env = env; diff --git a/linux-user/main.c b/linux-user/main.c index 0181bc2112..3df8aa2cc5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3540,7 +3540,7 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } -#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) +#if defined(TARGET_SPARC) || defined(TARGET_PPC) cpu_reset(ENV_GET_CPU(env)); #endif From 8e33944f8c648e579a2827ae6f30e4d66ee87f96 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 29 Jan 2013 13:36:02 +0100 Subject: [PATCH 0837/1634] PPC: Unify dcbzl code path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bit that makes a dcbz instruction a dcbzl instruction was declared as reserved in ppc32 ISAs. However, hardware simply ignores the bit, making code valid if it simply invokes dcbzl instead of dcbz even on 750 and G4. Thus, mark the bit as unreserved so that we properly emulate a simple dcbz in case we're running on non-G5s. While at it, also refactor the code to check the 970 special case during runtime. This way we don't need to differenciate between a 970 dcbz and any other dcbz anymore. We also allow for future improvements to add e500mc dcbz handling. Reported-by: Amadeusz Sławiński Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 6 ++---- target-ppc/helper.h | 3 +-- target-ppc/mem_helper.c | 21 ++++++++++++--------- target-ppc/translate.c | 33 ++++++++++++--------------------- target-ppc/translate_init.c | 10 +++++----- 5 files changed, 32 insertions(+), 41 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 953146eeba..8c081dbec5 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1857,10 +1857,8 @@ enum { PPC_CACHE = 0x0000000200000000ULL, /* icbi instruction */ PPC_CACHE_ICBI = 0x0000000400000000ULL, - /* dcbz instruction with fixed cache line size */ + /* dcbz instruction */ PPC_CACHE_DCBZ = 0x0000000800000000ULL, - /* dcbz instruction with tunable cache line size */ - PPC_CACHE_DCBZT = 0x0000001000000000ULL, /* dcba instruction */ PPC_CACHE_DCBA = 0x0000002000000000ULL, /* Freescale cache locking instructions */ @@ -1928,7 +1926,7 @@ enum { | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC \ | PPC_MEM_SYNC | PPC_MEM_EIEIO \ | PPC_CACHE | PPC_CACHE_ICBI \ - | PPC_CACHE_DCBZ | PPC_CACHE_DCBZT \ + | PPC_CACHE_DCBZ \ | PPC_CACHE_DCBA | PPC_CACHE_LOCK \ | PPC_EXTERN | PPC_SEGMENT | PPC_6xx_TLB \ | PPC_74xx_TLB | PPC_40x_TLB | PPC_SEGMENT_64B \ diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 83139d5225..18e039452f 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -25,8 +25,7 @@ DEF_HELPER_3(stmw, void, env, tl, i32) DEF_HELPER_4(lsw, void, env, tl, i32, i32) DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32) DEF_HELPER_4(stsw, void, env, tl, i32, i32) -DEF_HELPER_2(dcbz, void, env, tl) -DEF_HELPER_2(dcbz_970, void, env, tl) +DEF_HELPER_3(dcbz, void, env, tl, i32) DEF_HELPER_2(icbi, void, env, tl) DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index 902b1cd823..ba383c8f11 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -136,18 +136,21 @@ static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size) } } -void helper_dcbz(CPUPPCState *env, target_ulong addr) +void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl) { - do_dcbz(env, addr, env->dcache_line_size); -} + int dcbz_size = env->dcache_line_size; -void helper_dcbz_970(CPUPPCState *env, target_ulong addr) -{ - if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { - do_dcbz(env, addr, 32); - } else { - do_dcbz(env, addr, env->dcache_line_size); +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + if (!is_dcbzl && + (env->excp_model == POWERPC_EXCP_970) && + ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { + dcbz_size = 32; } +#endif + + /* XXX add e500mc support */ + + do_dcbz(env, addr, dcbz_size); } void helper_icbi(CPUPPCState *env, target_ulong addr) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 798b7acfc9..d96d1eddb7 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4118,29 +4118,21 @@ static void gen_dcbtst(DisasContext *ctx) /* dcbz */ static void gen_dcbz(DisasContext *ctx) { - TCGv t0; - gen_set_access_type(ctx, ACCESS_CACHE); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_update_nip(ctx, ctx->nip - 4); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - gen_helper_dcbz(cpu_env, t0); - tcg_temp_free(t0); -} + TCGv tcgv_addr; + TCGv_i32 tcgv_is_dcbzl; + int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0; -static void gen_dcbz_970(DisasContext *ctx) -{ - TCGv t0; gen_set_access_type(ctx, ACCESS_CACHE); /* NIP cannot be restored if the memory exception comes from an helper */ gen_update_nip(ctx, ctx->nip - 4); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - if (ctx->opcode & 0x00200000) - gen_helper_dcbz(cpu_env, t0); - else - gen_helper_dcbz_970(cpu_env, t0); - tcg_temp_free(t0); + tcgv_addr = tcg_temp_new(); + tcgv_is_dcbzl = tcg_const_i32(is_dcbzl); + + gen_addr_reg_index(ctx, tcgv_addr); + gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_is_dcbzl); + + tcg_temp_free(tcgv_addr); + tcg_temp_free_i32(tcgv_is_dcbzl); } /* dst / dstt */ @@ -8648,8 +8640,7 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE), GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE), GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE), GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE), -GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ), -GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT), +GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZ), GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC), GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x02000001, PPC_ALTIVEC), GEN_HANDLER(dss, 0x1F, 0x16, 0x19, 0x019FF801, PPC_ALTIVEC), diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index e143af532a..e2021c4a05 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6298,7 +6298,7 @@ static void init_proc_7457 (CPUPPCState *env) PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ @@ -6394,7 +6394,7 @@ static void init_proc_970 (CPUPPCState *env) PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ @@ -6496,7 +6496,7 @@ static void init_proc_970FX (CPUPPCState *env) PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ @@ -6586,7 +6586,7 @@ static void init_proc_970GX (CPUPPCState *env) PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ @@ -6677,7 +6677,7 @@ static void init_proc_970MP (CPUPPCState *env) PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT | \ + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ PPC_MEM_SYNC | PPC_MEM_EIEIO | \ PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ PPC_64B | PPC_ALTIVEC | \ From cca48a93a9a6c1c95ace89b299d3f9f47adadd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 03:32:01 +0000 Subject: [PATCH 0838/1634] target-ppc: Fix unused variable warning for FLUSH_ALL_TLBS 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 --- target-ppc/mmu_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index 0aee7a9063..f1901334b1 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -2260,8 +2260,9 @@ void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value) void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value) { +#if !defined(FLUSH_ALL_TLBS) target_ulong mask; -#if defined(FLUSH_ALL_TLBS) +#else int do_inval; #endif From 476b6d1619446b9c8f72d7523985ba4fdfeaa405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 03:32:02 +0000 Subject: [PATCH 0839/1634] target-ppc: Fix build for PPC_DEBUG_DISAS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In r5949 / 76db3ba44ee8db671f804755f13b016eefd13288 (target-ppc: memory load/store rework) variable little_endian was replaced with ctx.le_mode. Update the debug code. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index d96d1eddb7..2ac5794add 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9689,7 +9689,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, } LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n", ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), - opc3(ctx.opcode), little_endian ? "little" : "big"); + opc3(ctx.opcode), ctx.le_mode ? "little" : "big"); if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { tcg_gen_debug_insn_start(ctx.nip); } From a6f921b0c398c941bb3e17704ffa546849d243de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 03:32:04 +0000 Subject: [PATCH 0840/1634] target-s390x: Fix debug output (continued) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since its introduction in d5a439645a5a70fed5431318c3bce9dc2caa950f (s390x: helper functions for system emulation) the variable name was raddr. Fix this. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-s390x/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 857c89725c..d693a10be7 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -404,8 +404,8 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, /* check out of RAM access */ if (raddr > (ram_size + virtio_size)) { - DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, - (uint64_t)aaddr, (uint64_t)ram_size); + DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, + (uint64_t)raddr, (uint64_t)ram_size); trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); return 1; } From 07cc7d128111958e1079632129b1633cb2a435ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 03:32:03 +0000 Subject: [PATCH 0841/1634] target-s390x: Fix debug output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 71e470886fb6092504503a5fe41092ace71c096c (target-s390x: fix style) renamed the cpu_s390x_handle_mmu_fault() argument from _vaddr to orig_vaddr. Update the debug output code. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-s390x/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index d693a10be7..e62c93e037 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -387,7 +387,7 @@ int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, int prot; DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n", - __func__, _vaddr, rw, mmu_idx); + __func__, orig_vaddr, rw, mmu_idx); orig_vaddr &= TARGET_PAGE_MASK; vaddr = orig_vaddr; From f94667336ecf6566e090a895a37bc06da435d686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 30 Jan 2013 12:48:24 +0000 Subject: [PATCH 0842/1634] target-s390x: Clean up cpu_inject_*() signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Despite cautioning that S390CPU is needed for upcoming CPUState refactorings, commit 5d69c547d947798cba92d836d06f6e017ba2b19d (s390: I/O interrupt and machine check injection.) added functions cpu_inject_io() and cpu_inject_crw_mchk() with CPUS390XState argument, claiming consistency with cpu_inject_ext(). This complicates making cpu_interrupt() take a CPUState even more and it required to pass &cpu->env from some S390CPU-aware call sites already, creating inconsistency elsewhere. Address that. This also eliminates the need for CPUS390XState in s390_virtio_irq(). Signed-off-by: Andreas Färber Acked-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/s390-virtio-bus.c | 4 +--- target-s390x/cpu.h | 15 ++++++++++----- target-s390x/helper.c | 6 ++++-- target-s390x/interrupt.c | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 32f63b07ea..d4677814ca 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -113,12 +113,10 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size) static void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) { - CPUS390XState *env = &cpu->env; - if (kvm_enabled()) { kvm_s390_virtio_irq(cpu, config_change, token); } else { - cpu_inject_ext(env, VIRTIO_EXT_CODE, config_change, token); + cpu_inject_ext(cpu, VIRTIO_EXT_CODE, config_change, token); } } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 9be4a475a3..41b2d929cc 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -975,9 +975,11 @@ static inline uint64_t time2tod(uint64_t ns) { return (ns << 9) / 125; } -static inline void cpu_inject_ext(CPUS390XState *env, uint32_t code, uint32_t param, +static inline void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, uint64_t param64) { + CPUS390XState *env = &cpu->env; + if (env->ext_index == MAX_EXT_QUEUE - 1) { /* ugh - can't queue anymore. Let's drop. */ return; @@ -994,10 +996,11 @@ static inline void cpu_inject_ext(CPUS390XState *env, uint32_t code, uint32_t pa cpu_interrupt(env, CPU_INTERRUPT_HARD); } -static inline void cpu_inject_io(CPUS390XState *env, uint16_t subchannel_id, +static inline void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, uint16_t subchannel_number, uint32_t io_int_parm, uint32_t io_int_word) { + CPUS390XState *env = &cpu->env; int isc = ffs(io_int_word << 2) - 1; if (env->io_index[isc] == MAX_IO_QUEUE - 1) { @@ -1017,8 +1020,10 @@ static inline void cpu_inject_io(CPUS390XState *env, uint16_t subchannel_id, cpu_interrupt(env, CPU_INTERRUPT_HARD); } -static inline void cpu_inject_crw_mchk(CPUS390XState *env) +static inline void cpu_inject_crw_mchk(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; + if (env->mchk_index == MAX_MCHK_QUEUE - 1) { /* ugh - can't queue anymore. Let's drop. */ return; @@ -1090,7 +1095,7 @@ static inline void s390_io_interrupt(S390CPU *cpu, kvm_s390_io_interrupt(cpu, subchannel_id, subchannel_nr, io_int_parm, io_int_word); } else { - cpu_inject_io(&cpu->env, subchannel_id, subchannel_nr, io_int_parm, + cpu_inject_io(cpu, subchannel_id, subchannel_nr, io_int_parm, io_int_word); } } @@ -1100,7 +1105,7 @@ static inline void s390_crw_mchk(S390CPU *cpu) if (kvm_enabled()) { kvm_s390_crw_mchk(cpu); } else { - cpu_inject_crw_mchk(&cpu->env); + cpu_inject_crw_mchk(cpu); } } diff --git a/target-s390x/helper.c b/target-s390x/helper.c index e62c93e037..a5ce56bdb4 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -737,6 +737,8 @@ static void do_mchk_interrupt(CPUS390XState *env) void do_interrupt(CPUS390XState *env) { + S390CPU *cpu = s390_env_get_cpu(env); + qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, env->psw.addr); @@ -755,12 +757,12 @@ void do_interrupt(CPUS390XState *env) /* code is already in env */ env->exception_index = EXCP_EXT; } else if (env->pending_int & INTERRUPT_TOD) { - cpu_inject_ext(env, 0x1004, 0, 0); + cpu_inject_ext(cpu, 0x1004, 0, 0); env->exception_index = EXCP_EXT; env->pending_int &= ~INTERRUPT_EXT; env->pending_int &= ~INTERRUPT_TOD; } else if (env->pending_int & INTERRUPT_CPUTIMER) { - cpu_inject_ext(env, 0x1005, 0, 0); + cpu_inject_ext(cpu, 0x1005, 0, 0); env->exception_index = EXCP_EXT; env->pending_int &= ~INTERRUPT_EXT; env->pending_int &= ~INTERRUPT_TOD; diff --git a/target-s390x/interrupt.c b/target-s390x/interrupt.c index e51519dbd7..6d6580de3a 100644 --- a/target-s390x/interrupt.c +++ b/target-s390x/interrupt.c @@ -24,7 +24,7 @@ void s390_sclp_extint(uint32_t parm) #endif } else { env->psw.addr += 4; - cpu_inject_ext(env, EXT_SERVICE, parm, 0); + cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); } } #endif From 49e158785fa86f04e2d4027dd19719d8b79a4421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 30 Jan 2013 12:48:25 +0000 Subject: [PATCH 0843/1634] target-s390x: Pass S390CPU to s390_{add, del}_running_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares for moving the halted field to CPUState. Most call sites can already supply S390CPU, for some env becomes unused. Signed-off-by: Andreas Färber Acked-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/ipl.c | 6 ++++-- hw/s390x/s390-virtio.c | 8 ++++++-- target-s390x/cpu.c | 2 +- target-s390x/cpu.h | 8 ++++---- target-s390x/helper.c | 5 +++-- target-s390x/kvm.c | 13 +++++-------- 6 files changed, 23 insertions(+), 19 deletions(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 86e84153ad..206d552e16 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -58,10 +58,12 @@ typedef struct S390IPLState { static void s390_ipl_cpu(uint64_t pswaddr) { - CPUS390XState *env = &S390_CPU(qemu_get_cpu(0))->env; + S390CPU *cpu = S390_CPU(qemu_get_cpu(0)); + CPUS390XState *env = &cpu->env; + env->psw.addr = pswaddr; env->psw.mask = IPL_PSW_MASK; - s390_add_running_cpu(env); + s390_add_running_cpu(cpu); } static int s390_ipl_init(SysBusDevice *dev) diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index 2a1d9ac2da..e25c330320 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -130,8 +130,10 @@ static void s390_virtio_register_hcalls(void) */ static unsigned s390_running_cpus; -void s390_add_running_cpu(CPUS390XState *env) +void s390_add_running_cpu(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; + if (env->halted) { s390_running_cpus++; env->halted = 0; @@ -139,8 +141,10 @@ void s390_add_running_cpu(CPUS390XState *env) } } -unsigned s390_del_running_cpu(CPUS390XState *env) +unsigned s390_del_running_cpu(S390CPU *cpu) { + CPUS390XState *env = &cpu->env; + if (env->halted == 0) { assert(s390_running_cpus >= 1); s390_running_cpus--; diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 0b68db8305..c25009171d 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -70,7 +70,7 @@ static void s390_cpu_reset(CPUState *s) log_cpu_state(env, 0); } - s390_del_running_cpu(env); + s390_del_running_cpu(cpu); scc->parent_reset(s); diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 41b2d929cc..01e59b99f0 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -375,8 +375,8 @@ static inline void kvm_s390_interrupt_internal(S390CPU *cpu, int type, } #endif S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); -void s390_add_running_cpu(CPUS390XState *env); -unsigned s390_del_running_cpu(CPUS390XState *env); +void s390_add_running_cpu(S390CPU *cpu); +unsigned s390_del_running_cpu(S390CPU *cpu); /* service interrupts are floating therefore we must not pass an cpustate */ void s390_sclp_extint(uint32_t parm); @@ -385,11 +385,11 @@ void s390_sclp_extint(uint32_t parm); extern const hwaddr virtio_size; #else -static inline void s390_add_running_cpu(CPUS390XState *env) +static inline void s390_add_running_cpu(S390CPU *cpu) { } -static inline unsigned s390_del_running_cpu(CPUS390XState *env) +static inline unsigned s390_del_running_cpu(S390CPU *cpu) { return 0; } diff --git a/target-s390x/helper.c b/target-s390x/helper.c index a5ce56bdb4..3180b90ed8 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -441,8 +441,9 @@ hwaddr cpu_get_phys_page_debug(CPUS390XState *env, void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) { if (mask & PSW_MASK_WAIT) { + S390CPU *cpu = s390_env_get_cpu(env); if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) { - if (s390_del_running_cpu(env) == 0) { + if (s390_del_running_cpu(cpu) == 0) { #ifndef CONFIG_USER_ONLY qemu_system_shutdown_request(); #endif @@ -742,7 +743,7 @@ void do_interrupt(CPUS390XState *env) qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, env->psw.addr); - s390_add_running_cpu(env); + s390_add_running_cpu(cpu); /* handle machine checks */ if ((env->psw.mask & PSW_MASK_MCHECK) && (env->exception_index == -1)) { diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 2c24182001..3929771182 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -570,12 +570,10 @@ static int handle_diag(CPUS390XState *env, struct kvm_run *run, int ipb_code) static int s390_cpu_restart(S390CPU *cpu) { - CPUS390XState *env = &cpu->env; - kvm_s390_interrupt(cpu, KVM_S390_RESTART, 0); - s390_add_running_cpu(env); + s390_add_running_cpu(cpu); qemu_cpu_kick(CPU(cpu)); - dprintf("DONE: SIGP cpu restart: %p\n", env); + dprintf("DONE: SIGP cpu restart: %p\n", &cpu->env); return 0; } @@ -591,7 +589,7 @@ static int s390_cpu_initial_reset(S390CPU *cpu) CPUS390XState *env = &cpu->env; int i; - s390_del_running_cpu(env); + s390_del_running_cpu(cpu); if (kvm_vcpu_ioctl(CPU(cpu), KVM_S390_INITIAL_RESET, NULL) < 0) { perror("cannot init reset vcpu"); } @@ -701,7 +699,6 @@ static bool is_special_wait_psw(CPUState *cs) static int handle_intercept(S390CPU *cpu) { - CPUS390XState *env = &cpu->env; CPUState *cs = CPU(cpu); struct kvm_run *run = cs->kvm_run; int icpt_code = run->s390_sieic.icptcode; @@ -714,14 +711,14 @@ static int handle_intercept(S390CPU *cpu) r = handle_instruction(cpu, run); break; case ICPT_WAITPSW: - if (s390_del_running_cpu(env) == 0 && + if (s390_del_running_cpu(cpu) == 0 && is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } r = EXCP_HALTED; break; case ICPT_CPU_STOP: - if (s390_del_running_cpu(env) == 0) { + if (s390_del_running_cpu(cpu) == 0) { qemu_system_shutdown_request(); } r = EXCP_HALTED; From ba2e28e8a20cf78ea4f64fbf84055f969013f9f7 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Thu, 31 Jan 2013 09:12:15 +0200 Subject: [PATCH 0844/1634] Move XBZRLE encoding code to a separate file to allow testing Signed-off-by: Orit Wasserman Reviewed-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Eric Blake --- Makefile.objs | 2 +- savevm.c | 159 ---------------------------------------------- xbzrle.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 160 deletions(-) create mode 100644 xbzrle.c diff --git a/Makefile.objs b/Makefile.objs index 68eb0cef1a..21e9c911f5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -59,7 +59,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/ common-obj-y += migration.o migration-tcp.o common-obj-y += qemu-char.o #aio.o common-obj-y += block-migration.o -common-obj-y += page_cache.o +common-obj-y += page_cache.o xbzrle.o common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o diff --git a/savevm.c b/savevm.c index 304d1effe5..b947e6a303 100644 --- a/savevm.c +++ b/savevm.c @@ -2388,162 +2388,3 @@ void vmstate_register_ram_global(MemoryRegion *mr) { vmstate_register_ram(mr, NULL); } - -/* - page = zrun nzrun - | zrun nzrun page - - zrun = length - - nzrun = length byte... - - length = uleb128 encoded integer - */ -int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen, - uint8_t *dst, int dlen) -{ - uint32_t zrun_len = 0, nzrun_len = 0; - int d = 0, i = 0; - long res, xor; - uint8_t *nzrun_start = NULL; - - g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) % - sizeof(long))); - - while (i < slen) { - /* overflow */ - if (d + 2 > dlen) { - return -1; - } - - /* not aligned to sizeof(long) */ - res = (slen - i) % sizeof(long); - while (res && old_buf[i] == new_buf[i]) { - zrun_len++; - i++; - res--; - } - - /* word at a time for speed */ - if (!res) { - while (i < slen && - (*(long *)(old_buf + i)) == (*(long *)(new_buf + i))) { - i += sizeof(long); - zrun_len += sizeof(long); - } - - /* go over the rest */ - while (i < slen && old_buf[i] == new_buf[i]) { - zrun_len++; - i++; - } - } - - /* buffer unchanged */ - if (zrun_len == slen) { - return 0; - } - - /* skip last zero run */ - if (i == slen) { - return d; - } - - d += uleb128_encode_small(dst + d, zrun_len); - - zrun_len = 0; - nzrun_start = new_buf + i; - - /* overflow */ - if (d + 2 > dlen) { - return -1; - } - /* not aligned to sizeof(long) */ - res = (slen - i) % sizeof(long); - while (res && old_buf[i] != new_buf[i]) { - i++; - nzrun_len++; - res--; - } - - /* word at a time for speed, use of 32-bit long okay */ - if (!res) { - /* truncation to 32-bit long okay */ - long mask = (long)0x0101010101010101ULL; - while (i < slen) { - xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i); - if ((xor - mask) & ~xor & (mask << 7)) { - /* found the end of an nzrun within the current long */ - while (old_buf[i] != new_buf[i]) { - nzrun_len++; - i++; - } - break; - } else { - i += sizeof(long); - nzrun_len += sizeof(long); - } - } - } - - d += uleb128_encode_small(dst + d, nzrun_len); - /* overflow */ - if (d + nzrun_len > dlen) { - return -1; - } - memcpy(dst + d, nzrun_start, nzrun_len); - d += nzrun_len; - nzrun_len = 0; - } - - return d; -} - -int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen) -{ - int i = 0, d = 0; - int ret; - uint32_t count = 0; - - while (i < slen) { - - /* zrun */ - if ((slen - i) < 2) { - return -1; - } - - ret = uleb128_decode_small(src + i, &count); - if (ret < 0 || (i && !count)) { - return -1; - } - i += ret; - d += count; - - /* overflow */ - if (d > dlen) { - return -1; - } - - /* nzrun */ - if ((slen - i) < 2) { - return -1; - } - - ret = uleb128_decode_small(src + i, &count); - if (ret < 0 || !count) { - return -1; - } - i += ret; - - /* overflow */ - if (d + count > dlen || i + count > slen) { - return -1; - } - - memcpy(dst + d, src + i, count); - d += count; - i += count; - } - - return d; -} diff --git a/xbzrle.c b/xbzrle.c new file mode 100644 index 0000000000..fbcb35d0e3 --- /dev/null +++ b/xbzrle.c @@ -0,0 +1,173 @@ +/* + * Xor Based Zero Run Length Encoding + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Orit Wasserman + * + * 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" +#include "include/migration/migration.h" + +/* + page = zrun nzrun + | zrun nzrun page + + zrun = length + + nzrun = length byte... + + length = uleb128 encoded integer + */ +int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen, + uint8_t *dst, int dlen) +{ + uint32_t zrun_len = 0, nzrun_len = 0; + int d = 0, i = 0; + long res, xor; + uint8_t *nzrun_start = NULL; + + g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) % + sizeof(long))); + + while (i < slen) { + /* overflow */ + if (d + 2 > dlen) { + return -1; + } + + /* not aligned to sizeof(long) */ + res = (slen - i) % sizeof(long); + while (res && old_buf[i] == new_buf[i]) { + zrun_len++; + i++; + res--; + } + + /* word at a time for speed */ + if (!res) { + while (i < slen && + (*(long *)(old_buf + i)) == (*(long *)(new_buf + i))) { + i += sizeof(long); + zrun_len += sizeof(long); + } + + /* go over the rest */ + while (i < slen && old_buf[i] == new_buf[i]) { + zrun_len++; + i++; + } + } + + /* buffer unchanged */ + if (zrun_len == slen) { + return 0; + } + + /* skip last zero run */ + if (i == slen) { + return d; + } + + d += uleb128_encode_small(dst + d, zrun_len); + + zrun_len = 0; + nzrun_start = new_buf + i; + + /* overflow */ + if (d + 2 > dlen) { + return -1; + } + /* not aligned to sizeof(long) */ + res = (slen - i) % sizeof(long); + while (res && old_buf[i] != new_buf[i]) { + i++; + nzrun_len++; + res--; + } + + /* word at a time for speed, use of 32-bit long okay */ + if (!res) { + /* truncation to 32-bit long okay */ + long mask = (long)0x0101010101010101ULL; + while (i < slen) { + xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i); + if ((xor - mask) & ~xor & (mask << 7)) { + /* found the end of an nzrun within the current long */ + while (old_buf[i] != new_buf[i]) { + nzrun_len++; + i++; + } + break; + } else { + i += sizeof(long); + nzrun_len += sizeof(long); + } + } + } + + d += uleb128_encode_small(dst + d, nzrun_len); + /* overflow */ + if (d + nzrun_len > dlen) { + return -1; + } + memcpy(dst + d, nzrun_start, nzrun_len); + d += nzrun_len; + nzrun_len = 0; + } + + return d; +} + +int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen) +{ + int i = 0, d = 0; + int ret; + uint32_t count = 0; + + while (i < slen) { + + /* zrun */ + if ((slen - i) < 2) { + return -1; + } + + ret = uleb128_decode_small(src + i, &count); + if (ret < 0 || (i && !count)) { + return -1; + } + i += ret; + d += count; + + /* overflow */ + if (d > dlen) { + return -1; + } + + /* nzrun */ + if ((slen - i) < 2) { + return -1; + } + + ret = uleb128_decode_small(src + i, &count); + if (ret < 0 || !count) { + return -1; + } + i += ret; + + /* overflow */ + if (d + count > dlen || i + count > slen) { + return -1; + } + + memcpy(dst + d, src + i, count); + d += count; + i += count; + } + + return d; +} From 21e3cd295b52b3ac1528262b8639f2e896cd9467 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Thu, 31 Jan 2013 09:12:16 +0200 Subject: [PATCH 0845/1634] Add XBZRLE testing Signed-off-by: Orit Wasserman Reviewed-by: Paolo Bonzini Signed-off-by: Juan Quintela Reviewed-by: Eric Blake --- tests/Makefile | 3 + tests/test-xbzrle.c | 196 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 tests/test-xbzrle.c diff --git a/tests/Makefile b/tests/Makefile index c681cebd18..abe9c2a6c4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -50,6 +50,8 @@ check-unit-y += tests/test-hbitmap$(EXESUF) check-unit-y += tests/test-x86-cpuid$(EXESUF) # all code tested by test-x86-cpuid is inside topology.h gcov-files-test-x86-cpuid-y = +check-unit-y += tests/test-xbzrle$(EXESUF) +gcov-files-test-xbzrle-y = xbzrle.c check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -98,6 +100,7 @@ tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemu tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o +tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o xbzrle.o page_cache.o libqemuutil.a tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py diff --git a/tests/test-xbzrle.c b/tests/test-xbzrle.c new file mode 100644 index 0000000000..db93b0a3d2 --- /dev/null +++ b/tests/test-xbzrle.c @@ -0,0 +1,196 @@ +/* + * Xor Based Zero Run Length Encoding unit tests. + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates + * + * Authors: + * Orit Wasserman + * + * 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 +#include +#include +#include +#include +#include +#include +#include "qemu-common.h" +#include "include/migration/migration.h" + +#define PAGE_SIZE 4096 + +static void test_uleb(void) +{ + uint32_t i, val; + uint8_t buf[2]; + int encode_ret, decode_ret; + + for (i = 0; i <= 0x3fff; i++) { + encode_ret = uleb128_encode_small(&buf[0], i); + decode_ret = uleb128_decode_small(&buf[0], &val); + g_assert(encode_ret == decode_ret); + g_assert(i == val); + } + + /* decode invalid value */ + buf[0] = 0x80; + buf[1] = 0x80; + + decode_ret = uleb128_decode_small(&buf[0], &val); + g_assert(decode_ret == -1); + g_assert(val == 0); +} + +static void test_encode_decode_zero(void) +{ + uint8_t *buffer = g_malloc0(PAGE_SIZE); + uint8_t *compressed = g_malloc0(PAGE_SIZE); + int i = 0; + int dlen = 0; + int diff_len = g_test_rand_int_range(0, PAGE_SIZE - 1006); + + for (i = diff_len; i > 0; i--) { + buffer[1000 + i] = i; + } + + buffer[1000 + diff_len + 3] = 103; + buffer[1000 + diff_len + 5] = 105; + + /* encode zero page */ + dlen = xbzrle_encode_buffer(buffer, buffer, PAGE_SIZE, compressed, + PAGE_SIZE); + g_assert(dlen == 0); + + g_free(buffer); + g_free(compressed); +} + +static void test_encode_decode_unchanged(void) +{ + uint8_t *compressed = g_malloc0(PAGE_SIZE); + uint8_t *test = g_malloc0(PAGE_SIZE); + int i = 0; + int dlen = 0; + int diff_len = g_test_rand_int_range(0, PAGE_SIZE - 1006); + + for (i = diff_len; i > 0; i--) { + test[1000 + i] = i + 4; + } + + test[1000 + diff_len + 3] = 107; + test[1000 + diff_len + 5] = 109; + + /* test unchanged buffer */ + dlen = xbzrle_encode_buffer(test, test, PAGE_SIZE, compressed, + PAGE_SIZE); + g_assert(dlen == 0); + + g_free(test); + g_free(compressed); +} + +static void test_encode_decode_1_byte(void) +{ + uint8_t *buffer = g_malloc0(PAGE_SIZE); + uint8_t *test = g_malloc0(PAGE_SIZE); + uint8_t *compressed = g_malloc(PAGE_SIZE); + int dlen = 0, rc = 0; + uint8_t buf[2]; + + test[PAGE_SIZE - 1] = 1; + + dlen = xbzrle_encode_buffer(buffer, test, PAGE_SIZE, compressed, + PAGE_SIZE); + g_assert(dlen == (uleb128_encode_small(&buf[0], 4095) + 2)); + + rc = xbzrle_decode_buffer(compressed, dlen, buffer, PAGE_SIZE); + g_assert(rc == PAGE_SIZE); + g_assert(memcmp(test, buffer, PAGE_SIZE) == 0); + + g_free(buffer); + g_free(compressed); + g_free(test); +} + +static void test_encode_decode_overflow(void) +{ + uint8_t *compressed = g_malloc0(PAGE_SIZE); + uint8_t *test = g_malloc0(PAGE_SIZE); + uint8_t *buffer = g_malloc0(PAGE_SIZE); + int i = 0, rc = 0; + + for (i = 0; i < PAGE_SIZE / 2 - 1; i++) { + test[i * 2] = 1; + } + + /* encode overflow */ + rc = xbzrle_encode_buffer(buffer, test, PAGE_SIZE, compressed, + PAGE_SIZE); + g_assert(rc == -1); + + g_free(buffer); + g_free(compressed); + g_free(test); +} + +static void encode_decode_range(void) +{ + uint8_t *buffer = g_malloc0(PAGE_SIZE); + uint8_t *compressed = g_malloc(PAGE_SIZE); + uint8_t *test = g_malloc0(PAGE_SIZE); + int i = 0, rc = 0; + int dlen = 0; + + int diff_len = g_test_rand_int_range(0, PAGE_SIZE - 1006); + + for (i = diff_len; i > 0; i--) { + buffer[1000 + i] = i; + test[1000 + i] = i + 4; + } + + buffer[1000 + diff_len + 3] = 103; + test[1000 + diff_len + 3] = 107; + + buffer[1000 + diff_len + 5] = 105; + test[1000 + diff_len + 5] = 109; + + /* test encode/decode */ + dlen = xbzrle_encode_buffer(test, buffer, PAGE_SIZE, compressed, + PAGE_SIZE); + + rc = xbzrle_decode_buffer(compressed, dlen, test, PAGE_SIZE); + g_assert(rc < PAGE_SIZE); + g_assert(memcmp(test, buffer, PAGE_SIZE) == 0); + + g_free(buffer); + g_free(compressed); + g_free(test); +} + +static void test_encode_decode(void) +{ + int i; + + for (i = 0; i < 10000; i++) { + encode_decode_range(); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_rand_int(); + g_test_add_func("/xbzrle/uleb", test_uleb); + g_test_add_func("/xbzrle/encode_decode_zero", test_encode_decode_zero); + g_test_add_func("/xbzrle/encode_decode_unchanged", + test_encode_decode_unchanged); + g_test_add_func("/xbzrle/encode_decode_1_byte", test_encode_decode_1_byte); + g_test_add_func("/xbzrle/encode_decode_overflow", + test_encode_decode_overflow); + g_test_add_func("/xbzrle/encode_decode", test_encode_decode); + + return g_test_run(); +} From dbca1b3773185af0413e750f26d04b0110cff107 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Thu, 31 Jan 2013 09:12:17 +0200 Subject: [PATCH 0846/1634] Fix example for query-migrate-capabilities Signed-off-by: Orit Wasserman Reviewed-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Juan Quintela --- qmp-commands.hx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qmp-commands.hx b/qmp-commands.hx index f90efe590c..bbb21f3583 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2601,10 +2601,8 @@ Arguments: Example: -> { "execute": "query-migrate-capabilities" } -<- { "return": { - "capabilities" : [ { "capability" : "xbzrle", "state" : false } ] - } - } +<- { "return": [ { "state": false, "capability": "xbzrle" } ] } + EQMP { From 1b1fdfeae68c61786a474b02601fbba6040fc5a4 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Thu, 31 Jan 2013 09:12:18 +0200 Subject: [PATCH 0847/1634] Allow XBZRLE decoding without enabling the capability Before this fix we couldn't load a guest from XBZRLE compressed file. For example: The user activated the XBZRLE capability The user run migrate -d "exec:gzip -c > vm.gz" The user won't be able to load vm.gz and get an error. Signed-off-by: Orit Wasserman Reviewed-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Juan Quintela --- arch_init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch_init.c b/arch_init.c index dada6ded1a..8da868b988 100644 --- a/arch_init.c +++ b/arch_init.c @@ -851,9 +851,6 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) qemu_get_buffer(f, host, TARGET_PAGE_SIZE); } else if (flags & RAM_SAVE_FLAG_XBZRLE) { - if (!migrate_use_xbzrle()) { - return -EINVAL; - } void *host = host_from_stream_offset(f, addr, flags); if (!host) { return -EINVAL; From a31ca017aaf9074c1bb636b3ddaceb40f994375f Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Thu, 31 Jan 2013 09:12:19 +0200 Subject: [PATCH 0848/1634] Fix error message in migrate_set_capability HMP command Signed-off-by: Orit Wasserman Reviewed-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Juan Quintela --- hmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hmp.c b/hmp.c index 249b89b7e3..1689e6f1fd 100644 --- a/hmp.c +++ b/hmp.c @@ -892,7 +892,7 @@ void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict) qapi_free_MigrationCapabilityStatusList(caps); if (err) { - monitor_printf(mon, "migrate_set_parameter: %s\n", + monitor_printf(mon, "migrate_set_capability: %s\n", error_get_pretty(err)); error_free(err); } From b93d6d2468ba81b9e373066004f2084efbdcc9d6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 23 Jan 2013 16:52:49 +0100 Subject: [PATCH 0849/1634] qemu-iotests: Add regression test for b7ab0fea It turned out that the change in b7ab0fea was actually a real qcow2 corruption fix. This is a reproducer for the bug. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/047 | 75 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/047.out | 22 +++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 98 insertions(+) create mode 100755 tests/qemu-iotests/047 create mode 100644 tests/qemu-iotests/047.out diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047 new file mode 100755 index 0000000000..0cf36b434f --- /dev/null +++ b/tests/qemu-iotests/047 @@ -0,0 +1,75 @@ +#!/bin/bash +# +# Regression test for commit b7ab0fea (which was a corruption fix, +# despite the commit message claiming otherwise) +# +# Copyright (C) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto generic +_supported_os Linux + +size=128M + +_make_test_img $size + +function qemu_io_cmds() +{ +cat < wrote 327680/327680 bytes at offset 0 +320 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> wrote 131072/131072 bytes at offset 327680 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> wrote 131072/131072 bytes at offset 1048576 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> wrote 131072/131072 bytes at offset 458752 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> discard 131072/131072 bytes at offset 327680 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> qemu-io> qemu-io> wrote 491520/491520 bytes at offset 0 +480 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> qemu-io> qemu-io> read 491520/491520 bytes at offset 0 +480 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> read 98304/98304 bytes at offset 491520 +96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> read 131072/131072 bytes at offset 1048576 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> No errors were found on the image. +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index a0307de06b..1bbd2bf929 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -53,3 +53,4 @@ 044 rw auto 045 rw auto 046 rw auto aio +047 rw auto From 63ba17d39f1a8d262b31ea6a07dd3eb45d5a41e2 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 24 Jan 2013 10:02:08 -0800 Subject: [PATCH 0850/1634] block: Fix is_allocated_above with resized files In an image chain, if the base image is smaller than the current image, we need to make sure to use the current images count of unallocated blocks once we get to the end of the base image. Without this change the code will return 0 blocks when it gets to the end of the base image and mirror_run will fail its assertion. Signed-off-by: Vishvananda Ishaya Signed-off-by: Stefan Hajnoczi --- block.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index ba67c0def2..50dab8e595 100644 --- a/block.c +++ b/block.c @@ -2800,7 +2800,9 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, * * [sector_num+x, nr_sectors] allocated. */ - if (n > pnum_inter) { + if (n > pnum_inter && + (intermediate == top || + sector_num + pnum_inter < intermediate->total_sectors)) { n = pnum_inter; } From a04eca108e5efe8a09fe82f7079fcd1568ffc8d7 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 25 Jan 2013 10:57:20 -0800 Subject: [PATCH 0851/1634] block: Adds mirroring tests for resized images This test verifies two mirroring issues are fixed with resized images: * sync='top' creates an image that is the proper size * sync='full' doesn't cause an assertion failure and crash qemu Reviewed-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/041 | 48 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/041.out | 4 ++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 index b040820c51..720eeff921 100755 --- a/tests/qemu-iotests/041 +++ b/tests/qemu-iotests/041 @@ -344,6 +344,54 @@ class TestMirrorNoBacking(ImageMirroringTestCase): self.assertTrue(self.compare_images(test_img, target_img), 'target image does not match source after mirroring') +class TestMirrorResized(ImageMirroringTestCase): + backing_len = 1 * 1024 * 1024 # MB + image_len = 2 * 1024 * 1024 # MB + + def setUp(self): + self.create_image(backing_img, TestMirrorResized.backing_len) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('resize', test_img, '2M') + self.vm = iotests.VM().add_drive(test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + os.remove(backing_img) + try: + os.remove(target_img) + except OSError: + pass + + def test_complete_top(self): + self.assert_no_active_mirrors() + + result = self.vm.qmp('drive-mirror', device='drive0', sync='top', + target=target_img) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait() + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/inserted/file', target_img) + self.vm.shutdown() + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + + def test_complete_full(self): + self.assert_no_active_mirrors() + + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + target=target_img) + self.assert_qmp(result, 'return', {}) + + self.complete_and_wait() + result = self.vm.qmp('query-block') + self.assert_qmp(result, 'return[0]/inserted/file', target_img) + self.vm.shutdown() + self.assertTrue(self.compare_images(test_img, target_img), + 'target image does not match source after mirroring') + class TestReadErrors(ImageMirroringTestCase): image_len = 2 * 1024 * 1024 # MB diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out index 84bfd63fba..42314e9c00 100644 --- a/tests/qemu-iotests/041.out +++ b/tests/qemu-iotests/041.out @@ -1,5 +1,5 @@ -...................... +........................ ---------------------------------------------------------------------- -Ran 22 tests +Ran 24 tests OK From 7f2039f61113f11be92112adf31b6052e04d986f Mon Sep 17 00:00:00 2001 From: Othmar Pasteka Date: Wed, 30 Jan 2013 00:26:52 +0100 Subject: [PATCH 0852/1634] vmdk: Allow selecting SCSI adapter in image creation Introduce a new option "adapter_type" when converting to vmdk images. It can be one of the following: ide (default), buslogic, lsilogic or legacyESX (according to the vmdk spec from vmware). In case of a non-ide adapter, heads is set to 255 instead of the 16. The latter is used for "ide". Also see LP#545089 Signed-off-by: Othmar Pasteka Signed-off-by: Stefan Hajnoczi --- block/vmdk.c | 31 ++++++++++++++++++++++++++++--- include/block/block_int.h | 1 + 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 8333afb5e3..a8cb5c972d 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1442,6 +1442,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) int fd, idx = 0; char desc[BUF_SIZE]; int64_t total_size = 0, filesize; + const char *adapter_type = NULL; const char *backing_file = NULL; const char *fmt = NULL; int flags = 0; @@ -1453,6 +1454,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) const char *desc_extent_line; char parent_desc_line[BUF_SIZE] = ""; uint32_t parent_cid = 0xffffffff; + uint32_t number_heads = 16; const char desc_template[] = "# Disk DescriptorFile\n" "version=1\n" @@ -1469,9 +1471,9 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) "\n" "ddb.virtualHWVersion = \"%d\"\n" "ddb.geometry.cylinders = \"%" PRId64 "\"\n" - "ddb.geometry.heads = \"16\"\n" + "ddb.geometry.heads = \"%d\"\n" "ddb.geometry.sectors = \"63\"\n" - "ddb.adapterType = \"ide\"\n"; + "ddb.adapterType = \"%s\"\n"; if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) { return -EINVAL; @@ -1480,6 +1482,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) while (options && options->name) { if (!strcmp(options->name, BLOCK_OPT_SIZE)) { total_size = options->value.n; + } else if (!strcmp(options->name, BLOCK_OPT_ADAPTER_TYPE)) { + adapter_type = options->value.s; } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { backing_file = options->value.s; } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) { @@ -1489,6 +1493,20 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) } options++; } + if (!adapter_type) { + adapter_type = "ide"; + } else if (strcmp(adapter_type, "ide") && + strcmp(adapter_type, "buslogic") && + strcmp(adapter_type, "lsilogic") && + strcmp(adapter_type, "legacyESX")) { + fprintf(stderr, "VMDK: Unknown adapter type: '%s'.\n", adapter_type); + return -EINVAL; + } + if (strcmp(adapter_type, "ide") != 0) { + /* that's the number of heads with which vmware operates when + creating, exporting, etc. vmdk files with a non-ide adapter type */ + number_heads = 255; + } if (!fmt) { /* Default format to monolithicSparse */ fmt = "monolithicSparse"; @@ -1576,7 +1594,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) parent_desc_line, ext_desc_lines, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), - total_size / (int64_t)(63 * 16 * 512)); + total_size / (int64_t)(63 * number_heads * 512), number_heads, + adapter_type); if (split || flat) { fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, @@ -1660,6 +1679,12 @@ static QEMUOptionParameter vmdk_create_options[] = { .type = OPT_SIZE, .help = "Virtual disk size" }, + { + .name = BLOCK_OPT_ADAPTER_TYPE, + .type = OPT_STRING, + .help = "Virtual adapter type, can be one of " + "ide (default), lsilogic, buslogic or legacyESX" + }, { .name = BLOCK_OPT_BACKING_FILE, .type = OPT_STRING, diff --git a/include/block/block_int.h b/include/block/block_int.h index f7279b978a..eaad53e426 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -56,6 +56,7 @@ #define BLOCK_OPT_SUBFMT "subformat" #define BLOCK_OPT_COMPAT_LEVEL "compat" #define BLOCK_OPT_LAZY_REFCOUNTS "lazy_refcounts" +#define BLOCK_OPT_ADAPTER_TYPE "adapter_type" typedef struct BdrvTrackedRequest BdrvTrackedRequest; From 6f74c260b45a8f94007929c800d95c2303f1a7ec Mon Sep 17 00:00:00 2001 From: Liu Yuan Date: Tue, 29 Jan 2013 17:14:16 +0800 Subject: [PATCH 0853/1634] sheepdog: pass vdi_id to sheep daemon for sd_close() Sheep daemon needs vdi_id to identify which vdi is closed to release resources such as object cache. Cc: MORITA Kazutaka Cc: Kevin Wolf Cc: Stefan Hajnoczi Signed-off-by: Liu Yuan Reviewed-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 3e49bb83bb..d466b232d7 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -145,7 +145,7 @@ typedef struct SheepdogVdiReq { uint32_t id; uint32_t data_length; uint64_t vdi_size; - uint32_t base_vdi_id; + uint32_t vdi_id; uint32_t copies; uint32_t snapid; uint32_t pad[3]; @@ -1201,7 +1201,7 @@ static int do_sd_create(char *filename, int64_t vdi_size, memset(&hdr, 0, sizeof(hdr)); hdr.opcode = SD_OP_NEW_VDI; - hdr.base_vdi_id = base_vid; + hdr.vdi_id = base_vid; wlen = SD_MAX_VDI_LEN; @@ -1384,6 +1384,7 @@ static void sd_close(BlockDriverState *bs) memset(&hdr, 0, sizeof(hdr)); hdr.opcode = SD_OP_RELEASE_VDI; + hdr.vdi_id = s->inode.vdi_id; wlen = strlen(s->name) + 1; hdr.data_length = wlen; hdr.flags = SD_FLAG_CMD_WRITE; From 5b7d7dfd198f06ec5edd0c857291c5035c5c060f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 25 Jan 2013 17:07:27 +0100 Subject: [PATCH 0854/1634] bochs: Fix bdrv_open() error handling Return -errno instead of -1 on errors. While touching the code, fix a memory leak. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/bochs.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/block/bochs.c b/block/bochs.c index 37375834e9..a6eb33da42 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -114,11 +114,13 @@ static int bochs_open(BlockDriverState *bs, int flags) int i; struct bochs_header bochs; struct bochs_header_v1 header_v1; + int ret; bs->read_only = 1; // no write support yet - if (bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)) != sizeof(bochs)) { - goto fail; + ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs)); + if (ret < 0) { + return ret; } if (strcmp(bochs.magic, HEADER_MAGIC) || @@ -138,9 +140,13 @@ static int bochs_open(BlockDriverState *bs, int flags) s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog); s->catalog_bitmap = g_malloc(s->catalog_size * 4); - if (bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap, - s->catalog_size * 4) != s->catalog_size * 4) - goto fail; + + ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap, + s->catalog_size * 4); + if (ret < 0) { + goto fail; + } + for (i = 0; i < s->catalog_size; i++) le32_to_cpus(&s->catalog_bitmap[i]); @@ -153,8 +159,10 @@ static int bochs_open(BlockDriverState *bs, int flags) qemu_co_mutex_init(&s->lock); return 0; - fail: - return -1; + +fail: + g_free(s->catalog_bitmap); + return ret; } static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) From 1a60657f5729bac57e70802eb17e67ad793400fd Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 25 Jan 2013 17:07:28 +0100 Subject: [PATCH 0855/1634] cloop: Fix bdrv_open() error handling Return -errno instead of -1 on errors. While touching the code, fix a memory leak. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/cloop.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/block/cloop.c b/block/cloop.c index 5a0d0d805f..8fe13e92a1 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -57,27 +57,32 @@ static int cloop_open(BlockDriverState *bs, int flags) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size, max_compressed_block_size = 1, i; + int ret; bs->read_only = 1; /* read header */ - if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) { - goto cloop_close; + ret = bdrv_pread(bs->file, 128, &s->block_size, 4); + if (ret < 0) { + return ret; } s->block_size = be32_to_cpu(s->block_size); - if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) { - goto cloop_close; + ret = bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4); + if (ret < 0) { + return ret; } s->n_blocks = be32_to_cpu(s->n_blocks); /* read offsets */ offsets_size = s->n_blocks * sizeof(uint64_t); s->offsets = g_malloc(offsets_size); - if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) < - offsets_size) { - goto cloop_close; + + ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size); + if (ret < 0) { + goto fail; } + for(i=0;in_blocks;i++) { s->offsets[i] = be64_to_cpu(s->offsets[i]); if (i > 0) { @@ -92,7 +97,8 @@ static int cloop_open(BlockDriverState *bs, int flags) s->compressed_block = g_malloc(max_compressed_block_size + 1); s->uncompressed_block = g_malloc(s->block_size); if (inflateInit(&s->zstream) != Z_OK) { - goto cloop_close; + ret = -EINVAL; + goto fail; } s->current_block = s->n_blocks; @@ -101,8 +107,11 @@ static int cloop_open(BlockDriverState *bs, int flags) qemu_co_mutex_init(&s->lock); return 0; -cloop_close: - return -1; +fail: + g_free(s->offsets); + g_free(s->compressed_block); + g_free(s->uncompressed_block); + return ret; } static inline int cloop_read_block(BlockDriverState *bs, int block_num) From 59294e465953ffb07d42dc61c827bb98cc0ca423 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 25 Jan 2013 17:07:29 +0100 Subject: [PATCH 0856/1634] vpc: Fix bdrv_open() error handling Return -errno instead of -1 on errors. While touching the code, fix a memory leak. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/vpc.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index 7948609e50..82229ef5a0 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -163,24 +163,33 @@ static int vpc_open(BlockDriverState *bs, int flags) struct vhd_dyndisk_header* dyndisk_header; uint8_t buf[HEADER_SIZE]; uint32_t checksum; - int err = -1; int disk_type = VHD_DYNAMIC; + int ret; - if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE) + ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE); + if (ret < 0) { goto fail; + } footer = (struct vhd_footer*) s->footer_buf; if (strncmp(footer->creator, "conectix", 8)) { int64_t offset = bdrv_getlength(bs->file); - if (offset < HEADER_SIZE) { + if (offset < 0) { + ret = offset; + goto fail; + } else if (offset < HEADER_SIZE) { + ret = -EINVAL; goto fail; } + /* If a fixed disk, the footer is found only at the end of the file */ - if (bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, HEADER_SIZE) - != HEADER_SIZE) { + ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf, + HEADER_SIZE); + if (ret < 0) { goto fail; } if (strncmp(footer->creator, "conectix", 8)) { + ret = -EMEDIUMTYPE; goto fail; } disk_type = VHD_FIXED; @@ -203,19 +212,21 @@ static int vpc_open(BlockDriverState *bs, int flags) /* Allow a maximum disk size of approximately 2 TB */ if (bs->total_sectors >= 65535LL * 255 * 255) { - err = -EFBIG; + ret = -EFBIG; goto fail; } if (disk_type == VHD_DYNAMIC) { - if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, - HEADER_SIZE) != HEADER_SIZE) { + ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, + HEADER_SIZE); + if (ret < 0) { goto fail; } dyndisk_header = (struct vhd_dyndisk_header *) buf; if (strncmp(dyndisk_header->magic, "cxsparse", 8)) { + ret = -EINVAL; goto fail; } @@ -226,8 +237,10 @@ static int vpc_open(BlockDriverState *bs, int flags) s->pagetable = g_malloc(s->max_table_entries * 4); s->bat_offset = be64_to_cpu(dyndisk_header->table_offset); - if (bdrv_pread(bs->file, s->bat_offset, s->pagetable, - s->max_table_entries * 4) != s->max_table_entries * 4) { + + ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, + s->max_table_entries * 4); + if (ret < 0) { goto fail; } @@ -265,8 +278,13 @@ static int vpc_open(BlockDriverState *bs, int flags) migrate_add_blocker(s->migration_blocker); return 0; - fail: - return err; + +fail: + g_free(s->pagetable); +#ifdef CACHE + g_free(s->pageentry_u8); +#endif + return ret; } static int vpc_reopen_prepare(BDRVReopenState *state, From 69d34a360dfe773e17e72c76d15931c9b9d190f6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 25 Jan 2013 17:07:30 +0100 Subject: [PATCH 0857/1634] dmg: Fix bdrv_open() error handling Return -errno instead of -1 on errors and add error checks in some places that didn't have one. Passing things by reference requires more correct typing, replaced a few off_ts therefore - with a 32-bit off_t this is even a fix for truncation bugs. While touching the code, fix even some more memory leaks than in the other drivers... Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/dmg.c | 133 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 37 deletions(-) diff --git a/block/dmg.c b/block/dmg.c index ac397dc8f7..53be25d787 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -57,29 +57,42 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static off_t read_off(BlockDriverState *bs, int64_t offset) +static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result) { - uint64_t buffer; - if (bdrv_pread(bs->file, offset, &buffer, 8) < 8) - return 0; - return be64_to_cpu(buffer); + uint64_t buffer; + int ret; + + ret = bdrv_pread(bs->file, offset, &buffer, 8); + if (ret < 0) { + return ret; + } + + *result = be64_to_cpu(buffer); + return 0; } -static off_t read_uint32(BlockDriverState *bs, int64_t offset) +static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result) { - uint32_t buffer; - if (bdrv_pread(bs->file, offset, &buffer, 4) < 4) - return 0; - return be32_to_cpu(buffer); + uint32_t buffer; + int ret; + + ret = bdrv_pread(bs->file, offset, &buffer, 4); + if (ret < 0) { + return ret; + } + + *result = be32_to_cpu(buffer); + return 0; } static int dmg_open(BlockDriverState *bs, int flags) { BDRVDMGState *s = bs->opaque; - off_t info_begin,info_end,last_in_offset,last_out_offset; - uint32_t count; + uint64_t info_begin,info_end,last_in_offset,last_out_offset; + uint32_t count, tmp; uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i; int64_t offset; + int ret; bs->read_only = 1; s->n_chunks = 0; @@ -88,21 +101,32 @@ static int dmg_open(BlockDriverState *bs, int flags) /* read offset of info blocks */ offset = bdrv_getlength(bs->file); if (offset < 0) { + ret = offset; goto fail; } offset -= 0x1d8; - info_begin = read_off(bs, offset); - if (info_begin == 0) { - goto fail; - } - - if (read_uint32(bs, info_begin) != 0x100) { + ret = read_uint64(bs, offset, &info_begin); + if (ret < 0) { + goto fail; + } else if (info_begin == 0) { + ret = -EINVAL; goto fail; } - count = read_uint32(bs, info_begin + 4); - if (count == 0) { + ret = read_uint32(bs, info_begin, &tmp); + if (ret < 0) { + goto fail; + } else if (tmp != 0x100) { + ret = -EINVAL; + goto fail; + } + + ret = read_uint32(bs, info_begin + 4, &count); + if (ret < 0) { + goto fail; + } else if (count == 0) { + ret = -EINVAL; goto fail; } info_end = info_begin + count; @@ -114,12 +138,20 @@ static int dmg_open(BlockDriverState *bs, int flags) while (offset < info_end) { uint32_t type; - count = read_uint32(bs, offset); - if(count==0) - goto fail; + ret = read_uint32(bs, offset, &count); + if (ret < 0) { + goto fail; + } else if (count == 0) { + ret = -EINVAL; + goto fail; + } offset += 4; - type = read_uint32(bs, offset); + ret = read_uint32(bs, offset, &type); + if (ret < 0) { + goto fail; + } + if (type == 0x6d697368 && count >= 244) { int new_size, chunk_count; @@ -134,8 +166,11 @@ static int dmg_open(BlockDriverState *bs, int flags) s->sectors = g_realloc(s->sectors, new_size); s->sectorcounts = g_realloc(s->sectorcounts, new_size); - for(i=s->n_chunks;in_chunks+chunk_count;i++) { - s->types[i] = read_uint32(bs, offset); + for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) { + ret = read_uint32(bs, offset, &s->types[i]); + if (ret < 0) { + goto fail; + } offset += 4; if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) { if(s->types[i]==0xffffffff) { @@ -149,17 +184,31 @@ static int dmg_open(BlockDriverState *bs, int flags) } offset += 4; - s->sectors[i] = last_out_offset+read_off(bs, offset); - offset += 8; + ret = read_uint64(bs, offset, &s->sectors[i]); + if (ret < 0) { + goto fail; + } + s->sectors[i] += last_out_offset; + offset += 8; - s->sectorcounts[i] = read_off(bs, offset); - offset += 8; + ret = read_uint64(bs, offset, &s->sectorcounts[i]); + if (ret < 0) { + goto fail; + } + offset += 8; - s->offsets[i] = last_in_offset+read_off(bs, offset); - offset += 8; + ret = read_uint64(bs, offset, &s->offsets[i]); + if (ret < 0) { + goto fail; + } + s->offsets[i] += last_in_offset; + offset += 8; - s->lengths[i] = read_off(bs, offset); - offset += 8; + ret = read_uint64(bs, offset, &s->lengths[i]); + if (ret < 0) { + goto fail; + } + offset += 8; if(s->lengths[i]>max_compressed_size) max_compressed_size = s->lengths[i]; @@ -173,15 +222,25 @@ static int dmg_open(BlockDriverState *bs, int flags) /* initialize zlib engine */ s->compressed_chunk = g_malloc(max_compressed_size+1); s->uncompressed_chunk = g_malloc(512*max_sectors_per_chunk); - if(inflateInit(&s->zstream) != Z_OK) - goto fail; + if(inflateInit(&s->zstream) != Z_OK) { + ret = -EINVAL; + goto fail; + } s->current_chunk = s->n_chunks; qemu_co_mutex_init(&s->lock); return 0; + fail: - return -1; + g_free(s->types); + g_free(s->offsets); + g_free(s->lengths); + g_free(s->sectors); + g_free(s->sectorcounts); + g_free(s->compressed_chunk); + g_free(s->uncompressed_chunk); + return ret; } static inline int is_sector_in_chunk(BDRVDMGState* s, From 4f8aa2e19f88fe0dfaf8240ae666de7fd18dd1d0 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 25 Jan 2013 17:07:31 +0100 Subject: [PATCH 0858/1634] dmg: Use g_free instead of free The buffers are allocated with g_(re)alloc, so use g_free to free them. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/dmg.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/block/dmg.c b/block/dmg.c index 53be25d787..6d85801a84 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -355,15 +355,15 @@ static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num, static void dmg_close(BlockDriverState *bs) { BDRVDMGState *s = bs->opaque; - if(s->n_chunks>0) { - free(s->types); - free(s->offsets); - free(s->lengths); - free(s->sectors); - free(s->sectorcounts); - } - free(s->compressed_chunk); - free(s->uncompressed_chunk); + + g_free(s->types); + g_free(s->offsets); + g_free(s->lengths); + g_free(s->sectors); + g_free(s->sectorcounts); + g_free(s->compressed_chunk); + g_free(s->uncompressed_chunk); + inflateEnd(&s->zstream); } From 46536235d80a012cc4286b71426cafad0c7f41f0 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 25 Jan 2013 17:07:32 +0100 Subject: [PATCH 0859/1634] parallels: Fix bdrv_open() error handling Return -errno instead of -1 on errors. Hey, no memory leak to fix here while we're touching it! Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block/parallels.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/block/parallels.c b/block/parallels.c index 377375046f..8688f6ca4c 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -73,14 +73,18 @@ static int parallels_open(BlockDriverState *bs, int flags) BDRVParallelsState *s = bs->opaque; int i; struct parallels_header ph; + int ret; bs->read_only = 1; // no write support yet - if (bdrv_pread(bs->file, 0, &ph, sizeof(ph)) != sizeof(ph)) + ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph)); + if (ret < 0) { goto fail; + } if (memcmp(ph.magic, HEADER_MAGIC, 16) || - (le32_to_cpu(ph.version) != HEADER_VERSION)) { + (le32_to_cpu(ph.version) != HEADER_VERSION)) { + ret = -EMEDIUMTYPE; goto fail; } @@ -90,18 +94,21 @@ static int parallels_open(BlockDriverState *bs, int flags) s->catalog_size = le32_to_cpu(ph.catalog_entries); s->catalog_bitmap = g_malloc(s->catalog_size * 4); - if (bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4) != - s->catalog_size * 4) - goto fail; + + ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4); + if (ret < 0) { + goto fail; + } + for (i = 0; i < s->catalog_size; i++) le32_to_cpus(&s->catalog_bitmap[i]); qemu_co_mutex_init(&s->lock); return 0; + fail: - if (s->catalog_bitmap) - g_free(s->catalog_bitmap); - return -1; + g_free(s->catalog_bitmap); + return ret; } static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) From cd9234757528a1b7155a75ec2eedb375f71e99fa Mon Sep 17 00:00:00 2001 From: Philipp Hahn Date: Tue, 29 Jan 2013 22:50:31 +0100 Subject: [PATCH 0860/1634] vmdk: Allow space in file name The previous scanf() format string stopped parsing the file name on the first white white space, which seems to be allowed at least by VMware Workstation. Change the format string to collect everything between the first and second quote as the file name, disallowing line breaks. Signed-off-by: Philipp Hahn Reviewed-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- block/vmdk.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index a8cb5c972d..aef1abcb4f 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -641,7 +641,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, * RW [size in sectors] SPARSE "file-name.vmdk" */ flat_offset = -1; - ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64, + ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, access, §ors, type, fname, &flat_offset); if (ret < 4 || strcmp(access, "RW")) { goto next_line; @@ -653,14 +653,6 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, return -EINVAL; } - /* trim the quotation marks around */ - if (fname[0] == '"') { - memmove(fname, fname + 1, strlen(fname)); - if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') { - return -EINVAL; - } - fname[strlen(fname) - 1] = '\0'; - } if (sectors <= 0 || (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) || (strcmp(access, "RW"))) { From fdf263f63fad86b04032da86686a952edfe4644f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 31 Jan 2013 15:40:14 +0100 Subject: [PATCH 0861/1634] block/raw-posix: Build fix for O_ASYNC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit eeb6b45d48800e96f67ef2a5c80332557fd45ddb (block: raw-posix image file reopen) broke the build on OpenIndiana. illumos has no O_ASYNC. Exclude it from flags to be compared and instead assert that it is not set where defined. Cf. e61ab1da7e98357da47c54d8f893b9bd6ff2f7f9 for qemu-ga. Cc: qemu-stable@nongnu.org (1.3.x) Cc: Jeff Cody Suggested-by: Paolo Bonzini Signed-off-by: Andreas Färber Signed-off-by: Stefan Hajnoczi --- block/raw-posix.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 657af95637..8b6b92608b 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -345,11 +345,20 @@ static int raw_reopen_prepare(BDRVReopenState *state, raw_s->fd = -1; - int fcntl_flags = O_APPEND | O_ASYNC | O_NONBLOCK; + int fcntl_flags = O_APPEND | O_NONBLOCK; #ifdef O_NOATIME fcntl_flags |= O_NOATIME; #endif +#ifdef O_ASYNC + /* Not all operating systems have O_ASYNC, and those that don't + * will not let us track the state into raw_s->open_flags (typically + * you achieve the same effect with an ioctl, for example I_SETSIG + * on Solaris). But we do not use O_ASYNC, so that's fine. + */ + assert((s->open_flags & O_ASYNC) == 0); +#endif + if ((raw_s->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) { /* dup the original fd */ /* TODO: use qemu fcntl wrapper */ From 70ddd9f66d1d5234b38b4444f209c511e7757ce6 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 31 Jan 2013 17:43:51 -0600 Subject: [PATCH 0862/1634] Revert "e1000: no need auto-negotiation if link was down" This reverts commit 84dd2120247a7d25ff1bb337de21c0e76816ad2d. I'm not sure what issue the original commit was meant to fix, or if the logic is actually wrong, but it causes e1000 to stop working after a guest issues a reset. >From what I can tell a guest with an e1000 nic has no way of changing the link status, as far as it's NetClient peer is concerned, except in the auto-negotiation path, so with this patch in place there's no recovery after a reset, since the link goes down and stays that way. Revert this patch now to fix the bigger problem, and handle any lingering issues with a follow-up. Reproduced/tested with qemu-jeos and Ubuntu 12.10. Signed-off-by: Michael Roth Signed-off-by: Anthony Liguori --- hw/e1000.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index ee85c53d38..56f50d42fe 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -166,11 +166,6 @@ static void set_phy_ctrl(E1000State *s, int index, uint16_t val) { if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { - /* no need auto-negotiation if link was down */ - if (s->nic->nc.link_down) { - s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; - return; - } s->nic->nc.link_down = true; e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; From 6c8fec8372147a561f5b721d3a5180b73d7ce4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 16:16:19 +0100 Subject: [PATCH 0863/1634] configure: Keep -Werror enabled for Release Candidates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The automatic drop of -Werror during the RC phases has in the past led to warnings creeping into submaintainer trees. Last QEMU Summit it was concluded that -Werror should stay on and enabled only as part of the release process. To relieve our release manager, instead of always enabling -Werror or doing some number magic, let's enable it depending on whether a .git/ directory exists in the source tree. Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b7635e4fec..0657b1a1b5 100755 --- a/configure +++ b/configure @@ -1180,7 +1180,7 @@ fi z_version=`cut -f3 -d. $source_path/VERSION` if test -z "$werror" ; then - if test "$z_version" = "50" -a \ + if test -d "$source_path/.git" -a \ "$linux" = "yes" ; then werror="yes" else From 8aae84a1f2ad256d222c97411af17013b1c35799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 25 Jan 2013 09:12:54 +0100 Subject: [PATCH 0864/1634] i2c: Drop I2C_SLAVE_FROM_QDEV() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is not being used in hot paths and is obsoleted by I2C_SLAVE() QOM cast macro. Clean it up using a scripted conversion, so that it doesn't get used in new code. Some of its callers were combining it with FROM_I2C_SLAVE() macro, which is equally obsolete but needs to be replaced in a type-specific way. Signed-off-by: Andreas Färber Cc: Kuo-Jung Su Signed-off-by: Anthony Liguori --- hw/ds1338.c | 2 +- hw/i2c.c | 4 ++-- hw/i2c.h | 1 - hw/lm832x.c | 2 +- hw/max7310.c | 2 +- hw/pxa2xx.c | 2 +- hw/wm8750.c | 2 +- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/ds1338.c b/hw/ds1338.c index 379220638e..6f70538eb3 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -198,7 +198,7 @@ static int ds1338_init(I2CSlave *i2c) static void ds1338_reset(DeviceState *dev) { - DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE_FROM_QDEV(dev)); + DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE(dev)); /* The clock is running and synchronized with the host */ s->offset = 0; diff --git a/hw/i2c.c b/hw/i2c.c index 119e96bc0e..ec314a40d1 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -92,7 +92,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv) QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { DeviceState *qdev = kid->child; - I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev); + I2CSlave *candidate = I2C_SLAVE(qdev); if (candidate->address == address) { slave = candidate; break; @@ -204,7 +204,7 @@ const VMStateDescription vmstate_i2c_slave = { static int i2c_slave_qdev_init(DeviceState *dev) { - I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev); + I2CSlave *s = I2C_SLAVE(dev); I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s); return sc->init(s); diff --git a/hw/i2c.h b/hw/i2c.h index 883b5c588d..0e80d5a9cb 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -59,7 +59,6 @@ void i2c_nack(i2c_bus *bus); int i2c_send(i2c_bus *bus, uint8_t data); int i2c_recv(i2c_bus *bus); -#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(I2CSlave, qdev, dev) #define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev) DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr); diff --git a/hw/lm832x.c b/hw/lm832x.c index af49dd68bf..94b8ae06d8 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -476,7 +476,7 @@ static int lm8323_init(I2CSlave *i2c) void lm832x_key_event(DeviceState *dev, int key, int state) { - LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE_FROM_QDEV(dev)); + LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE(dev)); if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR)) return; diff --git a/hw/max7310.c b/hw/max7310.c index de2221ba01..c2df0b49eb 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -25,7 +25,7 @@ typedef struct { static void max7310_reset(DeviceState *dev) { - MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, I2C_SLAVE_FROM_QDEV(dev)); + MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, I2C_SLAVE(dev)); s->level &= s->direction; s->direction = 0xff; s->polarity = 0xf0; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 2367c6a4a4..373d0616ba 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1468,7 +1468,7 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, s = FROM_SYSBUS(PXA2xxI2CState, i2c_dev); /* FIXME: Should the slave device really be on a separate bus? */ dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0); - s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev)); + s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE(dev)); s->slave->host = s; return s; diff --git a/hw/wm8750.c b/hw/wm8750.c index bb85064c9b..d3ea5ba8f5 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -632,7 +632,7 @@ static void wm8750_fini(I2CSlave *i2c) void wm8750_data_req_set(DeviceState *dev, void (*data_req)(void *, int, int), void *opaque) { - WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE_FROM_QDEV(dev)); + WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE(dev)); s->data_req = data_req; s->opaque = opaque; } From 3e7b8f4e6f507e09e27b7449f3744596f19c0083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 18:56:18 +0100 Subject: [PATCH 0865/1634] isa: QOM'ify isa_bus_from_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceState::parent_bus is document as private and should be accessed through qdev_get_parent_bus(). Use a DEVICE() cast instead of accessing ISADevice's qdev field directly. Use ISA_BUS() in place of DO_UPCAST(). Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- hw/isa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/isa.h b/hw/isa.h index 62e89d3bcd..7a8874abfd 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -82,7 +82,7 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start, static inline ISABus *isa_bus_from_device(ISADevice *d) { - return DO_UPCAST(ISABus, qbus, d->qdev.parent_bus); + return ISA_BUS(qdev_get_parent_bus(DEVICE(d))); } extern hwaddr isa_mem_base; From 6bf0076643dac4f37cabb9233dc9170f1c2fdd49 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 28 Jan 2013 16:15:16 -0200 Subject: [PATCH 0866/1634] libqtest: Wait for the right child PID after killing QEMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running "make check" with gcov enabled, we get the following message: hw/tmp105.gcda:cannot open data file, assuming not executed The problem happens because: * tmp105-test exits before QEMU exits, because waitpid() at qtest_quit() fails; * waitpid() fails because there's another process already waiting for the QEMU process; * The process that is already waiting for QEMU is the child created by qtest_init() to run system(); * qtest_quit() is incorrectly waiting for the QEMU PID directly instead of the child created by qtest_init(). This fixes the problem by sending SIGTERM to QEMU, but waiting for the child process created by qtest_init() (that exits immediately after QEMU exits). Reported-by: Andreas Färber Signed-off-by: Eduardo Habkost Signed-off-by: Anthony Liguori --- tests/libqtest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/libqtest.c b/tests/libqtest.c index 913fa0535c..762dec4ac0 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -39,7 +39,8 @@ struct QTestState int qmp_fd; bool irq_level[MAX_IRQ]; GString *rx; - gchar *pid_file; + gchar *pid_file; /* QEMU PID file */ + int child_pid; /* Child process created to execute QEMU */ char *socket_path, *qmp_socket_path; }; @@ -144,6 +145,7 @@ QTestState *qtest_init(const char *extra_args) s->rx = g_string_new(""); s->pid_file = pid_file; + s->child_pid = pid; for (i = 0; i < MAX_IRQ; i++) { s->irq_level[i] = false; } @@ -165,8 +167,9 @@ void qtest_quit(QTestState *s) pid_t pid = qtest_qemu_pid(s); if (pid != -1) { + /* kill QEMU, but wait for the child created by us to run system() */ kill(pid, SIGTERM); - waitpid(pid, &status, 0); + waitpid(s->child_pid, &status, 0); } unlink(s->pid_file); From 350ed2fcd95d30b02609e8783f33735f356ad7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 31 Jan 2013 14:49:44 +0100 Subject: [PATCH 0867/1634] target-ppc: Fix target_ulong vs. hwaddr format mismatches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since HWADDR_PRIx is always the same now, use %016 for TARGET_PPC64 and %08 for common code. This may slightly change the ppc64 debug output. Signed-off-by: Andreas Färber Signed-off-by: Anthony Liguori --- target-ppc/mmu_helper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c index f1901334b1..1cc1c1649a 100644 --- a/target-ppc/mmu_helper.c +++ b/target-ppc/mmu_helper.c @@ -587,7 +587,7 @@ static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, } r = pte64_check(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " + LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h, (int)((pte0 >> 1) & 1), ctx->ptem); @@ -602,7 +602,7 @@ static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4); } r = pte32_check(ctx, pte0, pte1, h, rw, type); - LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " + LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem); @@ -633,7 +633,7 @@ static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, } if (good != -1) { done: - LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n", + LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n", ctx->raddr, ctx->prot, ret); /* Update page flags */ pte1 = ctx->raddr; From ec45f08313ce92039d52ea0338db4a0c862fef6a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:20 +0800 Subject: [PATCH 0868/1634] net: tap: using bool instead of bitfield Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/virtio-net.c | 2 +- include/net/tap.h | 4 ++-- net/tap-win32.c | 6 +++--- net/tap.c | 38 ++++++++++++++++++-------------------- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index dfb9687d2f..b5579b4dbf 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1102,7 +1102,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n); peer_test_vnet_hdr(n); if (peer_has_vnet_hdr(n)) { - tap_using_vnet_hdr(n->nic->nc.peer, 1); + tap_using_vnet_hdr(n->nic->nc.peer, true); n->host_hdr_len = sizeof(struct virtio_net_hdr); } else { n->host_hdr_len = 0; diff --git a/include/net/tap.h b/include/net/tap.h index bb7efb5439..883cebff07 100644 --- a/include/net/tap.h +++ b/include/net/tap.h @@ -29,10 +29,10 @@ #include "qemu-common.h" #include "qapi-types.h" -int tap_has_ufo(NetClientState *nc); +bool tap_has_ufo(NetClientState *nc); int tap_has_vnet_hdr(NetClientState *nc); int tap_has_vnet_hdr_len(NetClientState *nc, int len); -void tap_using_vnet_hdr(NetClientState *nc, int using_vnet_hdr); +void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr); void tap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo); void tap_set_vnet_hdr_len(NetClientState *nc, int len); diff --git a/net/tap-win32.c b/net/tap-win32.c index 265369c3c5..3052bbac14 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -722,9 +722,9 @@ int net_init_tap(const NetClientOptions *opts, const char *name, return 0; } -int tap_has_ufo(NetClientState *nc) +bool tap_has_ufo(NetClientState *nc) { - return 0; + return false; } int tap_has_vnet_hdr(NetClientState *nc) @@ -741,7 +741,7 @@ void tap_fd_set_vnet_hdr_len(int fd, int len) { } -void tap_using_vnet_hdr(NetClientState *nc, int using_vnet_hdr) +void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr) { } diff --git a/net/tap.c b/net/tap.c index eb40c42d7d..5542c98c03 100644 --- a/net/tap.c +++ b/net/tap.c @@ -55,10 +55,10 @@ typedef struct TAPState { char down_script[1024]; char down_script_arg[128]; uint8_t buf[TAP_BUFSIZE]; - unsigned int read_poll : 1; - unsigned int write_poll : 1; - unsigned int using_vnet_hdr : 1; - unsigned int has_ufo: 1; + bool read_poll; + bool write_poll; + bool using_vnet_hdr; + bool has_ufo; VHostNetState *vhost_net; unsigned host_vnet_hdr_len; } TAPState; @@ -78,15 +78,15 @@ static void tap_update_fd_handler(TAPState *s) s); } -static void tap_read_poll(TAPState *s, int enable) +static void tap_read_poll(TAPState *s, bool enable) { - s->read_poll = !!enable; + s->read_poll = enable; tap_update_fd_handler(s); } -static void tap_write_poll(TAPState *s, int enable) +static void tap_write_poll(TAPState *s, bool enable) { - s->write_poll = !!enable; + s->write_poll = enable; tap_update_fd_handler(s); } @@ -94,7 +94,7 @@ static void tap_writable(void *opaque) { TAPState *s = opaque; - tap_write_poll(s, 0); + tap_write_poll(s, false); qemu_flush_queued_packets(&s->nc); } @@ -108,7 +108,7 @@ static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt } while (len == -1 && errno == EINTR); if (len == -1 && errno == EAGAIN) { - tap_write_poll(s, 1); + tap_write_poll(s, true); return 0; } @@ -186,7 +186,7 @@ ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) static void tap_send_completed(NetClientState *nc, ssize_t len) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - tap_read_poll(s, 1); + tap_read_poll(s, true); } static void tap_send(void *opaque) @@ -209,12 +209,12 @@ static void tap_send(void *opaque) size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed); if (size == 0) { - tap_read_poll(s, 0); + tap_read_poll(s, false); } } while (size > 0 && qemu_can_send_packet(&s->nc)); } -int tap_has_ufo(NetClientState *nc) +bool tap_has_ufo(NetClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); @@ -253,12 +253,10 @@ void tap_set_vnet_hdr_len(NetClientState *nc, int len) s->host_vnet_hdr_len = len; } -void tap_using_vnet_hdr(NetClientState *nc, int using_vnet_hdr) +void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - using_vnet_hdr = using_vnet_hdr != 0; - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); assert(!!s->host_vnet_hdr_len == using_vnet_hdr); @@ -290,8 +288,8 @@ static void tap_cleanup(NetClientState *nc) if (s->down_script[0]) launch_script(s->down_script, s->down_script_arg, s->fd); - tap_read_poll(s, 0); - tap_write_poll(s, 0); + tap_read_poll(s, false); + tap_write_poll(s, false); close(s->fd); s->fd = -1; } @@ -337,7 +335,7 @@ static TAPState *net_tap_fd_init(NetClientState *peer, s->fd = fd; s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0; - s->using_vnet_hdr = 0; + s->using_vnet_hdr = false; s->has_ufo = tap_probe_has_ufo(s->fd); tap_set_offload(&s->nc, 0, 0, 0, 0, 0); /* @@ -347,7 +345,7 @@ static TAPState *net_tap_fd_init(NetClientState *peer, if (tap_probe_vnet_hdr_len(s->fd, s->host_vnet_hdr_len)) { tap_fd_set_vnet_hdr_len(s->fd, s->host_vnet_hdr_len); } - tap_read_poll(s, 1); + tap_read_poll(s, true); s->vhost_net = NULL; return s; } From 28a65891a0deb10b222890b9eb916ca32cb977bb Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:21 +0800 Subject: [PATCH 0869/1634] net: tap: use abort() instead of assert(0) Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- net/tap-linux.c | 4 ++-- net/tap-win32.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/tap-linux.c b/net/tap-linux.c index 059f5f34ab..0a6acc7d5a 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -164,7 +164,7 @@ int tap_probe_vnet_hdr_len(int fd, int len) if (ioctl(fd, TUNSETVNETHDRSZ, &orig) == -1) { fprintf(stderr, "TUNGETVNETHDRSZ ioctl() failed: %s. Exiting.\n", strerror(errno)); - assert(0); + abort(); return -errno; } return 1; @@ -175,7 +175,7 @@ void tap_fd_set_vnet_hdr_len(int fd, int len) if (ioctl(fd, TUNSETVNETHDRSZ, &len) == -1) { fprintf(stderr, "TUNSETVNETHDRSZ ioctl() failed: %s. Exiting.\n", strerror(errno)); - assert(0); + abort(); } } diff --git a/net/tap-win32.c b/net/tap-win32.c index 3052bbac14..601437ee2d 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -762,5 +762,5 @@ int tap_has_vnet_hdr_len(NetClientState *nc, int len) void tap_set_vnet_hdr_len(NetClientState *nc, int len) { - assert(0); + abort(); } From b356f76de31e343121cdab3a01b39182edce9519 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:22 +0800 Subject: [PATCH 0870/1634] net: introduce qemu_get_queue() To support multiqueue, the patch introduce a helper qemu_get_queue() which is used to get the NetClientState of a device. The following patches would refactor this helper to support multiqueue. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/cadence_gem.c | 9 ++--- hw/dp8393x.c | 9 ++--- hw/e1000.c | 22 ++++++------ hw/eepro100.c | 12 +++---- hw/etraxfs_eth.c | 5 +-- hw/lan9118.c | 10 +++--- hw/mcf_fec.c | 4 +-- hw/milkymist-minimac2.c | 4 +-- hw/mipsnet.c | 4 +-- hw/musicpal.c | 2 +- hw/ne2000-isa.c | 2 +- hw/ne2000.c | 7 ++-- hw/opencores_eth.c | 6 ++-- hw/pcnet-pci.c | 2 +- hw/pcnet.c | 7 ++-- hw/rtl8139.c | 14 ++++---- hw/smc91c111.c | 4 +-- hw/spapr_llan.c | 4 +-- hw/stellaris_enet.c | 5 +-- hw/usb/dev-network.c | 10 +++--- hw/virtio-net.c | 78 +++++++++++++++++++++++------------------ hw/xen_nic.c | 13 ++++--- hw/xgmac.c | 4 +-- hw/xilinx_axienet.c | 4 +-- hw/xilinx_ethlite.c | 6 ++-- include/net/net.h | 1 + net/net.c | 5 +++ savevm.c | 2 +- 28 files changed, 140 insertions(+), 115 deletions(-) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index b77423d449..b8071a4695 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -389,10 +389,10 @@ static void gem_init_register_masks(GemState *s) */ static void phy_update_link(GemState *s) { - DB_PRINT("down %d\n", s->nic->nc.link_down); + DB_PRINT("down %d\n", qemu_get_queue(s->nic)->link_down); /* Autonegotiation status mirrors link status. */ - if (s->nic->nc.link_down) { + if (qemu_get_queue(s->nic)->link_down) { s->phy_regs[PHY_REG_STATUS] &= ~(PHY_REG_STATUS_ANEGCMPL | PHY_REG_STATUS_LINK); s->phy_regs[PHY_REG_INT_ST] |= PHY_REG_INT_ST_LINKC; @@ -908,9 +908,10 @@ static void gem_transmit(GemState *s) /* Send the packet somewhere */ if (s->phy_loop) { - gem_receive(&s->nic->nc, tx_packet, total_bytes); + gem_receive(qemu_get_queue(s->nic), tx_packet, total_bytes); } else { - qemu_send_packet(&s->nic->nc, tx_packet, total_bytes); + qemu_send_packet(qemu_get_queue(s->nic), tx_packet, + total_bytes); } /* Prepare for next packet */ diff --git a/hw/dp8393x.c b/hw/dp8393x.c index b5014501df..c2d0bc8450 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -339,6 +339,7 @@ static void do_receiver_disable(dp8393xState *s) static void do_transmit_packets(dp8393xState *s) { + NetClientState *nc = qemu_get_queue(s->nic); uint16_t data[12]; int width, size; int tx_len, len; @@ -408,13 +409,13 @@ static void do_transmit_packets(dp8393xState *s) if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { /* Loopback */ s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; - if (s->nic->nc.info->can_receive(&s->nic->nc)) { + if (nc->info->can_receive(nc)) { s->loopback_packet = 1; - s->nic->nc.info->receive(&s->nic->nc, s->tx_buffer, tx_len); + nc->info->receive(nc, s->tx_buffer, tx_len); } } else { /* Transmit packet */ - qemu_send_packet(&s->nic->nc, s->tx_buffer, tx_len); + qemu_send_packet(nc, s->tx_buffer, tx_len); } s->regs[SONIC_TCR] |= SONIC_TCR_PTX; @@ -903,7 +904,7 @@ void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); qemu_register_reset(nic_reset, s); nic_reset(s); diff --git a/hw/e1000.c b/hw/e1000.c index 56f50d42fe..14b09d1949 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -166,7 +166,7 @@ static void set_phy_ctrl(E1000State *s, int index, uint16_t val) { if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { - s->nic->nc.link_down = true; + qemu_get_queue(s->nic)->link_down = true; e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; DBGOUT(PHY, "Start link auto negotiation\n"); @@ -178,7 +178,7 @@ static void e1000_autoneg_timer(void *opaque) { E1000State *s = opaque; - s->nic->nc.link_down = false; + qemu_get_queue(s->nic)->link_down = false; e1000_link_up(s); s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; DBGOUT(PHY, "Auto negotiation is completed\n"); @@ -291,7 +291,7 @@ static void e1000_reset(void *opaque) d->rxbuf_min_shift = 1; memset(&d->tx, 0, sizeof d->tx); - if (d->nic->nc.link_down) { + if (qemu_get_queue(d->nic)->link_down) { e1000_link_down(d); } @@ -319,7 +319,7 @@ set_rx_control(E1000State *s, int index, uint32_t val) s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], s->mac_reg[RCTL]); - qemu_flush_queued_packets(&s->nic->nc); + qemu_flush_queued_packets(qemu_get_queue(s->nic)); } static void @@ -470,10 +470,11 @@ fcs_len(E1000State *s) static void e1000_send_packet(E1000State *s, const uint8_t *buf, int size) { + NetClientState *nc = qemu_get_queue(s->nic); if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) { - s->nic->nc.info->receive(&s->nic->nc, buf, size); + nc->info->receive(nc, buf, size); } else { - qemu_send_packet(&s->nic->nc, buf, size); + qemu_send_packet(nc, buf, size); } } @@ -958,7 +959,7 @@ set_rdt(E1000State *s, int index, uint32_t val) { s->mac_reg[index] = val & 0xffff; if (e1000_has_rxbufs(s, 1)) { - qemu_flush_queued_packets(&s->nic->nc); + qemu_flush_queued_packets(qemu_get_queue(s->nic)); } } @@ -1112,10 +1113,11 @@ static bool is_version_1(void *opaque, int version_id) static int e1000_post_load(void *opaque, int version_id) { E1000State *s = opaque; + NetClientState *nc = qemu_get_queue(s->nic); /* nc.link_down can't be migrated, so infer link_down according * to link status bit in mac_reg[STATUS] */ - s->nic->nc.link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0; + nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0; return 0; } @@ -1247,7 +1249,7 @@ pci_e1000_uninit(PCIDevice *dev) qemu_free_timer(d->autoneg_timer); memory_region_destroy(&d->mmio); memory_region_destroy(&d->io); - qemu_del_net_client(&d->nic->nc); + qemu_del_net_client(qemu_get_queue(d->nic)); } static NetClientInfo net_e1000_info = { @@ -1294,7 +1296,7 @@ static int pci_e1000_init(PCIDevice *pci_dev) d->nic = qemu_new_nic(&net_e1000_info, &d->conf, object_get_typename(OBJECT(d)), d->dev.qdev.id, d); - qemu_format_nic_info_str(&d->nic->nc, macaddr); + qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr); add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); diff --git a/hw/eepro100.c b/hw/eepro100.c index 6bbefb505f..5b77bdc47c 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -828,7 +828,7 @@ static void tx_command(EEPRO100State *s) } } TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size))); - qemu_send_packet(&s->nic->nc, buf, size); + qemu_send_packet(qemu_get_queue(s->nic), buf, size); s->statistics.tx_good_frames++; /* Transmit with bad status would raise an CX/TNO interrupt. * (82557 only). Emulation never has bad status. */ @@ -1036,7 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val) } set_ru_state(s, ru_ready); s->ru_offset = e100_read_reg4(s, SCBPointer); - qemu_flush_queued_packets(&s->nic->nc); + qemu_flush_queued_packets(qemu_get_queue(s->nic)); TRACE(OTHER, logout("val=0x%02x (rx start)\n", val)); break; case RX_RESUME: @@ -1849,7 +1849,7 @@ static void pci_nic_uninit(PCIDevice *pci_dev) memory_region_destroy(&s->flash_bar); vmstate_unregister(&pci_dev->qdev, s->vmstate, s); eeprom93xx_free(&pci_dev->qdev, s->eeprom); - qemu_del_net_client(&s->nic->nc); + qemu_del_net_client(qemu_get_queue(s->nic)); } static NetClientInfo net_eepro100_info = { @@ -1895,14 +1895,14 @@ static int e100_nic_init(PCIDevice *pci_dev) s->nic = qemu_new_nic(&net_eepro100_info, &s->conf, object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); - TRACE(OTHER, logout("%s\n", s->nic->nc.info_str)); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + TRACE(OTHER, logout("%s\n", qemu_get_queue(s->nic)->info_str)); qemu_register_reset(nic_reset, s); s->vmstate = g_malloc(sizeof(vmstate_eepro100)); memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100)); - s->vmstate->name = s->nic->nc.model; + s->vmstate->name = qemu_get_queue(s->nic)->model; vmstate_register(&pci_dev->qdev, -1, s->vmstate, s); add_boot_device_path(s->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 0b474c0843..7c4d5880ac 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -555,7 +555,7 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) struct fs_eth *eth = opaque; D(printf("%s buf=%p len=%d\n", __func__, buf, len)); - qemu_send_packet(ð->nic->nc, buf, len); + qemu_send_packet(qemu_get_queue(eth->nic), buf, len); return len; } @@ -616,7 +616,8 @@ static int fs_eth_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, object_get_typename(OBJECT(s)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); + tdk_init(&s->phy); mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); diff --git a/hw/lan9118.c b/hw/lan9118.c index 6596979d8b..262f38992b 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -341,7 +341,7 @@ static void lan9118_update(lan9118_state *s) static void lan9118_mac_changed(lan9118_state *s) { - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } static void lan9118_reload_eeprom(lan9118_state *s) @@ -373,7 +373,7 @@ static void phy_update_irq(lan9118_state *s) static void phy_update_link(lan9118_state *s) { /* Autonegotiation status mirrors link status. */ - if (s->nic->nc.link_down) { + if (qemu_get_queue(s->nic)->link_down) { s->phy_status &= ~0x0024; s->phy_int |= PHY_INT_DOWN; } else { @@ -657,9 +657,9 @@ static void do_tx_packet(lan9118_state *s) /* FIXME: Honor TX disable, and allow queueing of packets. */ if (s->phy_control & 0x4000) { /* This assumes the receive routine doesn't touch the VLANClient. */ - lan9118_receive(&s->nic->nc, s->txp->data, s->txp->len); + lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len); } else { - qemu_send_packet(&s->nic->nc, s->txp->data, s->txp->len); + qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); } s->txp->fifo_used = 0; @@ -1335,7 +1335,7 @@ static int lan9118_init1(SysBusDevice *dev) s->nic = qemu_new_nic(&net_lan9118_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); s->eeprom[0] = 0xa5; for (i = 0; i < 6; i++) { s->eeprom[i + 1] = s->conf.macaddr.a[i]; diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 2423f64bf6..8a90bf81ae 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -174,7 +174,7 @@ static void mcf_fec_do_tx(mcf_fec_state *s) if (bd.flags & FEC_BD_L) { /* Last buffer in frame. */ DPRINTF("Sending packet\n"); - qemu_send_packet(&s->nic->nc, frame, len); + qemu_send_packet(qemu_get_queue(s->nic), frame, len); ptr = frame; frame_size = 0; s->eir |= FEC_INT_TXF; @@ -476,5 +476,5 @@ void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd, s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 43d6c195eb..2a8a4efa46 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -257,7 +257,7 @@ static void minimac2_tx(MilkymistMinimac2State *s) trace_milkymist_minimac2_tx_frame(txcount - 12); /* send packet, skipping preamble and sfd */ - qemu_send_packet_raw(&s->nic->nc, buf + 8, txcount - 12); + qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12); s->regs[R_TXCOUNT] = 0; @@ -480,7 +480,7 @@ static int milkymist_minimac2_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); return 0; } diff --git a/hw/mipsnet.c b/hw/mipsnet.c index feac8159ee..15761b1d5d 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -173,7 +173,7 @@ static void mipsnet_ioport_write(void *opaque, hwaddr addr, if (s->tx_written == s->tx_count) { /* Send buffer. */ trace_mipsnet_send(s->tx_count); - qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count); + qemu_send_packet(qemu_get_queue(s->nic), s->tx_buffer, s->tx_count); s->tx_count = s->tx_written = 0; s->intctl |= MIPSNET_INTCTL_TXDONE; s->busy = 1; @@ -241,7 +241,7 @@ static int mipsnet_sysbus_init(SysBusDevice *dev) s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); return 0; } diff --git a/hw/musicpal.c b/hw/musicpal.c index 7ac0a918fb..9e22f69fdf 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -257,7 +257,7 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index) len = desc.bytes; if (len < 2048) { cpu_physical_memory_read(desc.buffer, buf, len); - qemu_send_packet(&s->nic->nc, buf, len); + qemu_send_packet(qemu_get_queue(s->nic), buf, len); } desc.cmdstat &= ~MP_ETH_TX_OWN; s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 7c11229f1a..fa47e12857 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -77,7 +77,7 @@ static int isa_ne2000_initfn(ISADevice *dev) s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); return 0; } diff --git a/hw/ne2000.c b/hw/ne2000.c index 872115c454..03c420998b 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -300,7 +300,8 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) index -= NE2000_PMEM_SIZE; /* fail safe: check range on the transmitted length */ if (index + s->tcnt <= NE2000_PMEM_END) { - qemu_send_packet(&s->nic->nc, s->mem + index, s->tcnt); + qemu_send_packet(qemu_get_queue(s->nic), s->mem + index, + s->tcnt); } /* signal end of transfer */ s->tsr = ENTSR_PTX; @@ -737,7 +738,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev) s->nic = qemu_new_nic(&net_ne2000_info, &s->c, object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); add_boot_device_path(s->c.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); @@ -750,7 +751,7 @@ static void pci_ne2000_exit(PCIDevice *pci_dev) NE2000State *s = &d->ne2000; memory_region_destroy(&s->io); - qemu_del_net_client(&s->nic->nc); + qemu_del_net_client(qemu_get_queue(s->nic)); } static Property ne2000_properties[] = { diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index 746a959f6b..2496d4eba1 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -339,7 +339,7 @@ static void open_eth_reset(void *opaque) s->rx_desc = 0x40; mii_reset(&s->mii); - open_eth_set_link_status(&s->nic->nc); + open_eth_set_link_status(qemu_get_queue(s->nic)); } static int open_eth_can_receive(NetClientState *nc) @@ -499,7 +499,7 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx) if (tx_len > len) { memset(buf + len, 0, tx_len - len); } - qemu_send_packet(&s->nic->nc, buf, tx_len); + qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len); if (tx->len_flags & TXD_WR) { s->tx_desc = 0; @@ -606,7 +606,7 @@ static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val) } else { s->regs[MIIRX_DATA] = 0xffff; } - SET_REGFIELD(s, MIISTATUS, LINKFAIL, s->nic->nc.link_down); + SET_REGFIELD(s, MIISTATUS, LINKFAIL, qemu_get_queue(s->nic)->link_down); } } diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index a94f642136..54a849daae 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -279,7 +279,7 @@ static void pci_pcnet_uninit(PCIDevice *dev) memory_region_destroy(&d->io_bar); qemu_del_timer(d->state.poll_timer); qemu_free_timer(d->state.poll_timer); - qemu_del_net_client(&d->state.nic->nc); + qemu_del_net_client(qemu_get_queue(d->state.nic)); } static NetClientInfo net_pci_pcnet_info = { diff --git a/hw/pcnet.c b/hw/pcnet.c index 30f100007a..2126e22ffa 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1261,11 +1261,12 @@ static void pcnet_transmit(PCNetState *s) if (BCR_SWSTYLE(s) == 1) add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; - pcnet_receive(&s->nic->nc, s->buffer, s->xmit_pos); + pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); s->looptest = 0; } else if (s->nic) - qemu_send_packet(&s->nic->nc, s->buffer, s->xmit_pos); + qemu_send_packet(qemu_get_queue(s->nic), s->buffer, + s->xmit_pos); s->csr[0] &= ~0x0008; /* clear TDMD */ s->csr[4] |= 0x0004; /* set TXSTRT */ @@ -1730,7 +1731,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0"); diff --git a/hw/rtl8139.c b/hw/rtl8139.c index cfbf3f47c1..22d24ae6af 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1259,7 +1259,7 @@ static void rtl8139_reset(DeviceState *d) //s->BasicModeStatus |= 0x0040; /* UTP medium */ s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ /* preserve link state */ - s->BasicModeStatus |= s->nic->nc.link_down ? 0 : 0x04; + s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04; s->NWayAdvert = 0x05e1; /* all modes, full duplex */ s->NWayLPAR = 0x05e1; /* all modes, full duplex */ @@ -1787,7 +1787,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, } DPRINTF("+++ transmit loopback mode\n"); - rtl8139_do_receive(&s->nic->nc, buf, size, do_interrupt); + rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt); if (iov) { g_free(buf2); @@ -1796,9 +1796,9 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, else { if (iov) { - qemu_sendv_packet(&s->nic->nc, iov, 3); + qemu_sendv_packet(qemu_get_queue(s->nic), iov, 3); } else { - qemu_send_packet(&s->nic->nc, buf, size); + qemu_send_packet(qemu_get_queue(s->nic), buf, size); } } } @@ -3230,7 +3230,7 @@ static int rtl8139_post_load(void *opaque, int version_id) /* nc.link_down can't be migrated, so infer link_down according * to link status bit in BasicModeStatus */ - s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0; + qemu_get_queue(s->nic)->link_down = (s->BasicModeStatus & 0x04) == 0; return 0; } @@ -3446,7 +3446,7 @@ static void pci_rtl8139_uninit(PCIDevice *dev) } qemu_del_timer(s->timer); qemu_free_timer(s->timer); - qemu_del_net_client(&s->nic->nc); + qemu_del_net_client(qemu_get_queue(s->nic)); } static void rtl8139_set_link_status(NetClientState *nc) @@ -3503,7 +3503,7 @@ static int pci_rtl8139_init(PCIDevice *dev) s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); s->cplus_txbuffer = NULL; s->cplus_txbuffer_len = 0; diff --git a/hw/smc91c111.c b/hw/smc91c111.c index fe2389bf25..cf79c69b7e 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -237,7 +237,7 @@ static void smc91c111_do_tx(smc91c111_state *s) smc91c111_release_packet(s, packetnum); else if (s->tx_fifo_done_len < NUM_PACKETS) s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum; - qemu_send_packet(&s->nic->nc, p, len); + qemu_send_packet(qemu_get_queue(s->nic), p, len); } s->tx_fifo_len = 0; smc91c111_update(s); @@ -754,7 +754,7 @@ static int smc91c111_init1(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); /* ??? Save/restore. */ return 0; } diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index db34b485aa..d53d4ae021 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -199,7 +199,7 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev) dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf, object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev); - qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a); return 0; } @@ -462,7 +462,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, p += VLAN_BD_LEN(bufs[i]); } - qemu_send_packet(&dev->nic->nc, lbuf, total_len); + qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len); return H_SUCCESS; } diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 5e9053fa26..99d473006e 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -259,7 +259,8 @@ static void stellaris_enet_write(void *opaque, hwaddr offset, memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len); s->tx_fifo_len = 60; } - qemu_send_packet(&s->nic->nc, s->tx_fifo, s->tx_frame_len); + qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo, + s->tx_frame_len); s->tx_frame_len = -1; s->ris |= SE_INT_TXEMP; stellaris_enet_update(s); @@ -412,7 +413,7 @@ static int stellaris_enet_init(SysBusDevice *dev) s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); stellaris_enet_reset(s); register_savevm(&s->busdev.qdev, "stellaris_enet", -1, 1, diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 9dede4c68d..a131f9c851 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1012,7 +1012,7 @@ static int rndis_keepalive_response(USBNetState *s, static void usb_net_reset_in_buf(USBNetState *s) { s->in_ptr = s->in_len = 0; - qemu_flush_queued_packets(&s->nic->nc); + qemu_flush_queued_packets(qemu_get_queue(s->nic)); } static int rndis_parse(USBNetState *s, uint8_t *data, int length) @@ -1196,7 +1196,7 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) if (!is_rndis(s)) { if (p->iov.size < 64) { - qemu_send_packet(&s->nic->nc, s->out_buf, s->out_ptr); + qemu_send_packet(qemu_get_queue(s->nic), s->out_buf, s->out_ptr); s->out_ptr = 0; } return; @@ -1209,7 +1209,7 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); uint32_t size = le32_to_cpu(msg->DataLength); if (offs + size <= len) - qemu_send_packet(&s->nic->nc, s->out_buf + offs, size); + qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size); } s->out_ptr -= len; memmove(s->out_buf, &s->out_buf[len], s->out_ptr); @@ -1330,7 +1330,7 @@ static void usb_net_handle_destroy(USBDevice *dev) /* TODO: remove the nd_table[] entry */ rndis_clear_responsequeue(s); - qemu_del_net_client(&s->nic->nc); + qemu_del_net_client(qemu_get_queue(s->nic)); } static NetClientInfo net_usbnet_info = { @@ -1361,7 +1361,7 @@ static int usb_net_initfn(USBDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, object_get_typename(OBJECT(s)), s->dev.qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); snprintf(s->usbstring_mac, sizeof(s->usbstring_mac), "%02x%02x%02x%02x%02x%02x", 0x40, diff --git a/hw/virtio-net.c b/hw/virtio-net.c index b5579b4dbf..7ad65a2133 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -96,7 +96,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) && memcmp(netcfg.mac, n->mac, ETH_ALEN)) { memcpy(n->mac, netcfg.mac, ETH_ALEN); - qemu_format_nic_info_str(&n->nic->nc, n->mac); + qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); } } @@ -108,34 +108,36 @@ static bool virtio_net_started(VirtIONet *n, uint8_t status) static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) { - if (!n->nic->nc.peer) { + NetClientState *nc = qemu_get_queue(n->nic); + + if (!nc->peer) { return; } - if (n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { + if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return; } - if (!tap_get_vhost_net(n->nic->nc.peer)) { + if (!tap_get_vhost_net(nc->peer)) { return; } if (!!n->vhost_started == virtio_net_started(n, status) && - !n->nic->nc.peer->link_down) { + !nc->peer->link_down) { return; } if (!n->vhost_started) { int r; - if (!vhost_net_query(tap_get_vhost_net(n->nic->nc.peer), &n->vdev)) { + if (!vhost_net_query(tap_get_vhost_net(nc->peer), &n->vdev)) { return; } n->vhost_started = 1; - r = vhost_net_start(tap_get_vhost_net(n->nic->nc.peer), &n->vdev); + r = vhost_net_start(tap_get_vhost_net(nc->peer), &n->vdev); if (r < 0) { error_report("unable to start vhost net: %d: " "falling back on userspace virtio", -r); n->vhost_started = 0; } } else { - vhost_net_stop(tap_get_vhost_net(n->nic->nc.peer), &n->vdev); + vhost_net_stop(tap_get_vhost_net(nc->peer), &n->vdev); n->vhost_started = 0; } } @@ -206,13 +208,16 @@ static void virtio_net_reset(VirtIODevice *vdev) static void peer_test_vnet_hdr(VirtIONet *n) { - if (!n->nic->nc.peer) + NetClientState *nc = qemu_get_queue(n->nic); + if (!nc->peer) { return; + } - if (n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) + if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return; + } - n->has_vnet_hdr = tap_has_vnet_hdr(n->nic->nc.peer); + n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer); } static int peer_has_vnet_hdr(VirtIONet *n) @@ -225,7 +230,7 @@ static int peer_has_ufo(VirtIONet *n) if (!peer_has_vnet_hdr(n)) return 0; - n->has_ufo = tap_has_ufo(n->nic->nc.peer); + n->has_ufo = tap_has_ufo(qemu_get_queue(n->nic)->peer); return n->has_ufo; } @@ -238,8 +243,8 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs) sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); if (peer_has_vnet_hdr(n) && - tap_has_vnet_hdr_len(n->nic->nc.peer, n->guest_hdr_len)) { - tap_set_vnet_hdr_len(n->nic->nc.peer, n->guest_hdr_len); + tap_has_vnet_hdr_len(qemu_get_queue(n->nic)->peer, n->guest_hdr_len)) { + tap_set_vnet_hdr_len(qemu_get_queue(n->nic)->peer, n->guest_hdr_len); n->host_hdr_len = n->guest_hdr_len; } } @@ -247,6 +252,7 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs) static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features) { VirtIONet *n = to_virtio_net(vdev); + NetClientState *nc = qemu_get_queue(n->nic); features |= (1 << VIRTIO_NET_F_MAC); @@ -267,14 +273,13 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features) features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO); } - if (!n->nic->nc.peer || - n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { + if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return features; } - if (!tap_get_vhost_net(n->nic->nc.peer)) { + if (!tap_get_vhost_net(nc->peer)) { return features; } - return vhost_net_get_features(tap_get_vhost_net(n->nic->nc.peer), features); + return vhost_net_get_features(tap_get_vhost_net(nc->peer), features); } static uint32_t virtio_net_bad_features(VirtIODevice *vdev) @@ -295,25 +300,25 @@ static uint32_t virtio_net_bad_features(VirtIODevice *vdev) static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) { VirtIONet *n = to_virtio_net(vdev); + NetClientState *nc = qemu_get_queue(n->nic); virtio_net_set_mrg_rx_bufs(n, !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF))); if (n->has_vnet_hdr) { - tap_set_offload(n->nic->nc.peer, + tap_set_offload(nc->peer, (features >> VIRTIO_NET_F_GUEST_CSUM) & 1, (features >> VIRTIO_NET_F_GUEST_TSO4) & 1, (features >> VIRTIO_NET_F_GUEST_TSO6) & 1, (features >> VIRTIO_NET_F_GUEST_ECN) & 1, (features >> VIRTIO_NET_F_GUEST_UFO) & 1); } - if (!n->nic->nc.peer || - n->nic->nc.peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { + if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return; } - if (!tap_get_vhost_net(n->nic->nc.peer)) { + if (!tap_get_vhost_net(nc->peer)) { return; } - vhost_net_ack_features(tap_get_vhost_net(n->nic->nc.peer), features); + vhost_net_ack_features(tap_get_vhost_net(nc->peer), features); } static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, @@ -358,7 +363,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, } s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac)); assert(s == sizeof(n->mac)); - qemu_format_nic_info_str(&n->nic->nc, n->mac); + qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); return VIRTIO_NET_OK; } @@ -496,7 +501,7 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); - qemu_flush_queued_packets(&n->nic->nc); + qemu_flush_queued_packets(qemu_get_queue(n->nic)); } static int virtio_net_can_receive(NetClientState *nc) @@ -638,8 +643,9 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t unsigned mhdr_cnt = 0; size_t offset, i, guest_offset; - if (!virtio_net_can_receive(&n->nic->nc)) + if (!virtio_net_can_receive(qemu_get_queue(n->nic))) { return -1; + } /* hdr_len refers to the header we supply to the guest */ if (!virtio_net_has_buffers(n, size + n->guest_hdr_len - n->host_hdr_len)) @@ -787,7 +793,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) len = n->guest_hdr_len; - ret = qemu_sendv_packet_async(&n->nic->nc, out_sg, out_num, + ret = qemu_sendv_packet_async(qemu_get_queue(n->nic), out_sg, out_num, virtio_net_tx_complete); if (ret == 0) { virtio_queue_set_notification(n->tx_vq, 0); @@ -984,7 +990,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } if (n->has_vnet_hdr) { - tap_set_offload(n->nic->nc.peer, + tap_set_offload(qemu_get_queue(n->nic)->peer, (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_CSUM) & 1, (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO4) & 1, (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO6) & 1, @@ -1022,7 +1028,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) /* nc.link_down can't be migrated, so infer link_down according * to link status bit in n->status */ - n->nic->nc.link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; + qemu_get_queue(n->nic)->link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; return 0; } @@ -1046,16 +1052,18 @@ static NetClientInfo net_virtio_info = { static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) { VirtIONet *n = to_virtio_net(vdev); + NetClientState *nc = qemu_get_queue(n->nic); assert(n->vhost_started); - return vhost_net_virtqueue_pending(tap_get_vhost_net(n->nic->nc.peer), idx); + return vhost_net_virtqueue_pending(tap_get_vhost_net(nc->peer), idx); } static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) { VirtIONet *n = to_virtio_net(vdev); + NetClientState *nc = qemu_get_queue(n->nic); assert(n->vhost_started); - vhost_net_virtqueue_mask(tap_get_vhost_net(n->nic->nc.peer), + vhost_net_virtqueue_mask(tap_get_vhost_net(nc->peer), vdev, idx, mask); } @@ -1102,13 +1110,13 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n); peer_test_vnet_hdr(n); if (peer_has_vnet_hdr(n)) { - tap_using_vnet_hdr(n->nic->nc.peer, true); + tap_using_vnet_hdr(qemu_get_queue(n->nic)->peer, true); n->host_hdr_len = sizeof(struct virtio_net_hdr); } else { n->host_hdr_len = 0; } - qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(n->nic), conf->macaddr.a); n->tx_waiting = 0; n->tx_burst = net->txburst; @@ -1135,7 +1143,7 @@ void virtio_net_exit(VirtIODevice *vdev) /* This will stop vhost backend if appropriate. */ virtio_net_set_status(vdev, 0); - qemu_purge_queued_packets(&n->nic->nc); + qemu_purge_queued_packets(qemu_get_queue(n->nic)); unregister_savevm(n->qdev, "virtio-net", n); @@ -1149,6 +1157,6 @@ void virtio_net_exit(VirtIODevice *vdev) qemu_bh_delete(n->tx_bh); } - qemu_del_net_client(&n->nic->nc); + qemu_del_net_client(qemu_get_queue(n->nic)); virtio_cleanup(&n->vdev); } diff --git a/hw/xen_nic.c b/hw/xen_nic.c index dc12110dba..d5b39eadd3 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -185,9 +185,11 @@ static void net_tx_packets(struct XenNetDev *netdev) } memcpy(tmpbuf, page + txreq.offset, txreq.size); net_checksum_calculate(tmpbuf, txreq.size); - qemu_send_packet(&netdev->nic->nc, tmpbuf, txreq.size); + qemu_send_packet(qemu_get_queue(netdev->nic), tmpbuf, + txreq.size); } else { - qemu_send_packet(&netdev->nic->nc, page + txreq.offset, txreq.size); + qemu_send_packet(qemu_get_queue(netdev->nic), + page + txreq.offset, txreq.size); } xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); net_tx_response(netdev, &txreq, NETIF_RSP_OKAY); @@ -329,7 +331,8 @@ static int net_init(struct XenDevice *xendev) netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, "xen", NULL, netdev); - snprintf(netdev->nic->nc.info_str, sizeof(netdev->nic->nc.info_str), + snprintf(qemu_get_queue(netdev->nic)->info_str, + sizeof(qemu_get_queue(netdev->nic)->info_str), "nic: xenbus vif macaddr=%s", netdev->mac); /* fill info */ @@ -405,7 +408,7 @@ static void net_disconnect(struct XenDevice *xendev) netdev->rxs = NULL; } if (netdev->nic) { - qemu_del_net_client(&netdev->nic->nc); + qemu_del_net_client(qemu_get_queue(netdev->nic)); netdev->nic = NULL; } } @@ -414,7 +417,7 @@ static void net_event(struct XenDevice *xendev) { struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); net_tx_packets(netdev); - qemu_flush_queued_packets(&netdev->nic->nc); + qemu_flush_queued_packets(qemu_get_queue(netdev->nic)); } static int net_free(struct XenDevice *xendev) diff --git a/hw/xgmac.c b/hw/xgmac.c index 00dae7789c..4d7bb13ae1 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -235,7 +235,7 @@ static void xgmac_enet_send(struct XgmacState *s) frame_size += len; if (bd.ctl_stat & 0x20000000) { /* Last buffer in frame. */ - qemu_send_packet(&s->nic->nc, frame, len); + qemu_send_packet(qemu_get_queue(s->nic), frame, len); ptr = frame; frame_size = 0; s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS; @@ -391,7 +391,7 @@ static int xgmac_enet_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) | s->conf.macaddr.a[4]; diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 51c2896e44..a7e8e2cee7 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -826,7 +826,7 @@ axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr) buf[write_off + 1] = csum & 0xff; } - qemu_send_packet(&s->nic->nc, buf, size); + qemu_send_packet(qemu_get_queue(s->nic), buf, size); s->stats.tx_bytes += size; s->regs[R_IS] |= IS_TX_COMPLETE; @@ -853,7 +853,7 @@ static int xilinx_enet_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); tdk_init(&s->TEMAC.phy); mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr); diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 11dfbc3ac1..bdd6ab2467 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -118,7 +118,7 @@ eth_write(void *opaque, hwaddr addr, D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", __func__, addr * 4, value)); if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { - qemu_send_packet(&s->nic->nc, + qemu_send_packet(qemu_get_queue(s->nic), (void *) &s->regs[base], s->regs[base + R_TX_LEN0]); D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0])); @@ -139,7 +139,7 @@ eth_write(void *opaque, hwaddr addr, case R_RX_CTRL0: case R_RX_CTRL1: if (!(value & CTRL_S)) { - qemu_flush_queued_packets(&s->nic->nc); + qemu_flush_queued_packets(qemu_get_queue(s->nic)); } case R_TX_LEN0: case R_TX_LEN1: @@ -228,7 +228,7 @@ static int xilinx_ethlite_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, object_get_typename(OBJECT(dev)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); return 0; } diff --git a/include/net/net.h b/include/net/net.h index 4a92b6c3d2..5d8aecf0dd 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -77,6 +77,7 @@ NICState *qemu_new_nic(NetClientInfo *info, const char *model, const char *name, void *opaque); +NetClientState *qemu_get_queue(NICState *nic); void qemu_del_net_client(NetClientState *nc); NetClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, const char *client_str); diff --git a/net/net.c b/net/net.c index 2f0ab3a121..b98616172d 100644 --- a/net/net.c +++ b/net/net.c @@ -234,6 +234,11 @@ NICState *qemu_new_nic(NetClientInfo *info, return nic; } +NetClientState *qemu_get_queue(NICState *nic) +{ + return &nic->nc; +} + static void qemu_cleanup_net_client(NetClientState *nc) { QTAILQ_REMOVE(&net_clients, nc, next); diff --git a/savevm.c b/savevm.c index b947e6a303..4eb29b2ae2 100644 --- a/savevm.c +++ b/savevm.c @@ -81,7 +81,7 @@ static void qemu_announce_self_iter(NICState *nic, void *opaque) len = announce_self_create(buf, nic->conf->macaddr.a); - qemu_send_packet_raw(&nic->nc, buf, len); + qemu_send_packet_raw(qemu_get_queue(nic), buf, len); } From cc1f0f45425d0cca41ad421623f92bebc93a21a9 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:23 +0800 Subject: [PATCH 0871/1634] net: introduce qemu_get_nic() To support multiqueue, this patch introduces a helper qemu_get_nic() to get NICState from a NetClientState. The following patches would refactor this helper to support multiqueue. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/cadence_gem.c | 8 ++++---- hw/dp8393x.c | 6 +++--- hw/e1000.c | 8 ++++---- hw/eepro100.c | 6 +++--- hw/etraxfs_eth.c | 6 +++--- hw/lan9118.c | 6 +++--- hw/lance.c | 2 +- hw/mcf_fec.c | 6 +++--- hw/milkymist-minimac2.c | 6 +++--- hw/mipsnet.c | 6 +++--- hw/musicpal.c | 4 ++-- hw/ne2000-isa.c | 2 +- hw/ne2000.c | 6 +++--- hw/opencores_eth.c | 6 +++--- hw/pcnet-pci.c | 2 +- hw/pcnet.c | 6 +++--- hw/rtl8139.c | 8 ++++---- hw/smc91c111.c | 6 +++--- hw/spapr_llan.c | 4 ++-- hw/stellaris_enet.c | 6 +++--- hw/usb/dev-network.c | 6 +++--- hw/virtio-net.c | 10 +++++----- hw/xen_nic.c | 4 ++-- hw/xgmac.c | 6 +++--- hw/xilinx_axienet.c | 6 +++--- hw/xilinx_ethlite.c | 6 +++--- include/net/net.h | 2 ++ net/net.c | 20 ++++++++++++++++---- 28 files changed, 92 insertions(+), 78 deletions(-) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index b8071a4695..ab86c1702d 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -409,7 +409,7 @@ static int gem_can_receive(NetClientState *nc) { GemState *s; - s = DO_UPCAST(NICState, nc, nc)->opaque; + s = qemu_get_nic_opaque(nc); DB_PRINT("\n"); @@ -612,7 +612,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) uint8_t rxbuf[2048]; uint8_t *rxbuf_ptr; - s = DO_UPCAST(NICState, nc, nc)->opaque; + s = qemu_get_nic_opaque(nc); /* Do nothing if receive is not enabled. */ if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) { @@ -1152,7 +1152,7 @@ static const MemoryRegionOps gem_ops = { static void gem_cleanup(NetClientState *nc) { - GemState *s = DO_UPCAST(NICState, nc, nc)->opaque; + GemState *s = qemu_get_nic_opaque(nc); DB_PRINT("\n"); s->nic = NULL; @@ -1161,7 +1161,7 @@ static void gem_cleanup(NetClientState *nc) static void gem_set_link(NetClientState *nc) { DB_PRINT("\n"); - phy_update_link(DO_UPCAST(NICState, nc, nc)->opaque); + phy_update_link(qemu_get_nic_opaque(nc)); } static NetClientInfo net_gem_info = { diff --git a/hw/dp8393x.c b/hw/dp8393x.c index c2d0bc8450..0273fad4bf 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -676,7 +676,7 @@ static const MemoryRegionOps dp8393x_ops = { static int nic_can_receive(NetClientState *nc) { - dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque; + dp8393xState *s = qemu_get_nic_opaque(nc); if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN)) return 0; @@ -725,7 +725,7 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) { - dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque; + dp8393xState *s = qemu_get_nic_opaque(nc); uint16_t data[10]; int packet_type; uint32_t available, address; @@ -861,7 +861,7 @@ static void nic_reset(void *opaque) static void nic_cleanup(NetClientState *nc) { - dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque; + dp8393xState *s = qemu_get_nic_opaque(nc); memory_region_del_subregion(s->address_space, &s->mmio); memory_region_destroy(&s->mmio); diff --git a/hw/e1000.c b/hw/e1000.c index 14b09d1949..de2c7009b3 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -748,7 +748,7 @@ receive_filter(E1000State *s, const uint8_t *buf, int size) static void e1000_set_link_status(NetClientState *nc) { - E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + E1000State *s = qemu_get_nic_opaque(nc); uint32_t old_status = s->mac_reg[STATUS]; if (nc->link_down) { @@ -782,7 +782,7 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size) static int e1000_can_receive(NetClientState *nc) { - E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + E1000State *s = qemu_get_nic_opaque(nc); return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1); } @@ -798,7 +798,7 @@ static uint64_t rx_desc_base(E1000State *s) static ssize_t e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + E1000State *s = qemu_get_nic_opaque(nc); struct e1000_rx_desc desc; dma_addr_t base; unsigned int n, rdt; @@ -1235,7 +1235,7 @@ e1000_mmio_setup(E1000State *d) static void e1000_cleanup(NetClientState *nc) { - E1000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + E1000State *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/eepro100.c b/hw/eepro100.c index 5b77bdc47c..f9856ae8c6 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1619,7 +1619,7 @@ static const MemoryRegionOps eepro100_ops = { static int nic_can_receive(NetClientState *nc) { - EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque; + EEPRO100State *s = qemu_get_nic_opaque(nc); TRACE(RXTX, logout("%p\n", s)); return get_ru_state(s) == ru_ready; #if 0 @@ -1633,7 +1633,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) * - Magic packets should set bit 30 in power management driver register. * - Interesting packets should set bit 29 in power management driver register. */ - EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque; + EEPRO100State *s = qemu_get_nic_opaque(nc); uint16_t rfd_status = 0xa000; #if defined(CONFIG_PAD_RECEIVED_FRAMES) uint8_t min_buf[60]; @@ -1835,7 +1835,7 @@ static const VMStateDescription vmstate_eepro100 = { static void nic_cleanup(NetClientState *nc) { - EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque; + EEPRO100State *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 7c4d5880ac..ad36411193 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -523,7 +523,7 @@ static int eth_can_receive(NetClientState *nc) static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + struct fs_eth *eth = qemu_get_nic_opaque(nc); int use_ma0 = eth->regs[RW_REC_CTRL] & 1; int use_ma1 = eth->regs[RW_REC_CTRL] & 2; int r_bcast = eth->regs[RW_REC_CTRL] & 8; @@ -561,7 +561,7 @@ static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) static void eth_set_link(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + struct fs_eth *eth = qemu_get_nic_opaque(nc); D(printf("%s %d\n", __func__, nc->link_down)); eth->phy.link = !nc->link_down; } @@ -578,7 +578,7 @@ static const MemoryRegionOps eth_ops = { static void eth_cleanup(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + struct fs_eth *eth = qemu_get_nic_opaque(nc); /* Disconnect the client. */ eth->dma_out->client.push = NULL; diff --git a/hw/lan9118.c b/hw/lan9118.c index 262f38992b..0e844e535c 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -386,7 +386,7 @@ static void phy_update_link(lan9118_state *s) static void lan9118_set_link(NetClientState *nc) { - phy_update_link(DO_UPCAST(NICState, nc, nc)->opaque); + phy_update_link(qemu_get_nic_opaque(nc)); } static void phy_reset(lan9118_state *s) @@ -512,7 +512,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) static ssize_t lan9118_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - lan9118_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + lan9118_state *s = qemu_get_nic_opaque(nc); int fifo_len; int offset; int src_pos; @@ -1306,7 +1306,7 @@ static const MemoryRegionOps lan9118_16bit_mem_ops = { static void lan9118_cleanup(NetClientState *nc) { - lan9118_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + lan9118_state *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/lance.c b/hw/lance.c index a5997fd64e..4b92425299 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -87,7 +87,7 @@ static const MemoryRegionOps lance_mem_ops = { static void lance_cleanup(NetClientState *nc) { - PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; + PCNetState *d = qemu_get_nic_opaque(nc); pcnet_common_cleanup(d); } diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 8a90bf81ae..909e32b3e0 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -353,13 +353,13 @@ static void mcf_fec_write(void *opaque, hwaddr addr, static int mcf_fec_can_receive(NetClientState *nc) { - mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + mcf_fec_state *s = qemu_get_nic_opaque(nc); return s->rx_enabled; } static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + mcf_fec_state *s = qemu_get_nic_opaque(nc); mcf_fec_bd bd; uint32_t flags = 0; uint32_t addr; @@ -441,7 +441,7 @@ static const MemoryRegionOps mcf_fec_ops = { static void mcf_fec_cleanup(NetClientState *nc) { - mcf_fec_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + mcf_fec_state *s = qemu_get_nic_opaque(nc); memory_region_del_subregion(s->sysmem, &s->iomem); memory_region_destroy(&s->iomem); diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 2a8a4efa46..9992dcceaf 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -280,7 +280,7 @@ static void update_rx_interrupt(MilkymistMinimac2State *s) static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size) { - MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque; + MilkymistMinimac2State *s = qemu_get_nic_opaque(nc); uint32_t r_count; uint32_t r_state; @@ -410,7 +410,7 @@ static const MemoryRegionOps minimac2_ops = { static int minimac2_can_rx(NetClientState *nc) { - MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque; + MilkymistMinimac2State *s = qemu_get_nic_opaque(nc); if (s->regs[R_STATE0] == STATE_LOADED) { return 1; @@ -424,7 +424,7 @@ static int minimac2_can_rx(NetClientState *nc) static void minimac2_cleanup(NetClientState *nc) { - MilkymistMinimac2State *s = DO_UPCAST(NICState, nc, nc)->opaque; + MilkymistMinimac2State *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 15761b1d5d..ff6bf7fdcb 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -64,7 +64,7 @@ static int mipsnet_buffer_full(MIPSnetState *s) static int mipsnet_can_receive(NetClientState *nc) { - MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + MIPSnetState *s = qemu_get_nic_opaque(nc); if (s->busy) return 0; @@ -73,7 +73,7 @@ static int mipsnet_can_receive(NetClientState *nc) static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + MIPSnetState *s = qemu_get_nic_opaque(nc); trace_mipsnet_receive(size); if (!mipsnet_can_receive(nc)) @@ -211,7 +211,7 @@ static const VMStateDescription vmstate_mipsnet = { static void mipsnet_cleanup(NetClientState *nc) { - MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + MIPSnetState *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/musicpal.c b/hw/musicpal.c index 9e22f69fdf..272cb80303 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -190,7 +190,7 @@ static int eth_can_receive(NetClientState *nc) static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - mv88w8618_eth_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); uint32_t desc_addr; mv88w8618_rx_desc desc; int i; @@ -369,7 +369,7 @@ static const MemoryRegionOps mv88w8618_eth_ops = { static void eth_cleanup(NetClientState *nc) { - mv88w8618_eth_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + mv88w8618_eth_state *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index fa47e12857..342c6bdad1 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -38,7 +38,7 @@ typedef struct ISANE2000State { static void isa_ne2000_cleanup(NetClientState *nc) { - NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + NE2000State *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/ne2000.c b/hw/ne2000.c index 03c420998b..c989190c0e 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -167,7 +167,7 @@ static int ne2000_buffer_full(NE2000State *s) int ne2000_can_receive(NetClientState *nc) { - NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + NE2000State *s = qemu_get_nic_opaque(nc); if (s->cmd & E8390_STOP) return 1; @@ -178,7 +178,7 @@ int ne2000_can_receive(NetClientState *nc) ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) { - NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + NE2000State *s = qemu_get_nic_opaque(nc); int size = size_; uint8_t *p; unsigned int total_len, next, avail, len, index, mcast_idx; @@ -706,7 +706,7 @@ void ne2000_setup_io(NE2000State *s, unsigned size) static void ne2000_cleanup(NetClientState *nc) { - NE2000State *s = DO_UPCAST(NICState, nc, nc)->opaque; + NE2000State *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index 2496d4eba1..f9ba5eeaba 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -313,7 +313,7 @@ static void open_eth_int_source_write(OpenEthState *s, static void open_eth_set_link_status(NetClientState *nc) { - OpenEthState *s = DO_UPCAST(NICState, nc, nc)->opaque; + OpenEthState *s = qemu_get_nic_opaque(nc); if (GET_REGBIT(s, MIICOMMAND, SCANSTAT)) { SET_REGFIELD(s, MIISTATUS, LINKFAIL, nc->link_down); @@ -344,7 +344,7 @@ static void open_eth_reset(void *opaque) static int open_eth_can_receive(NetClientState *nc) { - OpenEthState *s = DO_UPCAST(NICState, nc, nc)->opaque; + OpenEthState *s = qemu_get_nic_opaque(nc); return GET_REGBIT(s, MODER, RXEN) && (s->regs[TX_BD_NUM] < 0x80) && @@ -354,7 +354,7 @@ static int open_eth_can_receive(NetClientState *nc) static ssize_t open_eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - OpenEthState *s = DO_UPCAST(NICState, nc, nc)->opaque; + OpenEthState *s = qemu_get_nic_opaque(nc); size_t maxfl = GET_REGFIELD(s, PACKETLEN, MAXFL); size_t minfl = GET_REGFIELD(s, PACKETLEN, MINFL); size_t fcsl = 4; diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 54a849daae..26c90bf372 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -266,7 +266,7 @@ static void pci_physical_memory_read(void *dma_opaque, hwaddr addr, static void pci_pcnet_cleanup(NetClientState *nc) { - PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; + PCNetState *d = qemu_get_nic_opaque(nc); pcnet_common_cleanup(d); } diff --git a/hw/pcnet.c b/hw/pcnet.c index 2126e22ffa..e0de1e3458 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1006,7 +1006,7 @@ static int pcnet_tdte_poll(PCNetState *s) int pcnet_can_receive(NetClientState *nc) { - PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + PCNetState *s = qemu_get_nic_opaque(nc); if (CSR_STOP(s) || CSR_SPND(s)) return 0; @@ -1017,7 +1017,7 @@ int pcnet_can_receive(NetClientState *nc) ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) { - PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + PCNetState *s = qemu_get_nic_opaque(nc); int is_padr = 0, is_bcast = 0, is_ladr = 0; uint8_t buf1[60]; int remaining; @@ -1199,7 +1199,7 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) void pcnet_set_link_status(NetClientState *nc) { - PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; + PCNetState *d = qemu_get_nic_opaque(nc); d->lnkst = nc->link_down ? 0 : 0x40; } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 22d24ae6af..b825e83f0b 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -786,7 +786,7 @@ static bool rtl8139_cp_rx_valid(RTL8139State *s) static int rtl8139_can_receive(NetClientState *nc) { - RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; + RTL8139State *s = qemu_get_nic_opaque(nc); int avail; /* Receive (drop) packets if card is disabled. */ @@ -808,7 +808,7 @@ static int rtl8139_can_receive(NetClientState *nc) static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt) { - RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; + RTL8139State *s = qemu_get_nic_opaque(nc); /* size is the length of the buffer passed to the driver */ int size = size_; const uint8_t *dot1q_buf = NULL; @@ -3429,7 +3429,7 @@ static void rtl8139_timer(void *opaque) static void rtl8139_cleanup(NetClientState *nc) { - RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; + RTL8139State *s = qemu_get_nic_opaque(nc); s->nic = NULL; } @@ -3451,7 +3451,7 @@ static void pci_rtl8139_uninit(PCIDevice *dev) static void rtl8139_set_link_status(NetClientState *nc) { - RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque; + RTL8139State *s = qemu_get_nic_opaque(nc); if (nc->link_down) { s->BasicModeStatus &= ~0x04; diff --git a/hw/smc91c111.c b/hw/smc91c111.c index cf79c69b7e..67fd074d85 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -631,7 +631,7 @@ static uint32_t smc91c111_readl(void *opaque, hwaddr offset) static int smc91c111_can_receive(NetClientState *nc) { - smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + smc91c111_state *s = qemu_get_nic_opaque(nc); if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) return 1; @@ -642,7 +642,7 @@ static int smc91c111_can_receive(NetClientState *nc) static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + smc91c111_state *s = qemu_get_nic_opaque(nc); int status; int packetsize; uint32_t crc; @@ -731,7 +731,7 @@ static const MemoryRegionOps smc91c111_mem_ops = { static void smc91c111_cleanup(NetClientState *nc) { - smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + smc91c111_state *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index d53d4ae021..6ef29362f5 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -85,7 +85,7 @@ typedef struct VIOsPAPRVLANDevice { static int spapr_vlan_can_receive(NetClientState *nc) { - VIOsPAPRVLANDevice *dev = DO_UPCAST(NICState, nc, nc)->opaque; + VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc); return (dev->isopen && dev->rx_bufs > 0); } @@ -93,7 +93,7 @@ static int spapr_vlan_can_receive(NetClientState *nc) static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - VIOsPAPRDevice *sdev = DO_UPCAST(NICState, nc, nc)->opaque; + VIOsPAPRDevice *sdev = qemu_get_nic_opaque(nc); VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF); vlan_bd_t bd; diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 99d473006e..6c701fb67b 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -80,7 +80,7 @@ static void stellaris_enet_update(stellaris_enet_state *s) /* TODO: Implement MAC address filtering. */ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + stellaris_enet_state *s = qemu_get_nic_opaque(nc); int n; uint8_t *p; uint32_t crc; @@ -122,7 +122,7 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si static int stellaris_enet_can_receive(NetClientState *nc) { - stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + stellaris_enet_state *s = qemu_get_nic_opaque(nc); if ((s->rctl & SE_RCTL_RXEN) == 0) return 1; @@ -384,7 +384,7 @@ static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) static void stellaris_enet_cleanup(NetClientState *nc) { - stellaris_enet_state *s = DO_UPCAST(NICState, nc, nc)->opaque; + stellaris_enet_state *s = qemu_get_nic_opaque(nc); unregister_savevm(&s->busdev.qdev, "stellaris_enet", s); diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index a131f9c851..abc6eac591 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1261,7 +1261,7 @@ static void usb_net_handle_data(USBDevice *dev, USBPacket *p) static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + USBNetState *s = qemu_get_nic_opaque(nc); uint8_t *in_buf = s->in_buf; size_t total_size = size; @@ -1308,7 +1308,7 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz static int usbnet_can_receive(NetClientState *nc) { - USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + USBNetState *s = qemu_get_nic_opaque(nc); if (is_rndis(s) && s->rndis_state != RNDIS_DATA_INITIALIZED) { return 1; @@ -1319,7 +1319,7 @@ static int usbnet_can_receive(NetClientState *nc) static void usbnet_cleanup(NetClientState *nc) { - USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; + USBNetState *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 7ad65a2133..e69313b381 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -170,7 +170,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) static void virtio_net_set_link_status(NetClientState *nc) { - VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; + VirtIONet *n = qemu_get_nic_opaque(nc); uint16_t old_status = n->status; if (nc->link_down) @@ -506,7 +506,7 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) static int virtio_net_can_receive(NetClientState *nc) { - VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; + VirtIONet *n = qemu_get_nic_opaque(nc); if (!n->vdev.vm_running) { return 0; } @@ -637,7 +637,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; + VirtIONet *n = qemu_get_nic_opaque(nc); struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; struct virtio_net_hdr_mrg_rxbuf mhdr; unsigned mhdr_cnt = 0; @@ -736,7 +736,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq); static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) { - VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; + VirtIONet *n = qemu_get_nic_opaque(nc); virtqueue_push(n->tx_vq, &n->async_tx.elem, 0); virtio_notify(&n->vdev, n->tx_vq); @@ -1035,7 +1035,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) static void virtio_net_cleanup(NetClientState *nc) { - VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; + VirtIONet *n = qemu_get_nic_opaque(nc); n->nic = NULL; } diff --git a/hw/xen_nic.c b/hw/xen_nic.c index d5b39eadd3..55b79606d4 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -236,7 +236,7 @@ static void net_rx_response(struct XenNetDev *netdev, static int net_rx_ok(NetClientState *nc) { - struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque; + struct XenNetDev *netdev = qemu_get_nic_opaque(nc); RING_IDX rc, rp; if (netdev->xendev.be_state != XenbusStateConnected) { @@ -257,7 +257,7 @@ static int net_rx_ok(NetClientState *nc) static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size) { - struct XenNetDev *netdev = DO_UPCAST(NICState, nc, nc)->opaque; + struct XenNetDev *netdev = qemu_get_nic_opaque(nc); netif_rx_request_t rxreq; RING_IDX rc, rp; void *page; diff --git a/hw/xgmac.c b/hw/xgmac.c index 4d7bb13ae1..50722988b9 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -310,7 +310,7 @@ static const MemoryRegionOps enet_mem_ops = { static int eth_can_rx(NetClientState *nc) { - struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct XgmacState *s = qemu_get_nic_opaque(nc); /* RX enabled? */ return s->regs[DMA_CONTROL] & DMA_CONTROL_SR; @@ -318,7 +318,7 @@ static int eth_can_rx(NetClientState *nc) static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) { - struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct XgmacState *s = qemu_get_nic_opaque(nc); static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int unicast, broadcast, multicast; @@ -366,7 +366,7 @@ out: static void eth_cleanup(NetClientState *nc) { - struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct XgmacState *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index a7e8e2cee7..34e344ce2c 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -617,7 +617,7 @@ static const MemoryRegionOps enet_ops = { static int eth_can_rx(NetClientState *nc) { - struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc); /* RX enabled? */ return !axienet_rx_resetting(s) && axienet_rx_enabled(s); @@ -640,7 +640,7 @@ static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) { - struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc); static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52}; @@ -785,7 +785,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) static void eth_cleanup(NetClientState *nc) { /* FIXME. */ - struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc); g_free(s->rxmem); g_free(s); } diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index bdd6ab2467..21c6f8c49c 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -167,7 +167,7 @@ static const MemoryRegionOps eth_ops = { static int eth_can_rx(NetClientState *nc) { - struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct xlx_ethlite *s = qemu_get_nic_opaque(nc); unsigned int rxbase = s->rxbuf * (0x800 / 4); return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S); @@ -175,7 +175,7 @@ static int eth_can_rx(NetClientState *nc) static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) { - struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct xlx_ethlite *s = qemu_get_nic_opaque(nc); unsigned int rxbase = s->rxbuf * (0x800 / 4); /* DA filter. */ @@ -201,7 +201,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) static void eth_cleanup(NetClientState *nc) { - struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; + struct xlx_ethlite *s = qemu_get_nic_opaque(nc); s->nic = NULL; } diff --git a/include/net/net.h b/include/net/net.h index 5d8aecf0dd..96e05c4117 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -78,6 +78,8 @@ NICState *qemu_new_nic(NetClientInfo *info, const char *name, void *opaque); NetClientState *qemu_get_queue(NICState *nic); +NICState *qemu_get_nic(NetClientState *nc); +void *qemu_get_nic_opaque(NetClientState *nc); void qemu_del_net_client(NetClientState *nc); NetClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, const char *client_str); diff --git a/net/net.c b/net/net.c index b98616172d..606e8606de 100644 --- a/net/net.c +++ b/net/net.c @@ -227,7 +227,7 @@ NICState *qemu_new_nic(NetClientInfo *info, nc = qemu_new_net_client(info, conf->peer, model, name); - nic = DO_UPCAST(NICState, nc, nc); + nic = qemu_get_nic(nc); nic->conf = conf; nic->opaque = opaque; @@ -239,6 +239,18 @@ NetClientState *qemu_get_queue(NICState *nic) return &nic->nc; } +NICState *qemu_get_nic(NetClientState *nc) +{ + return DO_UPCAST(NICState, nc, nc); +} + +void *qemu_get_nic_opaque(NetClientState *nc) +{ + NICState *nic = qemu_get_nic(nc); + + return nic->opaque; +} + static void qemu_cleanup_net_client(NetClientState *nc) { QTAILQ_REMOVE(&net_clients, nc, next); @@ -265,7 +277,7 @@ void qemu_del_net_client(NetClientState *nc) { /* If there is a peer NIC, delete and cleanup client, but do not free. */ if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - NICState *nic = DO_UPCAST(NICState, nc, nc->peer); + NICState *nic = qemu_get_nic(nc->peer); if (nic->peer_deleted) { return; } @@ -281,7 +293,7 @@ void qemu_del_net_client(NetClientState *nc) /* If this is a peer NIC and peer has already been deleted, free it now. */ if (nc->peer && nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - NICState *nic = DO_UPCAST(NICState, nc, nc); + NICState *nic = qemu_get_nic(nc); if (nic->peer_deleted) { qemu_free_net_client(nc->peer); } @@ -297,7 +309,7 @@ void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) QTAILQ_FOREACH(nc, &net_clients, next) { if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - func(DO_UPCAST(NICState, nc, nc), opaque); + func(qemu_get_nic(nc), opaque); } } } From 948ecf219c032e3483b35ba4e162e5eee17d8b77 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:24 +0800 Subject: [PATCH 0872/1634] net: intorduce qemu_del_nic() To support multiqueue nic, this patch separate the nic destructor from qemu_del_net_client() to a new helper qemu_del_nic() since the mapping bettween NiCState and NetClientState were not 1:1 in multiqueue. The following patches would refactor this function to support multiqueue nic. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/e1000.c | 2 +- hw/eepro100.c | 2 +- hw/ne2000.c | 2 +- hw/pcnet-pci.c | 2 +- hw/rtl8139.c | 2 +- hw/usb/dev-network.c | 2 +- hw/virtio-net.c | 2 +- hw/xen_nic.c | 2 +- include/net/net.h | 1 + net/net.c | 15 ++++++++++++++- 10 files changed, 23 insertions(+), 9 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index de2c7009b3..bb150c67dc 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1249,7 +1249,7 @@ pci_e1000_uninit(PCIDevice *dev) qemu_free_timer(d->autoneg_timer); memory_region_destroy(&d->mmio); memory_region_destroy(&d->io); - qemu_del_net_client(qemu_get_queue(d->nic)); + qemu_del_nic(d->nic); } static NetClientInfo net_e1000_info = { diff --git a/hw/eepro100.c b/hw/eepro100.c index f9856ae8c6..5d237968e7 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1849,7 +1849,7 @@ static void pci_nic_uninit(PCIDevice *pci_dev) memory_region_destroy(&s->flash_bar); vmstate_unregister(&pci_dev->qdev, s->vmstate, s); eeprom93xx_free(&pci_dev->qdev, s->eeprom); - qemu_del_net_client(qemu_get_queue(s->nic)); + qemu_del_nic(s->nic); } static NetClientInfo net_eepro100_info = { diff --git a/hw/ne2000.c b/hw/ne2000.c index c989190c0e..3dd1c844e8 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -751,7 +751,7 @@ static void pci_ne2000_exit(PCIDevice *pci_dev) NE2000State *s = &d->ne2000; memory_region_destroy(&s->io); - qemu_del_net_client(qemu_get_queue(s->nic)); + qemu_del_nic(s->nic); } static Property ne2000_properties[] = { diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 26c90bf372..df63b22463 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -279,7 +279,7 @@ static void pci_pcnet_uninit(PCIDevice *dev) memory_region_destroy(&d->io_bar); qemu_del_timer(d->state.poll_timer); qemu_free_timer(d->state.poll_timer); - qemu_del_net_client(qemu_get_queue(d->state.nic)); + qemu_del_nic(d->state.nic); } static NetClientInfo net_pci_pcnet_info = { diff --git a/hw/rtl8139.c b/hw/rtl8139.c index b825e83f0b..d7716beb9e 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3446,7 +3446,7 @@ static void pci_rtl8139_uninit(PCIDevice *dev) } qemu_del_timer(s->timer); qemu_free_timer(s->timer); - qemu_del_net_client(qemu_get_queue(s->nic)); + qemu_del_nic(s->nic); } static void rtl8139_set_link_status(NetClientState *nc) diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index abc6eac591..a01a5e793a 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1330,7 +1330,7 @@ static void usb_net_handle_destroy(USBDevice *dev) /* TODO: remove the nd_table[] entry */ rndis_clear_responsequeue(s); - qemu_del_net_client(qemu_get_queue(s->nic)); + qemu_del_nic(s->nic); } static NetClientInfo net_usbnet_info = { diff --git a/hw/virtio-net.c b/hw/virtio-net.c index e69313b381..a967006cfc 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1157,6 +1157,6 @@ void virtio_net_exit(VirtIODevice *vdev) qemu_bh_delete(n->tx_bh); } - qemu_del_net_client(qemu_get_queue(n->nic)); + qemu_del_nic(n->nic); virtio_cleanup(&n->vdev); } diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 55b79606d4..4be077d320 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -408,7 +408,7 @@ static void net_disconnect(struct XenDevice *xendev) netdev->rxs = NULL; } if (netdev->nic) { - qemu_del_net_client(qemu_get_queue(netdev->nic)); + qemu_del_nic(netdev->nic); netdev->nic = NULL; } } diff --git a/include/net/net.h b/include/net/net.h index 96e05c4117..f0d1aa2117 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -77,6 +77,7 @@ NICState *qemu_new_nic(NetClientInfo *info, const char *model, const char *name, void *opaque); +void qemu_del_nic(NICState *nic); NetClientState *qemu_get_queue(NICState *nic); NICState *qemu_get_nic(NetClientState *nc); void *qemu_get_nic_opaque(NetClientState *nc); diff --git a/net/net.c b/net/net.c index 606e8606de..47d56e3a14 100644 --- a/net/net.c +++ b/net/net.c @@ -291,6 +291,15 @@ void qemu_del_net_client(NetClientState *nc) return; } + assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC); + + qemu_cleanup_net_client(nc); + qemu_free_net_client(nc); +} + +void qemu_del_nic(NICState *nic) +{ + NetClientState *nc = qemu_get_queue(nic); /* If this is a peer NIC and peer has already been deleted, free it now. */ if (nc->peer && nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { NICState *nic = qemu_get_nic(nc); @@ -931,7 +940,11 @@ void net_cleanup(void) NetClientState *nc, *next_vc; QTAILQ_FOREACH_SAFE(nc, &net_clients, next, next_vc) { - qemu_del_net_client(nc); + if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { + qemu_del_nic(qemu_get_nic(nc)); + } else { + qemu_del_net_client(nc); + } } } From 6c51ae73fc68de2a4f11f5a7ebb52a4e79687e7d Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:25 +0800 Subject: [PATCH 0873/1634] net: introduce qemu_find_net_clients_except() In multiqueue, all NetClientState that belongs to the same netdev or nic has the same id. So this patches introduces an helper qemu_find_net_clients_except() which finds all NetClientState with the same id. This will be used by multiqueue networking. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- include/net/net.h | 2 ++ net/net.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/net/net.h b/include/net/net.h index f0d1aa2117..995df5c1ef 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -68,6 +68,8 @@ typedef struct NICState { } NICState; NetClientState *qemu_find_netdev(const char *id); +int qemu_find_net_clients_except(const char *id, NetClientState **ncs, + NetClientOptionsKind type, int max); NetClientState *qemu_new_net_client(NetClientInfo *info, NetClientState *peer, const char *model, diff --git a/net/net.c b/net/net.c index 47d56e3a14..16dd327782 100644 --- a/net/net.c +++ b/net/net.c @@ -508,6 +508,27 @@ NetClientState *qemu_find_netdev(const char *id) return NULL; } +int qemu_find_net_clients_except(const char *id, NetClientState **ncs, + NetClientOptionsKind type, int max) +{ + NetClientState *nc; + int ret = 0; + + QTAILQ_FOREACH(nc, &net_clients, next) { + if (nc->info->type == type) { + continue; + } + if (!strcmp(nc->name, id)) { + if (ret < max) { + ncs[ret] = nc; + } + ret++; + } + } + + return ret; +} + static int nic_get_free_idx(void) { int index; From 18a1541a8da40271056aab99100bdc38283c42ac Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:26 +0800 Subject: [PATCH 0874/1634] net: introduce qemu_net_client_setup() This patch separates the setup of NetClientState from its allocation, this will allow allocating an arrays of NetClientState and does the initialization one by one which is what multiqueue needs. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- net/net.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/net/net.c b/net/net.c index 16dd327782..3a5bdf6b3f 100644 --- a/net/net.c +++ b/net/net.c @@ -182,17 +182,12 @@ static char *assign_name(NetClientState *nc1, const char *model) return g_strdup(buf); } -NetClientState *qemu_new_net_client(NetClientInfo *info, - NetClientState *peer, - const char *model, - const char *name) +static void qemu_net_client_setup(NetClientState *nc, + NetClientInfo *info, + NetClientState *peer, + const char *model, + const char *name) { - NetClientState *nc; - - assert(info->size >= sizeof(NetClientState)); - - nc = g_malloc0(info->size); - nc->info = info; nc->model = g_strdup(model); if (name) { @@ -210,6 +205,20 @@ NetClientState *qemu_new_net_client(NetClientInfo *info, nc->send_queue = qemu_new_net_queue(nc); +} + +NetClientState *qemu_new_net_client(NetClientInfo *info, + NetClientState *peer, + const char *model, + const char *name) +{ + NetClientState *nc; + + assert(info->size >= sizeof(NetClientState)); + + nc = g_malloc0(info->size); + qemu_net_client_setup(nc, info, peer, model, name); + return nc; } From f7860455fd582b171e526b4b4647b9b9c9a3e703 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:27 +0800 Subject: [PATCH 0875/1634] net: introduce NetClientState destructor To allow allocating an array of NetClientState and free it once, this patch introduces destructor of NetClientState. Which could do type specific free, which could be used by multiqueue to free the array once. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- include/net/net.h | 2 ++ net/net.c | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/net/net.h b/include/net/net.h index 995df5c1ef..22adc994df 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -35,6 +35,7 @@ typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); typedef void (NetCleanup) (NetClientState *); typedef void (LinkStatusChanged)(NetClientState *); +typedef void (NetClientDestructor)(NetClientState *); typedef struct NetClientInfo { NetClientOptionsKind type; @@ -58,6 +59,7 @@ struct NetClientState { char *name; char info_str[256]; unsigned receive_disabled : 1; + NetClientDestructor *destructor; }; typedef struct NICState { diff --git a/net/net.c b/net/net.c index 3a5bdf6b3f..98a1934b62 100644 --- a/net/net.c +++ b/net/net.c @@ -182,11 +182,17 @@ static char *assign_name(NetClientState *nc1, const char *model) return g_strdup(buf); } +static void qemu_net_client_destructor(NetClientState *nc) +{ + g_free(nc); +} + static void qemu_net_client_setup(NetClientState *nc, NetClientInfo *info, NetClientState *peer, const char *model, - const char *name) + const char *name, + NetClientDestructor *destructor) { nc->info = info; nc->model = g_strdup(model); @@ -204,7 +210,7 @@ static void qemu_net_client_setup(NetClientState *nc, QTAILQ_INSERT_TAIL(&net_clients, nc, next); nc->send_queue = qemu_new_net_queue(nc); - + nc->destructor = destructor; } NetClientState *qemu_new_net_client(NetClientInfo *info, @@ -217,7 +223,8 @@ NetClientState *qemu_new_net_client(NetClientInfo *info, assert(info->size >= sizeof(NetClientState)); nc = g_malloc0(info->size); - qemu_net_client_setup(nc, info, peer, model, name); + qemu_net_client_setup(nc, info, peer, model, name, + qemu_net_client_destructor); return nc; } @@ -279,7 +286,9 @@ static void qemu_free_net_client(NetClientState *nc) } g_free(nc->name); g_free(nc->model); - g_free(nc); + if (nc->destructor) { + nc->destructor(nc); + } } void qemu_del_net_client(NetClientState *nc) From 1ceef9f27359cbe92ef124bf74de6f792e71f6fb Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:28 +0800 Subject: [PATCH 0876/1634] net: multiqueue support This patch adds basic multiqueue support for qemu. The idea is simple, an array of NetClientStates were introduced in NICState, parse_netdev() were extended to find and match all NetClientStates belongs to the backend and place their pointers in NICConf. Then qemu_new_nic can setup a N:N mapping between NICStates that belongs to a nic and NICStates belongs to the netdev. And a queue_index were introduced in NetClientState to track its index. After this, each peers of a NICState were abstracted as a queue. After this change, all NetClientState that belongs to the same backend/nic has the same id. When use want to change the link status, all NetClientStates that belongs to the same backend/nic will be also changed. When user want to delete a device or netdev, all NetClientStates that belongs to the same backend/nic will be deleted also. Changing or deleting an specific queue is not allowed. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/dp8393x.c | 2 +- hw/mcf_fec.c | 2 +- hw/qdev-properties-system.c | 46 ++++++++++++--- hw/qdev-properties.h | 6 +- include/net/net.h | 18 ++++-- net/net.c | 113 ++++++++++++++++++++++++++---------- 6 files changed, 139 insertions(+), 48 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 0273fad4bf..808157b38b 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -900,7 +900,7 @@ void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ s->conf.macaddr = nd->macaddr; - s->conf.peer = nd->netdev; + s->conf.peers.ncs[0] = nd->netdev; s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s); diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 909e32b3e0..8e60f09fbb 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -472,7 +472,7 @@ void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd, memory_region_add_subregion(sysmem, base, &s->iomem); s->conf.macaddr = nd->macaddr; - s->conf.peer = nd->netdev; + s->conf.peers.ncs[0] = nd->netdev; s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s); diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c index ce0f7933e6..ce3af22193 100644 --- a/hw/qdev-properties-system.c +++ b/hw/qdev-properties-system.c @@ -173,16 +173,47 @@ PropertyInfo qdev_prop_chr = { static int parse_netdev(DeviceState *dev, const char *str, void **ptr) { - NetClientState *netdev = qemu_find_netdev(str); + NICPeers *peers_ptr = (NICPeers *)ptr; + NICConf *conf = container_of(peers_ptr, NICConf, peers); + NetClientState **ncs = peers_ptr->ncs; + NetClientState *peers[MAX_QUEUE_NUM]; + int queues, i = 0; + int ret; - if (netdev == NULL) { - return -ENOENT; + queues = qemu_find_net_clients_except(str, peers, + NET_CLIENT_OPTIONS_KIND_NIC, + MAX_QUEUE_NUM); + if (queues == 0) { + ret = -ENOENT; + goto err; } - if (netdev->peer) { - return -EEXIST; + + if (queues > MAX_QUEUE_NUM) { + ret = -E2BIG; + goto err; } - *ptr = netdev; + + for (i = 0; i < queues; i++) { + if (peers[i] == NULL) { + ret = -ENOENT; + goto err; + } + + if (peers[i]->peer) { + ret = -EEXIST; + goto err; + } + + ncs[i] = peers[i]; + ncs[i]->queue_index = i; + } + + conf->queues = queues; + return 0; + +err: + return ret; } static const char *print_netdev(void *ptr) @@ -249,7 +280,8 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque, { DeviceState *dev = DEVICE(obj); Property *prop = opaque; - NetClientState **ptr = qdev_get_prop_ptr(dev, prop); + NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop); + NetClientState **ptr = &peers_ptr->ncs[0]; Error *local_err = NULL; int32_t id; NetClientState *hubport; diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h index ddcf774506..20c67f3443 100644 --- a/hw/qdev-properties.h +++ b/hw/qdev-properties.h @@ -31,7 +31,7 @@ extern PropertyInfo qdev_prop_pci_host_devaddr; .name = (_name), \ .info = &(_prop), \ .offset = offsetof(_state, _field) \ - + type_check(_type,typeof_field(_state, _field)), \ + + type_check(_type, typeof_field(_state, _field)), \ } #define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \ .name = (_name), \ @@ -77,9 +77,9 @@ extern PropertyInfo qdev_prop_pci_host_devaddr; #define DEFINE_PROP_STRING(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) #define DEFINE_PROP_NETDEV(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*) + DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers) #define DEFINE_PROP_VLAN(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*) + DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NICPeers) #define DEFINE_PROP_DRIVE(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) #define DEFINE_PROP_MACADDR(_n, _s, _f) \ diff --git a/include/net/net.h b/include/net/net.h index 22adc994df..43a045e052 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -9,24 +9,32 @@ #include "migration/vmstate.h" #include "qapi-types.h" +#define MAX_QUEUE_NUM 1024 + struct MACAddr { uint8_t a[6]; }; /* qdev nic properties */ +typedef struct NICPeers { + NetClientState *ncs[MAX_QUEUE_NUM]; +} NICPeers; + typedef struct NICConf { MACAddr macaddr; - NetClientState *peer; + NICPeers peers; int32_t bootindex; + int32_t queues; } NICConf; #define DEFINE_NIC_PROPERTIES(_state, _conf) \ DEFINE_PROP_MACADDR("mac", _state, _conf.macaddr), \ - DEFINE_PROP_VLAN("vlan", _state, _conf.peer), \ - DEFINE_PROP_NETDEV("netdev", _state, _conf.peer), \ + DEFINE_PROP_VLAN("vlan", _state, _conf.peers), \ + DEFINE_PROP_NETDEV("netdev", _state, _conf.peers), \ DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1) + /* Net clients */ typedef void (NetPoll)(NetClientState *, bool enable); @@ -60,10 +68,11 @@ struct NetClientState { char info_str[256]; unsigned receive_disabled : 1; NetClientDestructor *destructor; + unsigned int queue_index; }; typedef struct NICState { - NetClientState nc; + NetClientState ncs[MAX_QUEUE_NUM]; NICConf *conf; void *opaque; bool peer_deleted; @@ -82,6 +91,7 @@ NICState *qemu_new_nic(NetClientInfo *info, const char *name, void *opaque); void qemu_del_nic(NICState *nic); +NetClientState *qemu_get_subqueue(NICState *nic, int queue_index); NetClientState *qemu_get_queue(NICState *nic); NICState *qemu_get_nic(NetClientState *nc); void *qemu_get_nic_opaque(NetClientState *nc); diff --git a/net/net.c b/net/net.c index 98a1934b62..98068625d4 100644 --- a/net/net.c +++ b/net/net.c @@ -236,28 +236,44 @@ NICState *qemu_new_nic(NetClientInfo *info, void *opaque) { NetClientState *nc; + NetClientState **peers = conf->peers.ncs; NICState *nic; + int i; assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC); assert(info->size >= sizeof(NICState)); - nc = qemu_new_net_client(info, conf->peer, model, name); + nc = qemu_new_net_client(info, peers[0], model, name); + nc->queue_index = 0; nic = qemu_get_nic(nc); nic->conf = conf; nic->opaque = opaque; + for (i = 1; i < conf->queues; i++) { + qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, nc->name, + NULL); + nic->ncs[i].queue_index = i; + } + return nic; } +NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) +{ + return &nic->ncs[queue_index]; +} + NetClientState *qemu_get_queue(NICState *nic) { - return &nic->nc; + return qemu_get_subqueue(nic, 0); } NICState *qemu_get_nic(NetClientState *nc) { - return DO_UPCAST(NICState, nc, nc); + NetClientState *nc0 = nc - nc->queue_index; + + return DO_UPCAST(NICState, ncs[0], nc0); } void *qemu_get_nic_opaque(NetClientState *nc) @@ -271,9 +287,7 @@ static void qemu_cleanup_net_client(NetClientState *nc) { QTAILQ_REMOVE(&net_clients, nc, next); - if (nc->info->cleanup) { - nc->info->cleanup(nc); - } + nc->info->cleanup(nc); } static void qemu_free_net_client(NetClientState *nc) @@ -293,6 +307,17 @@ static void qemu_free_net_client(NetClientState *nc) void qemu_del_net_client(NetClientState *nc) { + NetClientState *ncs[MAX_QUEUE_NUM]; + int queues, i; + + /* If the NetClientState belongs to a multiqueue backend, we will change all + * other NetClientStates also. + */ + queues = qemu_find_net_clients_except(nc->name, ncs, + NET_CLIENT_OPTIONS_KIND_NIC, + MAX_QUEUE_NUM); + assert(queues != 0); + /* If there is a peer NIC, delete and cleanup client, but do not free. */ if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { NICState *nic = qemu_get_nic(nc->peer); @@ -300,34 +325,47 @@ void qemu_del_net_client(NetClientState *nc) return; } nic->peer_deleted = true; - /* Let NIC know peer is gone. */ - nc->peer->link_down = true; + + for (i = 0; i < queues; i++) { + ncs[i]->peer->link_down = true; + } + if (nc->peer->info->link_status_changed) { nc->peer->info->link_status_changed(nc->peer); } - qemu_cleanup_net_client(nc); + + for (i = 0; i < queues; i++) { + qemu_cleanup_net_client(ncs[i]); + } + return; } assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC); - qemu_cleanup_net_client(nc); - qemu_free_net_client(nc); + for (i = 0; i < queues; i++) { + qemu_cleanup_net_client(ncs[i]); + qemu_free_net_client(ncs[i]); + } } void qemu_del_nic(NICState *nic) { - NetClientState *nc = qemu_get_queue(nic); + int i, queues = nic->conf->queues; + /* If this is a peer NIC and peer has already been deleted, free it now. */ - if (nc->peer && nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - NICState *nic = qemu_get_nic(nc); - if (nic->peer_deleted) { - qemu_free_net_client(nc->peer); + if (nic->peer_deleted) { + for (i = 0; i < queues; i++) { + qemu_free_net_client(qemu_get_subqueue(nic, i)->peer); } } - qemu_cleanup_net_client(nc); - qemu_free_net_client(nc); + for (i = queues - 1; i >= 0; i--) { + NetClientState *nc = qemu_get_subqueue(nic, i); + + qemu_cleanup_net_client(nc); + qemu_free_net_client(nc); + } } void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) @@ -336,7 +374,9 @@ void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) QTAILQ_FOREACH(nc, &net_clients, next) { if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - func(qemu_get_nic(nc), opaque); + if (nc->queue_index == 0) { + func(qemu_get_nic(nc), opaque); + } } } } @@ -911,8 +951,10 @@ void qmp_netdev_del(const char *id, Error **errp) void print_net_client(Monitor *mon, NetClientState *nc) { - monitor_printf(mon, "%s: type=%s,%s\n", nc->name, - NetClientOptionsKind_lookup[nc->info->type], nc->info_str); + monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, + nc->queue_index, + NetClientOptionsKind_lookup[nc->info->type], + nc->info_str); } void do_info_network(Monitor *mon, const QDict *qdict) @@ -943,20 +985,23 @@ void do_info_network(Monitor *mon, const QDict *qdict) void qmp_set_link(const char *name, bool up, Error **errp) { - NetClientState *nc = NULL; + NetClientState *ncs[MAX_QUEUE_NUM]; + NetClientState *nc; + int queues, i; - QTAILQ_FOREACH(nc, &net_clients, next) { - if (!strcmp(nc->name, name)) { - goto done; - } - } -done: - if (!nc) { + queues = qemu_find_net_clients_except(name, ncs, + NET_CLIENT_OPTIONS_KIND_MAX, + MAX_QUEUE_NUM); + + if (queues == 0) { error_set(errp, QERR_DEVICE_NOT_FOUND, name); return; } + nc = ncs[0]; - nc->link_down = !up; + for (i = 0; i < queues; i++) { + ncs[i]->link_down = !up; + } if (nc->info->link_status_changed) { nc->info->link_status_changed(nc); @@ -976,9 +1021,13 @@ done: void net_cleanup(void) { - NetClientState *nc, *next_vc; + NetClientState *nc; - QTAILQ_FOREACH_SAFE(nc, &net_clients, next, next_vc) { + /* We may del multiple entries during qemu_del_net_client(), + * so QTAILQ_FOREACH_SAFE() is also not safe here. + */ + while (!QTAILQ_EMPTY(&net_clients)) { + nc = QTAILQ_FIRST(&net_clients); if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { qemu_del_nic(qemu_get_nic(nc)); } else { From 4e4f9ae7da90b55fe77307e58c867aa6b02a7384 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:29 +0800 Subject: [PATCH 0877/1634] tap: import linux multiqueue constants Import multiqueue constants from if_tun.h from 3.8-rc3. A new ifr flag IFF_MULTI_QUEUE were introduced to create a multiqueue backend by calling TUNSETIFF with the this flag and with the same interface name many times. A new ioctl TUNSETQUEUE were introduced. When doing this ioctl with IFF_DETACH_QUEUE, the queue were disabled in the linux kernel. When doing this ioctl with IFF_ATTACH_QUEUE, the queue were enabled in the linux kernel. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- net/tap-linux.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/tap-linux.h b/net/tap-linux.h index cb2a6d480a..65087e1419 100644 --- a/net/tap-linux.h +++ b/net/tap-linux.h @@ -29,6 +29,7 @@ #define TUNSETSNDBUF _IOW('T', 212, int) #define TUNGETVNETHDRSZ _IOR('T', 215, int) #define TUNSETVNETHDRSZ _IOW('T', 216, int) +#define TUNSETQUEUE _IOW('T', 217, int) #endif @@ -36,6 +37,9 @@ #define IFF_TAP 0x0002 #define IFF_NO_PI 0x1000 #define IFF_VNET_HDR 0x4000 +#define IFF_MULTI_QUEUE 0x0100 +#define IFF_ATTACH_QUEUE 0x0200 +#define IFF_DETACH_QUEUE 0x0400 /* Features for GSO (TUNSETOFFLOAD). */ #define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ From 5193e5fbb52a33f1f684b0d42d29a452dfd29e4a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:30 +0800 Subject: [PATCH 0878/1634] tap: factor out common tap initialization This patch factors out the common initialization of tap into a new helper net_init_tap_one(). This will be used by multiqueue tap patches. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- net/tap.c | 130 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 57 deletions(-) diff --git a/net/tap.c b/net/tap.c index 5542c98c03..23fb6e0306 100644 --- a/net/tap.c +++ b/net/tap.c @@ -591,6 +591,73 @@ static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr, return fd; } +static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, + const char *model, const char *name, + const char *ifname, const char *script, + const char *downscript, const char *vhostfdname, + int vnet_hdr, int fd) +{ + TAPState *s; + + s = net_tap_fd_init(peer, model, name, fd, vnet_hdr); + if (!s) { + close(fd); + return -1; + } + + if (tap_set_sndbuf(s->fd, tap) < 0) { + return -1; + } + + if (tap->has_fd) { + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); + } else if (tap->has_helper) { + snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", + tap->helper); + } else { + const char *downscript; + + downscript = tap->has_downscript ? tap->downscript : + DEFAULT_NETWORK_DOWN_SCRIPT; + + snprintf(s->nc.info_str, sizeof(s->nc.info_str), + "ifname=%s,script=%s,downscript=%s", ifname, script, + downscript); + + if (strcmp(downscript, "no") != 0) { + snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); + snprintf(s->down_script_arg, sizeof(s->down_script_arg), + "%s", ifname); + } + } + + if (tap->has_vhost ? tap->vhost : + vhostfdname || (tap->has_vhostforce && tap->vhostforce)) { + int vhostfd; + + if (tap->has_vhostfd) { + vhostfd = monitor_handle_fd_param(cur_mon, vhostfdname); + if (vhostfd == -1) { + return -1; + } + } else { + vhostfd = -1; + } + + s->vhost_net = vhost_net_init(&s->nc, vhostfd, + tap->has_vhostforce && tap->vhostforce); + if (!s->vhost_net) { + error_report("vhost-net requested but could not be initialized"); + return -1; + } + } else if (tap->has_vhostfd) { + error_report("vhostfd= is not valid without vhost"); + return -1; + } + + return 0; +} + int net_init_tap(const NetClientOptions *opts, const char *name, NetClientState *peer) { @@ -598,10 +665,10 @@ int net_init_tap(const NetClientOptions *opts, const char *name, int fd, vnet_hdr = 0; const char *model; - TAPState *s; /* for the no-fd, no-helper case */ const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */ + const char *downscript = NULL; char ifname[128]; assert(opts->kind == NET_CLIENT_OPTIONS_KIND_TAP); @@ -647,6 +714,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name, } else { script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT; + downscript = tap->has_downscript ? tap->downscript : + DEFAULT_NETWORK_DOWN_SCRIPT; fd = net_tap_init(tap, &vnet_hdr, script, ifname, sizeof ifname); if (fd == -1) { return -1; @@ -655,62 +724,9 @@ int net_init_tap(const NetClientOptions *opts, const char *name, model = "tap"; } - s = net_tap_fd_init(peer, model, name, fd, vnet_hdr); - if (!s) { - close(fd); - return -1; - } - - if (tap_set_sndbuf(s->fd, tap) < 0) { - return -1; - } - - if (tap->has_fd) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); - } else if (tap->has_helper) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", - tap->helper); - } else { - const char *downscript; - - downscript = tap->has_downscript ? tap->downscript : - DEFAULT_NETWORK_DOWN_SCRIPT; - - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "ifname=%s,script=%s,downscript=%s", ifname, script, - downscript); - - if (strcmp(downscript, "no") != 0) { - snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); - snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname); - } - } - - if (tap->has_vhost ? tap->vhost : - tap->has_vhostfd || (tap->has_vhostforce && tap->vhostforce)) { - int vhostfd; - - if (tap->has_vhostfd) { - vhostfd = monitor_handle_fd_param(cur_mon, tap->vhostfd); - if (vhostfd == -1) { - return -1; - } - } else { - vhostfd = -1; - } - - s->vhost_net = vhost_net_init(&s->nc, vhostfd, - tap->has_vhostforce && tap->vhostforce); - if (!s->vhost_net) { - error_report("vhost-net requested but could not be initialized"); - return -1; - } - } else if (tap->has_vhostfd) { - error_report("vhostfd= is not valid without vhost"); - return -1; - } - - return 0; + return net_init_tap_one(tap, peer, model, name, ifname, script, + downscript, tap->has_vhostfd ? tap->vhostfd : NULL, + vnet_hdr, fd); } VHostNetState *tap_get_vhost_net(NetClientState *nc) From 94fdc6d03034f594c53d5413590e23fcb7ffc268 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:31 +0800 Subject: [PATCH 0879/1634] tap: add Linux multiqueue support This patch add basic multiqueue support for Linux. When multiqueue is needed, we will first check whether kernel support multiqueue tap before creating more queues. Two new functions tap_fd_enable() and tap_fd_disable() were introduced to enable and disable a specific queue. Since the multiqueue is only supported in Linux, return error on other platforms. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- net/tap-aix.c | 10 +++++++++ net/tap-bsd.c | 11 ++++++++++ net/tap-haiku.c | 11 ++++++++++ net/tap-linux.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ net/tap-solaris.c | 11 ++++++++++ net/tap_int.h | 2 ++ 6 files changed, 97 insertions(+) diff --git a/net/tap-aix.c b/net/tap-aix.c index aff6c527e9..66e0574fd7 100644 --- a/net/tap-aix.c +++ b/net/tap-aix.c @@ -59,3 +59,13 @@ void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo) { } + +int tap_fd_enable(int fd) +{ + return -1; +} + +int tap_fd_disable(int fd) +{ + return -1; +} diff --git a/net/tap-bsd.c b/net/tap-bsd.c index 01c705b4c0..cfc7a289f8 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -145,3 +145,14 @@ void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo) { } + +int tap_fd_enable(int fd) +{ + return -1; +} + +int tap_fd_disable(int fd) +{ + return -1; +} + diff --git a/net/tap-haiku.c b/net/tap-haiku.c index 08cc034cee..664d40fb4d 100644 --- a/net/tap-haiku.c +++ b/net/tap-haiku.c @@ -59,3 +59,14 @@ void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo) { } + +int tap_fd_enable(int fd) +{ + return -1; +} + +int tap_fd_disable(int fd) +{ + return -1; +} + diff --git a/net/tap-linux.c b/net/tap-linux.c index 0a6acc7d5a..bdb0a790c8 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -41,6 +41,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required struct ifreq ifr; int fd, ret; int len = sizeof(struct virtio_net_hdr); + int mq_required = 0; TFR(fd = open(PATH_NET_TUN, O_RDWR)); if (fd < 0) { @@ -76,6 +77,20 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required ioctl(fd, TUNSETVNETHDRSZ, &len); } + if (mq_required) { + unsigned int features; + + if ((ioctl(fd, TUNGETFEATURES, &features) != 0) || + !(features & IFF_MULTI_QUEUE)) { + error_report("multiqueue required, but no kernel " + "support for IFF_MULTI_QUEUE available"); + close(fd); + return -1; + } else { + ifr.ifr_flags |= IFF_MULTI_QUEUE; + } + } + if (ifname[0] != '\0') pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); else @@ -209,3 +224,40 @@ void tap_fd_set_offload(int fd, int csum, int tso4, } } } + +/* Enable a specific queue of tap. */ +int tap_fd_enable(int fd) +{ + struct ifreq ifr; + int ret; + + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = IFF_ATTACH_QUEUE; + ret = ioctl(fd, TUNSETQUEUE, (void *) &ifr); + + if (ret != 0) { + error_report("could not enable queue"); + } + + return ret; +} + +/* Disable a specific queue of tap/ */ +int tap_fd_disable(int fd) +{ + struct ifreq ifr; + int ret; + + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = IFF_DETACH_QUEUE; + ret = ioctl(fd, TUNSETQUEUE, (void *) &ifr); + + if (ret != 0) { + error_report("could not disable queue"); + } + + return ret; +} + diff --git a/net/tap-solaris.c b/net/tap-solaris.c index 486a7ea838..12cc392c94 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -225,3 +225,14 @@ void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo) { } + +int tap_fd_enable(int fd) +{ + return -1; +} + +int tap_fd_disable(int fd) +{ + return -1; +} + diff --git a/net/tap_int.h b/net/tap_int.h index 1dffe12a45..ca1c21b451 100644 --- a/net/tap_int.h +++ b/net/tap_int.h @@ -42,5 +42,7 @@ int tap_probe_vnet_hdr_len(int fd, int len); int tap_probe_has_ufo(int fd); void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo); void tap_fd_set_vnet_hdr_len(int fd, int len); +int tap_fd_enable(int fd); +int tap_fd_disable(int fd); #endif /* QEMU_TAP_H */ From 16dbaf905b72636d1bb066968bceabd64eaa1a9d Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:32 +0800 Subject: [PATCH 0880/1634] tap: support enabling or disabling a queue This patch introduce a new bit - enabled in TAPState which tracks whether a specific queue/fd is enabled. The tap/fd is enabled during initialization and could be enabled/disabled by tap_enalbe() and tap_disable() which calls platform specific helpers to do the real work. Polling of a tap fd can only done when the tap was enabled. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- include/net/tap.h | 2 ++ net/tap-win32.c | 10 ++++++++++ net/tap.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/include/net/tap.h b/include/net/tap.h index 883cebff07..a994f20447 100644 --- a/include/net/tap.h +++ b/include/net/tap.h @@ -35,6 +35,8 @@ int tap_has_vnet_hdr_len(NetClientState *nc, int len); void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr); void tap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo); void tap_set_vnet_hdr_len(NetClientState *nc, int len); +int tap_enable(NetClientState *nc); +int tap_disable(NetClientState *nc); int tap_get_fd(NetClientState *nc); diff --git a/net/tap-win32.c b/net/tap-win32.c index 601437ee2d..91e9e844a0 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -764,3 +764,13 @@ void tap_set_vnet_hdr_len(NetClientState *nc, int len) { abort(); } + +int tap_enable(NetClientState *nc) +{ + abort(); +} + +int tap_disable(NetClientState *nc) +{ + abort(); +} diff --git a/net/tap.c b/net/tap.c index 23fb6e0306..8610ba2231 100644 --- a/net/tap.c +++ b/net/tap.c @@ -59,6 +59,7 @@ typedef struct TAPState { bool write_poll; bool using_vnet_hdr; bool has_ufo; + bool enabled; VHostNetState *vhost_net; unsigned host_vnet_hdr_len; } TAPState; @@ -72,9 +73,9 @@ static void tap_writable(void *opaque); static void tap_update_fd_handler(TAPState *s) { qemu_set_fd_handler2(s->fd, - s->read_poll ? tap_can_send : NULL, - s->read_poll ? tap_send : NULL, - s->write_poll ? tap_writable : NULL, + s->read_poll && s->enabled ? tap_can_send : NULL, + s->read_poll && s->enabled ? tap_send : NULL, + s->write_poll && s->enabled ? tap_writable : NULL, s); } @@ -337,6 +338,7 @@ static TAPState *net_tap_fd_init(NetClientState *peer, s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0; s->using_vnet_hdr = false; s->has_ufo = tap_probe_has_ufo(s->fd); + s->enabled = true; tap_set_offload(&s->nc, 0, 0, 0, 0, 0); /* * Make sure host header length is set correctly in tap: @@ -735,3 +737,38 @@ VHostNetState *tap_get_vhost_net(NetClientState *nc) assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); return s->vhost_net; } + +int tap_enable(NetClientState *nc) +{ + TAPState *s = DO_UPCAST(TAPState, nc, nc); + int ret; + + if (s->enabled) { + return 0; + } else { + ret = tap_fd_enable(s->fd); + if (ret == 0) { + s->enabled = true; + tap_update_fd_handler(s); + } + return ret; + } +} + +int tap_disable(NetClientState *nc) +{ + TAPState *s = DO_UPCAST(TAPState, nc, nc); + int ret; + + if (s->enabled == 0) { + return 0; + } else { + ret = tap_fd_disable(s->fd); + if (ret == 0) { + qemu_purge_queued_packets(nc); + s->enabled = false; + tap_update_fd_handler(s); + } + return ret; + } +} From e5dc0b402e64d245956c47cf22776e5206f322dc Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:33 +0800 Subject: [PATCH 0881/1634] tap: introduce a helper to get the name of an interface This patch introduces a helper tap_get_ifname() to get the device name of tap device. This is needed when ifname is unspecified in the command line and qemu were asked to create tap device by itself. In this situation, the name were allocated by kernel, so if multiqueue is asked, we need to fetch its name after creating the first queue. Only linux has this support since it's the only platform that supports multiqueue tap. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- include/net/tap.h | 1 + net/tap-aix.c | 6 ++++++ net/tap-bsd.c | 4 ++++ net/tap-haiku.c | 4 ++++ net/tap-linux.c | 13 +++++++++++++ net/tap-solaris.c | 4 ++++ net/tap_int.h | 1 + 7 files changed, 33 insertions(+) diff --git a/include/net/tap.h b/include/net/tap.h index a994f20447..c3eb85a74e 100644 --- a/include/net/tap.h +++ b/include/net/tap.h @@ -37,6 +37,7 @@ void tap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, int ecn, void tap_set_vnet_hdr_len(NetClientState *nc, int len); int tap_enable(NetClientState *nc); int tap_disable(NetClientState *nc); +int tap_get_ifname(NetClientState *nc, char *ifname); int tap_get_fd(NetClientState *nc); diff --git a/net/tap-aix.c b/net/tap-aix.c index 66e0574fd7..e760e9a0e7 100644 --- a/net/tap-aix.c +++ b/net/tap-aix.c @@ -69,3 +69,9 @@ int tap_fd_disable(int fd) { return -1; } + +int tap_fd_get_ifname(int fd, char *ifname) +{ + return -1; +} + diff --git a/net/tap-bsd.c b/net/tap-bsd.c index cfc7a289f8..4f22109e94 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -156,3 +156,7 @@ int tap_fd_disable(int fd) return -1; } +int tap_fd_get_ifname(int fd, char *ifname) +{ + return -1; +} diff --git a/net/tap-haiku.c b/net/tap-haiku.c index 664d40fb4d..b3b5fbb61e 100644 --- a/net/tap-haiku.c +++ b/net/tap-haiku.c @@ -70,3 +70,7 @@ int tap_fd_disable(int fd) return -1; } +int tap_fd_get_ifname(int fd, char *ifname) +{ + return -1; +} diff --git a/net/tap-linux.c b/net/tap-linux.c index bdb0a790c8..3b21662c13 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -261,3 +261,16 @@ int tap_fd_disable(int fd) return ret; } +int tap_fd_get_ifname(int fd, char *ifname) +{ + struct ifreq ifr; + + if (ioctl(fd, TUNGETIFF, &ifr) != 0) { + error_report("TUNGETIFF ioctl() failed: %s", + strerror(errno)); + return -1; + } + + pstrcpy(ifname, sizeof(ifr.ifr_name), ifr.ifr_name); + return 0; +} diff --git a/net/tap-solaris.c b/net/tap-solaris.c index 12cc392c94..214d95e626 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -236,3 +236,7 @@ int tap_fd_disable(int fd) return -1; } +int tap_fd_get_ifname(int fd, char *ifname) +{ + return -1; +} diff --git a/net/tap_int.h b/net/tap_int.h index ca1c21b451..125f83d5b0 100644 --- a/net/tap_int.h +++ b/net/tap_int.h @@ -44,5 +44,6 @@ void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo); void tap_fd_set_vnet_hdr_len(int fd, int len); int tap_fd_enable(int fd); int tap_fd_disable(int fd); +int tap_fd_get_ifname(int fd, char *ifname); #endif /* QEMU_TAP_H */ From 264986e2c8f14a0f4a32ac6f1e083905833a5fc7 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:34 +0800 Subject: [PATCH 0882/1634] tap: multiqueue support Recently, linux support multiqueue tap which could let userspace call TUNSETIFF for a signle device many times to create multiple file descriptors as independent queues. User could also enable/disabe a specific queue through TUNSETQUEUE. The patch adds the generic infrastructure to create multiqueue taps. To achieve this a new parameter "queues" were introduced to specify how many queues were expected to be created for tap by qemu itself. Alternatively, management could also pass multiple pre-created tap file descriptors separated with ':' through a new parameter fds like -netdev tap,id=hn0,fds="X:Y:..:Z". Multiple vhost file descriptors could also be passed in this way. Each TAPState were still associated to a tap fd, which mean multiple TAPStates were created when user needs multiqueue taps. Since each TAPState contains one NetClientState, with the multiqueue nic support, an N peers of NetClientState were built up. A new parameter, mq_required were introduce in tap_open() to create multiqueue tap fds. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- include/net/tap.h | 1 - net/tap-aix.c | 3 +- net/tap-bsd.c | 3 +- net/tap-haiku.c | 3 +- net/tap-linux.c | 4 +- net/tap-solaris.c | 3 +- net/tap.c | 158 ++++++++++++++++++++++++++++++++++++---------- net/tap_int.h | 3 +- qapi-schema.json | 5 +- 9 files changed, 139 insertions(+), 44 deletions(-) diff --git a/include/net/tap.h b/include/net/tap.h index c3eb85a74e..a994f20447 100644 --- a/include/net/tap.h +++ b/include/net/tap.h @@ -37,7 +37,6 @@ void tap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, int ecn, void tap_set_vnet_hdr_len(NetClientState *nc, int len); int tap_enable(NetClientState *nc); int tap_disable(NetClientState *nc); -int tap_get_ifname(NetClientState *nc, char *ifname); int tap_get_fd(NetClientState *nc); diff --git a/net/tap-aix.c b/net/tap-aix.c index e760e9a0e7..804d16448d 100644 --- a/net/tap-aix.c +++ b/net/tap-aix.c @@ -25,7 +25,8 @@ #include "tap_int.h" #include -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) +int tap_open(char *ifname, int ifname_size, int *vnet_hdr, + int vnet_hdr_required, int mq_required) { fprintf(stderr, "no tap on AIX\n"); return -1; diff --git a/net/tap-bsd.c b/net/tap-bsd.c index 4f22109e94..bcdb2682b5 100644 --- a/net/tap-bsd.c +++ b/net/tap-bsd.c @@ -33,7 +33,8 @@ #include #endif -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) +int tap_open(char *ifname, int ifname_size, int *vnet_hdr, + int vnet_hdr_required, int mq_required) { int fd; #ifdef TAPGIFNAME diff --git a/net/tap-haiku.c b/net/tap-haiku.c index b3b5fbb61e..e5ce436d24 100644 --- a/net/tap-haiku.c +++ b/net/tap-haiku.c @@ -25,7 +25,8 @@ #include "tap_int.h" #include -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) +int tap_open(char *ifname, int ifname_size, int *vnet_hdr, + int vnet_hdr_required, int mq_required) { fprintf(stderr, "no tap on Haiku\n"); return -1; diff --git a/net/tap-linux.c b/net/tap-linux.c index 3b21662c13..a9531892a6 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -36,12 +36,12 @@ #define PATH_NET_TUN "/dev/net/tun" -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) +int tap_open(char *ifname, int ifname_size, int *vnet_hdr, + int vnet_hdr_required, int mq_required) { struct ifreq ifr; int fd, ret; int len = sizeof(struct virtio_net_hdr); - int mq_required = 0; TFR(fd = open(PATH_NET_TUN, O_RDWR)); if (fd < 0) { diff --git a/net/tap-solaris.c b/net/tap-solaris.c index 214d95e626..9c7278f1bf 100644 --- a/net/tap-solaris.c +++ b/net/tap-solaris.c @@ -173,7 +173,8 @@ static int tap_alloc(char *dev, size_t dev_size) return tap_fd; } -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required) +int tap_open(char *ifname, int ifname_size, int *vnet_hdr, + int vnet_hdr_required, int mq_required) { char dev[10]=""; int fd; diff --git a/net/tap.c b/net/tap.c index 8610ba2231..1bf760995d 100644 --- a/net/tap.c +++ b/net/tap.c @@ -558,17 +558,10 @@ int net_init_bridge(const NetClientOptions *opts, const char *name, static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr, const char *setup_script, char *ifname, - size_t ifname_sz) + size_t ifname_sz, int mq_required) { int fd, vnet_hdr_required; - if (tap->has_ifname) { - pstrcpy(ifname, ifname_sz, tap->ifname); - } else { - assert(ifname_sz > 0); - ifname[0] = '\0'; - } - if (tap->has_vnet_hdr) { *vnet_hdr = tap->vnet_hdr; vnet_hdr_required = *vnet_hdr; @@ -577,7 +570,8 @@ static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr, vnet_hdr_required = 0; } - TFR(fd = tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required)); + TFR(fd = tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required, + mq_required)); if (fd < 0) { return -1; } @@ -593,6 +587,8 @@ static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr, return fd; } +#define MAX_TAP_QUEUES 1024 + static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, const char *model, const char *name, const char *ifname, const char *script, @@ -611,17 +607,12 @@ static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, return -1; } - if (tap->has_fd) { + if (tap->has_fd || tap->has_fds) { snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); } else if (tap->has_helper) { snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", tap->helper); } else { - const char *downscript; - - downscript = tap->has_downscript ? tap->downscript : - DEFAULT_NETWORK_DOWN_SCRIPT; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "ifname=%s,script=%s,downscript=%s", ifname, script, downscript); @@ -652,7 +643,7 @@ static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, error_report("vhost-net requested but could not be initialized"); return -1; } - } else if (tap->has_vhostfd) { + } else if (tap->has_vhostfd || tap->has_vhostfds) { error_report("vhostfd= is not valid without vhost"); return -1; } @@ -660,27 +651,54 @@ static int net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, return 0; } +static int get_fds(char *str, char *fds[], int max) +{ + char *ptr = str, *this; + size_t len = strlen(str); + int i = 0; + + while (i < max && ptr < str + len) { + this = strchr(ptr, ':'); + + if (this == NULL) { + fds[i] = g_strdup(ptr); + } else { + fds[i] = g_strndup(ptr, this - ptr); + } + + i++; + if (this == NULL) { + break; + } else { + ptr = this + 1; + } + } + + return i; +} + int net_init_tap(const NetClientOptions *opts, const char *name, NetClientState *peer) { const NetdevTapOptions *tap; - - int fd, vnet_hdr = 0; - const char *model; - + int fd, vnet_hdr = 0, i = 0, queues; /* for the no-fd, no-helper case */ const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */ const char *downscript = NULL; + const char *vhostfdname; char ifname[128]; assert(opts->kind == NET_CLIENT_OPTIONS_KIND_TAP); tap = opts->tap; + queues = tap->has_queues ? tap->queues : 1; + vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL; if (tap->has_fd) { if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_helper) { + tap->has_vnet_hdr || tap->has_helper || tap->has_queues || + tap->has_fds) { error_report("ifname=, script=, downscript=, vnet_hdr=, " - "and helper= are invalid with fd="); + "helper=, queues=, and fds= are invalid with fd="); return -1; } @@ -693,13 +711,61 @@ int net_init_tap(const NetClientOptions *opts, const char *name, vnet_hdr = tap_probe_vnet_hdr(fd); - model = "tap"; + if (net_init_tap_one(tap, peer, "tap", NULL, NULL, + script, downscript, + vhostfdname, vnet_hdr, fd)) { + return -1; + } + } else if (tap->has_fds) { + char *fds[MAX_TAP_QUEUES]; + char *vhost_fds[MAX_TAP_QUEUES]; + int nfds, nvhosts; + if (tap->has_ifname || tap->has_script || tap->has_downscript || + tap->has_vnet_hdr || tap->has_helper || tap->has_queues || + tap->has_fd) { + error_report("ifname=, script=, downscript=, vnet_hdr=, " + "helper=, queues=, and fd= are invalid with fds="); + return -1; + } + + nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES); + if (tap->has_vhostfds) { + nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES); + if (nfds != nvhosts) { + error_report("The number of fds passed does not match the " + "number of vhostfds passed"); + return -1; + } + } + + for (i = 0; i < nfds; i++) { + fd = monitor_handle_fd_param(cur_mon, fds[i]); + if (fd == -1) { + return -1; + } + + fcntl(fd, F_SETFL, O_NONBLOCK); + + if (i == 0) { + vnet_hdr = tap_probe_vnet_hdr(fd); + } else if (vnet_hdr != tap_probe_vnet_hdr(fd)) { + error_report("vnet_hdr not consistent across given tap fds"); + return -1; + } + + if (net_init_tap_one(tap, peer, "tap", name, ifname, + script, downscript, + tap->has_vhostfds ? vhost_fds[i] : NULL, + vnet_hdr, fd)) { + return -1; + } + } } else if (tap->has_helper) { if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr) { + tap->has_vnet_hdr || tap->has_queues || tap->has_fds) { error_report("ifname=, script=, downscript=, and vnet_hdr= " - "are invalid with helper="); + "queues=, and fds= are invalid with helper="); return -1; } @@ -709,26 +775,48 @@ int net_init_tap(const NetClientOptions *opts, const char *name, } fcntl(fd, F_SETFL, O_NONBLOCK); - vnet_hdr = tap_probe_vnet_hdr(fd); - model = "bridge"; - + if (net_init_tap_one(tap, peer, "bridge", name, ifname, + script, downscript, vhostfdname, + vnet_hdr, fd)) { + return -1; + } } else { script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT; downscript = tap->has_downscript ? tap->downscript : DEFAULT_NETWORK_DOWN_SCRIPT; - fd = net_tap_init(tap, &vnet_hdr, script, ifname, sizeof ifname); - if (fd == -1) { - return -1; + + if (tap->has_ifname) { + pstrcpy(ifname, sizeof ifname, tap->ifname); + } else { + ifname[0] = '\0'; } - model = "tap"; + for (i = 0; i < queues; i++) { + fd = net_tap_init(tap, &vnet_hdr, i >= 1 ? "no" : script, + ifname, sizeof ifname, queues > 1); + if (fd == -1) { + return -1; + } + + if (queues > 1 && i == 0 && !tap->has_ifname) { + if (tap_fd_get_ifname(fd, ifname)) { + error_report("Fail to get ifname"); + return -1; + } + } + + if (net_init_tap_one(tap, peer, "tap", name, ifname, + i >= 1 ? "no" : script, + i >= 1 ? "no" : downscript, + vhostfdname, vnet_hdr, fd)) { + return -1; + } + } } - return net_init_tap_one(tap, peer, model, name, ifname, script, - downscript, tap->has_vhostfd ? tap->vhostfd : NULL, - vnet_hdr, fd); + return 0; } VHostNetState *tap_get_vhost_net(NetClientState *nc) diff --git a/net/tap_int.h b/net/tap_int.h index 125f83d5b0..86bb224bc8 100644 --- a/net/tap_int.h +++ b/net/tap_int.h @@ -32,7 +32,8 @@ #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required); +int tap_open(char *ifname, int ifname_size, int *vnet_hdr, + int vnet_hdr_required, int mq_required); ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen); diff --git a/qapi-schema.json b/qapi-schema.json index 3a4817b391..cdd8384915 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2533,6 +2533,7 @@ 'data': { '*ifname': 'str', '*fd': 'str', + '*fds': 'str', '*script': 'str', '*downscript': 'str', '*helper': 'str', @@ -2540,7 +2541,9 @@ '*vnet_hdr': 'bool', '*vhost': 'bool', '*vhostfd': 'str', - '*vhostforce': 'bool' } } + '*vhostfds': 'str', + '*vhostforce': 'bool', + '*queues': 'uint32'} } ## # @NetdevSocketOptions From a9f98bb5ebe6fb1869321dcc58e72041ae626ad8 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:35 +0800 Subject: [PATCH 0883/1634] vhost: multiqueue support This patch lets vhost support multiqueue. The idea is simple, just launching multiple threads of vhost and let each of vhost thread processing a subset of the virtqueues of the device. After this change each emulated device can have multiple vhost threads as its backend. To do this, a virtqueue index were introduced to record to first virtqueue that will be handled by this vhost_net device. Based on this and nvqs, vhost could calculate its relative index to setup vhost_net device. Since we may have many vhost/net devices for a virtio-net device. The setting of guest notifiers were moved out of the starting/stopping of a specific vhost thread. The vhost_net_{start|stop}() were renamed to vhost_net_{start|stop}_one(), and a new vhost_net_{start|stop}() were introduced to configure the guest notifiers and start/stop all vhost/vhost_net devices. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/vhost.c | 82 +++++++++++++++++++++------------------------- hw/vhost.h | 2 ++ hw/vhost_net.c | 86 ++++++++++++++++++++++++++++++++++++++++++++----- hw/vhost_net.h | 4 +-- hw/virtio-net.c | 4 +-- 5 files changed, 120 insertions(+), 58 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index 0dd2a9aa40..8d41fdb53f 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -616,14 +616,17 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, { hwaddr s, l, a; int r; + int vhost_vq_index = idx - dev->vq_index; struct vhost_vring_file file = { - .index = idx, + .index = vhost_vq_index }; struct vhost_vring_state state = { - .index = idx, + .index = vhost_vq_index }; struct VirtQueue *vvq = virtio_get_queue(vdev, idx); + assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); + vq->num = state.num = virtio_queue_get_num(vdev, idx); r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state); if (r) { @@ -666,11 +669,12 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, goto fail_alloc_ring; } - r = vhost_virtqueue_set_addr(dev, vq, idx, dev->log_enabled); + r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled); if (r < 0) { r = -errno; goto fail_alloc; } + file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file); if (r) { @@ -706,9 +710,10 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, unsigned idx) { struct vhost_vring_state state = { - .index = idx, + .index = idx - dev->vq_index }; int r; + assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state); if (r < 0) { fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r); @@ -864,7 +869,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) } for (i = 0; i < hdev->nvqs; ++i) { - r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, true); + r = vdev->binding->set_host_notifier(vdev->binding_opaque, + hdev->vq_index + i, + true); if (r < 0) { fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r); goto fail_vq; @@ -874,7 +881,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) return 0; fail_vq: while (--i >= 0) { - r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false); + r = vdev->binding->set_host_notifier(vdev->binding_opaque, + hdev->vq_index + i, + false); if (r < 0) { fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r); fflush(stderr); @@ -895,7 +904,9 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) int i, r; for (i = 0; i < hdev->nvqs; ++i) { - r = vdev->binding->set_host_notifier(vdev->binding_opaque, i, false); + r = vdev->binding->set_host_notifier(vdev->binding_opaque, + hdev->vq_index + i, + false); if (r < 0) { fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r); fflush(stderr); @@ -909,8 +920,9 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) */ bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n) { - struct vhost_virtqueue *vq = hdev->vqs + n; + struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index; assert(hdev->started); + assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs); return event_notifier_test_and_clear(&vq->masked_notifier); } @@ -919,15 +931,16 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, bool mask) { struct VirtQueue *vvq = virtio_get_queue(vdev, n); - int r; + int r, index = n - hdev->vq_index; assert(hdev->started); + assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs); struct vhost_vring_file file = { - .index = n, + .index = index }; if (mask) { - file.fd = event_notifier_get_fd(&hdev->vqs[n].masked_notifier); + file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier); } else { file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq)); } @@ -942,20 +955,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->started = true; - if (!vdev->binding->set_guest_notifiers) { - fprintf(stderr, "binding does not support guest notifiers\n"); - r = -ENOSYS; - goto fail; - } - - r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, - hdev->nvqs, - true); - if (r < 0) { - fprintf(stderr, "Error binding guest notifier: %d\n", -r); - goto fail_notifiers; - } - r = vhost_dev_set_features(hdev, hdev->log_enabled); if (r < 0) { goto fail_features; @@ -967,9 +966,9 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) } for (i = 0; i < hdev->nvqs; ++i) { r = vhost_virtqueue_start(hdev, - vdev, - hdev->vqs + i, - i); + vdev, + hdev->vqs + i, + hdev->vq_index + i); if (r < 0) { goto fail_vq; } @@ -992,15 +991,13 @@ fail_log: fail_vq: while (--i >= 0) { vhost_virtqueue_stop(hdev, - vdev, - hdev->vqs + i, - i); + vdev, + hdev->vqs + i, + hdev->vq_index + i); } + i = hdev->nvqs; fail_mem: fail_features: - vdev->binding->set_guest_notifiers(vdev->binding_opaque, hdev->nvqs, false); -fail_notifiers: -fail: hdev->started = false; return r; @@ -1009,29 +1006,22 @@ fail: /* Host notifiers must be enabled at this point. */ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) { - int i, r; + int i; for (i = 0; i < hdev->nvqs; ++i) { vhost_virtqueue_stop(hdev, - vdev, - hdev->vqs + i, - i); + vdev, + hdev->vqs + i, + hdev->vq_index + i); } for (i = 0; i < hdev->n_mem_sections; ++i) { vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i], 0, (hwaddr)~0x0ull); } - r = vdev->binding->set_guest_notifiers(vdev->binding_opaque, - hdev->nvqs, - false); - if (r < 0) { - fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); - fflush(stderr); - } - assert (r >= 0); hdev->started = false; g_free(hdev->log); hdev->log = NULL; hdev->log_size = 0; } + diff --git a/hw/vhost.h b/hw/vhost.h index 44c61a5877..f062d48807 100644 --- a/hw/vhost.h +++ b/hw/vhost.h @@ -35,6 +35,8 @@ struct vhost_dev { MemoryRegionSection *mem_sections; struct vhost_virtqueue *vqs; int nvqs; + /* the first virtuque which would be used by this vhost dev */ + int vq_index; unsigned long long features; unsigned long long acked_features; unsigned long long backend_features; diff --git a/hw/vhost_net.c b/hw/vhost_net.c index d3a04caef6..8693ac27f6 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -140,12 +140,21 @@ bool vhost_net_query(VHostNetState *net, VirtIODevice *dev) return vhost_dev_query(&net->dev, dev); } -int vhost_net_start(struct vhost_net *net, - VirtIODevice *dev) +static int vhost_net_start_one(struct vhost_net *net, + VirtIODevice *dev, + int vq_index) { struct vhost_vring_file file = { }; int r; + if (net->dev.started) { + return 0; + } + + net->dev.nvqs = 2; + net->dev.vqs = net->vqs; + net->dev.vq_index = vq_index; + r = vhost_dev_enable_notifiers(&net->dev, dev); if (r < 0) { goto fail_notifiers; @@ -181,11 +190,15 @@ fail_notifiers: return r; } -void vhost_net_stop(struct vhost_net *net, - VirtIODevice *dev) +static void vhost_net_stop_one(struct vhost_net *net, + VirtIODevice *dev) { struct vhost_vring_file file = { .fd = -1 }; + if (!net->dev.started) { + return; + } + for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file); assert(r >= 0); @@ -195,6 +208,61 @@ void vhost_net_stop(struct vhost_net *net, vhost_dev_disable_notifiers(&net->dev, dev); } +int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, + int total_queues) +{ + int r, i = 0; + + if (!dev->binding->set_guest_notifiers) { + error_report("binding does not support guest notifiers\n"); + r = -ENOSYS; + goto err; + } + + for (i = 0; i < total_queues; i++) { + r = vhost_net_start_one(tap_get_vhost_net(ncs[i].peer), dev, i * 2); + + if (r < 0) { + goto err; + } + } + + r = dev->binding->set_guest_notifiers(dev->binding_opaque, + total_queues * 2, + true); + if (r < 0) { + error_report("Error binding guest notifier: %d\n", -r); + goto err; + } + + return 0; + +err: + while (--i >= 0) { + vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev); + } + return r; +} + +void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, + int total_queues) +{ + int i, r; + + r = dev->binding->set_guest_notifiers(dev->binding_opaque, + total_queues * 2, + false); + if (r < 0) { + fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r); + fflush(stderr); + } + assert(r >= 0); + + for (i = 0; i < total_queues; i++) { + vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev); + } +} + void vhost_net_cleanup(struct vhost_net *net) { vhost_dev_cleanup(&net->dev); @@ -224,13 +292,15 @@ bool vhost_net_query(VHostNetState *net, VirtIODevice *dev) return false; } -int vhost_net_start(struct vhost_net *net, - VirtIODevice *dev) +int vhost_net_start(VirtIODevice *dev, + NetClientState *ncs, + int total_queues) { return -ENOSYS; } -void vhost_net_stop(struct vhost_net *net, - VirtIODevice *dev) +void vhost_net_stop(VirtIODevice *dev, + NetClientState *ncs, + int total_queues) { } diff --git a/hw/vhost_net.h b/hw/vhost_net.h index 88912b85fd..2d936bb5f5 100644 --- a/hw/vhost_net.h +++ b/hw/vhost_net.h @@ -9,8 +9,8 @@ typedef struct vhost_net VHostNetState; VHostNetState *vhost_net_init(NetClientState *backend, int devfd, bool force); bool vhost_net_query(VHostNetState *net, VirtIODevice *dev); -int vhost_net_start(VHostNetState *net, VirtIODevice *dev); -void vhost_net_stop(VHostNetState *net, VirtIODevice *dev); +int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, int total_queues); +void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, int total_queues); void vhost_net_cleanup(VHostNetState *net); diff --git a/hw/virtio-net.c b/hw/virtio-net.c index a967006cfc..f4146aafc8 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -130,14 +130,14 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) return; } n->vhost_started = 1; - r = vhost_net_start(tap_get_vhost_net(nc->peer), &n->vdev); + r = vhost_net_start(&n->vdev, nc, 1); if (r < 0) { error_report("unable to start vhost net: %d: " "falling back on userspace virtio", -r); n->vhost_started = 0; } } else { - vhost_net_stop(tap_get_vhost_net(nc->peer), &n->vdev); + vhost_net_stop(&n->vdev, nc, 1); n->vhost_started = 0; } } From f23fd811ac4f49f482058cad3b465dc5dc0edc11 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:36 +0800 Subject: [PATCH 0884/1634] virtio: introduce virtio_del_queue() Some device (such as virtio-net) needs the ability to destroy or re-order the virtqueues, this patch adds a helper to do this. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/virtio.c | 9 +++++++++ hw/virtio.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/hw/virtio.c b/hw/virtio.c index ca170c319e..d8c77b054d 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -701,6 +701,15 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, return &vdev->vq[i]; } +void virtio_del_queue(VirtIODevice *vdev, int n) +{ + if (n < 0 || n >= VIRTIO_PCI_QUEUE_MAX) { + abort(); + } + + vdev->vq[n].vring.num = 0; +} + void virtio_irq(VirtQueue *vq) { trace_virtio_irq(vq); diff --git a/hw/virtio.h b/hw/virtio.h index 9cc7b85671..d3da1d25df 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -181,6 +181,8 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, void (*handle_output)(VirtIODevice *, VirtQueue *)); +void virtio_del_queue(VirtIODevice *vdev, int n); + void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len); void virtqueue_flush(VirtQueue *vq, unsigned int count); From e78a2b4285f6cc125dc7a514bebef97d9af1d812 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:37 +0800 Subject: [PATCH 0885/1634] virtio: add a queue_index to VirtQueue Add a queue_index to VirtQueue and a helper to fetch it, this could be used by multiqueue supported device. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/virtio.c | 8 ++++++++ hw/virtio.h | 1 + 2 files changed, 9 insertions(+) diff --git a/hw/virtio.c b/hw/virtio.c index d8c77b054d..e259348518 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -73,6 +73,8 @@ struct VirtQueue /* Notification enabled? */ bool notification; + uint16_t queue_index; + int inuse; uint16_t vector; @@ -931,6 +933,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { vdev->vq[i].vector = VIRTIO_NO_VECTOR; vdev->vq[i].vdev = vdev; + vdev->vq[i].queue_index = i; } vdev->name = name; @@ -1018,6 +1021,11 @@ VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n) return vdev->vq + n; } +uint16_t virtio_get_queue_index(VirtQueue *vq) +{ + return vq->queue_index; +} + static void virtio_queue_guest_notifier_read(EventNotifier *n) { VirtQueue *vq = container_of(n, VirtQueue, guest_notifier); diff --git a/hw/virtio.h b/hw/virtio.h index d3da1d25df..a29a54d4f3 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -280,6 +280,7 @@ hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n); uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n); void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx); VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n); +uint16_t virtio_get_queue_index(VirtQueue *vq); int virtio_queue_get_id(VirtQueue *vq); EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq); void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, From 0c87e93e3102f0c717f58ed90858e6b410fd4e04 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:38 +0800 Subject: [PATCH 0886/1634] virtio-net: separate virtqueue from VirtIONet To support multiqueue virtio-net, the first step is to separate the virtqueue related fields from VirtIONet to a new structure VirtIONetQueue. The following patches will add an array of VirtIONetQueue to VirtIONet based on this patch. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/virtio-net.c | 195 ++++++++++++++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 81 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index f4146aafc8..4b285c128d 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -26,28 +26,33 @@ #define MAC_TABLE_ENTRIES 64 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ +typedef struct VirtIONetQueue { + VirtQueue *rx_vq; + VirtQueue *tx_vq; + QEMUTimer *tx_timer; + QEMUBH *tx_bh; + int tx_waiting; + struct { + VirtQueueElement elem; + ssize_t len; + } async_tx; + struct VirtIONet *n; +} VirtIONetQueue; + typedef struct VirtIONet { VirtIODevice vdev; uint8_t mac[ETH_ALEN]; uint16_t status; - VirtQueue *rx_vq; - VirtQueue *tx_vq; + VirtIONetQueue vq; VirtQueue *ctrl_vq; NICState *nic; - QEMUTimer *tx_timer; - QEMUBH *tx_bh; uint32_t tx_timeout; int32_t tx_burst; - int tx_waiting; uint32_t has_vnet_hdr; size_t host_hdr_len; size_t guest_hdr_len; uint8_t has_ufo; - struct { - VirtQueueElement elem; - ssize_t len; - } async_tx; int mergeable_rx_bufs; uint8_t promisc; uint8_t allmulti; @@ -67,6 +72,12 @@ typedef struct VirtIONet DeviceState *qdev; } VirtIONet; +static VirtIONetQueue *virtio_net_get_queue(NetClientState *nc) +{ + VirtIONet *n = qemu_get_nic_opaque(nc); + + return &n->vq; +} /* TODO * - we could suppress RX interrupt if we were so inclined. */ @@ -135,6 +146,8 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) error_report("unable to start vhost net: %d: " "falling back on userspace virtio", -r); n->vhost_started = 0; + } else { + n->vhost_started = 1; } } else { vhost_net_stop(&n->vdev, nc, 1); @@ -145,25 +158,26 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = to_virtio_net(vdev); + VirtIONetQueue *q = &n->vq; virtio_net_vhost_status(n, status); - if (!n->tx_waiting) { + if (!q->tx_waiting) { return; } if (virtio_net_started(n, status) && !n->vhost_started) { - if (n->tx_timer) { - qemu_mod_timer(n->tx_timer, + if (q->tx_timer) { + qemu_mod_timer(q->tx_timer, qemu_get_clock_ns(vm_clock) + n->tx_timeout); } else { - qemu_bh_schedule(n->tx_bh); + qemu_bh_schedule(q->tx_bh); } } else { - if (n->tx_timer) { - qemu_del_timer(n->tx_timer); + if (q->tx_timer) { + qemu_del_timer(q->tx_timer); } else { - qemu_bh_cancel(n->tx_bh); + qemu_bh_cancel(q->tx_bh); } } } @@ -507,35 +521,40 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) static int virtio_net_can_receive(NetClientState *nc) { VirtIONet *n = qemu_get_nic_opaque(nc); + VirtIONetQueue *q = virtio_net_get_queue(nc); + if (!n->vdev.vm_running) { return 0; } - if (!virtio_queue_ready(n->rx_vq) || - !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) + if (!virtio_queue_ready(q->rx_vq) || + !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { return 0; + } return 1; } -static int virtio_net_has_buffers(VirtIONet *n, int bufsize) +static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) { - if (virtio_queue_empty(n->rx_vq) || + VirtIONet *n = q->n; + if (virtio_queue_empty(q->rx_vq) || (n->mergeable_rx_bufs && - !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) { - virtio_queue_set_notification(n->rx_vq, 1); + !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { + virtio_queue_set_notification(q->rx_vq, 1); /* To avoid a race condition where the guest has made some buffers * available after the above check but before notification was * enabled, check for available buffers again. */ - if (virtio_queue_empty(n->rx_vq) || + if (virtio_queue_empty(q->rx_vq) || (n->mergeable_rx_bufs && - !virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) + !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) { return 0; + } } - virtio_queue_set_notification(n->rx_vq, 0); + virtio_queue_set_notification(q->rx_vq, 0); return 1; } @@ -638,6 +657,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size) { VirtIONet *n = qemu_get_nic_opaque(nc); + VirtIONetQueue *q = virtio_net_get_queue(nc); struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; struct virtio_net_hdr_mrg_rxbuf mhdr; unsigned mhdr_cnt = 0; @@ -648,8 +668,9 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t } /* hdr_len refers to the header we supply to the guest */ - if (!virtio_net_has_buffers(n, size + n->guest_hdr_len - n->host_hdr_len)) + if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) { return 0; + } if (!receive_filter(n, buf, size)) return size; @@ -663,7 +684,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t total = 0; - if (virtqueue_pop(n->rx_vq, &elem) == 0) { + if (virtqueue_pop(q->rx_vq, &elem) == 0) { if (i == 0) return -1; error_report("virtio-net unexpected empty queue: " @@ -716,7 +737,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t } /* signal other side */ - virtqueue_fill(n->rx_vq, &elem, total, i++); + virtqueue_fill(q->rx_vq, &elem, total, i++); } if (mhdr_cnt) { @@ -726,30 +747,32 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t &mhdr.num_buffers, sizeof mhdr.num_buffers); } - virtqueue_flush(n->rx_vq, i); - virtio_notify(&n->vdev, n->rx_vq); + virtqueue_flush(q->rx_vq, i); + virtio_notify(&n->vdev, q->rx_vq); return size; } -static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq); +static int32_t virtio_net_flush_tx(VirtIONetQueue *q); static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) { VirtIONet *n = qemu_get_nic_opaque(nc); + VirtIONetQueue *q = virtio_net_get_queue(nc); - virtqueue_push(n->tx_vq, &n->async_tx.elem, 0); - virtio_notify(&n->vdev, n->tx_vq); + virtqueue_push(q->tx_vq, &q->async_tx.elem, 0); + virtio_notify(&n->vdev, q->tx_vq); - n->async_tx.elem.out_num = n->async_tx.len = 0; + q->async_tx.elem.out_num = q->async_tx.len = 0; - virtio_queue_set_notification(n->tx_vq, 1); - virtio_net_flush_tx(n, n->tx_vq); + virtio_queue_set_notification(q->tx_vq, 1); + virtio_net_flush_tx(q); } /* TX */ -static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) +static int32_t virtio_net_flush_tx(VirtIONetQueue *q) { + VirtIONet *n = q->n; VirtQueueElement elem; int32_t num_packets = 0; if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { @@ -758,12 +781,12 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) assert(n->vdev.vm_running); - if (n->async_tx.elem.out_num) { - virtio_queue_set_notification(n->tx_vq, 0); + if (q->async_tx.elem.out_num) { + virtio_queue_set_notification(q->tx_vq, 0); return num_packets; } - while (virtqueue_pop(vq, &elem)) { + while (virtqueue_pop(q->tx_vq, &elem)) { ssize_t ret, len; unsigned int out_num = elem.out_num; struct iovec *out_sg = &elem.out_sg[0]; @@ -796,16 +819,16 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) ret = qemu_sendv_packet_async(qemu_get_queue(n->nic), out_sg, out_num, virtio_net_tx_complete); if (ret == 0) { - virtio_queue_set_notification(n->tx_vq, 0); - n->async_tx.elem = elem; - n->async_tx.len = len; + virtio_queue_set_notification(q->tx_vq, 0); + q->async_tx.elem = elem; + q->async_tx.len = len; return -EBUSY; } len += ret; - virtqueue_push(vq, &elem, 0); - virtio_notify(&n->vdev, vq); + virtqueue_push(q->tx_vq, &elem, 0); + virtio_notify(&n->vdev, q->tx_vq); if (++num_packets >= n->tx_burst) { break; @@ -817,22 +840,23 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); + VirtIONetQueue *q = &n->vq; /* This happens when device was stopped but VCPU wasn't. */ if (!n->vdev.vm_running) { - n->tx_waiting = 1; + q->tx_waiting = 1; return; } - if (n->tx_waiting) { + if (q->tx_waiting) { virtio_queue_set_notification(vq, 1); - qemu_del_timer(n->tx_timer); - n->tx_waiting = 0; - virtio_net_flush_tx(n, vq); + qemu_del_timer(q->tx_timer); + q->tx_waiting = 0; + virtio_net_flush_tx(q); } else { - qemu_mod_timer(n->tx_timer, + qemu_mod_timer(q->tx_timer, qemu_get_clock_ns(vm_clock) + n->tx_timeout); - n->tx_waiting = 1; + q->tx_waiting = 1; virtio_queue_set_notification(vq, 0); } } @@ -840,48 +864,51 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); + VirtIONetQueue *q = &n->vq; - if (unlikely(n->tx_waiting)) { + if (unlikely(q->tx_waiting)) { return; } - n->tx_waiting = 1; + q->tx_waiting = 1; /* This happens when device was stopped but VCPU wasn't. */ if (!n->vdev.vm_running) { return; } virtio_queue_set_notification(vq, 0); - qemu_bh_schedule(n->tx_bh); + qemu_bh_schedule(q->tx_bh); } static void virtio_net_tx_timer(void *opaque) { - VirtIONet *n = opaque; + VirtIONetQueue *q = opaque; + VirtIONet *n = q->n; assert(n->vdev.vm_running); - n->tx_waiting = 0; + q->tx_waiting = 0; /* Just in case the driver is not ready on more */ if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) return; - virtio_queue_set_notification(n->tx_vq, 1); - virtio_net_flush_tx(n, n->tx_vq); + virtio_queue_set_notification(q->tx_vq, 1); + virtio_net_flush_tx(q); } static void virtio_net_tx_bh(void *opaque) { - VirtIONet *n = opaque; + VirtIONetQueue *q = opaque; + VirtIONet *n = q->n; int32_t ret; assert(n->vdev.vm_running); - n->tx_waiting = 0; + q->tx_waiting = 0; /* Just in case the driver is not ready on more */ if (unlikely(!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))) return; - ret = virtio_net_flush_tx(n, n->tx_vq); + ret = virtio_net_flush_tx(q); if (ret == -EBUSY) { return; /* Notification re-enable handled by tx_complete */ } @@ -889,25 +916,26 @@ static void virtio_net_tx_bh(void *opaque) /* If we flush a full burst of packets, assume there are * more coming and immediately reschedule */ if (ret >= n->tx_burst) { - qemu_bh_schedule(n->tx_bh); - n->tx_waiting = 1; + qemu_bh_schedule(q->tx_bh); + q->tx_waiting = 1; return; } /* If less than a full burst, re-enable notification and flush * anything that may have come in while we weren't looking. If * we find something, assume the guest is still active and reschedule */ - virtio_queue_set_notification(n->tx_vq, 1); - if (virtio_net_flush_tx(n, n->tx_vq) > 0) { - virtio_queue_set_notification(n->tx_vq, 0); - qemu_bh_schedule(n->tx_bh); - n->tx_waiting = 1; + virtio_queue_set_notification(q->tx_vq, 1); + if (virtio_net_flush_tx(q) > 0) { + virtio_queue_set_notification(q->tx_vq, 0); + qemu_bh_schedule(q->tx_bh); + q->tx_waiting = 1; } } static void virtio_net_save(QEMUFile *f, void *opaque) { VirtIONet *n = opaque; + VirtIONetQueue *q = &n->vq; /* At this point, backend must be stopped, otherwise * it might keep writing to memory. */ @@ -915,7 +943,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque) virtio_save(&n->vdev, f); qemu_put_buffer(f, n->mac, ETH_ALEN); - qemu_put_be32(f, n->tx_waiting); + qemu_put_be32(f, q->tx_waiting); qemu_put_be32(f, n->mergeable_rx_bufs); qemu_put_be16(f, n->status); qemu_put_byte(f, n->promisc); @@ -936,6 +964,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque) static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; + VirtIONetQueue *q = &n->vq; int i; int ret; @@ -948,7 +977,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } qemu_get_buffer(f, n->mac, ETH_ALEN); - n->tx_waiting = qemu_get_be32(f); + q->tx_waiting = qemu_get_be32(f); virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f)); @@ -1085,7 +1114,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->vdev.set_status = virtio_net_set_status; n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask; n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending; - n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); + n->vq.rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); + n->vq.n = n; if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) { error_report("virtio-net: " @@ -1095,12 +1125,14 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, } if (net->tx && !strcmp(net->tx, "timer")) { - n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_timer); - n->tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer, n); + n->vq.tx_vq = virtio_add_queue(&n->vdev, 256, + virtio_net_handle_tx_timer); + n->vq.tx_timer = qemu_new_timer_ns(vm_clock, + virtio_net_tx_timer, &n->vq); n->tx_timeout = net->txtimer; } else { - n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_bh); - n->tx_bh = qemu_bh_new(virtio_net_tx_bh, n); + n->vq.tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_bh); + n->vq.tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vq); } n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl); qemu_macaddr_default_if_unset(&conf->macaddr); @@ -1118,7 +1150,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, qemu_format_nic_info_str(qemu_get_queue(n->nic), conf->macaddr.a); - n->tx_waiting = 0; + n->vq.tx_waiting = 0; n->tx_burst = net->txburst; virtio_net_set_mrg_rx_bufs(n, 0); n->promisc = 1; /* for compatibility */ @@ -1139,6 +1171,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, void virtio_net_exit(VirtIODevice *vdev) { VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev); + VirtIONetQueue *q = &n->vq; /* This will stop vhost backend if appropriate. */ virtio_net_set_status(vdev, 0); @@ -1150,11 +1183,11 @@ void virtio_net_exit(VirtIODevice *vdev) g_free(n->mac_table.macs); g_free(n->vlans); - if (n->tx_timer) { - qemu_del_timer(n->tx_timer); - qemu_free_timer(n->tx_timer); + if (q->tx_timer) { + qemu_del_timer(q->tx_timer); + qemu_free_timer(q->tx_timer); } else { - qemu_bh_delete(n->tx_bh); + qemu_bh_delete(q->tx_bh); } qemu_del_nic(n->nic); From fed699f9ca6ae8a0fb62803334cf46fa64d1eb91 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:39 +0800 Subject: [PATCH 0887/1634] virtio-net: multiqueue support This patch implements both userspace and vhost support for multiple queue virtio-net (VIRTIO_NET_F_MQ). This is done by introducing an array of VirtIONetQueue to VirtIONet. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/virtio-net.c | 302 +++++++++++++++++++++++++++++++++++++----------- hw/virtio-net.h | 28 ++++- 2 files changed, 263 insertions(+), 67 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 4b285c128d..2b5f16b3ae 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -44,7 +44,7 @@ typedef struct VirtIONet VirtIODevice vdev; uint8_t mac[ETH_ALEN]; uint16_t status; - VirtIONetQueue vq; + VirtIONetQueue vqs[MAX_QUEUE_NUM]; VirtQueue *ctrl_vq; NICState *nic; uint32_t tx_timeout; @@ -70,14 +70,23 @@ typedef struct VirtIONet } mac_table; uint32_t *vlans; DeviceState *qdev; + int multiqueue; + uint16_t max_queues; + uint16_t curr_queues; } VirtIONet; -static VirtIONetQueue *virtio_net_get_queue(NetClientState *nc) +static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc) { VirtIONet *n = qemu_get_nic_opaque(nc); - return &n->vq; + return &n->vqs[nc->queue_index]; } + +static int vq2q(int queue_index) +{ + return queue_index / 2; +} + /* TODO * - we could suppress RX interrupt if we were so inclined. */ @@ -93,6 +102,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) struct virtio_net_config netcfg; stw_p(&netcfg.status, n->status); + stw_p(&netcfg.max_virtqueue_pairs, n->max_queues); memcpy(netcfg.mac, n->mac, ETH_ALEN); memcpy(config, &netcfg, sizeof(netcfg)); } @@ -120,6 +130,7 @@ static bool virtio_net_started(VirtIONet *n, uint8_t status) static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) { NetClientState *nc = qemu_get_queue(n->nic); + int queues = n->multiqueue ? n->max_queues : 1; if (!nc->peer) { return; @@ -131,6 +142,7 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) if (!tap_get_vhost_net(nc->peer)) { return; } + if (!!n->vhost_started == virtio_net_started(n, status) && !nc->peer->link_down) { return; @@ -141,16 +153,14 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) return; } n->vhost_started = 1; - r = vhost_net_start(&n->vdev, nc, 1); + r = vhost_net_start(&n->vdev, n->nic->ncs, queues); if (r < 0) { error_report("unable to start vhost net: %d: " "falling back on userspace virtio", -r); n->vhost_started = 0; - } else { - n->vhost_started = 1; } } else { - vhost_net_stop(&n->vdev, nc, 1); + vhost_net_stop(&n->vdev, n->nic->ncs, queues); n->vhost_started = 0; } } @@ -158,26 +168,38 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = to_virtio_net(vdev); - VirtIONetQueue *q = &n->vq; + VirtIONetQueue *q; + int i; + uint8_t queue_status; virtio_net_vhost_status(n, status); - if (!q->tx_waiting) { - return; - } + for (i = 0; i < n->max_queues; i++) { + q = &n->vqs[i]; - if (virtio_net_started(n, status) && !n->vhost_started) { - if (q->tx_timer) { - qemu_mod_timer(q->tx_timer, - qemu_get_clock_ns(vm_clock) + n->tx_timeout); + if ((!n->multiqueue && i != 0) || i >= n->curr_queues) { + queue_status = 0; } else { - qemu_bh_schedule(q->tx_bh); + queue_status = status; } - } else { - if (q->tx_timer) { - qemu_del_timer(q->tx_timer); + + if (!q->tx_waiting) { + continue; + } + + if (virtio_net_started(n, queue_status) && !n->vhost_started) { + if (q->tx_timer) { + qemu_mod_timer(q->tx_timer, + qemu_get_clock_ns(vm_clock) + n->tx_timeout); + } else { + qemu_bh_schedule(q->tx_bh); + } } else { - qemu_bh_cancel(q->tx_bh); + if (q->tx_timer) { + qemu_del_timer(q->tx_timer); + } else { + qemu_bh_cancel(q->tx_bh); + } } } } @@ -209,6 +231,8 @@ static void virtio_net_reset(VirtIODevice *vdev) n->nomulti = 0; n->nouni = 0; n->nobcast = 0; + /* multiqueue is disabled by default */ + n->curr_queues = 1; /* Flush any MAC and VLAN filter table state */ n->mac_table.in_use = 0; @@ -251,18 +275,70 @@ static int peer_has_ufo(VirtIONet *n) static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs) { + int i; + NetClientState *nc; + n->mergeable_rx_bufs = mergeable_rx_bufs; n->guest_hdr_len = n->mergeable_rx_bufs ? sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); - if (peer_has_vnet_hdr(n) && - tap_has_vnet_hdr_len(qemu_get_queue(n->nic)->peer, n->guest_hdr_len)) { - tap_set_vnet_hdr_len(qemu_get_queue(n->nic)->peer, n->guest_hdr_len); - n->host_hdr_len = n->guest_hdr_len; + for (i = 0; i < n->max_queues; i++) { + nc = qemu_get_subqueue(n->nic, i); + + if (peer_has_vnet_hdr(n) && + tap_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) { + tap_set_vnet_hdr_len(nc->peer, n->guest_hdr_len); + n->host_hdr_len = n->guest_hdr_len; + } } } +static int peer_attach(VirtIONet *n, int index) +{ + NetClientState *nc = qemu_get_subqueue(n->nic, index); + + if (!nc->peer) { + return 0; + } + + if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { + return 0; + } + + return tap_enable(nc->peer); +} + +static int peer_detach(VirtIONet *n, int index) +{ + NetClientState *nc = qemu_get_subqueue(n->nic, index); + + if (!nc->peer) { + return 0; + } + + if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { + return 0; + } + + return tap_disable(nc->peer); +} + +static void virtio_net_set_queues(VirtIONet *n) +{ + int i; + + for (i = 0; i < n->max_queues; i++) { + if (i < n->curr_queues) { + assert(!peer_attach(n, i)); + } else { + assert(!peer_detach(n, i)); + } + } +} + +static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl); + static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features) { VirtIONet *n = to_virtio_net(vdev); @@ -314,25 +390,33 @@ static uint32_t virtio_net_bad_features(VirtIODevice *vdev) static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) { VirtIONet *n = to_virtio_net(vdev); - NetClientState *nc = qemu_get_queue(n->nic); + int i; + + virtio_net_set_multiqueue(n, !!(features & (1 << VIRTIO_NET_F_MQ)), + !!(features & (1 << VIRTIO_NET_F_CTRL_VQ))); virtio_net_set_mrg_rx_bufs(n, !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF))); if (n->has_vnet_hdr) { - tap_set_offload(nc->peer, + tap_set_offload(qemu_get_subqueue(n->nic, 0)->peer, (features >> VIRTIO_NET_F_GUEST_CSUM) & 1, (features >> VIRTIO_NET_F_GUEST_TSO4) & 1, (features >> VIRTIO_NET_F_GUEST_TSO6) & 1, (features >> VIRTIO_NET_F_GUEST_ECN) & 1, (features >> VIRTIO_NET_F_GUEST_UFO) & 1); } - if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { - return; + + for (i = 0; i < n->max_queues; i++) { + NetClientState *nc = qemu_get_subqueue(n->nic, i); + + if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { + continue; + } + if (!tap_get_vhost_net(nc->peer)) { + continue; + } + vhost_net_ack_features(tap_get_vhost_net(nc->peer), features); } - if (!tap_get_vhost_net(nc->peer)) { - return; - } - vhost_net_ack_features(tap_get_vhost_net(nc->peer), features); } static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, @@ -470,6 +554,38 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_OK; } +static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, + VirtQueueElement *elem) +{ + struct virtio_net_ctrl_mq s; + + if (elem->out_num != 2 || + elem->out_sg[1].iov_len != sizeof(struct virtio_net_ctrl_mq)) { + error_report("virtio-net ctrl invalid steering command"); + return VIRTIO_NET_ERR; + } + + if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { + return VIRTIO_NET_ERR; + } + + memcpy(&s, elem->out_sg[1].iov_base, sizeof(struct virtio_net_ctrl_mq)); + + if (s.virtqueue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || + s.virtqueue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || + s.virtqueue_pairs > n->max_queues || + !n->multiqueue) { + return VIRTIO_NET_ERR; + } + + n->curr_queues = s.virtqueue_pairs; + /* stop the backend before changing the number of queues to avoid handling a + * disabled queue */ + virtio_net_set_status(&n->vdev, n->vdev.status); + virtio_net_set_queues(n); + + return VIRTIO_NET_OK; +} static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); @@ -499,6 +615,8 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt); } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); + } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { + status = virtio_net_handle_mq(n, ctrl.cmd, &elem); } s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status)); @@ -514,19 +632,24 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); + int queue_index = vq2q(virtio_get_queue_index(vq)); - qemu_flush_queued_packets(qemu_get_queue(n->nic)); + qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index)); } static int virtio_net_can_receive(NetClientState *nc) { VirtIONet *n = qemu_get_nic_opaque(nc); - VirtIONetQueue *q = virtio_net_get_queue(nc); + VirtIONetQueue *q = virtio_net_get_subqueue(nc); if (!n->vdev.vm_running) { return 0; } + if (nc->queue_index >= n->curr_queues) { + return 0; + } + if (!virtio_queue_ready(q->rx_vq) || !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { return 0; @@ -657,13 +780,13 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size) { VirtIONet *n = qemu_get_nic_opaque(nc); - VirtIONetQueue *q = virtio_net_get_queue(nc); + VirtIONetQueue *q = virtio_net_get_subqueue(nc); struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; struct virtio_net_hdr_mrg_rxbuf mhdr; unsigned mhdr_cnt = 0; size_t offset, i, guest_offset; - if (!virtio_net_can_receive(qemu_get_queue(n->nic))) { + if (!virtio_net_can_receive(nc)) { return -1; } @@ -758,7 +881,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q); static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) { VirtIONet *n = qemu_get_nic_opaque(nc); - VirtIONetQueue *q = virtio_net_get_queue(nc); + VirtIONetQueue *q = virtio_net_get_subqueue(nc); virtqueue_push(q->tx_vq, &q->async_tx.elem, 0); virtio_notify(&n->vdev, q->tx_vq); @@ -775,6 +898,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) VirtIONet *n = q->n; VirtQueueElement elem; int32_t num_packets = 0; + int queue_index = vq2q(virtio_get_queue_index(q->tx_vq)); if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) { return num_packets; } @@ -816,8 +940,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) len = n->guest_hdr_len; - ret = qemu_sendv_packet_async(qemu_get_queue(n->nic), out_sg, out_num, - virtio_net_tx_complete); + ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index), + out_sg, out_num, virtio_net_tx_complete); if (ret == 0) { virtio_queue_set_notification(q->tx_vq, 0); q->async_tx.elem = elem; @@ -840,7 +964,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); - VirtIONetQueue *q = &n->vq; + VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; /* This happens when device was stopped but VCPU wasn't. */ if (!n->vdev.vm_running) { @@ -864,7 +988,7 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) { VirtIONet *n = to_virtio_net(vdev); - VirtIONetQueue *q = &n->vq; + VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))]; if (unlikely(q->tx_waiting)) { return; @@ -932,10 +1056,46 @@ static void virtio_net_tx_bh(void *opaque) } } +static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl) +{ + VirtIODevice *vdev = &n->vdev; + int i, max = multiqueue ? n->max_queues : 1; + + n->multiqueue = multiqueue; + + for (i = 2; i <= n->max_queues * 2 + 1; i++) { + virtio_del_queue(vdev, i); + } + + for (i = 1; i < max; i++) { + n->vqs[i].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx); + if (n->vqs[i].tx_timer) { + n->vqs[i].tx_vq = + virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer); + n->vqs[i].tx_timer = qemu_new_timer_ns(vm_clock, + virtio_net_tx_timer, + &n->vqs[i]); + } else { + n->vqs[i].tx_vq = + virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh); + n->vqs[i].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[i]); + } + + n->vqs[i].tx_waiting = 0; + n->vqs[i].n = n; + } + + if (ctrl) { + n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl); + } + + virtio_net_set_queues(n); +} + static void virtio_net_save(QEMUFile *f, void *opaque) { VirtIONet *n = opaque; - VirtIONetQueue *q = &n->vq; + VirtIONetQueue *q = &n->vqs[0]; /* At this point, backend must be stopped, otherwise * it might keep writing to memory. */ @@ -964,9 +1124,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque) static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; - VirtIONetQueue *q = &n->vq; - int i; - int ret; + VirtIONetQueue *q = &n->vqs[0]; + int ret, i; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; @@ -1081,7 +1240,7 @@ static NetClientInfo net_virtio_info = { static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) { VirtIONet *n = to_virtio_net(vdev); - NetClientState *nc = qemu_get_queue(n->nic); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); assert(n->vhost_started); return vhost_net_virtqueue_pending(tap_get_vhost_net(nc->peer), idx); } @@ -1090,7 +1249,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) { VirtIONet *n = to_virtio_net(vdev); - NetClientState *nc = qemu_get_queue(n->nic); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx)); assert(n->vhost_started); vhost_net_virtqueue_mask(tap_get_vhost_net(nc->peer), vdev, idx, mask); @@ -1100,6 +1259,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, virtio_net_conf *net) { VirtIONet *n; + int i; n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET, sizeof(struct virtio_net_config), @@ -1114,8 +1274,11 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->vdev.set_status = virtio_net_set_status; n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask; n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending; - n->vq.rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); - n->vq.n = n; + n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); + n->max_queues = conf->queues; + n->curr_queues = 1; + n->vqs[0].n = n; + n->tx_timeout = net->txtimer; if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) { error_report("virtio-net: " @@ -1125,14 +1288,14 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, } if (net->tx && !strcmp(net->tx, "timer")) { - n->vq.tx_vq = virtio_add_queue(&n->vdev, 256, - virtio_net_handle_tx_timer); - n->vq.tx_timer = qemu_new_timer_ns(vm_clock, - virtio_net_tx_timer, &n->vq); - n->tx_timeout = net->txtimer; + n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256, + virtio_net_handle_tx_timer); + n->vqs[0].tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer, + &n->vqs[0]); } else { - n->vq.tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx_bh); - n->vq.tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vq); + n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256, + virtio_net_handle_tx_bh); + n->vqs[0].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[0]); } n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl); qemu_macaddr_default_if_unset(&conf->macaddr); @@ -1142,7 +1305,9 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n); peer_test_vnet_hdr(n); if (peer_has_vnet_hdr(n)) { - tap_using_vnet_hdr(qemu_get_queue(n->nic)->peer, true); + for (i = 0; i < n->max_queues; i++) { + tap_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true); + } n->host_hdr_len = sizeof(struct virtio_net_hdr); } else { n->host_hdr_len = 0; @@ -1150,7 +1315,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, qemu_format_nic_info_str(qemu_get_queue(n->nic), conf->macaddr.a); - n->vq.tx_waiting = 0; + n->vqs[0].tx_waiting = 0; n->tx_burst = net->txburst; virtio_net_set_mrg_rx_bufs(n, 0); n->promisc = 1; /* for compatibility */ @@ -1171,23 +1336,28 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, void virtio_net_exit(VirtIODevice *vdev) { VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev); - VirtIONetQueue *q = &n->vq; + int i; /* This will stop vhost backend if appropriate. */ virtio_net_set_status(vdev, 0); - qemu_purge_queued_packets(qemu_get_queue(n->nic)); - unregister_savevm(n->qdev, "virtio-net", n); g_free(n->mac_table.macs); g_free(n->vlans); - if (q->tx_timer) { - qemu_del_timer(q->tx_timer); - qemu_free_timer(q->tx_timer); - } else { - qemu_bh_delete(q->tx_bh); + for (i = 0; i < n->max_queues; i++) { + VirtIONetQueue *q = &n->vqs[i]; + NetClientState *nc = qemu_get_subqueue(n->nic, i); + + qemu_purge_queued_packets(nc); + + if (q->tx_timer) { + qemu_del_timer(q->tx_timer); + qemu_free_timer(q->tx_timer); + } else { + qemu_bh_delete(q->tx_bh); + } } qemu_del_nic(n->nic); diff --git a/hw/virtio-net.h b/hw/virtio-net.h index c0bb284df2..f5fea6e9bc 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -43,6 +43,8 @@ #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */ #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ #define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */ +#define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow + * Steering */ #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ @@ -73,6 +75,8 @@ struct virtio_net_config uint8_t mac[ETH_ALEN]; /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */ uint16_t status; + /* Max virtqueue pairs supported by the device */ + uint16_t max_virtqueue_pairs; } QEMU_PACKED; /* @@ -147,6 +151,26 @@ struct virtio_net_ctrl_mac { #define VIRTIO_NET_CTRL_VLAN_ADD 0 #define VIRTIO_NET_CTRL_VLAN_DEL 1 +/* + * Control Multiqueue + * + * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET + * enables multiqueue, specifying the number of the transmit and + * receive queues that will be used. After the command is consumed and acked by + * the device, the device will not steer new packets on receive virtqueues + * other than specified nor read from transmit virtqueues other than specified. + * Accordingly, driver should not transmit new packets on virtqueues other than + * specified. + */ +struct virtio_net_ctrl_mq { + uint16_t virtqueue_pairs; +}; + +#define VIRTIO_NET_CTRL_MQ 4 + #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0 + #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1 + #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000 + #define DEFINE_VIRTIO_NET_FEATURES(_state, _field) \ DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \ DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \ @@ -166,5 +190,7 @@ struct virtio_net_ctrl_mac { DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \ DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \ DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true), \ - DEFINE_PROP_BIT("ctrl_mac_addr", _state, _field, VIRTIO_NET_F_CTRL_MAC_ADDR, true) + DEFINE_PROP_BIT("ctrl_mac_addr", _state, _field, VIRTIO_NET_F_CTRL_MAC_ADDR, true), \ + DEFINE_PROP_BIT("mq", _state, _field, VIRTIO_NET_F_MQ, true) + #endif From 5f800801838f74a8a430fb41a7393fa5df0a61f9 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:40 +0800 Subject: [PATCH 0888/1634] virtio-net: migration support for multiqueue This patch add migration support for multiqueue virtio-net. Instead of bumping the version, we conditionally send the info of multiqueue only when the device support more than one queue to maintain the backward compatibility. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/virtio-net.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 2b5f16b3ae..e37358a40c 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1094,8 +1094,8 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl) static void virtio_net_save(QEMUFile *f, void *opaque) { + int i; VirtIONet *n = opaque; - VirtIONetQueue *q = &n->vqs[0]; /* At this point, backend must be stopped, otherwise * it might keep writing to memory. */ @@ -1103,7 +1103,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque) virtio_save(&n->vdev, f); qemu_put_buffer(f, n->mac, ETH_ALEN); - qemu_put_be32(f, q->tx_waiting); + qemu_put_be32(f, n->vqs[0].tx_waiting); qemu_put_be32(f, n->mergeable_rx_bufs); qemu_put_be16(f, n->status); qemu_put_byte(f, n->promisc); @@ -1119,13 +1119,19 @@ static void virtio_net_save(QEMUFile *f, void *opaque) qemu_put_byte(f, n->nouni); qemu_put_byte(f, n->nobcast); qemu_put_byte(f, n->has_ufo); + if (n->max_queues > 1) { + qemu_put_be16(f, n->max_queues); + qemu_put_be16(f, n->curr_queues); + for (i = 1; i < n->curr_queues; i++) { + qemu_put_be32(f, n->vqs[i].tx_waiting); + } + } } static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; - VirtIONetQueue *q = &n->vqs[0]; - int ret, i; + int ret, i, link_down; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; @@ -1136,7 +1142,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } qemu_get_buffer(f, n->mac, ETH_ALEN); - q->tx_waiting = qemu_get_be32(f); + n->vqs[0].tx_waiting = qemu_get_be32(f); virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f)); @@ -1206,6 +1212,20 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) } } + if (n->max_queues > 1) { + if (n->max_queues != qemu_get_be16(f)) { + error_report("virtio-net: different max_queues "); + return -1; + } + + n->curr_queues = qemu_get_be16(f); + for (i = 1; i < n->curr_queues; i++) { + n->vqs[i].tx_waiting = qemu_get_be32(f); + } + } + + virtio_net_set_queues(n); + /* Find the first multicast entry in the saved MAC filter */ for (i = 0; i < n->mac_table.in_use; i++) { if (n->mac_table.macs[i * ETH_ALEN] & 1) { @@ -1216,7 +1236,10 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) /* nc.link_down can't be migrated, so infer link_down according * to link status bit in n->status */ - qemu_get_queue(n->nic)->link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; + link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0; + for (i = 0; i < n->max_queues; i++) { + qemu_get_subqueue(n->nic, i)->link_down = link_down; + } return 0; } From a9c87c586ba9ee290792a98dc126b2861b7f8b03 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 30 Jan 2013 19:12:41 +0800 Subject: [PATCH 0889/1634] virtio-net: compat multiqueue support Disable multiqueue support for pre 1.4. Signed-off-by: Jason Wang Signed-off-by: Anthony Liguori --- hw/pc_piix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index ba09714d6c..0af436cfaf 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -313,6 +313,10 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { .driver = "virtio-net-pci",\ .property = "ctrl_mac_addr",\ .value = "off", \ + },{ \ + .driver = "virtio-net-pci", \ + .property = "mq", \ + .value = "off", \ } static QEMUMachine pc_machine_v1_3 = { From 3e3648b29f80c3c406dae127592150b550f20d2f Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 1 Feb 2013 12:55:56 -0600 Subject: [PATCH 0890/1634] xen: fix build problem introduced from per-queue peers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by Andreas Färber Signed-off-by: Anthony Liguori --- hw/xen_nic.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 4be077d320..34961c287a 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -326,8 +326,6 @@ static int net_init(struct XenDevice *xendev) return -1; } - netdev->conf.peer = NULL; - netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, "xen", NULL, netdev); From baeddded5fe6fa37d13fb94bf8dc0e9b2b184e21 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 29 Jan 2013 15:42:45 -0600 Subject: [PATCH 0891/1634] sparc: disable qtest in make check We've seen this repeatedly in buildbot but I can now reliably reproduce it myself too. With a few hundred runs of 'make check', qemu-system-sparc will hang consuming 100% CPU. I've attached GDB to the hung process and unfortunately, I can't get anything useful out of GDB (RIP is not a valid simple and there is nothing else on the stack). At any rate, since this only manifests in qemu-system-sparc and it doesn't appear to be a qtest specific problem, I think we should disable it until the problem is resolved. Signed-off-by: Anthony Liguori --- tests/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index abe9c2a6c4..83145f5d31 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -65,8 +65,8 @@ check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) -check-qtest-sparc-y = tests/m48t59-test$(EXESUF) -check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) +#check-qtest-sparc-y = tests/m48t59-test$(EXESUF) +#check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) gcov-files-sparc-y += hw/m48t59.c gcov-files-sparc64-y += hw/m48t59.c check-qtest-arm-y = tests/tmp105-test$(EXESUF) From e3c66d939480e0f372316c22184c07fb3de12873 Mon Sep 17 00:00:00 2001 From: liguang Date: Thu, 24 Jan 2013 13:03:25 +0800 Subject: [PATCH 0892/1634] vl: skip init accelerator if it's not available Signed-off-by: liguang Signed-off-by: Anthony Liguori --- vl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vl.c b/vl.c index 910abb6526..140ce84cc0 100644 --- a/vl.c +++ b/vl.c @@ -2577,18 +2577,18 @@ static int configure_accelerator(void) p = get_opt_name(buf, sizeof (buf), p, ':'); for (i = 0; i < ARRAY_SIZE(accel_list); i++) { if (strcmp(accel_list[i].opt_name, buf) == 0) { + if (!accel_list[i].available()) { + printf("%s not supported for this target\n", + accel_list[i].name); + continue; + } *(accel_list[i].allowed) = 1; ret = accel_list[i].init(); if (ret < 0) { init_failed = 1; - if (!accel_list[i].available()) { - printf("%s not supported for this target\n", - accel_list[i].name); - } else { - fprintf(stderr, "failed to initialize %s: %s\n", - accel_list[i].name, - strerror(-ret)); - } + fprintf(stderr, "failed to initialize %s: %s\n", + accel_list[i].name, + strerror(-ret)); *(accel_list[i].allowed) = 0; } else { accel_initialised = 1; From 217e21be6e0f2c1caa0b644f56aa60dba7ea7893 Mon Sep 17 00:00:00 2001 From: liguang Date: Thu, 24 Jan 2013 13:03:26 +0800 Subject: [PATCH 0893/1634] vl: correct error message when fail to init kvm command: qemu-system-x86_64 -hda disk.img -smp 32 --enable-kvm error: Number of SMP cpus requested (32) exceeds max cpus supported by KVM (16) failed to initialize KVM: Invalid argument No accelerator found! well, it did find kvm, but failed to init, so message "No accelerator found!" is confusing, this commit remove the confusing error message. Signed-off-by: liguang Signed-off-by: Anthony Liguori --- vl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/vl.c b/vl.c index 140ce84cc0..fe2898594d 100644 --- a/vl.c +++ b/vl.c @@ -2557,8 +2557,8 @@ static int configure_accelerator(void) const char *p = NULL; char buf[10]; int i, ret; - bool accel_initialised = 0; - bool init_failed = 0; + bool accel_initialised = false; + bool init_failed = false; QemuOptsList *list = qemu_find_opts("machine"); if (!QTAILQ_EMPTY(&list->head)) { @@ -2585,13 +2585,13 @@ static int configure_accelerator(void) *(accel_list[i].allowed) = 1; ret = accel_list[i].init(); if (ret < 0) { - init_failed = 1; + init_failed = true; fprintf(stderr, "failed to initialize %s: %s\n", accel_list[i].name, strerror(-ret)); *(accel_list[i].allowed) = 0; } else { - accel_initialised = 1; + accel_initialised = true; } break; } @@ -2602,7 +2602,9 @@ static int configure_accelerator(void) } if (!accel_initialised) { - fprintf(stderr, "No accelerator found!\n"); + if (!init_failed) { + fprintf(stderr, "No accelerator found!\n"); + } exit(1); } From d5286af5ef27bfe25aa0472eb4d695964ae16b23 Mon Sep 17 00:00:00 2001 From: liguang Date: Thu, 24 Jan 2013 13:03:27 +0800 Subject: [PATCH 0894/1634] accel: change {xen, kvm, tcg, qtest}_allowed from int to bool Signed-off-by: liguang Signed-off-by: Anthony Liguori --- hw/xen.h | 4 ++-- include/sysemu/kvm.h | 2 +- include/sysemu/qtest.h | 2 +- qtest.c | 2 +- vl.c | 12 ++++++------ 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/xen.h b/hw/xen.h index e3cca7fb92..6235f91fe0 100644 --- a/hw/xen.h +++ b/hw/xen.h @@ -21,9 +21,9 @@ enum xen_mode { extern uint32_t xen_domid; extern enum xen_mode xen_mode; -extern int xen_allowed; +extern bool xen_allowed; -static inline int xen_enabled(void) +static inline bool xen_enabled(void) { #if defined(CONFIG_XEN_BACKEND) && !defined(CONFIG_NO_XEN) return xen_allowed; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 6e6dfb374a..f2d97b580d 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -39,7 +39,7 @@ #define KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 0 #endif -extern int kvm_allowed; +extern bool kvm_allowed; extern bool kvm_kernel_irqchip; extern bool kvm_async_interrupts_allowed; extern bool kvm_irqfds_allowed; diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h index 723a4f9536..9a0c6b31c8 100644 --- a/include/sysemu/qtest.h +++ b/include/sysemu/qtest.h @@ -17,7 +17,7 @@ #include "qemu-common.h" #if !defined(CONFIG_USER_ONLY) -extern int qtest_allowed; +extern bool qtest_allowed; extern const char *qtest_chrdev; extern const char *qtest_log; diff --git a/qtest.c b/qtest.c index c9b58ceb8b..b7a3821ca7 100644 --- a/qtest.c +++ b/qtest.c @@ -24,7 +24,7 @@ const char *qtest_chrdev; const char *qtest_log; -int qtest_allowed = 0; +bool qtest_allowed; static DeviceState *irq_intercept_dev; static FILE *qtest_log_fp; diff --git a/vl.c b/vl.c index fe2898594d..f094f04a2c 100644 --- a/vl.c +++ b/vl.c @@ -263,9 +263,9 @@ static NotifierList exit_notifiers = static NotifierList machine_init_done_notifiers = NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers); -static int tcg_allowed = 1; -int kvm_allowed = 0; -int xen_allowed = 0; +static bool tcg_allowed = true; +bool kvm_allowed; +bool xen_allowed; uint32_t xen_domid; enum xen_mode xen_mode = XEN_EMULATE; static int tcg_tb_size; @@ -2544,7 +2544,7 @@ static struct { const char *name; int (*available)(void); int (*init)(void); - int *allowed; + bool *allowed; } accel_list[] = { { "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed }, { "xen", "Xen", xen_available, xen_init, &xen_allowed }, @@ -2582,14 +2582,14 @@ static int configure_accelerator(void) accel_list[i].name); continue; } - *(accel_list[i].allowed) = 1; + *(accel_list[i].allowed) = true; ret = accel_list[i].init(); if (ret < 0) { init_failed = true; fprintf(stderr, "failed to initialize %s: %s\n", accel_list[i].name, strerror(-ret)); - *(accel_list[i].allowed) = 0; + *(accel_list[i].allowed) = false; } else { accel_initialised = true; } From 013e118247d0f1894f329ad31b8f8a9e279555f3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:27 +0100 Subject: [PATCH 0895/1634] qdev: remove duplication between qbus_create and qbus_create_inplace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the common part to qbus_realize. Acked-by: Andreas Färber Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 97610167c2..59dce628fe 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -390,14 +390,16 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id) return NULL; } -static void qbus_realize(BusState *bus) +static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) { const char *typename = object_get_typename(OBJECT(bus)); char *buf; int i,len; - if (bus->name) { - /* use supplied name */ + bus->parent = parent; + + if (name) { + bus->name = g_strdup(name); } else if (bus->parent && bus->parent->id) { /* parent device has id -> use it for bus name */ len = strlen(bus->parent->id) + 16; @@ -430,10 +432,7 @@ void qbus_create_inplace(BusState *bus, const char *typename, DeviceState *parent, const char *name) { object_initialize(bus, typename); - - bus->parent = parent; - bus->name = name ? g_strdup(name) : NULL; - qbus_realize(bus); + qbus_realize(bus, parent, name); } BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) @@ -441,10 +440,7 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam BusState *bus; bus = BUS(object_new(typename)); - - bus->parent = parent; - bus->name = name ? g_strdup(name) : NULL; - qbus_realize(bus); + qbus_realize(bus, parent, name); return bus; } From 39355c3826f5d9a2eb1ce3dc9b4cdd68893769d6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:28 +0100 Subject: [PATCH 0896/1634] qdev: change first argument of qbus_create_inplace to void * Make it clear that no BUS() macro is needed in the callers (in fact it wouldn't work because the object has not been initialized yet with the right class). Suggested-by: Andreas Faerber Acked-by: Andreas F=E4rber Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev-core.h | 2 +- hw/qdev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/qdev-core.h b/hw/qdev-core.h index d1b8e37d80..2486f36853 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -231,7 +231,7 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id); typedef int (qbus_walkerfn)(BusState *bus, void *opaque); typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque); -void qbus_create_inplace(BusState *bus, const char *typename, +void qbus_create_inplace(void *bus, const char *typename, DeviceState *parent, const char *name); BusState *qbus_create(const char *typename, DeviceState *parent, const char *name); /* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, diff --git a/hw/qdev.c b/hw/qdev.c index 59dce628fe..b80b082a00 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -428,7 +428,7 @@ static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) } } -void qbus_create_inplace(BusState *bus, const char *typename, +void qbus_create_inplace(void *bus, const char *typename, DeviceState *parent, const char *name) { object_initialize(bus, typename); From 4fec6404465fdb1f09670b1451605c7cbf87c01e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:29 +0100 Subject: [PATCH 0897/1634] pci: use qbus_create in pci_bus_new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove knowledge of QOM innards. The common part of pci_bus_new and pci_bus_new_inplace is moved to a new function pci_bus_init. Acked-by: Andreas Färber Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/pci/pci.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 5fd1bcf08e..905dc4a219 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -274,13 +274,12 @@ int pci_find_domain(const PCIBus *bus) return -1; } -void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, +static void pci_bus_init(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, uint8_t devfn_min) { - qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name); assert(PCI_FUNC(devfn_min) == 0); bus->devfn_min = devfn_min; bus->address_space_mem = address_space_mem; @@ -293,6 +292,17 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, vmstate_register(NULL, -1, &vmstate_pcibus, bus); } +void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, + const char *name, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io, + uint8_t devfn_min) +{ + qbus_create_inplace(bus, TYPE_PCI_BUS, parent, name); + pci_bus_init(bus, parent, name, address_space_mem, + address_space_io, devfn_min); +} + PCIBus *pci_bus_new(DeviceState *parent, const char *name, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, @@ -300,10 +310,9 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name, { PCIBus *bus; - bus = g_malloc0(sizeof(*bus)); - pci_bus_new_inplace(bus, parent, name, address_space_mem, - address_space_io, devfn_min); - OBJECT(bus)->free = g_free; + bus = PCI_BUS(qbus_create(TYPE_PCI_BUS, parent, name)); + pci_bus_init(bus, parent, name, address_space_mem, + address_space_io, devfn_min); return bus; } From 52e636cdd8528b8f72f43b653356ac177524912b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:30 +0100 Subject: [PATCH 0898/1634] qom: preserve object while unparenting it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid that the object disappears after it's deleted from the QOM composition tree, in case that was the only reference to it. Acked-by: Andreas Färber Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- qom/object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qom/object.c b/qom/object.c index e200282172..034f15cdec 100644 --- a/qom/object.c +++ b/qom/object.c @@ -361,12 +361,14 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp) void object_unparent(Object *obj) { + object_ref(obj); if (obj->parent) { object_property_del_child(obj->parent, obj, NULL); } if (obj->class->unparent) { (obj->class->unparent)(obj); } + object_unref(obj); } static void object_deinit(Object *obj, TypeImpl *type) From 6c232d2ffb7cf60e9fdf5dc17c5d5f7fe6d1ca64 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:31 +0100 Subject: [PATCH 0899/1634] qom: document reference counting of link properties Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- include/qom/object.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/qom/object.h b/include/qom/object.h index 48e80ba229..bfd848ffe3 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -1041,6 +1041,11 @@ void object_property_add_child(Object *obj, const char *name, * between objects. * * Links form the graph in the object model. + * + * Ownership of the pointer that @child points to is transferred to the + * link property. The reference count for *@child is + * managed by the property from after the function returns till the + * property is deleted with object_property_del(). */ void object_property_add_link(Object *obj, const char *name, const char *type, Object **child, From 9d127820ebbdc76592e3922cbbe803533455f9a2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:32 +0100 Subject: [PATCH 0900/1634] qdev: add reference count to a device for the BusChild MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each device has a reference through the BusChild. This reference was not accounted for, add it now. Reviewed-by: Andreas Färber Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/qdev.c b/hw/qdev.c index b80b082a00..9a8b8c1621 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -64,7 +64,10 @@ static void bus_remove_child(BusState *bus, DeviceState *child) snprintf(name, sizeof(name), "child[%d]", kid->index); QTAILQ_REMOVE(&bus->children, kid, sibling); + + /* This gives back ownership of kid->child back to us. */ object_property_del(OBJECT(bus), name, NULL); + object_unref(OBJECT(kid->child)); g_free(kid); return; } @@ -82,9 +85,11 @@ static void bus_add_child(BusState *bus, DeviceState *child) kid->index = bus->max_index++; kid->child = child; + object_ref(OBJECT(kid->child)); QTAILQ_INSERT_HEAD(&bus->children, kid, sibling); + /* This transfers ownership of kid->child to the property. */ snprintf(name, sizeof(name), "child[%d]", kid->index); object_property_add_link(OBJECT(bus), name, object_get_typename(OBJECT(child)), From 6853d27a1253cd29c43d08b0624e7938a48d52a7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:33 +0100 Subject: [PATCH 0901/1634] qdev: move deletion of children from finalize to unparent A device will never be finalized as long as it has a reference from other devices that sit on its buses. To ensure that the references go away, deassociate a bus from its children in the unparent callback for the bus. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 9a8b8c1621..3c1ec7df44 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -433,6 +433,25 @@ static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) } } +static void bus_unparent(Object *obj) +{ + BusState *bus = BUS(obj); + BusChild *kid; + + while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { + DeviceState *dev = kid->child; + qdev_free(dev); + } + if (bus->parent) { + QLIST_REMOVE(bus, sibling); + bus->parent->num_child_bus--; + bus->parent = NULL; + } else { + assert(bus != sysbus_get_default()); /* main_system_bus is never freed */ + qemu_unregister_reset(qbus_reset_all_fn, bus); + } +} + void qbus_create_inplace(void *bus, const char *typename, DeviceState *parent, const char *name) { @@ -805,22 +824,15 @@ static void qbus_initfn(Object *obj) QTAILQ_INIT(&bus->children); } +static void bus_class_init(ObjectClass *class, void *data) +{ + class->unparent = bus_unparent; +} + static void qbus_finalize(Object *obj) { BusState *bus = BUS(obj); - BusChild *kid; - while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { - DeviceState *dev = kid->child; - qdev_free(dev); - } - if (bus->parent) { - QLIST_REMOVE(bus, sibling); - bus->parent->num_child_bus--; - } else { - assert(bus != sysbus_get_default()); /* main_system_bus is never freed */ - qemu_unregister_reset(qbus_reset_all_fn, bus); - } g_free((char *)bus->name); } @@ -832,6 +844,7 @@ static const TypeInfo bus_info = { .class_size = sizeof(BusClass), .instance_init = qbus_initfn, .instance_finalize = qbus_finalize, + .class_init = bus_class_init, }; static void qdev_register_types(void) From 06f7f2bb562826101468f387b4a34971b16e9aee Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:34 +0100 Subject: [PATCH 0902/1634] qdev: move unrealization of devices from finalize to unparent Similarly, a bus holds a reference back to the device, and this will prevent the device from going away as soon as this reference is counted properly. To avoid this, move the unrealization of devices to the unparent callback. This includes recursively unparenting all the buses and (after the previous patch) the devices on those buses, which ensures that the web of references completely disappears for all devices that reside (in the qdev tree) below the one being unplugged. After this patch, the qdev tree and the bus<->child relationship is defined as "A is above B, iff unplugging A will automatically unplug B". Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 3c1ec7df44..6f1b3117ff 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -738,23 +738,8 @@ static void device_initfn(Object *obj) static void device_finalize(Object *obj) { DeviceState *dev = DEVICE(obj); - BusState *bus; - DeviceClass *dc = DEVICE_GET_CLASS(dev); - - if (dev->realized) { - while (dev->num_child_bus) { - bus = QLIST_FIRST(&dev->child_bus); - qbus_free(bus); - } - if (qdev_get_vmsd(dev)) { - vmstate_unregister(dev, qdev_get_vmsd(dev), dev); - } - if (dc->exit) { - dc->exit(dev); - } - if (dev->opts) { - qemu_opts_del(dev->opts); - } + if (dev->opts) { + qemu_opts_del(dev->opts); } } @@ -771,8 +756,22 @@ static void device_class_base_init(ObjectClass *class, void *data) static void device_unparent(Object *obj) { DeviceState *dev = DEVICE(obj); + DeviceClass *dc = DEVICE_GET_CLASS(dev); + BusState *bus; - if (dev->parent_bus != NULL) { + while (dev->num_child_bus) { + bus = QLIST_FIRST(&dev->child_bus); + qbus_free(bus); + } + if (dev->realized) { + if (qdev_get_vmsd(dev)) { + vmstate_unregister(dev, qdev_get_vmsd(dev), dev); + } + if (dc->exit) { + dc->exit(dev); + } + } + if (dev->parent_bus) { bus_remove_child(dev->parent_bus, dev); } } From 62d7ba669dbd5b4c92664eea453d28448ab9cb4b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:35 +0100 Subject: [PATCH 0903/1634] qdev: add reference for the bus while it is referred to by the DeviceState Now that the unparent callbacks are complete, we can correctly account more missing references. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/qdev.c b/hw/qdev.c index 6f1b3117ff..1dabcad2a6 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -100,6 +100,7 @@ static void bus_add_child(BusState *bus, DeviceState *child) void qdev_set_parent_bus(DeviceState *dev, BusState *bus) { dev->parent_bus = bus; + object_ref(OBJECT(bus)); bus_add_child(bus, dev); } @@ -773,6 +774,8 @@ static void device_unparent(Object *obj) } if (dev->parent_bus) { bus_remove_child(dev->parent_bus, dev); + object_unref(OBJECT(dev->parent_bus)); + dev->parent_bus = NULL; } } From dc7389b79a15082fa4824bd3de966499f3b8cb2a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:36 +0100 Subject: [PATCH 0904/1634] qdev: inline object_delete into qbus_free/qdev_free We want object_delete to disappear, and we will do this one class at a time. Inline it for the qdev case, which we will tackle first. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 1dabcad2a6..09f59698c9 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -267,7 +267,8 @@ void qdev_init_nofail(DeviceState *dev) /* Unlink device from bus and free the structure. */ void qdev_free(DeviceState *dev) { - object_delete(OBJECT(dev)); + object_unparent(OBJECT(dev)); + object_unref(OBJECT(dev)); } void qdev_machine_creation_done(void) @@ -472,7 +473,8 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam void qbus_free(BusState *bus) { - object_delete(OBJECT(bus)); + object_unparent(OBJECT(bus)); + object_unref(OBJECT(bus)); } static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) From b09995aef1d4a5879000a196a82e37b0511c8e03 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:37 +0100 Subject: [PATCH 0905/1634] qdev: drop extra references at creation time qdev_free and qbus_free have to do unparent+unref, because nobody else drops the initial reference (the one included by object_initialize) before them. For device_init_func and do_device_add, this is trivially correct, since the DeviceState goes out of scope. For qdev_create, qdev_try_create and qbus_init, it is a bit more tricky. What we are doing here is just assuming that the caller knows what it's doing, and won't call qdev_free/qbus_free while the device is still there. This is a pretty reasonable assumption and (behind the scenes) is also what GObject/GTK does. GTK actually has a "floating reference" that goes away as soon as the caller does gtk_container_add or something like that, but in the end qbus_init and qdev_try_create are already adding the new object to its qdev parent! So in the end the two solutions are the same. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- hw/qdev-monitor.c | 5 ++++- hw/qdev.c | 5 ++--- vl.c | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c index 4e2a92b9dd..4f9a6eb39a 100644 --- a/hw/qdev-monitor.c +++ b/hw/qdev-monitor.c @@ -591,6 +591,7 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) { Error *local_err = NULL; QemuOpts *opts; + DeviceState *dev; opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); if (error_is_set(&local_err)) { @@ -602,10 +603,12 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) qemu_opts_del(opts); return 0; } - if (!qdev_device_add(opts)) { + dev = qdev_device_add(opts); + if (!dev) { qemu_opts_del(opts); return -1; } + object_unref(OBJECT(dev)); return 0; } diff --git a/hw/qdev.c b/hw/qdev.c index 09f59698c9..8258757a1d 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -143,7 +143,7 @@ DeviceState *qdev_try_create(BusState *bus, const char *type) } qdev_set_parent_bus(dev, bus); - + object_unref(OBJECT(dev)); return dev; } @@ -268,7 +268,6 @@ void qdev_init_nofail(DeviceState *dev) void qdev_free(DeviceState *dev) { object_unparent(OBJECT(dev)); - object_unref(OBJECT(dev)); } void qdev_machine_creation_done(void) @@ -428,6 +427,7 @@ static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); bus->parent->num_child_bus++; object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); + object_unref(OBJECT(bus)); } else if (bus != sysbus_get_default()) { /* TODO: once all bus devices are qdevified, only reset handler for main_system_bus should be registered here. */ @@ -474,7 +474,6 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam void qbus_free(BusState *bus) { object_unparent(OBJECT(bus)); - object_unref(OBJECT(bus)); } static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) diff --git a/vl.c b/vl.c index f094f04a2c..315598994f 100644 --- a/vl.c +++ b/vl.c @@ -2236,6 +2236,7 @@ static int device_init_func(QemuOpts *opts, void *opaque) dev = qdev_device_add(opts); if (!dev) return -1; + object_unref(OBJECT(dev)); return 0; } From 5c099537a646370d85f9a0f6bc18371ceeeb14dc Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:38 +0100 Subject: [PATCH 0906/1634] cpu: do not use object_delete CPUs are never added to the composition tree, so delete is achieved simply by removing the last references to them. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- linux-user/syscall.c | 2 +- target-i386/helper.c | 4 ++-- target-ppc/translate_init.c | 2 +- target-sparc/cpu.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 693e66fc4f..a148d9f7f4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5202,7 +5202,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, NULL, NULL, 0); } thread_env = NULL; - object_delete(OBJECT(ENV_GET_CPU(cpu_env))); + object_unref(OBJECT(ENV_GET_CPU(cpu_env))); g_free(ts); pthread_exit(NULL); } diff --git a/target-i386/helper.c b/target-i386/helper.c index bdf83084ff..d1cb4e2445 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1278,14 +1278,14 @@ X86CPU *cpu_x86_init(const char *cpu_model) env->cpu_model_str = cpu_model; if (cpu_x86_register(cpu, cpu_model) < 0) { - object_delete(OBJECT(cpu)); + object_unref(OBJECT(cpu)); return NULL; } x86_cpu_realize(OBJECT(cpu), &error); if (error) { error_free(error); - object_delete(OBJECT(cpu)); + object_unref(OBJECT(cpu)); return NULL; } return cpu; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index e2021c4a05..f0388508bc 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10358,7 +10358,7 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model) if (err != NULL) { fprintf(stderr, "%s\n", error_get_pretty(err)); error_free(err); - object_delete(OBJECT(cpu)); + object_unref(OBJECT(cpu)); return NULL; } diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index f404aa8b5f..4bc1afc755 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -119,7 +119,7 @@ SPARCCPU *cpu_sparc_init(const char *cpu_model) } if (cpu_sparc_register(env, cpu_model) < 0) { - object_delete(OBJECT(cpu)); + object_unref(OBJECT(cpu)); return NULL; } qemu_init_vcpu(env); From b76facc35b0153cee5a8972f8a3c70694a7e3913 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 25 Jan 2013 14:12:39 +0100 Subject: [PATCH 0907/1634] qom: remove object_delete This is now unused. Document the initial reference count of an object and when it will be freed/finalized. Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- include/qom/object.h | 27 ++++++++++----------------- qom/object.c | 7 ------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index bfd848ffe3..cf094e7142 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -553,9 +553,9 @@ struct InterfaceClass * object_new: * @typename: The name of the type of the object to instantiate. * - * This function will initialize a new object using heap allocated memory. This - * function should be paired with object_delete() to free the resources - * associated with the object. + * This function will initialize a new object using heap allocated memory. + * The returned object has a reference count of 1, and will be freed when + * the last reference is dropped. * * Returns: The newly allocated and instantiated object. */ @@ -565,30 +565,22 @@ Object *object_new(const char *typename); * object_new_with_type: * @type: The type of the object to instantiate. * - * This function will initialize a new object using heap allocated memory. This - * function should be paired with object_delete() to free the resources - * associated with the object. + * This function will initialize a new object using heap allocated memory. + * The returned object has a reference count of 1, and will be freed when + * the last reference is dropped. * * Returns: The newly allocated and instantiated object. */ Object *object_new_with_type(Type type); -/** - * object_delete: - * @obj: The object to free. - * - * Finalize an object and then free the memory associated with it. This should - * be paired with object_new() to free the resources associated with an object. - */ -void object_delete(Object *obj); - /** * object_initialize_with_type: * @obj: A pointer to the memory to be used for the object. * @type: The type of the object to instantiate. * * This function will initialize an object. The memory for the object should - * have already been allocated. + * have already been allocated. The returned object has a reference count of 1, + * and will be finalized when the last reference is dropped. */ void object_initialize_with_type(void *data, Type type); @@ -598,7 +590,8 @@ void object_initialize_with_type(void *data, Type type); * @typename: The name of the type of the object to instantiate. * * This function will initialize an object. The memory for the object should - * have already been allocated. + * have already been allocated. The returned object has a reference count of 1, + * and will be finalized when the last reference is dropped. */ void object_initialize(void *obj, const char *typename); diff --git a/qom/object.c b/qom/object.c index 034f15cdec..563e45b0cc 100644 --- a/qom/object.c +++ b/qom/object.c @@ -417,13 +417,6 @@ Object *object_new(const char *typename) return object_new_with_type(ti); } -void object_delete(Object *obj) -{ - object_unparent(obj); - g_assert(obj->ref == 1); - object_unref(obj); -} - Object *object_dynamic_cast(Object *obj, const char *typename) { if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) { From 02cd809099322d6bdbd3fb232e9dd1018b125866 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 1 Feb 2013 18:02:50 -0600 Subject: [PATCH 0908/1634] tap: unbreak -netdev tap,fd=X The multiqueue patch series broke -netdev tap,fd=X which manifests as libvirt not being able to start a guest. This was because it passed NULL for the netdev name which results in an anonymous netdev device regardless of what the user specified. Cc: Jason Wang Cc: Bruce Rogers Reported-by: Bruce Rogers Signed-off-by: Anthony Liguori --- net/tap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tap.c b/net/tap.c index 1bf760995d..48c254ed85 100644 --- a/net/tap.c +++ b/net/tap.c @@ -711,7 +711,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name, vnet_hdr = tap_probe_vnet_hdr(fd); - if (net_init_tap_one(tap, peer, "tap", NULL, NULL, + if (net_init_tap_one(tap, peer, "tap", name, NULL, script, downscript, vhostfdname, vnet_hdr, fd)) { return -1; From abd8d4a4d6dfea7ddea72f095f993e1de941614e Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 1 Feb 2013 15:10:33 -0600 Subject: [PATCH 0909/1634] Update version for 1.4.0-rc0 Signed-off-by: Anthony Liguori --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 52356d37e0..619d9ea8c8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.50 +1.3.90 From 7b2d9779818f4c0d4c31d3a0292bee1c4b633217 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Wed, 16 Jan 2013 19:04:27 +0100 Subject: [PATCH 0910/1634] util: Fix compilation of envlist.c for MinGW MinGW has no strtok_r, so we need a declaration in sysemu/os-win32.h. We must also fix the include statements in util/envlist.c to include that file. We currently don't need an implementation of strtok_r because the code is compiled but not linked for MinGW. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- include/sysemu/os-win32.h | 2 ++ util/envlist.c | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index d0e9234d24..bf9edeb9ab 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -73,6 +73,8 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result); #undef localtime_r struct tm *localtime_r(const time_t *timep, struct tm *result); +char *strtok_r(char *str, const char *delim, char **saveptr); + static inline void os_setup_signal_handling(void) {} static inline void os_daemonize(void) {} static inline void os_setup_post(void) {} diff --git a/util/envlist.c b/util/envlist.c index ff99fc44e9..ebc06cf0f3 100644 --- a/util/envlist.c +++ b/util/envlist.c @@ -1,9 +1,4 @@ -#include -#include -#include -#include -#include - +#include "qemu-common.h" #include "qemu/queue.h" #include "qemu/envlist.h" From fbeadf50f2f965741def823036b086bbc2999b1f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 1 Feb 2013 23:03:16 +0100 Subject: [PATCH 0911/1634] bitops: unify bitops_ffsl with the one in host-utils.h, call it bitops_ctzl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We had two copies of a ffs function for longs with subtly different semantics and, for the one in bitops.h, a confusing name: the result was off-by-one compared to the library function ffsl. Unify the functions into one, and solve the name problem by calling the 0-based functions "bitops_ctzl" and "bitops_ctol" respectively. This also fixes the build on platforms with ffsl, including Mac OS X and Windows. Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Tested-by: Andreas Färber Tested-by: Peter Maydell Signed-off-by: Blue Swirl --- include/qemu/bitops.h | 55 ++++++++++++++++----------------------- include/qemu/hbitmap.h | 2 +- include/qemu/host-utils.h | 26 ------------------ memory.c | 4 +-- util/bitops.c | 4 +-- util/hbitmap.c | 2 +- 6 files changed, 28 insertions(+), 65 deletions(-) diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 74e14e5724..8b88791862 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -13,6 +13,7 @@ #define BITOPS_H #include "qemu-common.h" +#include "host-utils.h" #define BITS_PER_BYTE CHAR_BIT #define BITS_PER_LONG (sizeof (unsigned long) * BITS_PER_BYTE) @@ -23,41 +24,29 @@ #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) /** - * bitops_ffs - find first bit in word. + * bitops_ctzl - count trailing zeroes in word. * @word: The word to search * - * Undefined if no bit exists, so code should check against 0 first. + * Returns -1 if no bit exists. Note that compared to the C library + * routine ffsl, this one returns one less. */ -static unsigned long bitops_ffsl(unsigned long word) +static unsigned long bitops_ctzl(unsigned long word) { - int num = 0; +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_ffsl(word) - 1; +#else + if (!word) { + return -1; + } -#if LONG_MAX > 0x7FFFFFFF - if ((word & 0xffffffff) == 0) { - num += 32; - word >>= 32; - } + if (sizeof(long) == 4) { + return ctz32(word); + } else if (sizeof(long) == 8) { + return ctz64(word); + } else { + abort(); + } #endif - if ((word & 0xffff) == 0) { - num += 16; - word >>= 16; - } - if ((word & 0xff) == 0) { - num += 8; - word >>= 8; - } - if ((word & 0xf) == 0) { - num += 4; - word >>= 4; - } - if ((word & 0x3) == 0) { - num += 2; - word >>= 2; - } - if ((word & 0x1) == 0) { - num += 1; - } - return num; } /** @@ -99,14 +88,14 @@ static inline unsigned long bitops_flsl(unsigned long word) } /** - * ffz - find first zero in word. + * cto - count trailing ones in word. * @word: The word to search * - * Undefined if no zero exists, so code should check against ~0UL first. + * Returns -1 if all bit are set. */ -static inline unsigned long ffz(unsigned long word) +static inline unsigned long bitops_ctol(unsigned long word) { - return bitops_ffsl(~word); + return bitops_ctzl(~word); } /** diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 73f5d1d8d3..250de03b03 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -170,7 +170,7 @@ static inline int64_t hbitmap_iter_next(HBitmapIter *hbi) /* The next call will resume work from the next bit. */ hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); - item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ffsl(cur) - 1; + item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + bitops_ctzl(cur); return item << hbi->granularity; } diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 2a32be4cc0..81c9a754ae 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -26,7 +26,6 @@ #define HOST_UTILS_H 1 #include "qemu/compiler.h" /* QEMU_GNUC_PREREQ */ -#include /* ffsl */ #if defined(__x86_64__) #define __HAVE_FAST_MULU64__ @@ -238,29 +237,4 @@ static inline int ctpop64(uint64_t val) #endif } -/* glibc does not provide an inline version of ffsl, so always define - * ours. We need to give it a different name, however. - */ -#ifdef __GLIBC__ -#define ffsl qemu_ffsl -#endif -static inline int ffsl(long val) -{ - if (!val) { - return 0; - } - -#if QEMU_GNUC_PREREQ(3, 4) - return __builtin_ctzl(val) + 1; -#else - if (sizeof(long) == 4) { - return ctz32(val) + 1; - } else if (sizeof(long) == 8) { - return ctz64(val) + 1; - } else { - abort(); - } -#endif -} - #endif diff --git a/memory.c b/memory.c index 410c5f80b4..cd7d5e0cf5 100644 --- a/memory.c +++ b/memory.c @@ -855,7 +855,7 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr, } if (!mr->ops->read) { - return mr->ops->old_mmio.read[bitops_ffsl(size)](mr->opaque, addr); + return mr->ops->old_mmio.read[bitops_ctzl(size)](mr->opaque, addr); } /* FIXME: support unaligned access */ @@ -908,7 +908,7 @@ static void memory_region_dispatch_write(MemoryRegion *mr, adjust_endianness(mr, &data, size); if (!mr->ops->write) { - mr->ops->old_mmio.write[bitops_ffsl(size)](mr->opaque, addr, data); + mr->ops->old_mmio.write[bitops_ctzl(size)](mr->opaque, addr, data); return; } diff --git a/util/bitops.c b/util/bitops.c index 4c3a836a01..7b853cf944 100644 --- a/util/bitops.c +++ b/util/bitops.c @@ -60,7 +60,7 @@ found_first: return result + size; /* Nope. */ } found_middle: - return result + bitops_ffsl(tmp); + return result + bitops_ctzl(tmp); } /* @@ -109,7 +109,7 @@ found_first: return result + size; /* Nope. */ } found_middle: - return result + ffz(tmp); + return result + bitops_ctol(tmp); } unsigned long find_last_bit(const unsigned long *addr, unsigned long size) diff --git a/util/hbitmap.c b/util/hbitmap.c index 2aa487db74..a0df5d3591 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -126,7 +126,7 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) * The index of this word's least significant set bit provides * the low-order bits. */ - pos = (pos << BITS_PER_LEVEL) + ffsl(cur) - 1; + pos = (pos << BITS_PER_LEVEL) + bitops_ctzl(cur); hbi->cur[i] = cur & (cur - 1); /* Set up next level for iteration. */ From ff057ccb07f07ee8f34ae4104f7ba8c2dcbc3f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 07:26:05 +0100 Subject: [PATCH 0912/1634] target-cris: Build fix for debug output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Around r3361 (81fdc5f8d2d681da8d255baf0713144f8656bac9) env->debug1 used to contain the address of an MMU fault. This is now written into env->pregs[PR_EDA] instead. Signed-off-by: Andreas Färber Signed-off-by: Edgar E. Iglesias --- target-cris/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index 0f6a1eeb0a..b580513848 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -60,7 +60,7 @@ void tlb_fill(CPUCRISState *env, target_ulong addr, int is_write, int mmu_idx, int ret; D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__, - env->pc, env->debug1, (void *)retaddr); + env->pc, env->pregs[PR_EDA], (void *)retaddr); ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx); if (unlikely(ret)) { if (retaddr) { From e3f9fe2d404ca10153e95499ece111c077b6690a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:45 -0200 Subject: [PATCH 0913/1634] cutils: unsigned int parsing functions There are lots of duplicate parsing code using strto*() in QEMU, and most of that code is broken in one way or another. Even the visitors code have duplicate integer parsing code[1]. This introduces functions to help parsing unsigned int values: parse_uint() and parse_uint_full(). Parsing functions for signed ints and floats will be submitted later. parse_uint_full() has all the checks made by opts_type_uint64() at opts-visitor.c: - Check for NULL (returns -EINVAL) - Check for negative numbers (returns -EINVAL) - Check for empty string (returns -EINVAL) - Check for overflow or other errno values set by strtoll() (returns -errno) - Check for end of string (reject invalid characters after number) (returns -EINVAL) parse_uint() does everything above except checking for the end of the string, so callers can continue parsing the remainder of string after the number. Unit tests included. [1] string-input-visitor.c:parse_int() could use the same parsing code used by opts-visitor.c:opts_type_int(), instead of duplicating that logic. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Reviewed-by: Laszlo Ersek Signed-off-by: Anthony Liguori --- include/qemu-common.h | 4 + tests/Makefile | 3 + tests/test-cutils.c | 251 ++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 99 +++++++++++++++++ 4 files changed, 357 insertions(+) create mode 100644 tests/test-cutils.c diff --git a/include/qemu-common.h b/include/qemu-common.h index af2379ff38..80016adae3 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -173,6 +173,10 @@ int qemu_fdatasync(int fd); int fcntl_setfl(int fd, int flag); int qemu_parse_fd(const char *param); +int parse_uint(const char *s, unsigned long long *value, char **endptr, + int base); +int parse_uint_full(const char *s, unsigned long long *value, int base); + /* * strtosz() suffixes used to specify the default treatment of an * argument passed to strtosz() without an explicit suffix. diff --git a/tests/Makefile b/tests/Makefile index 83145f5d31..a2d62b8596 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -52,6 +52,8 @@ check-unit-y += tests/test-x86-cpuid$(EXESUF) gcov-files-test-x86-cpuid-y = check-unit-y += tests/test-xbzrle$(EXESUF) gcov-files-test-xbzrle-y = xbzrle.c +check-unit-y += tests/test-cutils$(EXESUF) +gcov-files-test-cutils-y += util/cutils.c check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -101,6 +103,7 @@ tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o xbzrle.o page_cache.o libqemuutil.a +tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py diff --git a/tests/test-cutils.c b/tests/test-cutils.c new file mode 100644 index 0000000000..2a4556d3aa --- /dev/null +++ b/tests/test-cutils.c @@ -0,0 +1,251 @@ +/* + * cutils.c unit-tests + * + * Copyright (C) 2013 Red Hat Inc. + * + * Authors: + * Eduardo Habkost + * + * 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 +#include + +#include "qemu-common.h" + + +static void test_parse_uint_null(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + int r; + + r = parse_uint(NULL, &i, &endptr, 0); + + g_assert_cmpint(r, ==, -EINVAL); + g_assert_cmpint(i, ==, 0); + g_assert(endptr == NULL); +} + +static void test_parse_uint_empty(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = ""; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, -EINVAL); + g_assert_cmpint(i, ==, 0); + g_assert(endptr == str); +} + +static void test_parse_uint_whitespace(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = " \t "; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, -EINVAL); + g_assert_cmpint(i, ==, 0); + g_assert(endptr == str); +} + + +static void test_parse_uint_invalid(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = " \t xxx"; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, -EINVAL); + g_assert_cmpint(i, ==, 0); + g_assert(endptr == str); +} + + +static void test_parse_uint_trailing(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = "123xxx"; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, 0); + g_assert_cmpint(i, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_parse_uint_correct(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = "123"; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, 0); + g_assert_cmpint(i, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_parse_uint_octal(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = "0123"; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, 0); + g_assert_cmpint(i, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_parse_uint_decimal(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = "0123"; + int r; + + r = parse_uint(str, &i, &endptr, 10); + + g_assert_cmpint(r, ==, 0); + g_assert_cmpint(i, ==, 123); + g_assert(endptr == str + strlen(str)); +} + + +static void test_parse_uint_llong_max(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + char *str = g_strdup_printf("%llu", (unsigned long long)LLONG_MAX + 1); + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, 0); + g_assert_cmpint(i, ==, (unsigned long long)LLONG_MAX + 1); + g_assert(endptr == str + strlen(str)); + + g_free(str); +} + +static void test_parse_uint_overflow(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = "99999999999999999999999999999999999999"; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, -ERANGE); + g_assert_cmpint(i, ==, ULLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_parse_uint_negative(void) +{ + unsigned long long i = 999; + char f = 'X'; + char *endptr = &f; + const char *str = " \t -321"; + int r; + + r = parse_uint(str, &i, &endptr, 0); + + g_assert_cmpint(r, ==, -ERANGE); + g_assert_cmpint(i, ==, 0); + g_assert(endptr == str + strlen(str)); +} + + +static void test_parse_uint_full_trailing(void) +{ + unsigned long long i = 999; + const char *str = "123xxx"; + int r; + + r = parse_uint_full(str, &i, 0); + + g_assert_cmpint(r, ==, -EINVAL); + g_assert_cmpint(i, ==, 0); +} + +static void test_parse_uint_full_correct(void) +{ + unsigned long long i = 999; + const char *str = "123"; + int r; + + r = parse_uint_full(str, &i, 0); + + g_assert_cmpint(r, ==, 0); + g_assert_cmpint(i, ==, 123); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/cutils/parse_uint/null", test_parse_uint_null); + g_test_add_func("/cutils/parse_uint/empty", test_parse_uint_empty); + g_test_add_func("/cutils/parse_uint/whitespace", + test_parse_uint_whitespace); + g_test_add_func("/cutils/parse_uint/invalid", test_parse_uint_invalid); + g_test_add_func("/cutils/parse_uint/trailing", test_parse_uint_trailing); + g_test_add_func("/cutils/parse_uint/correct", test_parse_uint_correct); + g_test_add_func("/cutils/parse_uint/octal", test_parse_uint_octal); + g_test_add_func("/cutils/parse_uint/decimal", test_parse_uint_decimal); + g_test_add_func("/cutils/parse_uint/llong_max", test_parse_uint_llong_max); + g_test_add_func("/cutils/parse_uint/overflow", test_parse_uint_overflow); + g_test_add_func("/cutils/parse_uint/negative", test_parse_uint_negative); + g_test_add_func("/cutils/parse_uint_full/trailing", + test_parse_uint_full_trailing); + g_test_add_func("/cutils/parse_uint_full/correct", + test_parse_uint_full_correct); + + return g_test_run(); +} diff --git a/util/cutils.c b/util/cutils.c index 80bb1dcbf7..1439da4f99 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -270,6 +270,105 @@ int64_t strtosz(const char *nptr, char **end) return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB); } +/** + * parse_uint: + * + * @s: String to parse + * @value: Destination for parsed integer value + * @endptr: Destination for pointer to first character not consumed + * @base: integer base, between 2 and 36 inclusive, or 0 + * + * Parse unsigned integer + * + * Parsed syntax is like strtoull()'s: arbitrary whitespace, a single optional + * '+' or '-', an optional "0x" if @base is 0 or 16, one or more digits. + * + * If @s is null, or @base is invalid, or @s doesn't start with an + * integer in the syntax above, set *@value to 0, *@endptr to @s, and + * return -EINVAL. + * + * Set *@endptr to point right beyond the parsed integer (even if the integer + * overflows or is negative, all digits will be parsed and *@endptr will + * point right beyond them). + * + * If the integer is negative, set *@value to 0, and return -ERANGE. + * + * If the integer overflows unsigned long long, set *@value to + * ULLONG_MAX, and return -ERANGE. + * + * Else, set *@value to the parsed integer, and return 0. + */ +int parse_uint(const char *s, unsigned long long *value, char **endptr, + int base) +{ + int r = 0; + char *endp = (char *)s; + unsigned long long val = 0; + + if (!s) { + r = -EINVAL; + goto out; + } + + errno = 0; + val = strtoull(s, &endp, base); + if (errno) { + r = -errno; + goto out; + } + + if (endp == s) { + r = -EINVAL; + goto out; + } + + /* make sure we reject negative numbers: */ + while (isspace((unsigned char)*s)) { + s++; + } + if (*s == '-') { + val = 0; + r = -ERANGE; + goto out; + } + +out: + *value = val; + *endptr = endp; + return r; +} + +/** + * parse_uint_full: + * + * @s: String to parse + * @value: Destination for parsed integer value + * @base: integer base, between 2 and 36 inclusive, or 0 + * + * Parse unsigned integer from entire string + * + * Have the same behavior of parse_uint(), but with an additional check + * for additional data after the parsed number. If extra characters are present + * after the parsed number, the function will return -EINVAL, and *@v will + * be set to 0. + */ +int parse_uint_full(const char *s, unsigned long long *value, int base) +{ + char *endp; + int r; + + r = parse_uint(s, value, &endp, base); + if (r < 0) { + return r; + } + if (*endp) { + *value = 0; + return -EINVAL; + } + + return 0; +} + int qemu_parse_fd(const char *param) { int fd; From 8f302cb0900ba7f38b62da5759f07b77483d6fb9 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:46 -0200 Subject: [PATCH 0914/1634] vl.c: Fix off-by-one bug when handling "-numa node" argument The numa_add() code was unconditionally adding 1 to the get_opt_name() return value, making it point after the end of the string if no ',' separator is present. Example of weird behavior caused by the bug: $ qemu-img create -f qcow2 this-file-image-has,cpus=5,mem=1000,in-its-name.qcow2 5G Formatting 'this-file-image-has,cpus=5,mem=1000,in-its-name.qcow2', fmt=qcow2 size=5368709120 encryption=off cluster_size=65536 $ ./x86_64-softmmu/qemu-system-x86_64 -S -monitor stdio -numa node 'this-file-image-has,cpus=5,mem=1000,in-its-name.qcow2' QEMU 1.3.50 monitor - type 'help' for more information (qemu) info numa 1 nodes node 0 cpus: 0 node 0 size: 1000 MB (qemu) This changes the code to nove the pointer only if ',' is found. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- vl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 315598994f..0dae44cd60 100644 --- a/vl.c +++ b/vl.c @@ -1253,7 +1253,10 @@ static void numa_add(const char *optarg) value = endvalue = 0ULL; - optarg = get_opt_name(option, 128, optarg, ',') + 1; + optarg = get_opt_name(option, 128, optarg, ','); + if (*optarg == ',') { + optarg++; + } if (!strcmp(option, "node")) { if (get_param_value(option, 128, "nodeid", optarg) == 0) { nodenr = nb_numa_nodes; From 12e53a9d59c8cb272a423e1db036324579a3c697 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:47 -0200 Subject: [PATCH 0915/1634] vl.c: Abort on unknown -numa option type Abort in case an invalid -numa option is provided, instead of silently ignoring it. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- vl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vl.c b/vl.c index 0dae44cd60..586aa9a70a 100644 --- a/vl.c +++ b/vl.c @@ -1293,6 +1293,9 @@ static void numa_add(const char *optarg) bitmap_set(node_cpumask[nodenr], value, endvalue-value+1); } nb_numa_nodes++; + } else { + fprintf(stderr, "Invalid -numa option: %s\n", option); + exit(1); } } From ca4c6d363153f19abf3ffdf0ca1532daa581867d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:48 -0200 Subject: [PATCH 0916/1634] vl.c: Check for NUMA node limit inside numa_add() Instead of checking the limit before calling numa_add(), check the limit only when we already know we're going to add a new node. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- vl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 586aa9a70a..89de00398f 100644 --- a/vl.c +++ b/vl.c @@ -1258,6 +1258,12 @@ static void numa_add(const char *optarg) optarg++; } if (!strcmp(option, "node")) { + + if (nb_numa_nodes >= MAX_NODES) { + fprintf(stderr, "qemu: too many NUMA nodes\n"); + exit(1); + } + if (get_param_value(option, 128, "nodeid", optarg) == 0) { nodenr = nb_numa_nodes; } else { @@ -3003,10 +3009,6 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_numa: - if (nb_numa_nodes >= MAX_NODES) { - fprintf(stderr, "qemu: too many NUMA nodes\n"); - exit(1); - } numa_add(optarg); break; case QEMU_OPTION_display: From e4ce85b25838694d2d7396b5e969eb4830329631 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:49 -0200 Subject: [PATCH 0917/1634] vl.c: numa_add(): Validate nodeid before using it Without this check, QEMU will corrupt memory if a too-large nodeid is provided in the command-line. e.g.: -numa node,mem=...,cpus=...,nodeid=65 This changes nodenr to unsigned long long, to avoid integer conversion issues when converting the strtoull() result to int. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- vl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 89de00398f..4955c2972d 100644 --- a/vl.c +++ b/vl.c @@ -1249,7 +1249,7 @@ static void numa_add(const char *optarg) char option[128]; char *endptr; unsigned long long value, endvalue; - int nodenr; + unsigned long long nodenr; value = endvalue = 0ULL; @@ -1270,6 +1270,11 @@ static void numa_add(const char *optarg) nodenr = strtoull(option, NULL, 10); } + if (nodenr >= MAX_NODES) { + fprintf(stderr, "qemu: invalid NUMA nodeid: %llu\n", nodenr); + exit(1); + } + if (get_param_value(option, 128, "mem", optarg) == 0) { node_mem[nodenr] = 0; } else { From 5f1399651eaab1b04e49107250d182968a227aa6 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:50 -0200 Subject: [PATCH 0918/1634] vl.c: Use parse_uint_full() for NUMA nodeid This should catch many kinds of errors that the current code wasn't checking for: - Values that can't be parsed as a number - Negative values - Overflow - Empty string Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- vl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vl.c b/vl.c index 4955c2972d..d6f6422de4 100644 --- a/vl.c +++ b/vl.c @@ -1267,7 +1267,10 @@ static void numa_add(const char *optarg) if (get_param_value(option, 128, "nodeid", optarg) == 0) { nodenr = nb_numa_nodes; } else { - nodenr = strtoull(option, NULL, 10); + if (parse_uint_full(option, &nodenr, 10) < 0) { + fprintf(stderr, "qemu: Invalid NUMA nodeid: %s\n", option); + exit(1); + } } if (nodenr >= MAX_NODES) { From 845e5bf9cd49873c72f84796cabf107c3f520f37 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:51 -0200 Subject: [PATCH 0919/1634] vl.c: Extract -numa "cpus" parsing to separate function This will make it easier to refactor that code later. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- vl.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/vl.c b/vl.c index d6f6422de4..de164f8725 100644 --- a/vl.c +++ b/vl.c @@ -1244,15 +1244,34 @@ char *get_boot_devices_list(size_t *size) return list; } +static void numa_node_parse_cpus(int nodenr, const char *cpus) +{ + char *endptr; + unsigned long long value, endvalue; + + value = strtoull(cpus, &endptr, 10); + if (*endptr == '-') { + endvalue = strtoull(endptr+1, &endptr, 10); + } else { + endvalue = value; + } + + if (!(endvalue < MAX_CPUMASK_BITS)) { + endvalue = MAX_CPUMASK_BITS - 1; + fprintf(stderr, + "A max of %d CPUs are supported in a guest\n", + MAX_CPUMASK_BITS); + } + + bitmap_set(node_cpumask[nodenr], value, endvalue-value+1); +} + static void numa_add(const char *optarg) { char option[128]; char *endptr; - unsigned long long value, endvalue; unsigned long long nodenr; - value = endvalue = 0ULL; - optarg = get_opt_name(option, 128, optarg, ','); if (*optarg == ',') { optarg++; @@ -1290,21 +1309,7 @@ static void numa_add(const char *optarg) node_mem[nodenr] = sval; } if (get_param_value(option, 128, "cpus", optarg) != 0) { - value = strtoull(option, &endptr, 10); - if (*endptr == '-') { - endvalue = strtoull(endptr+1, &endptr, 10); - } else { - endvalue = value; - } - - if (!(endvalue < MAX_CPUMASK_BITS)) { - endvalue = MAX_CPUMASK_BITS - 1; - fprintf(stderr, - "A max of %d CPUs are supported in a guest\n", - MAX_CPUMASK_BITS); - } - - bitmap_set(node_cpumask[nodenr], value, endvalue-value+1); + numa_node_parse_cpus(nodenr, option); } nb_numa_nodes++; } else { From c881e20eed4911ab6f8c674f2b1bf225a2cdde71 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 4 Feb 2013 16:27:52 -0200 Subject: [PATCH 0920/1634] vl.c: validate -numa "cpus" parameter properly - Accept empty strings without aborting - Use parse_uint*() to parse numbers - Abort if anything except '-' or end-of-string is found after the first number. - Check for endvalue < value Also change the MAX_CPUMASK_BITS warning message from "A max of %d CPUs are supported in a guest" to "qemu: NUMA: A max of %d VCPUs are supported". Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- vl.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/vl.c b/vl.c index de164f8725..a8dc73d61d 100644 --- a/vl.c +++ b/vl.c @@ -1249,21 +1249,43 @@ static void numa_node_parse_cpus(int nodenr, const char *cpus) char *endptr; unsigned long long value, endvalue; - value = strtoull(cpus, &endptr, 10); - if (*endptr == '-') { - endvalue = strtoull(endptr+1, &endptr, 10); - } else { - endvalue = value; + /* Empty CPU range strings will be considered valid, they will simply + * not set any bit in the CPU bitmap. + */ + if (!*cpus) { + return; } - if (!(endvalue < MAX_CPUMASK_BITS)) { + if (parse_uint(cpus, &value, &endptr, 10) < 0) { + goto error; + } + if (*endptr == '-') { + if (parse_uint_full(endptr + 1, &endvalue, 10) < 0) { + goto error; + } + } else if (*endptr == '\0') { + endvalue = value; + } else { + goto error; + } + + if (endvalue >= MAX_CPUMASK_BITS) { endvalue = MAX_CPUMASK_BITS - 1; fprintf(stderr, - "A max of %d CPUs are supported in a guest\n", + "qemu: NUMA: A max of %d VCPUs are supported\n", MAX_CPUMASK_BITS); } + if (endvalue < value) { + goto error; + } + bitmap_set(node_cpumask[nodenr], value, endvalue-value+1); + return; + +error: + fprintf(stderr, "qemu: Invalid NUMA CPU range: %s\n", cpus); + exit(1); } static void numa_add(const char *optarg) From ded67782e6d06069873adce7f9074d273ae75760 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Mon, 4 Feb 2013 10:07:51 -0600 Subject: [PATCH 0921/1634] acpi_piix4: fix segfault migrating from 1.2 b0b873a07872f7ab7f66f259c73fb9dd42aa66a9 bumped the vmstate version and introduced an old-style load function to handle migration from prior (<= 1.2) versions. The load function passes the top-level PIIX4PMState pointer to vmstate_load_state() to handle nested structs for APMState and pci_status, which leads to corruption of the top-level PIIX4PMState, since pointers to the nested structs are expected. A segfault can be fairly reliably triggered by migrating from 1.2 and issuing a reset, which will trigger a number of QOM operations which rely on the now corrupted ObjectClass/Object members. Fix this by passing in the expected pointers for vmstate_load_state(). Cc: qemu-stable@nongnu.org Signed-off-by: Michael Roth Signed-off-by: Anthony Liguori --- hw/acpi_piix4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 0d33849e95..65b26013bd 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -235,7 +235,7 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_be16s(f, &s->ar.pm1.evt.en); qemu_get_be16s(f, &s->ar.pm1.cnt.cnt); - ret = vmstate_load_state(f, &vmstate_apm, opaque, 1); + ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1); if (ret) { return ret; } @@ -253,7 +253,7 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_be16s(f, &temp); } - ret = vmstate_load_state(f, &vmstate_pci_status, opaque, 1); + ret = vmstate_load_state(f, &vmstate_pci_status, &s->pci0_status, 1); return ret; } From 0123c486367ab77c3c5ed349616a862eb474a03f Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Mon, 4 Feb 2013 15:22:08 -0600 Subject: [PATCH 0922/1634] s390x: silence warning from GCC on uninitialized values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As best I can tell, this is a false positive. [aliguori@ccnode4 qemu-s390]$ make CC s390x-softmmu/target-s390x/helper.o /home/aliguori/git/qemu/target-s390x/helper.c: In function ‘do_interrupt’: /home/aliguori/git/qemu/target-s390x/helper.c:673:17: error: ‘addr’ may be used uninitialized in this function [-Werror=maybe-uninitialized] /home/aliguori/git/qemu/target-s390x/helper.c:620:20: note: ‘addr’ was declared here /home/aliguori/git/qemu/target-s390x/helper.c:673:17: error: ‘mask’ may be used uninitialized in this function [-Werror=maybe-uninitialized] /home/aliguori/git/qemu/target-s390x/helper.c:620:14: note: ‘mask’ was declared here cc1: all warnings being treated as errors make[1]: *** [target-s390x/helper.o] Error 1 make: *** [subdir-s390x-softmmu] Error 2 Cc: Cornelia Huck Cc: Stefan Weil Signed-off-by: Anthony Liguori --- target-s390x/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 3180b90ed8..95f1ff5443 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -617,7 +617,7 @@ static void do_ext_interrupt(CPUS390XState *env) static void do_io_interrupt(CPUS390XState *env) { - uint64_t mask, addr; + uint64_t mask = 0, addr = 0; LowCore *lowcore; IOIntQueue *q; uint8_t isc; From b22dd1243f38286263d40496ce5298a8a7d96eea Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 3 Feb 2013 21:33:16 +0100 Subject: [PATCH 0923/1634] target-s390x: Fix wrong comparison in interrupt handling gcc with -Wextra complains about an ordered pointer comparison: target-s390x/helper.c:660:27: warning: ordered comparison of pointer with integer zero [-Wextra] Obviously the index was missing in the code. Signed-off-by: Stefan Weil Signed-off-by: Anthony Liguori --- target-s390x/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 95f1ff5443..043feb2739 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -657,7 +657,7 @@ static void do_io_interrupt(CPUS390XState *env) cpu_unmap_lowcore(lowcore); env->io_index[isc]--; - if (env->io_index >= 0) { + if (env->io_index[isc] >= 0) { disable = 0; } break; From fb3a508531227bc7fb7eee22c51d30bf2ceb15f5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 25 Jan 2013 16:43:37 +0100 Subject: [PATCH 0924/1634] trace: Fix simple trace dropped event record for big endian We use atomic operations to keep track of dropped events. Inconveniently, GLib supports only int and void * atomics, but the counter dropped_events is uint64_t. Can't stop commit 62bab732: a quick (gint *)&dropped_events bludgeons the compiler into submission. That cast is okay only when int is exactly 64 bits wide, which it commonly isn't. If int is even wider, we clobber whatever follows dropped_events. Not worth worrying about, as none of the machines that interest us have such morbidly obese ints. That leaves the common case: int narrower than 64 bits. Harmless on little endian hosts: we just don't access the most significant bits of dropped_events. They remain zero. On big endian hosts, we use only the most significant bits of dropped_events as counter. The least significant bits remain zero. However, we write out the full value, which is the correct counter shifted left a bunch of places. Fix by changing the variables involved to int. There's another, equally suspicious-looking (gint *)&trace_idx argument to g_atomic_int_compare_and_exchange(), but that one casts unsigned *, so it's okay. But it's also superfluous, because GLib's atomic int operations work just fine for unsigned. Drop it. Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Signed-off-by: Stefan Hajnoczi --- trace/simple.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/trace/simple.c b/trace/simple.c index ce17d64bd7..ccbdb6a930 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -53,7 +53,7 @@ enum { uint8_t trace_buf[TRACE_BUF_LEN]; static unsigned int trace_idx; static unsigned int writeout_idx; -static uint64_t dropped_events; +static int dropped_events; static FILE *trace_fp; static char *trace_file_name; @@ -63,7 +63,7 @@ typedef struct { uint64_t timestamp_ns; uint32_t length; /* in bytes */ uint32_t reserved; /* unused */ - uint8_t arguments[]; + uint64_t arguments[]; } TraceRecord; typedef struct { @@ -160,7 +160,7 @@ static gpointer writeout_thread(gpointer opaque) uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)]; } dropped; unsigned int idx = 0; - uint64_t dropped_count; + int dropped_count; size_t unused __attribute__ ((unused)); for (;;) { @@ -169,16 +169,16 @@ static gpointer writeout_thread(gpointer opaque) if (dropped_events) { dropped.rec.event = DROPPED_EVENT_ID, dropped.rec.timestamp_ns = get_clock(); - dropped.rec.length = sizeof(TraceRecord) + sizeof(dropped_events), + dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t), dropped.rec.reserved = 0; while (1) { dropped_count = dropped_events; - if (g_atomic_int_compare_and_exchange((gint *)&dropped_events, + if (g_atomic_int_compare_and_exchange(&dropped_events, dropped_count, 0)) { break; } } - memcpy(dropped.rec.arguments, &dropped_count, sizeof(uint64_t)); + dropped.rec.arguments[0] = dropped_count; unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); } @@ -220,11 +220,11 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi if (new_idx - writeout_idx > TRACE_BUF_LEN) { /* Trace Buffer Full, Event dropped ! */ - g_atomic_int_inc((gint *)&dropped_events); + g_atomic_int_inc(&dropped_events); return -ENOSPC; } - if (g_atomic_int_compare_and_exchange((gint *)&trace_idx, + if (g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx)) { break; } From e722d705ae7648a6bd94848319a11eb0afd58a17 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 25 Jan 2013 16:43:38 +0100 Subject: [PATCH 0925/1634] trace: Direct access of atomics is verboten, use the API The GLib Reference Manual says: It is very important that all accesses to a particular integer or pointer be performed using only this API and that different sizes of operation are not mixed or used on overlapping memory regions. Never read or assign directly from or to a value -- always use this API. Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Reviewed-by: Harsh Prateek Bora Signed-off-by: Stefan Hajnoczi --- trace/simple.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/trace/simple.c b/trace/simple.c index ccbdb6a930..592ff483cc 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -166,13 +166,13 @@ static gpointer writeout_thread(gpointer opaque) for (;;) { wait_for_trace_records_available(); - if (dropped_events) { + if (g_atomic_int_get(&dropped_events)) { dropped.rec.event = DROPPED_EVENT_ID, dropped.rec.timestamp_ns = get_clock(); dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t), dropped.rec.reserved = 0; while (1) { - dropped_count = dropped_events; + dropped_count = g_atomic_int_get(&dropped_events); if (g_atomic_int_compare_and_exchange(&dropped_events, dropped_count, 0)) { break; @@ -214,7 +214,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi uint64_t timestamp_ns = get_clock(); while (1) { - old_idx = trace_idx; + old_idx = g_atomic_int_get(&trace_idx); smp_rmb(); new_idx = old_idx + rec_len; @@ -275,7 +275,8 @@ void trace_record_finish(TraceBufferRecord *rec) record.event |= TRACE_RECORD_VALID; write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); - if ((trace_idx - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) { + if ((g_atomic_int_get(&trace_idx) - writeout_idx) + > TRACE_BUF_FLUSH_THRESHOLD) { flush_trace_file(false); } } From b6b2c9628084f1672b92393cf84039a075a95301 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 25 Jan 2013 16:43:39 +0100 Subject: [PATCH 0926/1634] trace: Clean up the "try to update atomic until it worked" loops Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Reviewed-by: Harsh Prateek Bora Signed-off-by: Stefan Hajnoczi --- trace/simple.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/trace/simple.c b/trace/simple.c index 592ff483cc..74701e3272 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -171,13 +171,10 @@ static gpointer writeout_thread(gpointer opaque) dropped.rec.timestamp_ns = get_clock(); dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t), dropped.rec.reserved = 0; - while (1) { + do { dropped_count = g_atomic_int_get(&dropped_events); - if (g_atomic_int_compare_and_exchange(&dropped_events, - dropped_count, 0)) { - break; - } - } + } while (!g_atomic_int_compare_and_exchange(&dropped_events, + dropped_count, 0)); dropped.rec.arguments[0] = dropped_count; unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp); } @@ -213,7 +210,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi uint32_t rec_len = sizeof(TraceRecord) + datasize; uint64_t timestamp_ns = get_clock(); - while (1) { + do { old_idx = g_atomic_int_get(&trace_idx); smp_rmb(); new_idx = old_idx + rec_len; @@ -223,12 +220,7 @@ int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasi g_atomic_int_inc(&dropped_events); return -ENOSPC; } - - if (g_atomic_int_compare_and_exchange(&trace_idx, - old_idx, new_idx)) { - break; - } - } + } while (!g_atomic_int_compare_and_exchange(&trace_idx, old_idx, new_idx)); idx = old_idx % TRACE_BUF_LEN; From 8f44015e4600041e200506720e39de7728c5cde9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 25 Jan 2013 16:43:40 +0100 Subject: [PATCH 0927/1634] trace: Fix location of simpletrace.py in docs Missed when commit 4c3b5a48 moved it. Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Reviewed-by: Harsh Prateek Bora Signed-off-by: Stefan Hajnoczi --- docs/tracing.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tracing.txt b/docs/tracing.txt index 453cc4a63d..14db3bffb4 100644 --- a/docs/tracing.txt +++ b/docs/tracing.txt @@ -23,7 +23,7 @@ for debugging, profiling, and observing execution. 4. Pretty-print the binary trace file: - ./simpletrace.py trace-events trace-* + ./scripts/simpletrace.py trace-events trace-* == Trace events == @@ -198,7 +198,7 @@ The "simple" backend produces binary trace files that can be formatted with the simpletrace.py script. The script takes the "trace-events" file and the binary trace: - ./simpletrace.py trace-events trace-12345 + ./scripts/simpletrace.py trace-events trace-12345 You must ensure that the same "trace-events" file was used to build QEMU, otherwise trace event declarations may have changed and output will not be From 5f876756c57c15f5e14d4136fc432b74f05f082b Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 6 Feb 2013 05:12:06 -0600 Subject: [PATCH 0928/1634] bios: recompile BIOS SeaBIOS is really close to spilling over to 256k. Until we can better handle migration across RAM block size changes, recompile SeaBIOS with a compiler that causes the binary to still fit in 128k. This was built with: gcc version 4.7.2 20121109 (Red Hat 4.7.2-8) (GCC) On 64-bit Fedora 18. Signed-off-by: Anthony Liguori --- pc-bios/bios.bin | Bin 262144 -> 131072 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index 924bee30d54a711a9d849ec4c67d38bef9ca03f4..ab5dd9db6addf9d6a6f67697231ef604bab02fc8 100644 GIT binary patch literal 131072 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 q<)rWeHdb1VSAF{X0pXtguPo$vJ`2qN literal 262144 zcmeFadw5jU)d#$1<|LVfA!h;u28j}M)I_i)6_uEvlN*Gq;f`Fj#dHAMBFq5R0Es7Q zvvZhNTeY?CYpoR9TJ^1|mk&Y&B>z=)@h2S?>e}pcg?~Mlkj+=sf5Ws3DuNYjPN?038Hf0^OL)SS{!+&}L8w zbO{tU5;%iy1N|7Z2=qJ9^Ppk(AU)_k(1d%@519q?KcBI2pr3(;Jiyq0{RHKLHi0@o*De4?pdW)OK~I2w_7G(Ar;LqS z$=Gi}{{#9GH2zV>CV?IT{Tx&aa{Ll~4|;nQuml|iy|#w2CeR*G-*V)yU~C;|1Ly?k zcokzm{Wa>9_R<}BYg|x40H|XI?zw{ z0B6vj_F@c!M(<_<;_9f@v7X*D=-#>UTZ*6*L+23(zIdkaXyA(9*$>Wzb)5fPCG| z*wkCl_n@g6;2pFU`tPrxoFAaPA2Ajl&e%}sx_^KcWi$4-yV38Un{rS;=(b$w1W@1} z$QtNtQ0cvlJpxiZ=s!?1=;sB{X@!t6(ApyCF3`uI1EA|iLHB~DfaZdp0R0uz1TsJ) zM*}<1VbHE(#-@+Kcme%vEXo4C3;G=NH7I2q$^*>>eF<7U0qp|WCZg{^g`kO`QqZfQ zzubp81!OOQ+<~@(22NtE3bYy220AkZV}B~-6qG{*9rsVr=b)n?H}u_T(8r+68H`0{ zVlKNM;}YbU1w9HH51I>F2I8PibI~5q_46RRpoO4apf5oy=3{(-?sx#t523$6*`?5V zpiQ9spE7pyO0*mFKB)hrka+6;Oh)B(ETamM0*g)q>spzGQ}*Kx=b=zWl_1~LPB1@vwJ{RDdTzo2VD2S6u4 zOP|Di2RZ|~@i&Y;3fczx8kG23v!4^!V=~ zL!j55g`9&tf54msvi=X|KG0hr`yU|}pi|F-{}&+hpszsF)?v(nj)FG+88*Xuj9pO1 zix@9|K|P>*{>oT6sPS)%t$B&DtiPl0K=*-O20ivN#ssJiv=?*=)bADa1?W!D!=RTy zt*>%j00wEazt?K;%A5w-wmTLZ@a zCh!J&nP@X`dz-P>K|9}J?7|kL4PxE~#Xv2Mkb!OBDU3FPGMgB?We4g9-TfZssh!{( zuoAorP`OZejNMXyb#B3D87@&jfulz``zq`d@2dBR~b9F`&7ig`lON6`*~0TiBPN zv!IJ0dya+m0WAhS0s1@WP0$ulGiVQJKZxa8mpaUCL9 z1g_H>z1#&u7H*SyjWecC(dW3G`mpn#L`UeWoxCHnWpHzL$BN9HQI4f!EWnTB4$ZZt4L`2?S74&5X3S1@ncy}s4%?)EF!e>^{ix3FQ!++=0N^vwN~^rYwU+Dbzsin8Fn||Io|Ox{dUwr>bv(J~d!k z;7JPSB?>>#P&iFx6&KhN*tK@Pqv9ZI2MA7mteqFzdA?o8Ukea6bcfsfVM;Qa#(%8n zKT%?P^j`Xd3U4)N89cW!8pn;8%dKrwfb`r(>T~{43E$IG`5IJCIHgSCr+S*Q2!XTF z(cOsDQ(LAHnWhjd4aLV zbgMo~;WjibMPK5~SxVqfcJdM@pQ-36`uz&;n-xTcR6XCBlSi?6PM(k6QL=(jo7Nly z6MC_dQ*2)rSDg~`D2cvm)r=ibJ>G4r zE}pLcGL>JbE}l^ec`D__Gizqsw6AQ{GiQYkI4h2jDIYrGNW7rdmAP$+7b*^mki+)G zQ@mJd^4JmY(I+Sn@l1V;qD4x|ADv8yBT~~FSKfaK(#KuzzlxvPjp6*E zmT>-Uth6cr2Z^jHe;5{sESx|5R5<^R_NM$1tQO9Ze2*f2#@oeDNgGy};ry9OIRAcY zIDa;N=O`%PftZTFKaQzQ`Ahy%j-L5Xg(K4)w*OQ(EnEMkaOb}i{xx`PoT6Q@`mWV3 z*nGXU3l`r^d|&9It9qu5ejU{_t@Nu@&$I;YkA=R9*AA+QpF-*m-dpXoG|v`l&IdJD z=5__ro^hf;tux-=ucpMM9bA*Ozr53;KHV5d`+OK;)D8B~0ei)EJeKp;o4& z1Fn9|;38f+4&)T2|5ymi_ zf6*Pd1OW|@X$qW$Ky8~_B=%8a5QXQ9aL4S%ZnivNOK`)RQEfddkHtz)zTQD^m%H9f z7T{(r2MZRnfbOtz3OkPRuWfU5mC2iXr*{`hMOyxerXrAP5^bxsoM>E^wohdv!BhE) zeob+#GZ~MpyeUpGpI9Ts1y{Iw;(}MjnOf5YuR##<Z9zu&~4A!p0%GhMH6ks z_P#S6$O!d!hL^eRO@(d;m4RRCZB`ZYIr$}hjZ^=b3-J#Au#g6aj^FcNY9F%mpLYju z0hgDvj%V&3@HwU+$KVSzK@N`cWXyMZzMa3@q`0X_6fGK(buKFg4*d4Ms~q~z(yNYx zgW+zJrhJcypf4G^Q(x)gKCn>sA6XdUa1Wg0Rv@m9!Mk-dVQ?$Io98Pz0`8>)R@ie! zQWq>$wGOr-DJxh34Hdk+oYbtg%_Zgs!o1=b?XdBwZjb(?M};3hDKN{zpQXpkA+_pl z$XLx-OJJ7O3{&e)<@nqlwes(XD8H~xt$YFPT#;OUVXIm-4`GofMZ|s|f<9NP#!*mT z{88)1S_89e-KEU3X5Hds%z=ZoO9UoLt>&6c>;A1zM-aZ}1CR1ap*i&EF$8LAcerS=PW<8?UC+;N+^x zzp^L3#{pzy9!6O=4?pVW;k4tdz^$i7r|AQNH$UY))azE9u0 zmWtq?f+a_EKYG_57`_6ckh<`r$`p)r>s18ieiZ ztlIBO%9-j;Tcy~hx`%}hI@LP0;y^p{g$^j?+spYknV%;{68A*=TpiJCyn96ADX{G5 z1?EuN_`s|Eo)fKq$q@qskN!?~xnqUy43Hh<0;P`zd+9lAMc=AxdqJG2TLe&#ZO+#k z74(&JB0AmIYtIo9mdG2>oeQU$-O*I(90B0qC}wDdVpX5`{iRqe^2E2XSYWKuBaupA zR$R~6h|{*lUo|#(^>~PFWDc^Zb(5`uahC3E<1AWZ*T4)Nw8N4}h?SG9jnz7>YtBY) zMGg#iGI=Yu(J&XIp6qX!g?zWR(!qT5!1$U6Lr0u^rJ{wM(dl|$wJs@;Z{fCz3uM&z zhpTn@7HzAQ_l2&#Wn?*pIrS+{7;=evfh)Eb!Ku8!p4$=-l-{8u_Qc&<*sfhp zUH!lOF@?9&)MqMrJF5SXJKTUVjj$yfZ;J9x5(*jaS zi!(ZJR8??IGT+0uV%8%A9NCHm<_iC~IVgiLDEPOE)rfsudrEN3N4f?C( zC1%=Yw+BBK|3E!aea#*ini;y(D=Wx{KJL*vJpS_$C-faZnYBOQb7x@ay45<@=Wgh9 zedur0*M>eB82UpD7llG^qR?D~<~~UhNI^GWNr+Ub6m-jXQaLCn<2$L+)VkcyGbzZm zQGLx-k4jw>bnBHMdL1G%A;r*o6ip_RVnbi@TsOv+GUQ=A;up`UfuXk|HZ}9(g&&vn z!r<)em3b6!TTX(@bUb99?8;>M5Lwcwq|A>IN10tHh$i7w3{)3}xtNG;4`b+|g+nki zBAq=@){o)Wnfc+u?7N1y|VpUxpu zDSIX=L(X*Mbn@Ki@t9@-C(ozjNg;lp_kdr-Vp4wo0Xz<&$IZ{vaG)e;$>!%@pck|w z^F#jX^Fex<>Q1Nf`P0w0;k6(urd_nFRkxEsp+mERfjRCBeYi~@Z$p!9_CRh{<}R29 zcz0MLLmsv{dYYB_eqeYuW&&5{ZfY<%5GXoyhdVPOMw87sq|Am9WlOV-w>fp6E!F0; zxlk;Sw53v)1coN#$DX-s;W+`;t{5^BDQzRSGCPog_`nU%QD zJkKwOF8AU-D_C?pGT-Ns(1l)nyfqa%!9~@XuW4E^eI&y;QLFX=wu)^uf_es&cFX~1 z!bfO-)_!ed3)VTzcYT914&DTdFna@K?xc-mK);@H=HXIk?Id->{%Bc43MIk#VmyQ- z%9)2ztD;40rI>USb;I`ZGIu=l+oFlb#%LE}{tMA!kuc$364n*E6S56|qPhVyMs~Ze zFS3fVqn7TBDuU47GY?Z5I3dQtwNaiGgmG=EW75VS^BsCMDI}=t>^&>4(Y3XB5$%BG z4$gIrVrO@`Pxis`fg}L8)XZIB=JG85$f0db5bZR+ISt|J%bj75V%36i{36M6v^30K z@Cci^0Rxd4yOAo)o(g*`-mu4-gk=)a|0+-%r%!`VB94C=>cqMk23X<>Oh?18P}+J| z_0$n@yj5$1NlBqW3Ju;>U6^eN=P3&Vd2t03tIn2Z zv{*3dWbKXGYts5xr#Z*oR~7T0&1^>UMl8#}yV9@6(8Ze6ZJaoZQRH%$9#=Os1Dtaq zi%+e`l+8-9{s6XPDP9751Cr_1>+r21=K?b#kCEK2{QSOz}R1KraPOH}1oXq-}G8A0=wZ zE6-;B&H$Ln4CO&ic=*hVd~4K_Uw${jGq>uBJ21y-2^T4rz=XI4h;3JWmoU3yEd#dV zY=H^!4TPA<$yYrw@fQ9`Lqbo)4nzco!$IR$n{4^N_=&f)sX$rA0?XpVMG4lx1bYLS zie@3tn}rN{ZWeF31AE7;rSUyx8+j!9eO4s9z4r3EQgbZG%PZd_N#2}Tx*6p+b+J_&(weH;4r~LDv)@up3lDu?JKWPCZY- zD7sa*!^S&|fx_R_N0D;ylz4q;hvi~sbjmctfp!Gu#K95f0Vs*m>*sHvwH>AIuA3fP{8NsE; zOGhg4{`897kfCzkLE)DWUK=|hUb2EB*$J%GnvFD3V%7FX-{hZ?UWwd=aiMNF8T#7J z4N+{Dcj&TNtXkCv31*ml?jSygfzOKfMO8+(C+V14N7F=htMB?LCEhP6St2#3CqZ@V z3B*TxPw~bm^4LknX5HTted$-7QwQl<)6jtI*%|W_tNLQ15C0%v1DCQcq zE>z;pL5gb3zQ*%Nb^pv7hr1`?>5O%M1a|0>^9KGrmCRI8&LGs=CgJz z4PBTDW$w~v*+uU~deOR_0<8LE;dGx0YqY@LcZ!4T2)NBBDcWO7%s)uCsdb)yi-Q@9 zr=&SxPp0ayvoQ7Z;Z~R=if+?s8B(=ZFGyQCH8#Ae_-rzZEpx<{*<4jKT3bR1 zZ!QfPHmz+Cn)?1E@3YjJM^0ew-j;y^V#`vImh#wjoAK8uwZIX%AKl$mpKY1F?_&;* zcn%X%16VN)HYw@yU%*s=JB079*bOIdIpVR~0>SIbslIyI9y)2~?G4{T5Kr)36}yH} zvUViN+RmFraOp|%22m!I3}77Ut1b4>QM(Y{6C$k;T;3clCO`3Lv(Ad`=~PtncWQHn zPCC14qv@97s99hetWcy`QhVvi=wsxGUf#w3j*1;_Dvd1Pmj7I0H>3ZdO!yZws1(r@ zMKtbY#rB~+Y!WpwzR9%f)XxtTN(b?Fe-Hx!s>qW5-iM`Gp_)hT=6XdNWL0+pYe-HFgS1tlaL4 zyL+s~@5qn7hi2IBw)=bMd!k#2xj=y>YA?u+mc0tot9u}tUS@O-wwz2iGd#kzi6^dh z2iIF_O$Tu~(sVnBk>JVh*B%dYOIOHcl;FMC8;31vOToLEnwN&=l{Urw_6wESYn$TM z;+IljJar-AL}#K?lc{G_hHmBUh=<5P^tX8NWOgw1Ef!U3o#-;YHPmT?`ah8H4)y%L z!x)MRTCUi~yOOIz8oWoQOTQONf$&}Fa&#{55FY*RsLpO_KvcnK5{3W9SVdvUS4o3< zwKV*V8dgBlMSE`#SluL;`}E{S8qxwbzT+g~3aJ^No~$kBJHCgDg6#hmmyD}K-t@AB zO(#mI!vV7$uqei9svFwX|I_N$!wcY_bQ)hG2mv!|3a?{_A1KIy$y|06F?m^g4=s4f z;{Q?oj{p>hHU2;Z0_Sq)S9CgWfg9++q8q)RbzrJ}ms<5RL<%{Gc7abCd%gAN4M9<-? z+BVV>Hn8d>t!*cq6zkUsC!vMQSDmt8_3G$aghqCV40=&ZW{1{cTao5Hf&gzSnMnez zf8w3ysn-y^5qgYKfkh`Z1Dl^kC-qfr@T2BTFu;SaHxFG|-1_w#tx4fI`h>QcF_!8H z@97g-GB0F@R^31c&abM0PupgUr%HyvA?DDhZHwN`L$oHIaMIR`_X=B>-Yf8^h3BYs ztKQRsN_NxI_;4Q1O#*hu{(DfPtW|+L@E%%LLq6 z!K}SNTYWl+4b**Y`wk|W9g=8vhyWkGyqC8G9y*JmvR&+un+tFKjyc%=3{)n^5^%tr zbzlYwI`w`pA}~AOxwQXCCrf6_;_B&#=R2?|4|m}}?@QFk%{?$KI@~RE{c$d#N95E$ z1u-3*ZygLTXt(Mj9fb*!JR@X=WMF0;iWTgzdN+!MKf|c_G8Su~m#QFqJpLQK39xj$ zQ(={eE<=8Y(fPILHeGQ?Xh@6=D^7;}`SUdIb0@Z}IadbfUa@FNVHNCpxN)ag>xaY;LozvGl6vc+Z zdt=nMx99CUqW2qy8mgzd2L>h#g?DHe-vuYegBxi{Iwq_n)6V*NENGCzUOn9ch`4sDBfrFx=`W1$0cd!k(n zyDXhK{oL43UHW^y-yGVeZ`ZcRAQsVF{q9mS0&(=AQ{J5O`NK1NTGFuiW?k(4mA%L z=e?PpP)ZU8myXy*Cqn|(E6s!_U%y0)j3H`WJ8u?-1HIl_bxy6sA$&6Q?G*<*urC4T z;6BZUGY7-{d~4}o#jS2|x$6lGa7p_~Y3lmZOMhG(R%|3x=W8vP1y1cdSeodf8T!_J zZKa7|FKn}g3oMvV3#`yV;0ngQy}Cew88@Vu>MIQ$#VLV7p@Y`Mmg<7IZ~?k{TmsHb zA+a0HNW+{^6;rEjK?^a6hl`fe>Tjz125@PQl!K)nE~p0dfV#eU>5s3f8p|XISoIX8 zdYq`C#^I()y5@yD%z42oJetCZ2cKmQ`2}IiJy8coEr)o;_HcCZ*z z+<0~Rk_0Z1NFjFKI;;zW@9*5XlLRC46m8Sk0)@jY{L{>%+~poJ$2~N3(H2NcE#-4> zDCN_Xnh6QQaTI5r8pk|2ihJofSh^Dubj59~`V=Ap{R15fmGKLDYlIb=pka~5{KLF& zBls%4ak&jrU>NuB2kcn!7$tbXGGGjTFvCRWinZMdU=7cPVf+ZeqTrsMXtK?pP%@tw z$GJ5$8UBt$rDj}G)?U*HcbZ0cQf#=J7IRa)=}$ir$*z;JCl693TpaR?)9IA0cpoRtrE7e z0(f(FbUT;E!f|9}W3zWGjVr%9ef1ek_Au*0rr(wP`TO`TjJtF(id{626+C9(*RJ<_ z^K;UqgI2qtS?HP>ZEw3@1b6sNCrbvbP{%~taCc;};R?Jxe7_1m?BX48k_TOJ^u{}l zc@d0+I4X?)Q3Sm;0ucZZ6)SwSozHO4(C0JAZ*f&e52cQVw0RI)2w6=hHH7D4{ALit zi6OOe2nG#=FCF6GwtSiLjabHG%S7)@71mRI;1mzip!aI4yR$}j4 z>_CaBh{pDZD|^>cb%m0>Z+Rm2qaBeJ%1Dljhk=O8oqa-md@X`j*t0LHzj_=`1Xs>j zr~g{0BXOW<2qx}<*cO8VPDf66^r!qw{>>1SF%V_&U)uR12NeyDUD?>bT6*t_BpOrM zaJDSJJ+{<|mozjpeF*l%2ZFK5C3rJ8Z;`~vhZ#n@;3(e(z@m2Yy5q&Z*ynb*0?$*E zQH0}47a$jnPgH1+yhA*2uU^`^I+p&1N*aU!#J_?6GbaD?;v}uO+@pnXr|ARU_vtz(fvExfE&&XNq z^ygU6sVV5xe_P@$RAQ>xkJ+e8T}!7#yK8`+%82=fp`jTN4VpVl8OGTfbYvkl5j{iG zhC|ynR7h!}@KlKB#wlG3>-Q?&djJ!nd4Q`GYwN5a9kp73Ffk$G6=%69g2r*}$wgKi zCIc?cdi<%y(XB}+^xvJaLeF#$GKGh+3fpZSPfhEG5sY)K;@s!l4@g(=gqigejDeZF zXs~y|`7Q+(y{kuk2ByPX4mQw!kh~!Z@aP(rnmhCr zjwTkS!nqzY99S#C*n_b2`4FJN^aq#Z>M%8^X~UX>p6OnDO_4L#s#XrgqAS-{GuftA z{t{*-d;sM*r&QGs<6f;B6<_{Xs@2yU4ZK->y9LA85p`%C%IZ`srXUv%h>0UV}C5jd;YQqGwqRBn)R}QWuVQr+zlP4+~VpV!IRmaQ=cvYrBk+ob_-L zGNXuktO-)(47Dl7UG%n<-qhDHXi>dl+(=;|l0Tf;=#6u3i6STL)|(OtYFGDKMBN`kPVFf2WGKH4FEYdp^C(axGtR=5^mq@`DnPN^vvfG1b= z=sq>GQ>*8=-PQB^mg@7ch@9`LnI}%r&hO7>D13%ppX)+sDwaHH<3eBc)81Q1-r@96 zTY_2#HImp4pM7FuAm0f%&~-x7r_(PfwTVzJ85~E0M)NS*l|kCTZ_{z6Zb>^#BDZD0 zIfw;r-&TY%Y|{9Wv&fa6_yu3m!Hd7Gz%y=ZGN?S4O{iGxmP6a2+OpU5qBQCu2JOkT zwszggui>5A4l8$N7p3}#@>QwPTQH0rW5jZD-$C8+Bv*0XY`Ycb%NlK{z_TrXaO?bV4b%K1wki z)r^9>*;YL|De^}u?gGv;)?$h^1)!R`_y>ESnUY1fiuYkSv|fXVjU*x%o2qvSb@WVh zbfg!`z{15`FW>@D>afB!m7%PuFLlDB~IcB}R*jMoS{S(P(ke zXmN_s@=eQ?(V|w~0FGhZS6)lMLA8?hZA3{>gx?tx&MTei>KPMh)ua1~4(%^G^qQ^? zP3`W`YoRM}g#CQWO)Q;|nLVItt%5TSnfHPD>AlH29Sw6Xge_=j<>(RD4 zA@xohChQ!5Q?^$xa_J?hrquVwK1zuL_7B_!QJTLTV}!Z5uT6J6&hK+T$a5dJK|^UB zgO;Dwnw*g&CRR&F{iBzZ=(l z6W8tM_f#A(fh`zNz7xRCQ$k-k6I(03rju=D-i)&)tNr!+COZ=3^gdd!BKcZy+!kr_G=zsS=Qo=oA8 z77Q^r4Y3U4cK{Y4Y4^{Bz&V-E3B~BB7lq;cDf8dueVxF5vD@S@`r{@zOcyw9e~zp) zvl$PW4=!U49#eOs7x*B$vP({BiOF4sGB$9oU_ZXAPBy*V3TJX>cGjEW?sB=6cS?ur6WaJ*++U2 z?wGjD(bG@IWY~7qoDqRfob2)MjG`;kg&0XA#cXjp@(xwdHC3dWQ$=5H35>3#78&=T zsgdU?390|jpkiI$?FYI&747rgFk#Zw>=1}MXLX~D$!&m_RI&Hz9+Ye0mjTMrd&zEf zgcU0Z{u!zn=s1iZ`jMK^l;2!O(o>*@3Lpj-FR~a2lK;R zT&ctKelFn-8??OtqBQTD-KGboFq4BD7w>TJKRk`i9%SJa&(Z_D0=(imJmqsUH_lXc zJ5sfgFThC)XE1#h>U)mBti9sAim&^m%DJ#ptsI1uSIbBJ&>uqILqWzJ!W7gayv`is?ti)H7Th!kH;s*oFc;I4?Mod6KR!U?vr?9t8-l z?x(kB@b(UKI@l&JUf~xad-C7#$WLblJ=uGf#)S(LVsW@v1k+jTu=}Ik+>!4DWfj0= zDu-2laS4j^zwtdlO*rqQ#YVaM=aDd(%a><7HpG%wTinRD31^{UsZ$eB=Z9FWV4soRjO}xscx)NI_^7W&9T99dbV=xN`hk?H`cn`LH!3{rMPd;H|77A>L zcYqnQhc(l69mz*{*Rv3^iepa9arF#;aEjguO(RCfdC>_wX+pae`zugt4nU7Y5Rabw zAEGC;_hMVfFB-W80#$J3ILfCHnukm?{|I~AbBpW zZB22mWyKE>o{DfCA}}9LBAupTMIEtZxOHy50B^ zHaZW(xZh$rI4g(?XWFr$`Y>!`_R5}a$3e+<{m$qqj#&qM(HR$VE~Q}>cSGo0+=+xX zK3)0FrC8GW#_Vme*gVuY>N`>5mZ}F)xNPblfRiX&*EmuU56H8LyEy@JC;4)eGV|`RxmmUb6cgo2WHgi0^39Cc03&g{Cj) z;VNhrti^0NV&c0K+n2td#zcDHLQqx2fDi(kedmR@M&F#vGUSa;G5W$Yy4Z;H``6cr=sN;8qam-l)SiTk$W zycafH>7cF;hjjNtp6|!#|8KBEetwuFZvt!YwjPPR4mmJjqPIhvile+x7=hu#FhZ_A z%KKCh9fTN~#;zRY#W7`a+;-UrY5E;xBhW6=86fxX=QJE?-Jf+1`zK*^7LK%raXI9G zL%7JuoF#!Y?hU~&z5q}2!EloI4rn_3;dIA#?@g(+21VvK<`a#eviGZbC3#5rHO$@EGBE~sE)XFXfx;r z$0p#$_?}qHWZsVJZeS;L!a3brK`ga45r}YOcO8f7I@mCxDJ}yR2W4!Eqhs^*BzBqT zp7qARBJ1lZbpB9%X8_J0I?O~!!=j0K6&GGcyuYp6@~XTKx%H8$kje%!E9##`bWPIT zc3*<`6+A{=BmaUQwen*q>3mQ0khc-9#yX&-)-{s^MiZ>!HoPahdFeNmdy%h|@_pt# zNeSszD6Z0BcfY9!dK4@dwb0LOUbKx*YvvPzkw4*8zt2hce&cWh*gsXDZ`W5iY=io) zP@sjdlO3mBWXo^lt^BlU72q%jpVq1uHN)V#dBrfCNXVY{!Ezjr%JH`>?YAN>XYS7B z$$HT?9TkYA(LPtd>2q-aq-9cUg(J4Yt|#a-6yp7536)W;{2J{3jl6LxZ8LawhRspFZV+0ti z-7hkQYCr4B{JEKVJFcRK4yN+=68F*G>ve*iJBXb{7JLODD7;<9IUH8&@;56mh}gF< zM2!Oo)Nn5u*OsIrDJLe=O!VV*W#V(P#R!Hsi-AaTM^){$lBe(I0x7tDW3f3X|tUkGW>!U zshtAe#XTc&tB)R%B_bofb^i5TBx*@V)m7RAZGI(+;%5aJOfN zR^a0WQ7aFbAFbGQJ{G%AJK?H|J^K7cT4^-U2PDkTQ~U{W8;5~|hGDd@5MQ*=DXbhT zKAaqfO)b`jD-gC$OtV2>l1_K};JAsNTTka+fd4H4ofa}!+X(eH2C2KcAAzmFYcFS*`{I)kNdu1d=FFi4RikHgs{*vB$EA zLA6Pi3Q+*%B94|GkITVPvslkbq8E}evU3NizrOV%*69QBhc*welk#ExS!hRNO9*U* z`NwcNRlG~uR>zl83gc3BXX*K^DM8=e+QAdtX?zsKt&#Qtoe+((^fhs~yS;pXcP5g1 z(+MeY&Mpouq&%i!N#Z~A#VNWHKI@*nOMFE`pP8z^QjRqB)i{E0+}6cW zwg~gzVay8to4PBJ-rL?&H%BJ3Zbo%C_LOga@kF1AYmCnz3;1va3NxlQ(R{$_7vPVv zIcP%A6{S1RZFTy_7+-C6c( zziaNai8Xh(EpetE5ind#Uf!T&Ve|QK^xQO)4t4laa7NMGvLPUG<}A&NuQXy2)5GXF z;0Hz{IKJ}TBUE_DOle=ZrY%;RcEvsR3#BQ6qWFA=2#y!4%BE4moe%d-vz5p5c@E5z zJ8&XW$AKhQg=ZvFu)sOZ$EERQsrooqV3MQOb0RRwj&;+?z@&Jx8frs)N9jp%WDVDu zt{gGKN|YS+IDid)5HS6J%`*3IU z2v!I#)$dU7x84cQCw96VN7qweQyc}hqqKGH zICNIN)3Tm^o8n4rZI{`vsp1Fd38NA_y!2G$=z4OFas6;saatZnJ=asy(0Y50XzsEkQJe@BPq8~F0j_!w zEWdbLh@rV8=o$p(N09h?xFNG;vpM(=El}%P&TX~$Mjd*9?+HcXv;&qL9B;gdPQn1R z={Gh^ao@q!}(Q zSUtr17LfEF>(M0dQ68}hkE+JK7&noh!4j+QL@JZ-x%3$rQe};N7ylSdPpzKnw!y}> z)qjBTXRO1v8Z7_YqP>lm!51EH;2nn_z%3~;qFN0F`iY|>Rd$FpB(#gv6DR8?!+sWlJ7Q!;8#u77}PzY(>Qi%6|nj_Qon5JW7Z z63Q32lfR6{(a*^%iO?{r)n1-@Fi&%=8^$F+CKoCH>kkL8N6lGuGQ!J@h3ZK$l zxT9Lhp%nJAgFFHlRe?FjLEKldAt=t^`e1tD3Q*SpSNaY?RxolC$~VsmC|UdIxV-Or zaa`UQ-heOIKY;roPQS6J(AxqjjJ$-F2Of4?`O*59sS78GqSY!JUT_xAnmf&xEJQpA z5s$1RJdf7DLMd@c!KpaLj zEk}y^bE5?~ZT1bA6aH-sjN8L#4;orp-|jS8020CmnQT6owYT=HvDpmk<(*5V3_~gN zzB34&|3NWlW(9>#9{eBT6UBa|`e!=nU4GE%?;nnP@(ZYF^8(4=F^@(53w$1Wu)0xe z`&MhV9DWchse-KF;rv?r;e0hqj7iuVhaP+>-PehC)4`1E5)Wd%ZYNVDQ*jS~uVo=7 zFFKjAiT+^9Isa8)cnX~|RbSoFD-`L)_iQp~YY~V4&!1UO_g6M~&{&Q&@A)$&-WAmF zyU-CcXVnfD9C!|U{#jGqe0WLi&4(X(Lr0Zj5lFvqIbuStZaMr&?OF=04Tw0TJ@iOr z@Xov(`WK^z5Fgy^?=%=;iW(~EEi{DUfrTA?O zlIwW?;{8d`Q31uaIG9`g-j%QeYQWLU(oCUyf)S+LzIb~QZi@$8DFKI5puwBZe}$W8 zPI!>lKMc$p{&E=}fDL=ax6j(Mg2v+4V0^7_x++kdQ8hT ziTEq$&TF0D+5Kv=G7oGHoCe`#RSfsC(*37lyy_*x;oiYFnv{wov@wD6Uv!jH_bBGT zFT@yIN1Y8eT!ume5jr1=7iA#?eSZo|I6C`t{(vQ%@-d3U7vsPPgJGrT*}-_0@&21V zeO6|e?HQZjqG)Oao#AQ9OGhMrGU$gdq+|Zr5MFcz;x0cf1VNWnw*sopE!BA~Nv zuo%h@SbTlOE>!7Bvy{emL7&G5M+aPUv z0aljege*U3^^Gvrz@^l!?Qb-tDb4HZDNZc2{(-C{O}8W1xB=rM+5oWx*Q}m+FV-FI zt}UpuO%|kqtO=oQ%1iZ#H!2T-VrN)v3Dch2mBqs;@Pq?IW??;7J-9*K7h$2IuySNC zG7Bp*3o9}UTbxFDy(H6iZATV&HhDZ$8TF_~Av3DL(=Bq2t3}SGPw@bS49J_qL-Ka^ z6uO&k+F&8GLu}S(H~ZA=nI%|mY>l4K8Mj6ah};mg|LVm?iE#@35C&B2zeox~sc>#L5D;Kit^^$j7bXV-3=q}TiO){22TSQ;MoZRK| z7T-j9FFKfiQgM-?50}Snq@Pg48c+hLi)A+QlV|?IFB#d$iL>P^KE&i7kM96{a^}UJ zH9Z7rH~-Lh2{rMpsH(XLd=hks1#g_S*K!zyX5C3e){edKBDq|_xBF}ftky^uBFx$ zm@LHiun@p$oZjNr)+FcBYj96dT-y>JFFwhEeNeH4-i^w=?L9jUZvgi$EECpK+q%9H zYmRPwk^?g2;IvZ3w;2lQ6EdTcOYp~0;(ZZw_@WfpbT>{jR)BqNn=5K5DqjVw_yUdv z^v(RdXq~vcS`A%>3?RP2V9?7BSKfqSCj`Y7LVoWoY3_j(vtF}g`g zF9_G%?#qFanAUko{qE8}wrTBVlY0gB4--)MqJSF?%%U8PK z#VB9dkF8v-Zt&ocYNBOp^fme(AiCWYr9fq`o(`mIcejZSEc(}LcSZ1<;z|Lo-HF+J zXV0~}GylLe23IScPHQzT!pGR%hS$GED^4O$pJ?89!=hQHYE2Dj_?IMNA)^<@H9iKg zwW)9`_V=lsQ{72WVGa~|0!3nrj)t4NXL!(Eg(e)M-h~fLc0?_n@)2~QwF3g8h%U#7 zvg$V87`+)E0!65ucVed_1x4Cx92U=rByqDfF+Up_{1I`v^`qzyP+KXE0zl?p#^TO} zuLKi!M|<(KkD3ZUQotDYlHhrrO)UKyZ5I6Cs*amk8-|31J!L$CMR8;vN%gS|?^b*; z#Ax|nbnMN@d_R0M)*c;6H?*#|!8ZqS@jd{__a36uParikmYCkWofPsU+8qkP(yd<5DHD9(2}b{^C|S=O9-8b&~?U94@CP zT2PXf=D&r1@iu+7Bic{h z5KpOc%~bs8v6t-lP~CDG_=oT*>e)(UFWRy0CA#S!etQP^Q|s>Gop(=ziBJg*M~8z( z6-AHsggPj6KvyWT%>Q1NKL0k$Y*a%9ZFxv!7{*WEeT{!G6?Pgip3%{$TK6N~es_Z3 zQHcR`9D(@=)C(M?BjZ!ls!Kq-DQ*OOM~K0qA=6PW{nhr$*z3=M>e`rL%_S4?yAMM z-a}koUpn$v<^EI?0wB!7afJxSPZ54>S=+mvF4ORB8M-2oM_k^CEFbbCn7j zZ~Wp#2uD*rjcuIUxOvm`W26K2zg^2x@zHMheN6{1jr6h18ZLAf;CdchCKIq!Jclrk z{}!Pbc-wch0@MkTwHY@f8J*0(E_%y4TFAvwxtSeUAAD2MIRmIHcNhlDOTj?&8KEP` z_b^y-tQvCB?Qa}n?)Ks81wP*u*zEol;;wid@jXNe0PKy|LeB(^YtdBP*Z;88;Uc+OpkAM8_&pqQt&VDiHm(|KrZ1}T;65Hp%$9yMc9X~vpA z0J4MxmPO8<JvM=G1F)ANgdBoGf&y6*wkSHWKCo<#`UM;Wl5F6B?V^ASL=p`$oI{IvLD zq>&7P$278_B71t#lsw;H?{sS0@xO_B-6#OFAvkc+QzShV0}NM_m|BG^oH)Eb1NQyp z7fk!YKh*nMB)W?GznP^7?omb>l|jpbOV@x89NaL!vs)9-Pv`TeJQx_4VWeET4qmBI zmadT8R<$aMkcJ@gVm^ENZ`6-!RSUv&jq(IatY+q#5^JE?#&rtZLSwwV)2>#%frM&Z zi7kK&>>^67D^>za;`kesPJHT=Kb4MlAUrOxB;E{H>z2d^RwnRGA`!kSe2VLCBud<| zg$7aiK~=4~UzEHAs?5#>C;SZzH&(hO9$)rV@U3CQW4|Joe+n1lPfcdkx)A}dg}*|@ z@`joCtJbZw1iaSnpgAJQYt@3bu0mgafYNqgWrEW=YwV$zqQz{hleW-$JMtkg)wVjc zOZc{N9iH>DPnA8>@TrNF_pc^aFCyY!umU1iRq<3Ys-W*9S1mx&z@`o-{w|)1OMx(0 z^e)u00+TEz(7g6p!Q~{27P6Y4(uNtGM@h%0{$Sub$EZ)-f}+N%Poz`juMjXO&c#0w z$DjUAE!RSh>~DO1^YQUrSJ^Rt(iU=KL~KZp?+M^LdwLCl!K)($j;vcKKel z>VbiRL@s<`uIAG-6uGVFe-$<<+{zLrYc1i9t z)ld-l{H6NZd4xFm@YnM5v`)MKLu_Tkv*hcizeFhr@W5JDj7Okek5wf;W=X0I1?$>o zvmV^PNJjuRyt-?`y#rB`_j@%t{$FbHey=7BL28?>wSK3j^eZ)`ch%(hUQPdRZE{>y zlL=wq4Nq@Wwsm0*HSadMj)%{GiWls^XP@>TUic(=YVPWVn9g2Yya220cK=~hEVyRJ z=x)-S_)GsaX^x&JSJ#uSjYmT~Tr0s(lQtE9TaZ*2qX)a2Be&S4hWX(P`~;ij6#rKjsDRcm79A5$Tv)26|sW@KqZ0p+A%Ujcg$${j|Fr ztrH$;t@Do6#kE#cnOa(roj<{!Q)|nfWc3f%^O7vhP_60o{f9^T;3{f5$Nlbw{n7d9 zxEHQ&$P<@u@lR!Jfi6ec(LN>KQd0Sy>qJ$*Lom$;`lMvq_@;}1aJAAu#DZamQig`; zJ1!(aQ{6+wyh1KP+yN@p6HED8HYQ?s$5}a*8UXy=KgQl-tOI zcdrz4Kjpp;mqO1|rGwYOD;_N+ezD%{gHE4?Ul%^LI@$a;I&$GBP|Gi*`udjR)9Luw ze0mf{ZlOCjyTeaIZm7N{gKu_sfW59la3S(tu(TN=M(huw`<&qXrf8A|iMK|M!6fr; zMeJ2w`QI;~*DrU_hqqC5*DRU<1%`$UEv0{pKqnCqo{8*;T6F+&q`yM4^SYA#jasz_ z@9Jw|d`}GMXJF}$FGMTw7iWYnDg0G;J8HuRr~wGA$(yvNksKnAr&>G#4?OL}6a5!> zgQT6m>4tRybzhBOv@b|6uLza&s=Jb2G*3KYD&6Ju@{|WN4zS-wFS^hpYu(NC@&>u~ zP})v<5hwCd8VwDU1{({^eLyc7gVzbAwbIK|V#Ge}{)}F9+)QBLyqaF#V2UWMjb1i+ zFql!=A$obmgYk>f40_SXnnh{H@Pb~+*mDrPJx4D%34kxRqd2TN#0^id_ADOp^Q8H+ z7C(@&7x6>?p^Gy@M{KC37H^Rcp-Z$)G}d80{+{B+h%Yt=J{cd6Q=m>7LVt=h2Bh>Q z1R2Nw3{em|MAt}bz_fE+ty8)+Nsdq+zN7}Ie-`OLefm>WAAgEei$`la&qWGdr->Q% zLlBDP@hggDYg%@5*$MF-8rbCKCrP?Ed4;&*U+Qm)?!;JgpbNVr6v?O9`C?^KNnouos}YojO7B6X`V>2Az5jm9KyDlp zNx;XS^oe#D5%fU@7d9Ihx%aOy`UIKG-HaO5d;Wz*AHJTj_E*Frn7dvu_n#QM;rmPt z1yg@V1zk+h8Tf0UNT~75-y0frICP&Yko#-=8w_hja3J>ylV`KZ=UXfUE8RO&pP;Q# z%0vGUz+%w1^&XTn1POShVtU=HwfC>U_$RymsfpAkU3AZ>XN+dH}ypb@8=3$)HRy^(L@jXW>Z%>b> zr&8NOh^-L7325sB5m~vgMgr1mHfVIKQqGw>3Prj>zB_b^E`V$`?B`hYpuQa z+H0>}qAQZpRY!LH%D0r%`1-YJR4a7LFd%FKxMu*D1a%n+6vb~+>;_E=qZx0SsiYyP zVicEbQanW};U?qX%~Z0$N~IF+pfZsrq!Qt0G?OZ_w}?tZWE5-82qzlh>kNRzSZ{vuZOKg)~aY zE2Bu6JmK9(tne?)`zwO_v%Xdyoi8E!qC@a~4p9vGH<<`UIk^AqFGOtJ_tntlr-X%L zzq-AF2X5^kG#AFz?OnL<^vx$@n$=Ij3wx^mOXb>9 z72E$##db7}4ZV*#g9H%aR! z{GHZMkk*?(Ot@mpCuGITRLkd6``22|60YzX^LWo{NBf0q&%E6-*QQ^%X+BlXwddZqxDnC?AdrD(!|NpZU-wmcFb5j?m*STi0&)mXG$3oR9MHt z9VU&B_@)Rgg}wosPXUQ5z>T=&n82a^Iz+_;q*{nWX)a%9ND5iu8{W_;G%JK@4m6fW zd?l1qCgYvE$tBL5~(kr4S5dBRo=JSegZ*}Z~lN~q=$1aTb{USfUHr2Q$r zkTOEL#4Z7RyWC-QQswAwNl~SODt29 zWSO}{mnhLe0Z9-hT&eXFvXUVDw@hP#;K+a=-C}X4JJ&>a_ZFks_!_(5&HpA5W$?|F z*hRHgu}incrrE`+SS1@huE{F~DG>{K4W@a#j9HXW^7R0@Ws&OZ*Cw{ zY*Sw;ul>Ao!l>_QzmP@V;d&g0o>VfQ3lI+5Ehk}DvvVH#FD*9Q9h;qla}V;Z&c~nU z#dGdw)kS>_w255&(n*1b9r{;;89HKNYjR+?D)QA=?q~PtADH$J(;7cMgxny*$1>q zP8$EFP}qZB9^Uvjg~q=rl8-I4W@Pe4E_TCw2E?gPRGlNm_#O};8FG_+W_D8xdx}R;I*!WShhd)xFePn|6m_3P2z@o$} z;PcJga|)y>AoCn|c^omc0>pYwfd!Eg<5 zmLV7FWUxqVV3d_9TteI>gu0r1&k=}J_}0o894z7Ikus#i31Ub7MtyWYIqf7fVRJpl zeMp=5WcitzEc1BE4E>M?!|3Od%}n{|EdVXi@Z}>&2T2H|L8wsX*#NV)!>pZ8r6j9v1QTr~tZI)!hbF;W(`U1p)uU}GL2HC}j}S9kO8_+{JYdJ?N` zp9%rb26ziFXMgH@3?`ROl^&1YDvlB{rumIhBgKB^8v~Sy!Tu=6tIj5DEsnDCkwz$6 zc{V&5N1;^}yju$V<#%YyYENXZiyh%N{jFk`XS~QcCOL!t*olz`*B=djz+oa|BMGZH zJQ%utn(3OcRccJw@kyn>HjOjK;V*Q@W{HzaY?brIj&g^z3UEJyG&8|%T`YBvVhN3T zxHl*vW}3TOg(r+{Sc=Uv8`N3O%rctIQD=A4zw>QPohUf$#O@A8|I$Y1TQjr5S1v1Zg7jDCeSI-8`@ zg|_Fye8bZN^gHBAbx%sx-4`)6L@)dg8&;AkPuY(pXTvB?S!|r_ZP~ZWV5?(fWS=rm z1yE+FZ+`SP8!A@i0|oP~+Nl2;Q>XcGQIz|pg>LVY>jaBxQQcu zss$@W(feH7ohM%8UI%aZ#A=H0ytt3st$50bKu6RDso>EYGAor{>x ze0HgZ#PV9yARZR*7wAvHOzoJi;>RQeVt@%@DyOhP(^tT6--zZpCP_x|IJNZA(zcFiupmMnSEl$2y z1y_@S9x4HaLkw4xdi96Jg+U3o?1(qTA+`GC?8x3?fFHueoNdy~=zZ5D(O(dq2i7@$ zU(iyXw-IUIGKu?+tx@ecg zWQt}RN1Bnkt8o_LZr*l5{KP2!G~OmUS-jD~d*fbF8>wyjdo96VfMw(7I#tg}ch$SZ zbq*K(79H3*gO{D?g|$TgohWoMA=xRCF5%jVt`~Wy{AbSz9+HBVQ4j-KF(2evAkVw+ z>io?)%(76MYMn2mP*>L6MN08JId1DOo+i)y(yM<=;2IU6*Ii<>fCVV${{dFYq7T*B z?`U=Lf_C`BX=b0s?W$W6NK@e8$j z;RJ4O^@fkf%Zk~`y4=I& z%p}^Qh0bl6kTX_SZ~DoWKsJWNSeIGd+k10wxIPzp9Z{w`CX>D-6Tp9 zb31Ona${X9*CoMJ1^Rr8Pwr3JOPCc!0aaJPl>)mWi&T~S9_LgH4nSU5eEs`S%zl3_?a zU*wR3!)X0Jjl3!Y3_&JgHuDG{^%jx1_(Vo_1p(GhLV}mT8=>AMKk*3vA}w^kv?Rhs z&8jhZ3>X>d@r_7BzE+Hxgkl^N!=w263YKIn11L)zw3ZP!n(iz+b1?FjcIG`kDLqC) z_KZi6xcJOLi34a6lrpP#SPhJ?`%uWx=Yb*WLVcdF>&D3*4Uj z+Eeu7=zLr#WWJpH@QFFr0}^ENm_cL3jNOGvI(u0FEIm#6_!N6t+*{zUkDD!{cRHBr zd1Wtlx_9I|Yn|mZ&GEgq09nLh+5xw8Xt28Vt9CUAgR8!{H(0)>$;PL89q0Ay!vDlP+a%WfT ziLMh}7*At?eI%7ay_fD1lWNkl^)?~g7l$+J3N#KiPb|U&^OPE{Il8th0M2c*tN5*u ze{O%E6GxM;%xJ^-Ac_9zh|6f8uxt1;>bkO!Zv=@)2pY@!1cL7hkH6E%=^WYSV%CJ? zX)g`Ip1^r0PPMUslU*4~X~frUQF3ppYo>K4PFs#66;vJuS z#fkqk2a3)Y$jw-={j5G3*IiXTnX6a1W^h2{a1Ou8+cG$)y*CiNL3(obdV1#El`i_g z(M$v>aylgDc3p|Q+V)SaXgj&rcsITtIC6Va_-N{0kmR>m#Vr?OqenzOv2J`~E7r6x zeR)icnJZ+>w5}6V3=tz7!Rf+RNm2w&gVa@9ZeGVkZ(wkmfVJ~6(lPEB8y;0IvfRzt zNUBabsT$e4RLvh`awHc1(UR688g1-fBU%jg&bV9{{DR0}L;6hN{gjxRdZeeN`h70_ zVQ$p$Slrt$>R*}u_b4qnsX}xxdtoud5@A<>OJ3xD!4s+b1@S(x?ep2eRRXV@(%Xd0 z@nvv5ZNuT-u5>Z2+IPDUHr)MJ{SX=ZFSLdclYaR4=(pW1Qeqs@4XHZBX2?4ZA@4)hC+hWgB5&CARVNVSg_rw+U-dcD1~J0&u$uQ` zXvfJ^(Gif=Vd>Wu`DAURV>!hY*yG( z=4)8rw0#ctSR%z6c*HwL5^B6CbD+nr4ZcDkcrbMk)c72^$7v7Pvhx}G5vXkuhGxII z&8xM93XGoh$^OX+?jv)ey@OcoB*&KN7fw}0I&wg?z8hhDOAY&a(fq!4L79W>I~!sGMNoeW%ey;H& znO_sl0Rwt&u#Ecrk9>2rGPu?s)u3umDAx)xMqafgI#dU&iv`N`sxsE{QiF-#t}}n+ zusLCIO6Y0)NI9?G-{8_3a?j}#%>JM+b``;suHQ;!(4#AK3-?tj5SWta#$fs7f8+`3 z5Ai;7Fu%#_+ii*8btrRAy6;lObS#0J8%}ktXEJPyd>Wun^#vaN!`Rb;C|KK}ylLP+ z-7sSGfvC~Lxsi@Cai$Ue3naWv5X(?+UQa0wR@61kahvaY7Rz$a6i3o5&?iJ1J*{(;mZ`DJ3{U6atD*-lh6g>Y5`U;_1`W7ujT1r0$(Fen1L9ogN+UF(y-P>r!dJ zn*f!B`Uvxt-DaX8r%~jEZ!ug(fuCjv@=fWEJ*dO;=x zjYs!U3l+%l=2aso=$#LTnvR(f=fSO>*e2hPNtTX{H>q$ho*>TO3YQi?evk_zU)iHb0#+}s@YLE4e}ByZ-9xN!kVhWV zSqz4!Q_#04=-z;F>faa#`jp6`X|G&8;nmiOOk|GuE(H~|f_Sa-9e7^4#b|g+dPF(+ z0Hp8p4f)<{cJQ`IkjNLSIMq6@^F=y*~DbhWqd`-dnn(RA?OITz8GBe(-mRZ#+$)^iO|%GCzrm$6XmxtFZ4pc!hJN%{6Jxnn zMgKF7kNUGA7zn<|C*=#K%DDJ2Yu6!GP#gS>#BSyXV{0S4aN0(Z`{f_314NkR9U*S)_rd|qZ_vTo*kg?|CC?dpQTr2$Ht8f1V07_ zc4zxmtg$MhmSoXBBj{!}>$CI&v-Ee9R|^^+e+Q4`je7+p>8@=&S}YhskVZ@N zFOti7S>S#-YfjLECB1R;O0YCUh@(CzC<0XT#@P2k(S5<0>G`gWgo2`p6qrU)+?vbQ z4y(+sEk4Dj>&w{eUNZEfSUVP*-TUZPtDG&#I#$co>#@n`G2$GlKlFVW%hq`TXs`hE z>;q;!Zvj(mwzqWu(UvBcD2m3GN6r<6KSLwELm2+2WuY9*CkpujhxA91NTTQ_pUhcI z$xzGga8{^~d;6O+D1Ew={w-CyC$Wa~vgZP0!DHr`8Qu%!{c1D5h&&DCp)X(F0%|&9 zAr@mY+x!P&S^VunvCZR8?C7L8kFzb(D|1w@D3%Mv*xKSwshPg)V{;R3)UHOMAo`%u zhezXH>7R`5QnO9v-vIhx6TDRai+;|m@Q`sQ70#X&{2|pt9nwxk9bx7tls6MN;GV|4 zQbtCR1vcRky1~^pLRdmR8?)~rPkXC_Z;UyYZdcekg1$AcJcwKDTsPYlADaUYjP>N> zWyUM%aXo|C5I2r8mmOQ&F?NVV>JzzGc3e-I=`vn~Qe+$#(+~(;_5eimYn^h~sNvg~ z@b=`zy=~=J8^?dide_!EoUg{IWq`Cty|WPL8+?Pv;MVjVm`y7f)-PQw8@HnM$cFOt zdLP@uwibU07ZmwR8691^e~9U?O4=(c4e_;WoLx%!{^Gk4(M7@cx)**Ug@eKkwSq!d z;z8ZON45;p?CwsVbwxGX{}s}ZQMu4~_Q#ZrZW-bz)Q>lvVccEE95b)i& zPL*HCb^wG>Z1g5b0v8W-#ViNq*qCD!h;?uH14T6MmA*@NW#niP9$473(!VI(-}z^7 zSljp*>J)eL8@xxqRXgfY+*~uc()3f{T+PxWpPa?=!M%Mq4C>x?U$0zaOc4qgcXJWR zVq+~zH1rlGrT=yl;uzayY9#z3{p~~)od9CGbpm+PnQRXeWOk@va~HF2P%1uCg1<@2 zi$B~;%0KI;L}q+IF6hd9!sXq65ycEVF!F=YVCE_}VyI)Pqo$?R zQ6WcC1!dPmPZX6!SKAVA>gQX>FF}>LeF>aQofhax|8rt67AKA8!SAMB#JH4RlPv>l zdyt+m#;eJxM#FDz{jA+EZoe4mtk-P_uk z`e-V3R=h!_{-wq8x_kScK=6$8K_bY8rkhU%h0_B z)bA&ek~bBkymLm66zV=-3%zA#o*w%T2bmouYq!kAtLKEG<~&RiTD{ z*Lb;B)1DXaR=VV&4KVN-Wwk4#oJk0VJc$J0XToQ7gTixYDl((Muzg5#IjC1|lfG=w%WV?MVkQ!uAS7|qSK0**SjN+4dFTqRRlQh7gR^nJZXV_Ji}@)d5NFaE+>Y_%iR_knstUTd zlY|v?aU0ZzaY&1zE}5%R+5JKRCzhCV)&Jmo>8GWlV=Yt@7@Z}@^$TcdYCaQHOO9Z$ zERF78N#57gbfXG{noEwjm0>tJs}WQ}zeDt@V(jm3VI5LJE&EXsoiP3r{OIj%o211D zjfKZV>dQ7Rfmf)Oa$_s{SjIPY33cGC0-Q7H$laO)gpOml+?PGLO{7fr!;dfWYVzuJ zCZaV@FEaKb5WU8|9cR*CL!!(JzBD(-_8HlK!mNq=Ul^^i?14=n_kerbhgHGn1W_G} z;m9NGX5+uSRA#BBf?Q*}1{BdQ(ft+%pX4R@hcwrJk6cis@>-XHBDPDCDB?8WEYOe#qy&mKA52=hcy4LZ`71 z6?$Aw#P~>8j=R|pDw9Zi=W9s2&QnyBL>jZxch#L^-S^}a(q>(8OYX2B>Yo=SCp1+0 z(t7{}(p-#$8AyBmZlW`g_G3ZXt~Ao-Q^FOH*5iMPwCrgLY3)CtvP(#tgWG^K($r+- z64EN?U52#bM1VAoQe2KSWqH;453rT;yH)H7IZ^(=*bPKsW8AYga<(Q^Ry!u&7P^D? zM?%B-T^G8A-?gD)ejf~7$8UY8uy#yuTc|JZeL^07=TTDR>;iZ5ZBlq1vR~+y1xx0( z=$Ev}cIAE10W{m_S0m!Zs${z{vOjG?ti3;rsEmF@DSe%lD-6vOYlEA*8T1?_bkY6B@bytLOP;DgDM#}}U^`Tz; zJ{WTGJ1>;Y?}Bi)0Lm#H1#S@lIgTe5A%I-9c(=f?S>-ve@|;(B&MycLmDHc)@O6Qd za(-U;MmB7einYQR6gk9Fv{Xf+^*ruTmMjj74^{*1!bOWQ54(xu8 z>#vSHj<-Y@RX-;y`*xg69~1d>9uvDff~ z#r>R!sPKJ*m!i{6zIGDYLLSaV9TpgVrb3YQ}JA8n3;wMlS5!L_Kk9j%wCr z`v%w%F@8tR+CyF`?$6R=HoBP}!|D9OZXoJ$0nk1ne7f{>26VsG-Kk)z z``#s(3I(R;zD&d9Ro*@u_X<~}wH~NW0>h(aK4YMa--fY=^vuC-iOw1xt@Igr#6~NN zjgFb}9AfNL&k|!hPu-AGI)BEiIjerEipV`X@TDV+d<b2}OAL@)EO zMEQpp_3Bw-+{aUSXV@Xr@3cbcUuOv9#ipuBm^S?-roJSVP~E=Nt1l(d$;DKNxeGP7 zAI{-itYUg+bn=kQNYQBO&L~^|{^24THf4!Oz=QI>d_AkHezbJXjo{U|=PqhzO9y(z z`Et}hI@~wfLpB4N-$Ebx8v8ruAqQ`?hwT1bie;g!89zgTI4_Ox#-l61zla#62u7ND z38%RbdiUr}z7fPhk#^?2!nM(%q6e1A_ftQS{&BY)r)a!X*e!C(<3uD8h&`6wau6H; z<;ubQQ#53U_~n-)F{ptj%vD_IG6Ko`FOpxS7u)yj*tD#zv-H=F#U8V6eL)Tiymqvu zomJXs{NpxDP3LC0n;+o?-@e)I=2g6*6|}cB`9=e%Txa<%Ek)@oa7PPjqh%a*;*wU1 z-rCdD&YJt6r{*vKJCiY_)r=!}?L*r^QitA-a-~5c-K_69Q?_1OsD);kf-*o}86YBi zvbS#4-#Z4X9L8cZvP8%exvZ8#hwrYd0QE^E3s%i$)b0w!-RClW}@LfFS0>;%jm^L+@gd1>t*p( z8-)Y-()1c%;+mDy3$kr!+IyjcV|uInF7+`50OsO5CqZFN`@{B~eqPeN|10ue#`{vc zpV~z-O$LBDDgMW(y*L2DV<4Lo2u`OMq*E=Lahe*vQ6>-C*BbM zhj=LQFYB5si2okHoyv#g2;fSN0KXkiTsJJYw5KKP{v?bkEdLGg^&{?Aj?9|Pwj%1s z{nJ@>Wg@%YME1F;Ae;G265qGY`Wl9>Lce70V^lB5#Ia%mJ;dgcI2jYIydwIr>xM-i zax8Le8HY=~zXeO$ML15r;pxw~AnI!oBucK#u1ZdyUKi6QmxgQQsOvy<<^dZ+ivCXS z8=-sfnXi8wx<0knu>@T%r)?%y1^AcRB~%63QM7R>sm2Y*7WlDxBxaJ5XXJfyzb z5>KXYGSi<3%r<75pY=n=P_^SCl2*(O*_v=f{(81+&6l&({hW$no(G#sgK;PplXOUqy;Ah; z|M!3G99O^C`CWi!-T(b6q2+Ks*M&2+*MDtLaOeGeOZtVs-!yi;_2xqaqA`h@SQ~k`zZROEuI_UtAhpql<%DMcwht*^ z4tlbM_(!WMh@+i(F_nGHXc?wtGwm$)&8Ez?0|V}P`QW}0#+pvyeYMc4bm2d^RCwPu z0sik6u13am;i`c@WrjYtHaai67CK__{(c%~Aym6vs)ge0_UuSy ziCUvUN5iA}kGY@t5sBcTx*a*ZlWK^a7v7?laPnyK%gIv?JsiZ4Eg_=enDp zkT2>uE)Gwp+tZlEwu~?)(lv%3-mE z$vC%7tU$Xq-K>PEV#KiflF6M{=WX^jg^w}8!(Q40e5hf}6MLP5s1~-krk)XN0fdmCTal9cmhg$e*> zq4Jc2I{F8u;`NDf)ST8Kat$ZngLP@$bOG}cnS##A(7HOKK+T#(6eU%~G8Yxy^lONv zJjQyI(LwM`qu%_ZkU`if)zcErTnFo<2lh@;?Z0+>SJz##+YRYCMgq4xhG|Y0yQrKK z!mtZ_0WCZ_xJj~nk1Thqvu8b{USBi|ZslUke4XoPx=6?sJz^(iQy);4C%-@ti`~sL z8N3;2Hjd98osHE$aiQzo+ven$ml^Jm;)hZ^P!>@=V%60-fGmU+vUq0po;tRuP@Gun z-j-wO*f`!Y+8)Xt?F+9+WQ$pQqGsdxtkGGaL2I1iS3pE)q9?pMXtd4Ud|L2O0<0bo zRLDq!VO1*FLxMJ6LbPu3`Kvm@)Q(=tj5umWIPksNWKzh#QXET~rhnlH9vl#jEanwT z+)ZMo)+$;MV{-*Xb*OhT_Y1yAWY9=!iib`%dpSTan_KhooIHJ{Pda*hv0zr8GemXt zoh2RPhm#q01H!A%QEYqLQR(lq#z+69*uLpQT1@cUm8_LN7xcb82^S}DgOgQ0*CNf* z^x`Y_rRqpgP4(s#%y1sFa>JKWM6aRz3%8-N@T-&*;EwYD)4m7n=|si>Ia#8 zdY$6vN|U3Le2VP6#HZn_g5K!>dJ}+BU4c~B*@Kccj?dwsZ1X?S;K-N>hfv6{SxKNa z@~91M_NTli8FZj9XxX72Z zvODM(%y=dud=qk@RrLiO;6=2F>d|G)MybCOWMO@+!s7_D1J-?9h3xV&MqqB@Rbtb96zygV=84tFl*5A&N=H6yG={{+i4MTvH+I!_G(O zL1lpM(I?pAT<_LV<}AO{KY_(t&#EF;x8-vKem%e;2+^Zx9c6_Q!AVL9Z4BhLa6+E5 zjBh1uS%seRk*}>fyOEgU_gVtE5iv#=L+r+*KPB;IWrwpTxhuZq3&ySUV?_XC-=}8% zpLABZ=set%wuVS=Oc)E(?BVo786i;=soTnymZ@WK?8-_sbMt{gS&0URq?t4}UJ<8k zktvZJNROx;+PJa)Do`g`UkVZ5TkYB+q&xh@l3rQ$mb9J_=;j064uPbNTiZkl?gT}F=R0J&l|=>yFEGWtpFzCAVEIrRso49F(0@epvUlSlo6a-1YM zA`S1K$1z0Th9r$`@;yh!)@mW7H4B6bxM}n^Dl$8CJ9f1)fo$L@e5UbyHu?NNJR1rB zGf(+0Vy+=(rhmob!f=AYT;nROEe&g}+FDz@a?sq3WwxeWYqR5(x6b8k@1gZAmEUfu z922jc=809_i45~vI%%0#e{In29RQ~p6;NPYtB#jhs^Vo?b|H~qCS^|!i0H?ENmXCbzk?r?p1y|E} zTvxO`C`j0Lr&Q^nN61=<86gU@ZJ21gSFreC-3yr zZZ1^7I0i4s^wVzXr`@-=RB^%F*CXvM{vIv^Rm+0AeegW|z+t~8N@Ab3lh+Iqi+lQN3DTT8;vMVQ*RC8(#ckP3E;9M4;jC~dGR%=7K4AdpF*VFMzR~B~-JL7&U$Gk8*k%gh3vLky;tEU}BJsFOlZ?E^Y zNyn$9UfinkwfL>9(jX5zqe7J~m#)$VN?QC1UJ8PKkc>g?-Hu)~40wRBQPt z`ecte)xvT**eFtQe!62i#;T4<3`|$f&{Zs)4wzleMsppxjQgGdldm$IOAzG z9=byS1=W3nF9?jmG>q2+VK9AfPu1S0aX^mJQ3%dOu^=W^h+Q|~ynVjNC?M}@eF zAfz#1Kf<7XVi*5x8`kS7*C z)y*i(Y4o?7?@jr+ic&Y3ZsL;t+J1rIb#(07?y#UMz5f{+rV%p@>ZB;=LI$S$m~IQ>_;UnWWdEl)M2(7j?HY-5;pbc)Rq zjdL&^S}12xi!9;X#&&k2@m|ms#pgEjV9Oi%AHwhj5MN>RR`FSb)>!<&KH?i;&hDT1 zDaDT*?sGqpoctGRYkHD(_()`x`|*u@wNCL3$6djQ!JHkwdOjA(@8!N0`gW>?!K`>C zErfI7V2$Zb(WI6@RH5qa_7%hHD5x1I{lTj{il)6mHY&T-_?Ba#am~*?52=dOnu3s<*J`9G^-1h4+rbM_cLn0sww5>@| zfS?*Kg6cN@Z|~Y6#k5WJj~fpZ{Q>6dLV>Fo#~ffh)IvT}K4{$}FTACRe5l21sEA%R zYk#I*I=@Ru%{=tuirG)CaBnxoGt0T}-KJLa{elpU7CgjEQeA^C~C`8F`aEQWL!RIyl{&BV=2Q3P=ZozAwTnj zb=|;E+?g>mCub2e^T5m*JaUsukRDY<`drUO=7=op@mlv*mdjHfIqwah*+@k3Ys?;> zufe>(DiC~0<_F&&rEuK1S9m_XJsUZ?BGu9Nn;qSc&kO{Q_<}o_X{cTX^FjAM1aPqQ z{a4C}L<3k9Yx0TaK)3nSojR~@s>55KCEjQruCQ7ZoB{I&wX|m|rwK>tt{qhzYfjwP zCaKenjd4638%e!`^O;%YV@J7soQJeD?FxSu&ypp3k^43M2TkPQ-S_xO?3DE%JV~(Q zi57nKfy^@d$X%`aRr(lt`bTk&)V*OLy`OlJqdTVAJ3cc>t(A=t?O52T<=XNcuPB@2 z%Myqez$07hc1%5rZvOJzSdWE|wC*`9pOPlmBGy}%oydqOlbESzGh!+vW^8861c|x$ zmy9%1Bxd9%88HEgxhpf*Oo_S0$Vf9+V%|EQ5i?(6-cv10LRcd)CqK?evs7XpxR?jRCG1fh{DqnqCw;_) z2PO@MO@s6y+%9FTA1dH+9?V>N8*}a<+v=5=$G3_xJ@#nM4tqddFo}fyt;DtLHox6) zf_j*_FyqZVuv0dcUXh=d<>$BZ(}vOk7lbSU+4qW^%L-k!#y&Azm~chTS+S`;XA650 zF8#ll9sLna;5&&d{cV^!82+7pvmDdY$H-=reyf;W=mTW)%6NAU(0#F1HnV>9hFcp4 z@ontU##`xIc(QzID{pGv`g!r2Eh@gl-tc?3<_k=n+FBZCTkH8J2yX20IKO5V`Ftsh z#J4`C68501)`!$j^|ybbnIO|a`&pUm>!HV-uWi7TU?#=zPB*A4vwvN@kF1992CvP>nxm;D}D<&Q*6)j8}y^uQ>b0Z)nq7 z;YT>Ug)bxJ*vy`HR@cC(L8)2&mTxC?hh@tAg;q>fWtB4b4Iqi2-Sxba~%a+udA zHI9d1Na2YTFcli#Pzcf7Tw%`nQvbSUxN-J73avvCbD?AyeSV=N)K5A17kW zy97hF^0GwY5{M>7?~PS?S`Q>shv$#^1F!C;0?LxqSyOtWV>`L(3>{p?Q48bb&FMa_ z4St@6Gs-+j^>LM8_)$XcZIkUO7zH$7lsO!f97mE$QR?+)8zCFpN+`^Q-y5RVV?e~jEi;YInc>riU2x` zr5c7>N|WbOc{13EcjOxVzZzftay{cOUc}K?*34p4EEwQaje9Z%71gp2w}?`ieAdM3 z3*yYo{gwjeelQEV33v^U*ev%EZZ=Ci;lWX8`N}21+KzFydM#FeO&o_Pq+^LD=XYu@ zrF3^>UrHE>XEQ^`SCk#e?$73!7&NDRrjTi{nMu5vpf62a^~$55SshK1m{VKiH`0+8 z_dBd{KO39%PAZh8H+he&0}{ZHxWK3Z&Y-?qMHbW=LIZ&z&cRc%+9(f6mLuj-2DXyc)S zpni66g|CKVluPlr!Y`|*n(p{l`Xl4XiEKsT%hTN~7DQ$jT+NAZx`0Febb+8&x?rot zu&a7fopALf+{Wq$W^{sC@Ie;8$sW7BAEXZ`HJeh+v_CV`_OQg`{%q?`rj(cr@oHYo zO46Kk(nd3>(-I%ApKbBy;8nuU?km@Zu`!~*sXEjwbdE|%zj!7kdV6uRkDY;r-H zNMke6P%{yQ6l7D6%p%PX{kqrFPwMF>K5O=-ucUWWeg|rlf>>i9T#Q%!0 zD8I02jenHdc38bFIzZ_fPFn|TMY#9A^;i75e|E~-e#|SH6mCT6==wI3wyvJ0G)>ou zg7eTRqT}ThWv!HrZwpmB;udYjmKaZ!!o-mC`5u#ZC`on-rwJ zTrgL}z7Q2}fkaxin9_ ztS6gtWzxc3W(%*-shg$q^6b))?xqHcxDo``R7(~|`$)=Y53|c(^R{FduDUFQ&|8;54$U z&)*~RZus~Ul`~=RqC1p3HP(o(Pu%@wkV0YSizG@>LxG}(LKGNI<vT|#Y(K0N>rcT)n zKu$*X^!U3xby_qbc&T4Ht4cp7vIzbDW;T|_-8C0qbcp%z$Eh!^%*^n5%f|)c7D7%m zLHFzFb+!v5^Db?dcKe*f#4L++7#EF5#Q z+*p7)*5nv=A~Cxwm2a$Tuo-$keB-?Xf{&!9mroBud>u57NeaXGga`B7&X*|By3sVyDW>Z+;L40P8bk=O&t5rIMfif>S-7W3z^#|UjQv!p?^jA>XNTPvRGim4Ns zdQ}6t0|Vy1`h5j}El!6DHjdqfeKvdt1un>_sx=1 z%%Bd?yl9{RTeQBG1Bvl^e9$|Qi#RqHNxSiGi+kJaBj0duc!5yE9hR`Y;lfpGiY>2k z2Y}u_=*`GEi~I5KsBc>M(}ssETKJRBmzheljQn+CZLHi;x*x(Q(&HN|@*Q{B@2_cKNZ%k5zuM=U5 zL1b@5BAa^(JmIH}Z~sR1wf`oTb{UuH80+2!7n2{uyXY9XOF|1RG<@@f)Yr~3^^J#$ z6yXoJcU|zyv@_U;DV^!_I|CI#ByM_s7Z=DVtz=p!7uW1iF81mOYWNU$t{(MJdIazz zOMB5Furss;tw;qRjmIek}k;-Tm$F3gqV=-g2QQ^JcJC-bx}A!+2iHFVn=Z)>%Bw}ftLovq%o z68&0Ns5g74Z)=dZRqocXis%a2TOZ;rFau_hbDRa@#e7BpbCBQ$;tk^lO~YNYH?p^A zlmg2AaxfXQD_ncDxEkKi?srREM@o zuNW8Rc6IIeEBd*{&bpkQTATc|HemT@>_pAc`J+zR<^1s5ZuReU=H;zgd4KKl70aqu ztX#BIULXW*$;!HQ)pg5PrQh$b3oTll@omwPy5-fY>X+6f)7Ia=c=^hD?ZIXDhpU&= z-cy|_w0>DAOqz7OnNHPJy=-l0*{TN?t)P-{{o?9icyaZrWn_>_E%xl5?yC#4Y&ktV z{RiA+b-42TT{CEKZeFi~Ym0~6>g;`0(Tz6`zs=is;5Tj=cKhf)*WK{Vp(93(x!zY& zI`WQheftl{grm&hU*f-te+iG|zlG6ZAH^?wKw4A1c;(7aecg&h^|G{Ix~y)+%5^Eo zlkK7%0?zUWmWQfW)`ga@d_cw2Em>ZjY?>zT()enXXmPlnRxBaU;|-d2JF8@2Oev$P zZ%-As3$dSy`~E04yRY!~JVf^b|3Beh%3rnY9;&WhvTE6)(6Z`f4}?~&Q)Ox3HdU5! zlUcs!!LP>^WYoEHNHQIHE#O1)|Dlf=mrvfzIQb@jsknzoC;FFh0yE1b`KHk>iBql2 zh?DmB&Vc2PWW6OBuoRQ`KJv<9Ujs{0o;MkH-DPnSy!Z3f#nS59MN1)g^S!=a z-s={HmISNm^wRD*< z^zsMlm#qp_FB>tmM7w|4J&WoW)mM|UdPVpFZCQO?b^Vh1<>?5?Pw?`%FnJWYOD6sn z1tC%uv1BF0xpKt{Rh1cEx031>tyr;gNk-V@bd^tiS6!&BUcL$*>t3BIHu+)kiu<(H zb=9@YA6Qzw8rl-Maew`iZm=v9Sdw4}Y$~j(N21j&%M3#!tIWt$Iui`!-vhPF?+LGh z*C^{cAu??)VH_bpquc;%v1OH<6U zd_>9cq1Cl3!bnK-U9}uBv{b9BA1ab=_2PAAaZ8qp@HeHR$gH|mD;F=TUb<}c@+Hga zDO-43{!+3e=c%4r7QFvGzxjj_st=)ek*Tw+f`z3OsumQN_2M zjI83#TBbAPt*TqJM4^zuKuE22`6@L`NR~tLBYzF*mmg&8?LY3RJ-NB3_Rw>*FUy+i z^!B;Fr>EbwH{LRIq&>&g>#Bh_lw3Vv(2(J`kNTFo|24%o4;yiZ#pcNC-S;|Q;Z1{Y zy>0ZEZ)f+&FDUxPH%ny?Ubez5Ibz$2s(r4+sA{x{(`HU7wtI>^6K(Ugc?}ii691G zb=6hn)$=x79q>;qaa2#3Sm7Fbz-e_2HYZvR0{u$%BuYG9OnZq zJ+v&BLV+6nEaNR_U1wbu2k{mcL$aow;qzHnI?P;($Wu=+7MS0~0;j7>lxFgmrKv9< zQ~ezhvq$rF*EQ=jhkwRx!}EtZOEwO^l->N?z(Wz98BG65{5s9+&#(5+sM6*&-c(*O zcBU;*QdP~qeo3YJog%-bDyCG$luFFJM!!uGTS+{nh@T1kRLWbWyiJj}DZG`+*HZaf zDqlWowI)!RdJP7q3>#V}rORhtDyPUtUZzZuPtWy!>S-xm zlivy27Ab1;B-?id3C^B@s@sN}uYCiRsn>4=rrb8Xj^x$ynU~6H`N+$ZYWdV8Wk~*- zEj6C04ztrM9b&4M>U9gfPJcsJ69O}*YV_WLi+LK@@JP7#?8<2sMS&R=)kWUhs;g#> z)#@asrcR<3JyhfL)I8_<-qSVO(=~ZrU0by0dVcTeMcSrCF0r)RqHS@y9nul``Ocn? z=Sn9XxTvu-U#EG>veV=>Z-d`Hd;HjHMScK~1u&2u$^|EIo4wxC(wfQ?C9d3w)D% zq|A96Zk{pIPYX>}%Y(@TEd|a#<1KZ}_dHqGX)x0&ZIzaly-u6A;r7Yp73t(wt2b96 zKaEe7u|}(5UN_#dR9njPx-8H-Z^MmK@0^v+=shPjxXz=B87IXIy{s5# zR=ONI=&$B2<@LX zv&QmVFNvwR6yvmdCOs!)0c(5;;Vy0vpa_jVG@Z09xI+Ida4c3#uHodh%6 zd2P3LUfZpm*LH6wL9?Cn8hzii%1A16vH){COJK(I5(ht}@-tL^hB>^wCr)S3e=hf7 zXG4%VZ0;6kp7*wi)BQ6nB$!c>-_x0=XKT4?)v}Hgh{QSV{7!r>@0p;pp)M%zTO@kk zhABBh0jW8Oi}|q3wq+!*%J1v!t@qS&tqfPJiZo4DMJ!(2=3GyJ5b(VD)fE$~v`6LL z*`Q+FYIU56h^2n5ur* zWz`S+JJk=Hx8Y73t*^SgdYf5&iiBiQM3<+g_j%rI)!E)W6UPE7QPR7f@jYcK=)Kh+ zm^#+NqTV04b6QZVsmsrEIz(+Ne~apZEsLC4ntE8Zx*9?@ZObBWe}4dyzLe`Zdks^2 zStxm({y^oVta;Zt_pvUTp=P@;I*aBtx>SIl>N1aaQZ_Gs4brNrUWR5tCbHw~&(u62 zP$Y}3(H1@De7MG$qdm0PvUszL=w&PsnE)=Xdw8)$Tk_m>-+vlq>k?K>RkK7Mq;)le=ELMw!>W5_+eA0U`|#>s4x2NJ-jUF)@Pb)Ez8-v6EJdTRg5`~RPRwJ(2p(W>3E(K>o*$Wi<9 zSptdd+LyI1tJvBjneVC9ty{IWUuwtPFSNa+9UXll>}<1b{WNmu;_-xQ^k-p*3hlET zcfX(?sEzh{>i2H#7hpzr@`n z=LFaHmbz|jIDd<~xt4I}09E}`ck^6c5;rxR4~J$qoL}p1`Vko$&eyw}zb(lI^3!$$ zQPOGZo)nB>*tNDrM{)I14yP5d-LW-yt;=h>IhpFrhsqQ9M`GywB5|0tMSGJNb2W#4 zLdOMPoKM)7<1*#-&cl+zZ(}pu7QMQyBw0qA2n(rF9Us--qjQdtDX}=S_HR-97Z;=){`63aI;r}!lQm8ve$C;3^TdKCpy!Z8{e5jjf&cn z*XHT}A9wE_A7ynde$PxM7edGk7%(W{h?5wUK!RuigC>MaKrWFGL=iQT>bwN$q;ILw3lD)IbM3sv8O$!l=g6|VnUFMR*Tpwm8u9DXB-GoESI3<{jU8ylLXYB z_C3GP`^U?NJo7yJzSmxR?X}ikd+pZXo6jZshI6Js96>{6Vve9M;4iS26a7h1Yr%_h zAHWOxGJsbcTlP-u^ktf!qk)f~yW)c%s}n_>PWWQ2(|;_{r?dUBAo@BNga`NOoqJ}{ z8^M>OlLHsJ!L_ZorA&OymmMnN#EAZ`PM!FPw4&O1!+Sm%-N8oEmUj|ahkua1ixPcRzT^w1pMV_?(hCGevswN zv3OC7a~GQ9mj|4!A3NheVv+n^m-J5Sbouxsc))OAAr~~h>F5_4tW7xt z#|CR7kO!QB6VAF1#R`ObrnzrDcou1y?%UnX_gJ@Eu=#7Qv$S+~bN14{Ho5tGmV9>2 z|5TGT5u{o>cjBvSX9W*sd`_1BcJ~f}=*hsbxaNNnux`rjh>pHARxY!M!`STeluZLW z3ONhw$3EtqCEsE3{UF$>OVSPKch)SeJ+Ao&x-@4;KrWkPj2&AoJMN^)$VjHYd^{!} zgM}7or+$IsX^hKj!CjaL`6pR?U88nQ36_2k(nrmr*EY|?$|*SKNOVY3inDP}G&JW( zQ_8?86Xry{_Ry`-#EGRJ_&$s#fSP}bP6|C*PvOnQ-GQ#en$Zord|7*^9Vdh{@SXD0 zTzcG?4QIQ5*vL0_JPDyC$3wnOE`Wgsr_tj5TyxCHf@DlG{Bf4;78mnxZ}81i|GIrZ zDkdC}BkUmUlt=KbQ$OPt<2x2|V(K@!E$y2>_zh?3y2u+Rd6O^7o2~Oo2|MK>c^&=8 zEp!z-G3{=+(^OIpLI*IJbN#v$vGU+jsR%!n! z(xh6mNwujhqd35oZ^vjQ5=!5Z!wQ3A@8?{;TXDwMdMv5#l_zP!PTd5+dGduX1g~ZV zKkf+sT*%DXz&@AGbuzqHz9r43WTJcOlr{7X$JVfM9XKuZi>+SsENk=pM4`2s3do^x zjl&$6fQ&Nr_XUo`srb*eWuGm$>$ncxbb~lvwROm8VY~0;;GgT>mt1xGrPzKEqnZ0? z0#iWMwSAs~`&R~9LN?{#8aD8e(>HkAW1kOT95MeK)w=Vs&%eM~6DNUWtp>A8g0DNa z9^#%*Dc6{YZ|lnhjmZ#vIW~EYKj-ufz!BG>?cWrSAd@PRi>oWbeulzgXnB;MZ^o5s%Ip3v|OlpfBa z$l$aOf~DbL=b2;HX&($M4Tq+E5GoC0XlUfoXdnDj_zOV{35ea> z+G#l7jc8~)ex5pPjpVuY5g%mxZ=YXWxgIVp%(+GuE2o^? zo~=)RJ>Dh`9~eBYy`B6NkEb^lgbDouGCAj{yjmE<1&p!_+T&(898 zopE=%-094P08VTeeaARX=cbc}+vA@RLwg1NFM)C9>F(~X&!S&Q-;SqM-X~d}#X?Qr znCNh|2#)=WV`R&w@3ybWJ=l1l{lWGD?Qd^tX@8UVKklTL`S*%5#>6M@3Ld}$#$_q~ z>644*|1|diB+kWU^ccD_STxek)rijouL{n?^H~zS;ANKW&r?ybtLchKL%mMCuEM8b zL~OC<`!+{!uRqMWw}R+VtSN<0k64Vh?UyW2mhkI9Xkq0MX{zvI7!TrRaTF_olk3=P zQWh3hCa~CrQ)z$jMj7td(DkpJAQ9gq(>>u)04BU0_SRTIWQc=DCW~p;+LR12k<=!o zK6flIxpKZ_-bS|Emf!ts2_}Y5{DOlZQ>h@7G;yCdwepE89G24HefCh9eMy^)l$7}j z{7tpK58^>zdhqq;@9hS1xh*GQvG>I_f3JnFs9RsjAvZ_pix@7mbK$}vx$R}2H5w14 z+=thl{FBDL4pTm-TU;*QRA|fV_GO3HoM-MC_YbU3H|E~J%I{KY*MuO<@@Cbkr z{e51x*UoY$h=av(3x^cfNT2)^Y2t|4=)K0($8S=$Omyy%gI)3;b@>uQ&eOZ{z1M`# zb@fj9RHNF&N+HwH8^XT^M$uOSFXwaHz>IWGva|lM;@lYC-6vDe{mySnTRUTI4WFV; zur)d${D2g*bFa-s0)eI>&d7D!kParu1ZkaIvo73sWl}I)-?DCf_&%w_gh#p2uqC1D zl+d@*xkSEl1j2pgkyvG*Q%d+@iYdi2ratIc%#c++CO}zEF!tPFCT88*{Yc%?bUyst z{T(VS4*!YP0kr7N;a%WUqy_-zww!q>pCsOEODp$D8P|SY8G=QeB#5zF(zCkbBFoUV zG&x}!2p8*BbiI2~;G>qO$ydJb5A?A7B4#UHd#_4zo%L*1w0nldMu%N z*j3vb*)`CIgOb88QI{MBdzU0Vce^`7kIQ}07J(fXNI8AU*YkD_@QCIHTg|)PQ{2W? z?}$1nZZ3L{Lskqvf6V{xD@n<64gCj@8w`gl3Wlt$|wboX3{*1qahPWHQ!_J zQ|NTvJApzt0_Xur!o+ud@0zz92o%8<<9cr{UTsU@=mq!5Y!i@#?GSmv83|Jp!@hCh z9LQ`8Uxpj_GUS1p$}}N|+Hw5-WD$f+4F8$ojK0*T@Zf>)Z-hz<5-zu&k%O!j--F?I zSiNFJ-fa|FS{Wj;GO4H36iP*INpD_gqjjypPt^(BG~bRuRUE_%S!eeeJI4ND!J_x6 zA_m6YZsb2<$_4fMg=a{M>T_Fq+7vjxM$ZpHqLij$@dJ+2Rs?El_jkoP>cti}5alE` zSA0S^n@TQgT;RSE=jH=jk0cuREc(B7MQo^0TQc;V_Q(kw?UZS^BcCqL;-IVDG*dst zRdDb)l+|+~Y4DxMd!!QiR3oH44k6b7e*=)w&?>aENcb(>`M!x|C#|UqyFWKlHLvMzZ6Dn4Q;mIO;6k|+Jgr}89ePlZ)ABh-b}as3!4iAjc(<6| z%7v9+sFV+e$`2TNnGA>cn0;c}6+86A3y1##Vn%PO98y4|uBK7u_yP9x@KWMr_=a@< zRu=&@#ZRX=a1`RVIIw$-9#0O(B;gufcZMVr_kG6}+!vc_66$EUoT?)(9$F-UQisd_ z3WT{V!TR37zj6>J6Eq9YAuM(`!U+S!?Yf4N-g6V)gvF6_g3IO_XfAjAX*Fhhk}RFu#C?LC^+|61kn2_7>i027mw8E>Zlq1Y&fh&IOYk7t6fU6M zf!(8Zm!PD9<5@fI`kjO&)+UCZmlf(SmHj!77|tU14(az| z&Z66T&W!Bn?3Tkj2Tgw~3)~}vM>$d;Y=#M9B>>Z%nf9zeEsK6=hV%I7U|Z$oQuceF z(crrCa7c{#3}(jD;zIyt^}f1V?bE<_N8JSN&tM*BK?pC>p9_5Xp*0-sZC=C;=+W%Z zY^R$G3zO<5PDgDI{oW-vr53nJpI$eCuo8Tbu1P^xGBldloO0R3*J^%WnI-k#Oa1po zUZeWI$Nfl*-TDfTBH109$Buav2}~{)2Hktj)8$5gt_UYm6%87QcSp1>79A08WX6Q^ ziO~Q?QJVmK4Y!;ND{qw+zHo{m`?U3AJL^iI-O=w&&isuD9=Y=#gQGJ*9r+C<1`ip) zKJ+vMX0hb0BX9T$O8-j1@h)8b$Z8#!ob`sZHN9)Qk6b$}K~AFJkjHE9D2Sehj}Dhh z5#y*L951cuY%e#y&U^}U9yp)uduPWvmb&AOZGmIw8e#uz9XdgfTMgeJjRYk?nT*hI z3qilH{EoD+kdifC3p1vd2)ILMapiXP@WNF%?yN8aljmRX6#< zw=Eo^R*4y5isul z4G)%q-JOM8czkx_8-dA-G&*umjou+>Jk;T5*m7d!WcJKz>DVlbbfhqq$CLp(t~Wc< zMvHX%;E{_`yLIZ}slZ}bEOGEiSOmAg?%9jE^|${FI`~%vkIEtP7Uc~RYSLS~&~%}j zHsem5JYoeI#K*lY(2^)LlWSDaog8o6b#+%TGT~((XP#Q3H-_gy&0@lNjOl(Lt8zlm z+FBbW6a{{-Z5v`|5jzIw_RkvOOcD;BQ5=NRKVQ@W;^uQ^O{{d|+XH2V|q2)>2ZL|Tf z+kbrK98kxL2MgMIHt1tgTv{LrszOU$+3uo3!>;;(zaY{RN{LUFH|bsEQqFX6k5dfS2>~D z(X_}Os?Fj8ygdomiuc&yMn5&|eMA@s`A2Jp%?xgop+IaNdhpD_z)@G-%h=-KGi>h+ zRy=5BP14>OkSvap5R=`) zFH@|6wh`$>_-4>J`V)2^ei+?rni^`1ClM&h(w>&BM zZA)BrQYZm=J;;NxGSujXTqk#O0Wna66T!3Lh!&+Z#o<*vufOBbqy1RYx3qM-8$M@) zP%baaQlVnoHUWC`2KU2c<8-Ul z+rPQgdVD)b+8w=C!8#{cyu(T7OWe*<+|4c#$esYS!uxfJxaaz_acNd+2gijY3ov(Z zY+a$bKgZSrr{h=QZC6Q`9(PYRx@4Y4uXoSpTl%XL1s3<1JS;<#Imw^_Uaj@$T20fJH;m(M+L6{B?++NNDt zJWNw?p`Q`TbBE@kpM6~C#|L{nNuzNLLuvTGNX&&zzB?(zrwegEFkpwDoZ){W>RzI5 zX?omUN0e-cj-$tNJ;rsLP~!-^9Q9XeAjp8%yT45`*)0l{4X&q2 zqX)dnXhvRwcR*gEHzzO7SEhNY5PnwYCINrP*0qfFoAV7gEvEoLhy#;K>WgkPz#S@N zQK-?$Xx|Ld2rN^Lej9C!4z65Jj>w(hn&_!2zbE-`mYD$6L<1r%H0nr{{!s@Up5(Ze z9I;l$d9To!|BHz5lbpacI=eXXNCIQ^yjymMt&yK&+(nZN!FG?`sn1?>sQ;-w`EgdZ z%@Z1n^?j&Jw~ui{o{)P`Fs~_PNaJj0J}&7}e5Z`=J8(ge;Mls5p6x2uVj2^$0zxh@ z4ECeWND>d~QlXMDA+A%p>QSlj z-Oe{-{}Dfo{TY6K4SOK1I`yx*5y088^$ux=Ib8-rT9f>fuJfkocI}iEESi{ma3>I8 zIh8edZ``Oe!6)6~`5GL%k00Ht*&OTN@VOECxrDAD2jCv2*9^!_XqY?1&iIBuN}6E( zA0EWHbZmyg3b5AX8GTC{csSd#C7ihYjA~ zEIbLb<2yff9@~U(v05bs(a{CpY;CtUkG}y|T^v_}9^Zn`E}CQs)!KvKku1Tt7=zSq zyv_O!2G8PxPzB24QZA_A6Veb!7ISD?IgxwO<%MN{ObZ9ZRG;3;{ z%Hea1wU-DUG)8_jBkyD6_w+ju*za#NNEf)YmSIWaS1vs3=69p~LXBmC3C&5W`v?Kw z()y9J?hpLt2cLJ#k_sX`#*h5t^>KbkozVPSO%H>=b^pkSc#C5P{3|AMoAD~?p6As}*TO3|WA2up4eovX5dV9A zXiOZ~r0;O6cONh!{%Axb5+Qvg;~^vBFZ=+5ACdWper5J-(A^Ba(_A_lK9I}U!%5Ah z+4{xVTslU-q&Jt2?Z5$h^S7r2UMiIR#ywn+36uIUmJW`F8)+qXD>h{F8)&!t62ps; z=c8{yU!;EI^~;FiOPXnkbnuj+tj=ow4xA;9bejrCbMa>Ls-(t!?5c{=tf|n-Es?G7 z$MZU2&+=+vmxws{n?H=UV3Sv-VTJv-+xJSBb zUN}LRfnm*aizLAaA-}Mvv|Vmo^V1wbv_Z$8b2%E=F14I)bvo+*jhE02?)=tRwp20K z?{RG1=lB&9iWYuqKuI!QVZe#EVI83v`o_!=Cz}^e4emQhSQ3^zldf|-(NYvR;*Sqd zYV*SUj!lng-0t{|HS!>o8sF=_p?VKbxcxDk2AZ+9NQsWM`L6K4Z}$!c){U*lxq@nF z%b5d#BPkIvW-)!Gg3s1qsgP2VJ=>fG#bxg5ki!WMf(aej%KYdI=owR)Oz0 zxt@_bR)PhrW|H?n@b>Y03KFfsnYhPbA>13j@S*Vdz9CU3kXL(WFh{lt5=8s4{}Qhk zqq^O~9BRIPJ8Oe@@=OYToT*N&){rnNhoSP%K1pJD8mq*~Zb30{Pf=5|3 z@EL;0A4+oU-($yZFoI&J$oWV_20k%VB%U{~2p$bDM@hv#nJHA_UD!~|cDyfaV(?AV z(Kud>)5Gb6#l*&*4W2h-9sc$y!1mJXBpGg1q&Vc6;%^O$WoDF}$0MX+5 z9}@HxdE&@8Y>;H+-YwRL;Ebg09Fvf%dCrDgjl2zBSGk{_gD@Ysu^ z)8r1Q1%fD|d~KM;8xrMZTrqSjua&8@Nc?>gZ_Dw4Ey=MyBDu*Z+!+~4Dv|v};kE=d zM&0prTAzD(qWz~+Veh^DP}(?sp9Eg%*1i>?7ARIUo1}S!hQqaDRgtW3Ux-X%mP2fu zq+o06NiE)a2NYM{B(1oLy6;&8<&gq7Ln0JRUn0+|uyknzYZ%xmB83mAmn01jr5w#1 z1IC88X!ft|bkR<4U*-e7eEhcCsX*L@dXu*^9+t?jiIB@)f6MQb{OAYTc1AJ*mnWoz zetg7Jf(Q(}j^u{lTI2N^ZvB;8FMr*iaCf7lp@NU51@4T-!N0<`05(>-_v}-=tI*n! z3Qb}B&K6il6}<63Byey1bNt9OM9-_9{iS5W_j_=_&v=7)OP~65JTr8cxQrMVpq2YAJP%^8Tg8i#M9;GF#tSuVDVHAi5wxb1=Y z7Lve*N6qX#@scLyTDL%WbSDvBv|;gEh!I_r`8tTHX}-FpGruLeSY9^sVzWeN8fEz} z#QWemnjYCL;Mw?+Jb%!}6D9MpTUBtlE_TcQ)+08R!4fsqYE{olS&l8c^3}6a*q-?R z;t6e!#%q();J&)uf_#{!p)<p7QYes8MT(__%SGV z8BS_kI3{q_Eb~^n?k_8MEv>9ry1d%Aa*_)l9FsHFxK>oGnw(MYB4~0(Z8B#{XHIfu zRJ-t9^dhM7*#s#M?t9?~VEBa>08I$XZ{jUUJ_Nd zLR^-tbCoUi;tV9&GOws`rfZ6C#d4Ros%%xYs;H{g5U=*F5tvn!k4d&vc$bdFMO9T< zHr`CKs~Em&bB<95Q^v%lYFF0EvRWM=^M`f`9*j!1tXa9zwG_~}%BnoMdY%>V;jNUG zRJ)e0Ub$vPg|~u=d_8E;1IR@ct6Y`q)>KsK0@jpyXfwH2F9piwt}n-GfUf}irc&h6 zSemsNzA+g-!8CFdEt~@~PMJBc#B%$zIi;2<5C$n|*($Xfkb0O{_`6BII2=OZ@m5|E z7$YaimfDI{ljzBsbuRHHG-eE)xozPbx3Q0vN)-`ty+Sgy)to=PAz zmx{%cip&U&iy)BhBfhREYQFgaPOn&9<0{9O3up{s18x>~t!rLJx>pk`&5HQ#&?8W`g!gR9%73ru${e zsWQCGF+=He*_vfbDS7p(73-K86|R+K%T~F7mQ15H;v#C57Z?~T8?%m>tm;vus%7mm zXQ~i2BRttM1EPsrBG;<2<=}<}1dX5tQwLGopw!Z!tya0IS7mEWA4;bS8BR;`kL_F)8seCLdp#cn*f1~rqH(efB0 z-t44tvN~l;Z?k1QWoRTsoaC8gj$!zUK$mNN1-|H{J_e4FFc$D?J$t1DVtAjq%5}rI z`XGV=H~$ z^3^q~EQPCmE6VjC8BvxgMhi@0&Fo~)_PqlSC>~n=2lg& zUP0Txk~COKmX@v3bPV@2ePC}4eUInB>g*Wt)KIU!A=~I`Hg#pokQ%}G`Kwr!UAC$` zyS(ClpT~0BytxbJ&zozRF>OIXp=JKOsRb4?Fm}~rEfXi)G`nzW_8d#`_;2J`=HE79 z!cEf_S?(y)-I(N(=B%t(xf+g56H5w(=vJ_bFvSFnOX(aaB%m_UT}XN_AXz44W(ufX z<;$v^b$JT^f!t6PPy$tuW)glClN)u@+85tnfwTXmUh?XvQU z)y9~X!{4lu6@W#%e5`N{=7eW?(HYFt8Ub`28RfNLc}DsDYgm19CYP;RH;M*%D!ljV zG)8tp9#~W1xwpEKWy>t_>skonUy`+?Vg+-;1i1E|HVL57AS#f`vWd&?S zg$37V6&CHu4Dve(E~KagDnM8GZ}2uN%EW8sWZ3)JI#OaJvRX4)0?NOqnN`^pODn65 zZvB0rhjhd1!Zs#bTrLq@;9wRM$TTwj0|G^3!DNx(zbk85mF7@k(V?}_yUCL$_pnu& zF}_$Y?!@$Ab$~&(@MG2Msv!}*`AlA4{Ll&2(3xUouBxbUncS8z0Bg!X)@yQ&G+G?e z^EAfd#YB*c1Q>x~ANjxwyQW7-XBVz{wKA!m$P_XgG_zxtrTg(EF=QDFaW9$rn~fc3 zG`3VYSzQ?2(4b=_>k(_RmaR4xK+W)eeKP!uf)8r|`gGO+_&}Cq7jmUbOAz#wna{|r z0x`cf30>wp8|)LR zS8?H{FAb}yT81zp1smCYtCp`~eJ~jqmv5O14hqRxS6NZJ#^9J?HsHp5%SO9oweLx! z`2e4=l!gcqYwuJ&H3<|DRlDX)n>w>}j%)6`1^7UlRx)kw0%RqYQo%f7Z%t%`uo#el zD3>qut%ORsEZV!~GVvQLGKxXQDx`(1>{D}ca;?*5yB5rwKXbu6S4r`-!kN=&78Wd+ z$$B6}TUQ`l@pSFlP?Noj!i!|BgaKOq<*2C(r;aV0+7qrpR#865)psEk@JjK8Q|Hf{ zw?STvQFQx*!P6T1Ibm)#Ph4s;`BMTV3v3>NP&9D%Kh=GFe0eQN_x%R=5mJ zjEv@pr0tq2P8*p{#{VT2=!nY)TODKi?$?5_$^JtfQC_TAE}v2=Ob9%MLEyermheB> zhLCL;8DkbNEBS0ou>O>Fa!s{kuvE5O9QY3M(9=8KYdYr-FJ& z`<7{co3`{J8d~)PC;blDUC-@@4y6|4Mpp}ud>0~25eh*BLzIXpch(@6ia_Rqi(4u3gYZ-H7fzdMnO`tR513`{Lhx>G zX^8;UQZ$c8>D=4q&bwnSvW6xSrlK*M+6|TCWGPToq03fV&@3rrV!i3|k3Etd4$FBC z;2-Dj9sXY9??wJL@wfjvhvn(npxWk#7TqYNL&Qq;YKebv91 zFL<0;SKPaFWx1r${@G2YT)zA21uyzG{hymELrafRkVIPhCjn-fK7PbCqb}tbe!LOP zd6#3X@=t!*%Cv~@gDII3mSRCaoSi%78)L?0=VW`v-(NnVtm6J`F#d*|+;O@0=1k1J z>Be!{tR_nLna8=lV}#{l$1C2vBE=-lOL5f4W0X)cI4{{z z|BQt6cQix^iM${m103~3`N&IkG`uN+<9X~U9EOQ$q0?y#%ZM$?UUUc87xLG?i^XAK zI_F@8Z{1sHuepG&<>TaVZ2eX`W@B=ku-{(C*5yfo*SgKTkCPWOq@?Ji>2ik~wtOu` z!B3-C_i+JZ_*~fh`H6{VeeoFNuAYPIp?%>e*mV_Kmvw&>v%iW^ozy>Z&-$&=2dOV9 zv^+hCT~4f~C3Pn*P*rr+Mb+e*)v&4F>wN?JF7B^P@;Mv2y>au{><`}NjJygobhRU5 z)$XncHJDZYVo%}lM}mg!^xjP|ds0We9r5&v`1O@-+_&FP4opvC_~W& zJcpxxp8R4!OeKNir13$|1SWI3!2Ufq=7{t55yhkSaY)lhdEv?`es0`nKmP%3}Z?K~DHIdW8BPl~!NdQ54XJjXMtHJYwE9lscnenfS4C%E3AwQ5H`{olAN zGc@Efiziq-Ottk1a>jzTr@d;ijPdBxfXQP*LmqpzLls0j^cyEJ$aIHVs7f}xq42q* z>dsq^us&a|g2#AoJi|%Q{;Khn zSm`PhCRfV(nQHB@s~z)}K-Gs=cE7b_F=uNdt19WcQJo6DBsmwjlRX=ysEtw-W_fW^ zx)jFzGCQy&)?F1o@nZ(S?AH0mPCeH3c~2Y{_XXc%BrGbQXGzK!Pw1NofTvsK9#m(} zcp3-Bf@j$X-mil{A&fIr64{s#D;UV^_>4vGxXNf@u+(IEdM9lD>!zfR&7WNq>ib0f z?yn?O+a-g-mRAK|z9@zFzfl03|j_{hIob;{2q z<#20WLQR(9zypZrPkRFok6=KeM`0wGsJ5MQlE!F8Uff!p-xl#$FG>@ZG=IXGB3bNe z+ovq=Dx8FoBu2oFhQ0J*s@ond@%XN%{X&?>CY~=nmPgBW2Uasvaty`D2 zgC&;IeBaV#c^V6y@)FO>z{oxgq&%zl)~Y0^a>H&*6x=Y{5|Qx=uQzi~{!;FA2}z)s zv`C#r1En3Hu)qr>KjKw|Z#6P|?-$tFqbtDYt%Ww#dc-Mj)y|%Q58VQ!_hvSwUTabP z_V})@-@oo^6?p$4U6zcBr!mE?!Y46H^faZoqZ}~U?Bcgg zB2t({OJcEwPaGrU=VN5|rfuSunp8JjQWc*l80MSr-zlFn^3SLHD z{gQnD|{)QJ+@zX_Drz`RPKJr4v{*-JL{nlYO;WS z{UkM6;QpNgl`Z(mnq#fWjNYIo%TRiA9!ge|1tolgqC?bV!94HfYO-Ld*TJ;wR&7-A zA5sOw*`mJy>lCYTGPy~MxJOQ0dV<3ZRZXUDU_6-LZ)D}h;ir1VbL)5Ld z-8cy60^v4}&Z>$Wu`oiLwA~L<=BiQA4l@Y54$dk)D*}bdAM7Z0Q?~>@2EOF z4N&aF1HN>%Lr6Ev#nZdHGefDncnsOo9UTO5TV&@^WaCkspn``4?Eo7mp9R8wNck`Z zOa*~|ikm4kOh#n69-?Yc{I}Fn0uOqyYEM_;TLcS&t(+iqPTW)7f8rmi6Fn0->$EnT*_~#o zb;iifCTr$11(s-P-*2x*aBJkBncQOOD|GubfBTi=SD)}JgOPU&F9!+e;$!LrfKSOvMn-*@Idx=}>RmuNht=i*ZH7o=)+BjCLTah;J4y1K%j%>; z52Vn*(Qf_fR1+grH`RbMH|M#l{t=kHWtO~(ep8xiJ>m2O^|~Ay?auUsrgJ*hcdgmQ zP5B#JKy?{`$iL$1HXp#5Azn-5pDdmY8r|0e7eV@Ao+jx6Lwz0J3*1ZvIS*k6f$hAV zP}YxixXZ&>WJ#oC2hiy;Kri4Rv1cQA1FW+$J;8;x{}r%D_W`z0BhINnjc6J41CxG> zG1e-0Bv$_)Io0sLsxj@7=_K?IMuQop!m}_#hL15oE@UqF7QHWph~Ji0zrXhOF-@u4 z-eFRYkx7lvB$K*>Nxf4~>OGlHy-4;wb?wZs*W07uMALMu8Q=+4JE5mGIPsm2!wd3l zkB;}Bd#@&~2QiyceX}gSBOOn#%1^ z!OlFt|8>eod`x(7kYriz#kgAK?I zjMZ*pR@8A(fYBafzIYmMOEXsiVNGSue8n)DQ?}1A4&ao@|J7lf0M@{J@C0K+^eI0{ zaQG%rc;Ci0rp-X1YhwakLu+6e;1TT}|2oLnz!>y5TVY0^6OM}l=&Rzy4QtADS)=E= zt&y$q1lgJ8O`3li#8(<$q4^`EhVgukm(R7sJV7t>)kqu4*HbFZOsqmxnqo|m1&Ns^ z*{_i7IUC{buV4~0wI+HvV=*YscQau-y++uBHa<{mP;T%+yM77*3O>k@;@3cfGy20R z&vj{$Uuh!Bc`upCE8MUiXVsYxb(KkKS(n^;uU?QR%@ShT6K91c(;Da*BtNTaL=ANL zW)2>$O{4l;Y7efHhP)_wqeJA4g<9Gy!BW|J_jug~d+ak)e+vIVT$=t!k>`Uz002Wu zc&BvTk{n7ZNcV8SY|L=SBZDX*^X9 zQ#+G@n7_;F9mp#wId9@i;57mIjUXk%k@@UnvQFM%%M1?rKC@*#zE9N9gUsGe75LZ* zx<1~$`4xVifI!hU-hR-n(fEfVBk}p8ZXQ2|m3hsX8NBKL=+NMhC%ZQbRW~af8 zohFlqb)1grK`f}5Le8E!Hz+p6j8-z~dRS{Cr0=Yw1m(UEDXK{R5= zJ3G4t8*d*WQG-nIoK=Bcqh)LxZ+DSM`qy~-)#h99_K_;^MYq?pv2Am)M7Vh=l$Q)% zX39$@FD`kx7V;@;F9O@gfIX3A(g{?Kt9~D|OthXrdj9Y#g;!ewbOS8j6cIDhVBXSI zzg-*KqS>)RrJ9mhH3b(}V@wiGL<&0Io}*jL%XkyJr9C=F7JYbO0oX#jD4}4K(Mg75 zvn$$DflgKUm8o?1u9xJ}024+uQNG3)KVyxK$V6S>z6tzWHo-erqL?TXV7T&S0sbH#)Hn-`!Ob%q0E5);4CxMat5IhWXdg;Y@p6O@XiY<@ zut(w7mv>*MM_K0__o#tOIuQ$0@Rma|%cdRARL>rex6)1mhy1ZSdLPQ7@4t(O-`lv? z;0R=*4b^ArU%F8aYhS;74LQ<{lu@0e3dlp0Bzcyw+`~$I{wkdQs($-)3wYr9H^q?~ z`zoa&RI6)LcLFCvE3;p7!F^#upJ9P++VHLlzlOlvn;(L!&Kxt?DUXUDE+Ag&z^Y+hD`2=au0xScTU}=%_<#=%*^sWm$h52nNnt)_%}u41>GI zC>*UIMC?-9-3?o@u>#bd<80a6u-J!t9GNLr!UK_z z?yw@=iIOThT%;*OVFg8OQ9Cx@N9Q#rM}GQ64@UF~idvrns}Lva=NeQx?N+rt-@<%t z&D09RBM*tfQ0?FvPBfCNy28n*p)Eo#10S-qzvPmc6xf%d`h`0-Wn?~+Z|T)i23q{S zQ!wv#-*~lC7rQ6(seBP=-BP@0{#3YR18{3sfg=y~U1>dyQ*IGu%nng-Mw2{Eag2c~ z^h`owP=(%8m)2&MHmbL@_`gwFOElZ;Nn@*Mc{0w^(~ib{G~eDww`#T;rH!F6ipdHW zf$bF$PLbbf4)d@GUa`3fvhb>iW5E7RWqlbBC+HpULxkYgEmHe7mpt*#&5sWr$%LvgB*#6C_WtZqu|iJ)!hv&%zT+~x zF7CU5r?|!!f=Y+;`wD^}h+|79e`rje{iJ#T9NG^aqb~nZCz?^t?_PdaArzpma*;*qjgOG@Kxe`!B# zOe667|4AT;TItJUQoqrSlpef~b%OncJ*cz?iAp;Y58L45<)Wd@ii?gH5;)L?TD#$j zxX5xFWiQmi&-^r9eQa`g8XuN+u~8;|+o6hO zs)S$uh`!&c^GMTcH6vZ-z1Q~OV%%GW}Vf8mqKd`yElf*l-Qu? zdLv(0)bCuhCUU3M?BglPZf2fJU{4>V=`_{sV|zQv?!B~+FG(K-7+>zA+Wvu(3X`PF}&Nt(0 zJ0HPMMxOy@s<4X@qiuSaDfsa?U2-c6!*sO7k!>Q@3Ko5@rwT{Ivuq(G5N@F0Hw{dg z1HX<=+r$rsI?hA`jUar-uh7VGS~pM-Kz5u!0C-#w;6~2a#}L3*DC2B(fJ8uRYRJZs#jI`L8MUiVm^>Gp|Cge=_@Q~l!sX+?(+>7 zzYB@7B<4rI*=KeCSp3esws9AYKMO@+G@9)q}{9S^&Rf2Hv6 z@wdS!*im5@5BGOre)5H-W~6vtSOD=j=$&%mWkUT8UV~wEH>Kf#z zkF(Yc^moB4y~+1LM*|$x+q|uI)Q_?HyT0#exWUS17oCXw4sxS?^2J+T;R3JsBt-t;h!TTCc}33u8io~owLZ$q*s zc6qOht;axjzo+SLcLF#$bmJa*P2}}XD@#If$S})qUnGxASK48S(tZ=zp)$T;I(yT=HyK^3Wc$4b=1r+RT`C%eG|`lrZlRw)p!B0Ch~7UX zquE$IJbD?`!c(Pq{I$c9d{Dmp;mqGy3t~*vrY70D#by3tRQMAdyNc`*eCsz& zjfc$GEERqUcXw)3ryAO&S@l$tRfl26iFJP!-W7o3cuf`$bFa5Yv#uHF;j%=`uwsW~ z^_EvQgUG~UUX#L%`yk9#STH_;YZ7Tc#<;Li%$UiG!@m^Q0 z5j5tvrGvL=END$b)`;SBn5h5-fZN?a}mJYl-d5^ zuS4)9I*0r+Fkr*WHkgqIH*JvcP0jjAO>77cCX||ZOXrQ6cpKVV21_{FSEB@Ky$_W` z0%{Q>Va9HFny9#q7j`Z1^`;WCc za-FWqY%W!qU7#x7(&z$JUEGDnU3B0f0Y&41$P*S5f-n;z)L6vt)SGcCyuxhHKMKXV zo+bqJn?SK4)&!|b=y%}Az2K><{lUn+ahHq^n*zkPKd3<}NEFG7qy5_0?rCeya4qoZ zP5JBNqBjcj^SU;%8y<(TmYCOFYpZdHaor}XnARo4Mc%fGS>0@#2zh605uaAfTj?zp zb;z>y@5(57#O6ip=;Xz)qoxpRfJp< z9nC8ncmxe#_WG5!rBf$2e=Zjrob@F_>%G-#j)>Yj_P z)fGdyF{;y5E&htCCiYf^%yw~AaNBZ^f>U8qXIJy0iA+u>Zq8!$zVJ{_z1w^0{fU75 zk;tE|9*pX=WbwIBAl(sZ5c`38bzp0S#iome7d&8lP?_hR!h=QghYb}LPr9Ku9buo$kQd!Voa>7;k*)jD) z*7p=Q6(p$ex4z9thZji-yF6gije&yA4*|kbASxbGtflSj;=)3PMYh|~)%4*r7%I<(qLG-*xi%bxE!`n^97Lv*{&<$!o`mda zDww{?WR9!(I!(2$_U|N6KoXgSbc{(LV*6*Z1%Y>awId5nnGCNAH;YvRj-JeY$}D5O zY20P3z5b*3IqLr`0`H;IZ7%Ov^*u@Cp6?q z(H9&*^-{Bp&(t45YhS^lP*fZHQPg^x2EqvVVH5{yrsXMQeXDnl=0u)?#S`5nES-A# z0}(@uQ9%cXe9*0meAjIb!955^(JH^1R=&u9wm-;TX5GiHQzHeE`pKArfx{+I4Kc#IA#HW9xTwB-qm+5yWV_zXcppJ2R=5+oKklV=(UxE9SrNU# z$S^1ddjXrLae4vZ?PC)`h}T%kO+*wp+yf+f^-$0Y6j^T=c;~1eWy|9RTWzKpxm<|u zgQy_U3b<763DRInp$#Oyc>w(q_u0DTF53YjLt*?zvK-7}mY+yg+?Yz<6@w3`>Ct_j zCc8Utg)dD_r-TIFl8v{`)+mzK!Mruz^$!ipTPnuE4-KIDtMkS<>Wi$A$E;j#d{rc9 z&GUJ0&8ziR=T*ZFTO+kr!;CbeBXW=E556UHufK?O@_|IRe_ekgMRtce^JfqwDx0Y~ zSzK?j@FO)$zC%LWzGXMk=X7kU?NB>pf082OB0n=C3I%J?L&S`-eU{!wFi(S>Sdwht51=D9HC zZT9H35^tb_ub+gF4O^|4`R<1XlrqQ~dG(7+=$dG$1TYvSsPIpOe>El?lP#3PoZo|9 zr}D0S^gMh(h|(f72-_Y8(t!*2`7YP1u`ICI+*+|XV~^7r6Q9~XD2FS(8hy*vUZ<*D zq087HW!xDZ@xgsPq@rm^xZ8geANn#!RrnZ=@cL|X#WZ(Q5nU8sJ!R_BbMDicU?VZNsFq)I;I|XajQn+MNk>z7!DPi4w z>T+aJEs%~tAPur_-R(~EAH&h0s{8OE=|kX);g0&jh}FWFv*6$um6`k~JcO z78D5nt|N~6Kk@TE2V^YpYpQaihI^VwS$9Rs5uZErS^e`PdAz>=V&q1C_Sqt1_&M@L z;kMbn>P`r+8#+DXumbm4dNX+-y73@K60F(_b)^~o-=*&oQZ6cJYV4GlLRhW=8F8AguEB|7YT6^;*2~lAtxiv%mqNbkFm@L z#w;<<{D6ZyM80N?tU){EXnX*8miRJ6`xiKd9^rh7Z(I*q-Nt3emdt0Xz~e`~u>M_( z)((cARz9b}^H)*5Em4aig`#WjQp>whwKxCEkNzOUe@j@Mc`1oXy@{}iixZ-E@on$< zwnt}~of^uxtxcm5H4YN$+^x~1%}1j5vtttHl_^@1RKLsHKkAIV>Jn|tZ8Lr2+vLC} zXioiM-)L3&9<3Aos9udyWY58=!bQ^9du11bU3{6n5G!X7{)Wc**=}3mz9KU;=3)Jo z&f69GEe*vG=2c>EskrRJb2A2aRq>wCdiNFbp61O`FKFmu+MzE!0HsTzc{*$tA4{wN zK1dlV$nMUu-eU#NFl!oR)-=kj3GANQhs%}i$I0E6wckL(%6p$}h;8o!JQW@x{RkZM zHy&bKhXZG3f3gmHWm?pv2I3c#m^QUI^2zx=>)+iyjWTwX(p6FBGqS(r!<^FCvdUoa zEG!FVJozB{{@LV;%Ml8R-V=9oJjxrZ6Byg4*=a#ZCl zt;vv{Gye6K1Fvb1^l2%6px+{EwhGIQO`ay+0^JFiI{Vk>&9(Th-P|3$29=>_!qilo z&%qj=vQY43*j!ZzMyNXpw1jrSHG-YY@t#W zya1yR6+(#8_1SRsb+jj;Z!^9j^h2L7QNf6M+f1xbBz?=7k-0!Yw!!t2J`@cz-E&Zoj~A1f^Vl3ItLOFU(+Ax4VxqTFczyl$u>5(7nPe3-3KK#%xT0v5Q7H4YSE-5@v-9KtsC z^Iss;j*zn#hrKS1PI)A{8)WN6s>B5vsl1?a&vG{;x?Bd30|N`(w_u|pP0ee3rR990 z3cdq*aW=l8-```?6;gTxa=j0&c$n=1!7mTUBxBDa|1d6`r6??Ex3sEowf+RbWbDHg zd_}6eFBMNFiFoo1YCG8 zHa`=c-BkH_-X`a~bYzyg&4^}S7?N~>U7yn`(9ZS6d-An`3#M2pdMoJ68;~J7^IE*> z_pam_Z#ZqDJ1NJ=it>g3djyV1)Q>~qk@`ewR_ZZ{yGK2MygOd% z*O_$8T4FRS1HXio!i0-s7fHUw^k3@`vfhyyvIj-B+NSqUvjr|xubH;y1vXF!Dw9G8 z-~^qfTJs5EE3j{aq^)oNK}wSSD}=Q#H}`#szVmdO%{wp#UW#QN*rJ;685#?v8bW22 zY(Wb9ade6buRcuPQ9WAqYfVMRRZ8D;q$(?aPd_W|oZ?gA4H(pdH7SvmC>}~yz$}&0 zEZMKtYl7@PcOjj!<-0w-2QZq~mIlIaM=Qk|FY%zLyF!gX7C#vyZ6l zITsbUpLi*(H&hpPNP-t#3cV-I#O&Ag9m-!w@V#ogt0!1$UQOt8jo!s-`{;|p?~v5O zoS<;0;@(JI@x2mz533J$LMUv)4+&IDzLac&B%|nF7)X_$ze=cCZf}e(H&HU&Nu$uXr<{OX-G`|#N2iw6&U;*Y@xj_{xGOu7O6EKN$WgblabAl6g*8coH|&CrNmzEPDZh*6UX|NMBe}ueRB%I z$6%T=;x9>rikY()Mj`8Dt&x~r0etq}TxF*ZV>ONBG!lu_&1tC)Q-)w|taN$|O!L(G8}C7o`wB7=tinFTU3 zPQ-lt?a{yyFCZ*5+|S$-*~Cg@v5; zbzX}-(Yxw_ajNq9K4t#bNux|nZ7x0z#`JANIV;U=y}(`&L)3Z}d@={wj#wsQb#Sj9 zlR69Awj7Q-%#8-&RT6>S1zU1chg;h3Q-xUhLq^trAPMF(E;QBZ%QspH&IsS!_@=C~ zjDVVgK2x{%&+36|RONv_?Y+>^+urEF5AI`ju_alkCZ1aVb5Z&9ZZ)FlQ6N+VbYq&sr*xdSt44)oSv?q=& z2Tt#@dhezVyGoYC?Yj%Y zzfH8}(UrtVt5D`F)$wt$u7@|hLCRi?8E<0DXk*DZU;dq3Rr%l2g~}s+K-b2dg@Qhk z3I%TX(Q?-ES;z=ok~FYe4qV2zOkz45CMP)Xnk*f#AtOX8k-ac6XxsKjneyRRAR98& z6HthT*P0*KGZc(EdNFNjppD<;+IbSzI@DyT(D8VS?j9Q(JvH}*Gt@ydQ9|Kaz|Mkz zCgOpY63`bDwYayD6Ut$2S_Q>C@_V|O19q5ZT^u63Pq+6>hQVqF2Cfi0jCJ-(2hBtatlOV*2r5a$ z&fY2;Z)OuGPHhMDtY1d-zv$>)BHguiU8Sx*z=npE6LwT12VNZw&8)C!6_Dybjn%cd zPhDZl_RsWTY^iI0pSu2lfGMNpFO}(t5!G6jlXKU52l2em3;fP4@uF2YH^VoQQ|a)w zu@(*JQ;3{JDzst-yQff&!|uoIhiL|$n{ARxU)AYf67xu~vza()J+|HvJt!O*laXW^%1P+iqHSnsfo`O@ zz3BE(vF`(;`f^QdMv$>FMFZiSwPsAuIk%<}VNMl)22jzI2aX|>y@F!Ld~;z`(plg>I?vIcgu_>jddY58@Tza! zryb?&Vdd+BF_n3m4D@@M_we&Z4y0EsQpafu&Jg~*jdD1YDCd4T>&y5>CcacH22*VN zZ`n2R?ApD=hI7#**9(lVa>@F$FxW-9G8NNZ+*f`*YkCf)ZKZqk>IW=?#8 zmEnJL@>Y&!#z>p&O_>(Sa@ZvJ30g3=ZJUaQ`_H90>PK2@?(?6+Q-a-EGm4Xr4xI7S zIOI~JUsx`1*IH^^#KBOJN-&tZapfN$)|j@crA94hWbg7Xi ztorlSIr?*5{KmG(Ko03`PQW0zK+MmECqz|`<~;G%Xlps#>H&jl~tG+vH{;@ zl`{uoc^o^(g7vZNANtRA`^HoDFsspo-m{s%HQLd8Hd6v*12BL1ZzFT9G*8Y)=|Xh= zh~C8gQU&$5}!+expEK-iGMM=N8j3FMn5v$1&FLK1)3?&T1O$ltdIM7BQ3dc>bqWeYX*iU*C zN)t;OBk!7|##att+tGLrlBzCk5sTLQXuyKEB^jB28%tZHHDPz!2@Z|e);BbGXR;35 zadBXZ4t)ONz*HT$yKi9QolYIN=izsv8} zv;FlLiyA4Cy;y@!Hje{s{;p{v(FTg0)n*d1sC2eJ$Z?^{tM!UI>nLmMov5e?9?<^w zrj~Y`0(7?j(SN=l^%ef})~ZtfdHY&tbeR8qfA95GSNhotn-U!-rA#o^?b|to zVjLzk3=a-*fS5x}=6=~B$L36rv}bd4`ivz&OXw}jp%RyrXh_W(4G@FdjH-7-q?wMIT9%PwPh`j34^*l ze+sS%O>Gm|UR6mP67-oWJG_5IYZ>#W0PG?A=GC zI3sWPgdw9i8Zq^6DvTG~kvR0tH1s2OGEWvGSIpDak&Sl_!awJhI;2&Bvu@uwibR8h*-{5@qWWEEled2I7AJ4AgSpTyZ~f&ho;Ts& zjSPs9W(KhqF*4{_odK>;XW*I0b+U$9qOU~PJJ9fkFDda$@dw~iq}BZeKqvH=z(mwJ z@-FAomA)pFg2nq!5u5gLP|g2dHi0cnsx^h{yV@ zB`8EjkB~#rUy%gC@_-6oY08ANxDh@{ZG-pkj^6TIlCMl{gRk$7jw2jCQR@VbtKX5j zJ9;(dAS?t36y47yc`u{LKWHQe{QrInpyuE#PE=?_2b)CQw0ROeH+UwSd6P2?1GQNg>rqZ|6*n~VB&2c_9kN{LNtWk|qFyW8^A?rl%?RD0Z&T2Doa+i)?^8WgnK(&~c)DrN{p zyc8m0a(?gnzDWkQx_h2y|Hpa7@-{|(A z2r4KD5Qj|ot7}$hHYWR@K7WM9gN3_Cmu%wX6FFxxSOudI$CIhs!CHmyD$)I9L(hpl z+vrT%zhraVA`f}cBhrji>?pM&Gt+`}2&~k^$~Z!c^`6LQ@{0+e0wk==gSqQ@m_oW> z{SK3I`n*mwyva|Q4?5aSqYlBzJju~B%DMbNK*|u#^psA_+b);~)^TA1)^W|f9X9Xz z(|`=7rpBV{I*x_m!2qk#XpYLkPoK6cdTZ=?MPttuRmal8i1-QmY=={D9xV9kVl0re zQv5Iw=Q+Zp)aRike!-yKE&DXpp#hGnOVxj0_|JslE~g_;dTRt>5M<$Dmv@tiJui9d z2?*&4=D=QXvL!`HyQFH&b)p4>+Vsottz9p#LQ3z2MxzVITeL>ss1o&%QkhLFw4B#U zbXN7M+sC7Oc>yg3Oir9gG2D=MXDp7i5;{*tt5kSR7>Q&|Shv|?y&_4gx2tg zsF{Ay?{cjN&eh^7o9}r}zQW^CcFl(bY4Oy^=bBcF&+PC(cIpEl=MEH-ntMY~TK+0j zzD$L$fM!Z?rGhD63 z0}wGh)GFgz;0-XR&gg^?&j3(^N}Jb;jgB-;t54S-5>~sc7=``FL{>aEy(^Wnb;P@j=-Dycp7_x=cL3n z%2ngUYEnEWOwpcikhl5t5z^ny8R%IqIFZBEC=acsvBzlaF=?!M&+24#jj*ml;D%b% zv;u0nl(vYnrg4St{g!fWPEPbRx_qujA~F-W@SahQ%tWcF(t9m=-{$fY5M3}f?xC}C z7dMjvHio<$QDuOza!H24HQH@GHSW>@IC;Ns>*#_tEVRa<@KjDMg^=rsJEpn%;Ma- zIFn1J`yx#Ru^@9Teir&WIJ@7#iKd|?&j{|;IrY`VJs0PL4og1K6e#G&+98q~zZU&e zeHnVHs&hKh4%v4Yb#W*Izbs?Sf%Qp{hx)fo$xaxJ=4)3iqH=BDBv5WJ+gzxfae$Wz zAmfN^mK|gTISHdAk_tB7wCiF(pX>m1w8L~322}Ob|3F|@FqZZ)R6?l=#=0enAhS$p zM$uS3m|cxvHU!iNZt57Kcpef;en^bboXXvZ44N^^gue-5V}^e6nBVZVf=4uD|0-7! z*qhth7zaaLrWU;DD!?rqn~CnA++m5ZL>+61ATyF0MkK@BY%gy>)tw9NJ#R`m+!ib| zn(r=T1i3@yzU$oU0WySU2@+)JSs0WGWy@{}lXqMKoAv8jlk~_ICS`6#EObj@l7@#3 zC)HNnAinJHXt%p_ltq%9Ho{Acvvd-O>*l#`N7dKJIaYn06n4sKpBr<{U7#zHMR+3< z#o$!@;dccI7yu!XeXu_8P{$k);c6NqV}r1r?04` zw3TVgZ7DkC%OmqhjkgqIVF^F^@~+T^IO0VS|~T9 zA9Mbo(f*XsmHyPw4AFReRACK7XJz54n+jbMJ3Oomu9qK@O~_xkZ`xTUwVPH`?vW-; zFoN^+2tO=WPV>xlF}BAn$M>D(2=d%2t(i|D$oC}x79Lmdeu`}QKXPO=Amk6r(@YcK zvZwy8F2-Be%+_CbQvftk05l)zDCupIb&*G*ztpWh^fpP6e~wMidH^CjlyDp{W%SLH zX2;@wYP1jrW?c%s3p#<$ZV*T=mf==2eO)g|Sgrtf^f$4EQK7W$RV7t7=^bK&;24$?Fr710f;|NbdpYYh z8*74$zO~q~O-eJC_18#rP`1hU(F|AZk14*|?^S3#u-BH+#tcQKV34*hHX)})|Ju6n*g`$P=Dt)gf5gS;w`;vMb{wU`REBAK?)q+%}3^0$6$2a@p>*Ixx&AO^%oFuQFfP8`8l5onJ4eK?M?yd`kJi=++Es8CgE{uL z>tAGa3ax$1PzHo@aw?4b1sdRbT*a1k(I(PGw%+!&Nx4F3vGUB8wqmgOTz zH=oL9<(THRx9;ZxO0Nwc-hCkvk#St^O7A=s|px_gqpdQXO2N&aY5 z25AY@jOwKW;Gw8ouvD;}orDfGSqPhX+3Oba?smf_o7`}fcQT2XH% z<7gEE7L1-l17BMXY+=eu4B6v$OSCl!4%54njKN=Fh+Hi8VTl~5mX59fmd|^i*R}4i z@opzz^&~V}7UP$i;_sT|U8$4`nH;FMl@5T2yka9XweC)4T;xYznyDi-UrK5jKwUOW zJ;96_!^u7GpF@faW4vf;BqD`yCb+gVF{37q8P99XkZuc&Y99TW#tDb$7t$=&;JT@T z4n-sFV-AO4(a?@{Lus2;80Y{g>XnEN8~5pf?>sbj&P=!+jZ`H2XC{gCdk&}i%}M^Q zp~AJ9qE!C_(ORxqVUrbTTXIWpQCA5D?XP4KbBb3;bCV;k)(av{NG@8`XSAEZ@Q0o`TeF-MU=e zb;Nb+@^G;F)}`+j7zpO^NN7d{fMPQunM?PZ` zU9K{ct4-1{GjMwQW6~`=mivn zP)i0u(~6Sy*v*#j7eEtDsEEycQOYPvP62{N$sS$0De7pBa2-^=WOF8K9TjRu#-ii4Y(iVMq0-j8U+t zNxnsBn@geQ=ir66?DP){jl^PBuC>?Zz;;aUzFwAV8aYquomWdY%SMnEauHq8hC~9) zHIexFu;k^BYaTX!IxQYH@*#iZtfcLJnv302#J)C%dvjOKar@eIF|a$1J+G_wE4$o6 zV`fHl2r)$#LmmXRwl1z3mq=@zXA%4@Z?Gc#mOb_=p>)?HuiIn4LoIJ#hnP|<{dZi; zcc%c+9CWyDW|T98~7r7kjDHxJQ;(gk-WD2VAv-ZLw=?8naxF zIAMi;3vN9QZnqi3gG$Lhi&Y!ADOx?I)hdb=k5vDg`DoQ%HiRz&+Q zN-NPhN*5VzqsWt=zOK$lZ9@-^Xpq7v^vKpj(&zT$JFjYFiTwrmZHA!Z?MC}M#?EUS zxp1G*zW1R0je{9)9PIIiQN(2W$as>TOlJ`8Ov$c4y!Effj!A{-3aS%jA9BXrupODRsk2~d(xO5ubYkFELd!J z(S}1v+v5~UnkFN$QckUr_sKXPhJrYK5y|8^)%zSjf8$Blv+30iZ-(o+^B2TH%&ggW z87W4#A!S6O%{_le%?VaXt6*H_l&h+4_w>=u$3QPev(WR0NENcByiu zPLAs%14h#TNz!R}=Q@(?`eUPE9w zfrH%6#Rd`h4ZE&bKLW49{ETJhFrtT$k)R#M&cQb^WKVpP7*!xq8@~BYuU~g9SXHJy z8qc11tEYTH*%BOmL$;vg*W>W z-vsAduW|;9hjs1W*t2@kf->#sUED?AB(9=y4?Doh*70(XXTj=4OPA_|3sx=hJh)`l zN?iMPI^r!_x?%}E(w?#{$Gg(#PQSlayG@_krqf?(`Ylv75ogtsxNHG#sKwcD7(dA3 z`WVO5ivXfH+?Dr|9w)CjNbX2wx=8kT?wD0r*cFGco&~r~&a3cv7FxfHtl!1v?_%+= zJi5ZO#QN19mq!C(4-Rv!B-Zc3a`Sn$^}EQ*vQ(Za!ei*)u4;8CybyP@cu~iHEk1jf ztdgg$>h>~RaIX%pSkl>C(+%{}73HN%R!BQ#$|TMp61Z+7k?HGbB_oA437v^2~ph)Z#)7a#UHg8^iG5LT9X)-G5YnqR&YOvEX0 zPKfT~5*Vm@07wNsiGi+m*18%WcJmj8aaS*e3a*OZSC8bBEQ`W;6&8SoRxURKWlJhT zQjS$*e6-Ab^L4eM#g;qfVOFn5Pjw6Eo#kKFBh~5}&1iGb0oS5639)*-1uZX))4pUA zB0F$dx5g7*>cIi^z{O_SODf8jEYhG}QiiAL@Y1245)iH$k01zz{MoDu!C!(GR9O_0D-Dp4dCOHxM{}-$xS9$CK^#B(i+^j+Qm(pYhAP zMlfOig2ggy=mPy0KfTrv{D1r9P4Lw#Fc+FLUj{^+H%ng<{q`~udAE8=hb!=`KmzOrRJy`qqnJk$L@?yjNTrd8J!lL5uF;H5}h8M6rG^1 zkKU*zt2M4eAz!alUYF|x4L0BwxND9~ z@G5|O#o#LlZNzuAbH1~`Q~f}xo39*lC2?#t($dq?H>49*UDyK2uTuAC%*g1Lp)vwU z|KHWEcQ@57pq6x>&^@`k>K;(5dfeHgdk@tkphB5NnVFd?GoT*md3Vn~Jyp+u3iq1T zt7k9OE1;J4zP)#s-l}&%t#nUwyWGkhQ00B5_sQs^`UKRyeb@E9s;|^G@2ZEc>UWid zuFSeJt812oIzJ1tZ_T!4tL%VU-G65P9{pASfLiP+@Hjlm6Hvy0+XkczPy+(07vhdH(qz+MG-uB#+ZK>#gA1*>OK`D&aY;v`D!Vlo7HSptdkB2qqtw(JrYcCYM-91S$Q=^LXWEEq zDy-j5A30qjJW9d7&wW)ag1dDHkt zu!tK&Ug5kwZq$up{N6(b$pla%=ld(t1NnYqaXSa)d?dL}8Pr zb@cVmA6UYcK6Fm(Qi$&PzjA9P9$hbp{aAX75iIGHEkCW{B(9whpc2_8Takdd8wyw= zYJnJIumhgRy3=8L&{5MeYNG6L0j)@YgYFmpV8wt|GbN)Sb&Q%Me;g|DPH+6UU6t6D zYdg=?`x1m~E$c?X4Rg5!b0MIz8)JUlTtBTgPzcfujI`^~mythr)qJ7QEv`PF61uH& z3BRc*VRG}iyE%(n@-Az!Bh%n(L2abrF3XCweraj_eRl$?5w*bYPQVrL_a{Kp=lc^N z3-tX7X!Z9c`0kf`RqU}3FP+8-^HLC!n`}e7iQf8pqUu7C+ab~;HUEZPV03V zv>oLQ3Y{Q=_L;HubxG>zONY-$9<2cqNs0S~*2)+T@kvs}%&yDy#y*sGO*&)dtL&p& z66!`9Q+Yal}uw9{}6T8ftrrfBn|1$~_sc(iYEB+weL0U}V@ zF7Xx|%w|GIwuEGGXsRBm6kPmn`jyDr7WA0|L2Z!wOtqVWK9dAog?$PU(lG`%Y8~X( z6euLk(*OeW0wAl)qQatwQ!D>{$Dl?j(J6xzAv43P`vhiKJ#avbGGvh3HyBq|G0Y@F zcu>;YV*?SRL4O9dp-$m%k+#swipV+a+Qd~%EcLb6+tD<2LD@n9P#?)KhY|D~BoyrR zr%rK_*@!|=x{N)-IkBeSUph@lzwi|0rAHGc3{)PKC0*n0gxO-$)woT;cklri@5&bG zcc7XoAbdXC!IMB&1e4DFgD51QZAau?!65-9p2KB56gk_v=X<$HT@o3parsBtY4Rk~ z6f(M}#kqAiX^Q%$Q{3A~=xTMsB#l9JrG1^}UPp%PeM)>O8=kxrmy4K6Y2S3o#ypbD zsYZY>*zJ0mW>oL9oUb86u~&e!fjfs-pAQl`jV!}n-2%`@rZ~+GXz9#=2xdMe!dqIg zl!xsi!6hY&CW>GZX_q6NBexpTTcEwoIQJC^4(PI&T}Y#YjlCq3*7l*NNJb%=h)CoB zQzFrU!V0oD)hA>bWg>_i7BuCHmB>aRg=Kj!^`^y8a+bD}FdwHH*sg4+;(^cU zKIw*rg+hNok)oN4u-_$Eda%zM0QSjk02Z4Io$`AH8mdD(l+ylS3U;HGi{^sc8hDmV zdEVs~EetYXeUitJcaC9uQ~ZkzFoG3LGfy{R)##Z-$iGEQ~sg&IUG(pnxLdW=ZqJWOcp^K4+XdZ7RhV&A%Qt(F_QMXbI z#7G7=^L0NcNZaU!)wT8cH*qZ&{r(< zY2-#77A4ce$Bd0JjY}iW^5Ug5p(s{AJme1b(<^el+oDU2nl6229L77iCPM($JBXYG zJwfb?4DSc;TL2crUgHR(WM= z*<*4en}!%>C*ykJpQA1dc>ke@9xItFn@iU!cPxXnWHPUO!I#oZpoF-aS4 z!h~E#2V``Nm@>;3V_^8-;+)BLUMz0SUy~})wich!JZ&|EQZxx!l-S(hM6)@=m_!K4 zN$hxvWFvkF@u(>|lGuCfJ&0<*5&UKz*uPGR2C&{_{6QeJb+34PX=s)OAr%`?KjFCb zF2}9ZyhEXpqEyCl5)n$Qlm4A^tI>Sd{dy@1qoVsc$y!Ug@{&SuI{gy?c=bNZniCK4 zj}bh*k*dRgIe#G=5lw3YgcTx|oo1-*qpIZ5fTN^7kir;EN)zwFk?D}ONHNMfFMm{0 zKRvVlZ&+N4?9&p8(UPsxA%%6tkmWi_Cl1KBlDWMc%G2&M=JbE-ttW5x;*~MngC)wP zUcpd^+PSt3v4Vyc`}V4zLknie-s||g=I8_`$%>@+Ti8nf30)K)KcW=05Fu`s`rk7U zJl-4o$%_ZG-iUYXfBZLrGI`>Z=@D1W!%1t0`)A52a&342G*`{!6#t!}2mD@F?bwu- zJN(tS)3NyLDrqO|F`|9R3KF7E@wjhkv)LrhD?* zE`GQQ-z3MrbolqUYBH1k&92(h$+6zaGWDQ_JytpKnAuOX%>I(x;{E7}nA7pm6HHD7 zgf)W3nv!`wEF?`_sAjdqgtd{RT8?SB)vZTU<~PYOI`X2>DI5Bnc-F(BU~=qPF$I-H z=_A)_f1GQRTdwrGL$myST(!%SV=GW$!lUSXfJ;SgyE&zTDcpWzqOIcg3>~}gJN+Mm_4u}l9 zbQr@#Xpdp$OJ*ipZm7L%K{HJ;dMKMXpkqE^f+FZJ_bM3DVpeT_il&GsQD(wfql+e9 zM&!kx5-ZB`98Ta;&}bJ5Zul8xzidP{KPh=Gbwg(xWV)dfc2b7p67Q+ie+q0m)WX~h z=z?`~aBAnOfo(Jb2fH-x((*do+Tr3i={p_U#h!s(g?mu#`>mvHN>*$e5jdCwChOe5 zCA0oNFRE355Dxv;7VkUcr_kG>8x8(^yX8TL_C%I+%+dcAq zwJ%}S)E(w)Zbm|X?>U>N%>EsU^%f_-c6G+s@sAVG4JLhT$k!c6_zScKBKh{%DON%j zfX_-GWFMO(3!7?wkE^y(wM_2pxNS`@igPQ!^jcy0M=!vcDCQ?Z!A%+=QknqdXUVom zSNt%%;JRKfu~px=E_3>=Q)h;k>dt2vW8Qt}K6cjY+&$LJu0JS|xB(Q1EI*rx|CZ73 zfhVs}q>A&RBnjue$;OyN>0@d?>Q)!uomls-z4_-Tlpt7_L;T@?8cn8(9K9e z=N7X&oIu#COQuHyynZym&i>JW6duvVMs%?eU2H@b8_~r^q}Y15*6f(W>MZ_9Wn*HN z=fG#)miG4ZU$%S$RDyR4_ci6MSXu=>_auD&&4ZI!^DpTA|C=4F?8Z}bZH$S`PC4|+ zv8=jzIw9Rotc%R$4BxQ7+Gf09B+{No@Q8Z_u{{R*6yRjL--=JhZHc)yZu z&X$QDof~pe_akq)Zn-|?8)G@5hB=cBku$$>4e)KbO<2z`EfJ0+6RX54%t(Smgs&&h zV-BwYGa}l0-~?VI2_tAordJG@zwT)HwON{xZz@D-yFXGTChO^{xCNCp6W1Z8RVe9$ zGu^QLi6VQ0ViUE+0DUlYqeL6Gwk2?ka6}Y)YsWR$Y~!D*oJ5L|uE<>sCYGM)0+yc4 z{$c4!0?JkUrtG)5V8IGv^>M&&fo{OGBJ?u3op`i;+Qe0AH#_3PW;Yv21x`})$hwzkSV#7Xli^>1EfoV*6jaDgp`na}n>2^w8?{=^EyUAu42sCbZ@4ano-_s&9H9o4!)NnrEiR`2@5^&j1NCP)i6&m2F94^! z(qg)FhUYZ`@z!W@=^BIf`c%2@zf+k2fI9&IPUu)^7n1)10DfDg2f93glTz=~V<}LV zm(BAULzk}+Pi6QjeZJ8$ev(bv!4LfhA>VCl6I=xVx=X~<9>)2nzQq?*md_XU`LbkQ z=zn=2O0AKu$wvUu*v4Y<*g6)7zaBsbFZ(<6?*en6EEntFVPtFz*@k_l&(f@aFwyMl^^5N z7u&GySiw@TJFP|h1HY!DU%enNaUkOQ{eEN2neZ?&!_t?`w7yDqy{PY>{JSx!y7iki xJ*qxT#g4HQ@rH40%YL{+C@>%BB*tHV$#uxyllMl|8Q%@VM~)gkW(-8){{bbsr@a6G From 91107fdf4443d2171e06840e87277bb7a047343b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 4 Feb 2013 16:21:06 -0800 Subject: [PATCH 0929/1634] bswap: Fix width of swap in leul_to_cpu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The misnamed HOST_LONG_BITS is really HOST_POINTER_BITS. Here we're explicitly using an unsigned long, rather than uintptr_t, so it is more correct to select the swap size via ULONG_MAX. Acked-by: Andreas Färber Signed-off-by: Richard Henderson Signed-off-by: Anthony Liguori --- include/qemu/bswap.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index e6d4798142..d3af35d1d9 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -2,8 +2,8 @@ #define BSWAP_H #include "config-host.h" - #include +#include #include "fpu/softfloat.h" #ifdef CONFIG_MACHINE_BSWAP_H @@ -458,7 +458,15 @@ static inline void cpu_to_32wu(uint32_t *p, uint32_t v) static inline unsigned long leul_to_cpu(unsigned long v) { - return le_bswap(v, HOST_LONG_BITS); + /* In order to break an include loop between here and + qemu-common.h, don't rely on HOST_LONG_BITS. */ +#if ULONG_MAX == UINT32_MAX + return le_bswap(v, 32); +#elif ULONG_MAX == UINT64_MAX + return le_bswap(v, 64); +#else +# error Unknown sizeof long +#endif } #undef le_bswap From 84208085d357d95b84f6e281ec3aa028e988e5ff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 4 Feb 2013 16:21:07 -0800 Subject: [PATCH 0930/1634] configure: Fix build with XFree The build is broken on ppc64-linux, possibly only with new binutils: ld: hw/lm32/../milkymist-tmu2.o: undefined reference to symbol 'XFree' ld: note: 'XFree' is defined in DSO /lib64/libX11.so.6 so try \ adding it to the linker command line So let's follow the linker's advice. Signed-off-by: Richard Henderson Signed-off-by: Anthony Liguori --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 0657b1a1b5..8789324a9b 100755 --- a/configure +++ b/configure @@ -2388,7 +2388,7 @@ fi ########################################## # opengl probe, used by milkymist-tmu2 if test "$opengl" != "no" ; then - opengl_libs="-lGL" + opengl_libs="-lGL -lX11" cat > $TMPC << EOF #include #include From ddcb73b7782cb6104479503faea04cc224f982b5 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 5 Feb 2013 21:00:21 +0200 Subject: [PATCH 0931/1634] e1000: fix link down handling with auto negotiation Fixes a couple of regression bugs introduced by b9d03e352cb6b31a66545763f6a1e20c9abf0c2c and related to auto-negotiation: - Auto-negotiation currently sets link up even if it was forced down from the monitor. - If Auto-negotiation was in progress during migration, link will never come up. As a fix, don't touch NC link_down field at all, instead add code on receive path to check guest link status. Signed-off-by: Michael S. Tsirkin Signed-off-by: Anthony Liguori --- hw/e1000.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index bb150c67dc..d6fe815eda 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -166,7 +166,6 @@ static void set_phy_ctrl(E1000State *s, int index, uint16_t val) { if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { - qemu_get_queue(s->nic)->link_down = true; e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; DBGOUT(PHY, "Start link auto negotiation\n"); @@ -178,8 +177,9 @@ static void e1000_autoneg_timer(void *opaque) { E1000State *s = opaque; - qemu_get_queue(s->nic)->link_down = false; - e1000_link_up(s); + if (!qemu_get_queue(s->nic)->link_down) { + e1000_link_up(s); + } s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; DBGOUT(PHY, "Auto negotiation is completed\n"); } @@ -784,7 +784,8 @@ e1000_can_receive(NetClientState *nc) { E1000State *s = qemu_get_nic_opaque(nc); - return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1); + return (s->mac_reg[STATUS] & E1000_STATUS_LU) && + (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1); } static uint64_t rx_desc_base(E1000State *s) @@ -810,8 +811,13 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) size_t desc_size; size_t total_size; - if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) + if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) { return -1; + } + + if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) { + return -1; + } /* Pad to minimum Ethernet frame length */ if (size < sizeof(min_buf)) { @@ -1110,14 +1116,37 @@ static bool is_version_1(void *opaque, int version_id) return version_id == 1; } +static void e1000_pre_save(void *opaque) +{ + E1000State *s = opaque; + NetClientState *nc = qemu_get_queue(s->nic); + /* + * If link is down and auto-negotiation is ongoing, complete + * auto-negotiation immediately. This allows is to look at + * MII_SR_AUTONEG_COMPLETE to infer link status on load. + */ + if (nc->link_down && + s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN && + s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) { + s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; + } +} + static int e1000_post_load(void *opaque, int version_id) { E1000State *s = opaque; NetClientState *nc = qemu_get_queue(s->nic); /* nc.link_down can't be migrated, so infer link_down according - * to link status bit in mac_reg[STATUS] */ + * to link status bit in mac_reg[STATUS]. + * Alternatively, restart link negotiation if it was in progress. */ nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0; + if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN && + s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG && + !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) { + nc->link_down = false; + qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500); + } return 0; } @@ -1127,6 +1156,7 @@ static const VMStateDescription vmstate_e1000 = { .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, + .pre_save = e1000_pre_save, .post_load = e1000_post_load, .fields = (VMStateField []) { VMSTATE_PCI_DEVICE(dev, E1000State), From facf98ad987a38d97e12511f81375380b407a828 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 5 Feb 2013 11:27:45 +0530 Subject: [PATCH 0932/1634] qemu/iovec: Don't assert if sbytes is zero Since these values can possibly be sent from guest (for hw/9pfs), do a sanity check on them. A 9p write request with 0 bytes caused qemu to abort without this patch Signed-off-by: Aneesh Kumar K.V Signed-off-by: Anthony Liguori --- util/iov.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/iov.c b/util/iov.c index c0f5c56618..fbe675d373 100644 --- a/util/iov.c +++ b/util/iov.c @@ -304,6 +304,10 @@ void qemu_iovec_concat_iov(QEMUIOVector *dst, { int i; size_t done; + + if (!sbytes) { + return; + } assert(dst->nalloc != -1); for (i = 0, done = 0; done < sbytes && i < src_cnt; i++) { if (soffset < src_iov[i].iov_len) { From a911a182a6bfd3b0257b13f862b0d4fbd9392715 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 5 Feb 2013 11:27:46 +0530 Subject: [PATCH 0933/1634] qemu/9p: Don't ignore error in fid clunk We use the clunk request to do the actual xattr operation. So don't ignore the error value for fid clunk. Security model "none" don't support posix acl. Without this patch guest won't get EOPNOTSUPP error on setxattr("system.posix_acl_access") Signed-off-by: Aneesh Kumar K.V Signed-off-by: Anthony Liguori --- hw/9pfs/virtio-9p.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index b795839620..d3ea820eae 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -327,7 +327,7 @@ static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp) return retval; } -static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp) +static int put_fid(V9fsPDU *pdu, V9fsFidState *fidp) { BUG_ON(!fidp->ref); fidp->ref--; @@ -348,8 +348,9 @@ static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp) pdu->s->migration_blocker = NULL; } } - free_fid(pdu, fidp); + return free_fid(pdu, fidp); } + return 0; } static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid) @@ -1537,9 +1538,10 @@ static void v9fs_clunk(void *opaque) * free the fid. */ fidp->ref++; - err = offset; - - put_fid(pdu, fidp); + err = put_fid(pdu, fidp); + if (!err) { + err = offset; + } out_nofid: complete_pdu(s, pdu, err); } From 15af6321f4d1f90d0ae1b5cb05093c48b41c4533 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Mon, 4 Feb 2013 00:36:25 +0400 Subject: [PATCH 0934/1634] vnc: recognize Hungarian doubleacutes As reported in http://bugs.debian.org/697641 , some Hungarian keys does not work with qemu when using vnc display. This is because while the Hungarian keymap mentions these symbols, qemu know nothing about them. So add them. This patch is applicable to -stable for all previous releases. Signed-off-by: Michael Tokarev Signed-off-by: Anthony Liguori --- ui/vnc_keysym.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h index df33cfe53c..6250bec692 100644 --- a/ui/vnc_keysym.h +++ b/ui/vnc_keysym.h @@ -215,10 +215,14 @@ static const name2keysym_t name2keysym[]={ { "Zabovedot", 0x1af}, { "zacute", 0x1bc}, { "Zacute", 0x1ac}, +{ "Odoubleacute", 0x1d5}, +{ "Udoubleacute", 0x1db}, { "cacute", 0x1e6}, { "Cacute", 0x1c6}, { "nacute", 0x1f1}, { "Nacute", 0x1d1}, +{ "odoubleacute", 0x1f5}, +{ "udoubleacute", 0x1fb}, /* modifiers */ {"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */ From f38f7a847e316def8606d25441878d723de84b65 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 5 Feb 2013 13:12:43 +0100 Subject: [PATCH 0935/1634] target-m68k: Fix comment * spelling fix ito -> into * reorder to match load/store Signed-off-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- target-m68k/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index e763195f86..3f1478cc20 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -574,7 +574,7 @@ static inline TCGv gen_ea_once(CPUM68KState *env, DisasContext *s, return gen_ldst(s, opsize, tmp, val, what); } -/* Generate code to load/store a value ito/from an EA. If VAL > 0 this is +/* Generate code to load/store a value from/into an EA. If VAL > 0 this is a write otherwise it is a read (0 == sign extend, -1 == zero extend). ADDRP is non-null for readwrite operands. */ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, From 2a0e1ad66e4177dddc6c8fb7aeadc095aafac828 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Mon, 4 Feb 2013 00:36:25 +0400 Subject: [PATCH 0936/1634] vnc: recognize Hungarian doubleacutes As reported in http://bugs.debian.org/697641 , some Hungarian keys does not work with qemu when using vnc display. This is because while the Hungarian keymap mentions these symbols, qemu know nothing about them. So add them. This patch is applicable to -stable for all previous releases. Signed-off-by: Michael Tokarev Reviewed-by: Laszlo Ersek Signed-off-by: Stefan Hajnoczi --- ui/vnc_keysym.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/vnc_keysym.h b/ui/vnc_keysym.h index df33cfe53c..6250bec692 100644 --- a/ui/vnc_keysym.h +++ b/ui/vnc_keysym.h @@ -215,10 +215,14 @@ static const name2keysym_t name2keysym[]={ { "Zabovedot", 0x1af}, { "zacute", 0x1bc}, { "Zacute", 0x1ac}, +{ "Odoubleacute", 0x1d5}, +{ "Udoubleacute", 0x1db}, { "cacute", 0x1e6}, { "Cacute", 0x1c6}, { "nacute", 0x1f1}, { "Nacute", 0x1d1}, +{ "odoubleacute", 0x1f5}, +{ "udoubleacute", 0x1fb}, /* modifiers */ {"ISO_Level3_Shift", 0xfe03}, /* XK_ISO_Level3_Shift */ From 82e59a676c01b3df3b53998d428d0a64a55f2439 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:14 +0100 Subject: [PATCH 0937/1634] qmp: Fix design bug and read beyond buffer in memchar-write Command memchar-write takes data and size parameter. Begs the question what happens when data doesn't match size. With format base64, qmp_memchar_write() copies the full data argument, regardless of size argument. With format utf8, qmp_memchar_write() copies size bytes from data, happily reading beyond data. Copies crap from the heap or even crashes. Drop the size parameter, and always copy the full data argument. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- hmp.c | 4 +--- qapi-schema.json | 4 +--- qemu-char.c | 8 +++----- qmp-commands.hx | 4 +--- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/hmp.c b/hmp.c index 1689e6f1fd..9fdf1ce516 100644 --- a/hmp.c +++ b/hmp.c @@ -664,13 +664,11 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict) void hmp_memchar_write(Monitor *mon, const QDict *qdict) { - uint32_t size; const char *chardev = qdict_get_str(qdict, "device"); const char *data = qdict_get_str(qdict, "data"); Error *errp = NULL; - size = strlen(data); - qmp_memchar_write(chardev, size, data, false, 0, &errp); + qmp_memchar_write(chardev, data, false, 0, &errp); hmp_handle_error(mon, &errp); } diff --git a/qapi-schema.json b/qapi-schema.json index cdd8384915..9e2cbbd1ae 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -346,8 +346,6 @@ # # @device: the name of the memory char device. # -# @size: the size to write in bytes. -# # @data: the source data write to memchar. # # @format: #optional the format of the data write to chardev 'memory', @@ -359,7 +357,7 @@ # Since: 1.4 ## { 'command': 'memchar-write', - 'data': {'device': 'str', 'size': 'int', 'data': 'str', + 'data': {'device': 'str', 'data': 'str', '*format': 'DataFormat'} } ## diff --git a/qemu-char.c b/qemu-char.c index ac5d62dd9a..9c1dd1326d 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2753,9 +2753,8 @@ static bool qemu_is_chr(const CharDriverState *chr, const char *filename) return strcmp(chr->filename, filename); } -void qmp_memchar_write(const char *device, int64_t size, - const char *data, bool has_format, - enum DataFormat format, +void qmp_memchar_write(const char *device, const char *data, + bool has_format, enum DataFormat format, Error **errp) { CharDriverState *chr; @@ -2774,12 +2773,11 @@ void qmp_memchar_write(const char *device, int64_t size, return; } - write_count = (gsize)size; - if (has_format && (format == DATA_FORMAT_BASE64)) { write_data = g_base64_decode(data, &write_count); } else { write_data = (uint8_t *)data; + write_count = strlen(data); } ret = cirmem_chr_write(chr, write_data, write_count); diff --git a/qmp-commands.hx b/qmp-commands.hx index bbb21f3583..8468f1022d 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -467,7 +467,7 @@ EQMP { .name = "memchar-write", - .args_type = "device:s,size:i,data:s,format:s?", + .args_type = "device:s,data:s,format:s?", .mhandler.cmd_new = qmp_marshal_input_memchar_write, }, @@ -481,7 +481,6 @@ char device. Arguments: - "device": the name of the char device, must be unique (json-string) -- "size": the memory size, in bytes, should be power of 2 (json-int) - "data": the source data write to memory (json-string) - "format": the data format write to memory, default is utf8. (json-string, optional) @@ -491,7 +490,6 @@ Example: -> { "execute": "memchar-write", "arguments": { "device": foo, - "size": 8, "data": "abcdefgh", "format": "utf8" } } <- { "return": {} } From 3ab651fc819178cf6a518af5860cc49f42cff455 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:15 +0100 Subject: [PATCH 0938/1634] qmp: Clean up design of memchar-read The data returned has a well-defined size, which makes the size returned along with it redundant at best. Drop it. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- hmp.c | 11 ++++------- qapi-schema.json | 18 ++---------------- qemu-char.c | 21 +++++++++------------ qmp-commands.hx | 2 +- 4 files changed, 16 insertions(+), 36 deletions(-) diff --git a/hmp.c b/hmp.c index 9fdf1ce516..f6bb7675ba 100644 --- a/hmp.c +++ b/hmp.c @@ -677,21 +677,18 @@ void hmp_memchar_read(Monitor *mon, const QDict *qdict) { uint32_t size = qdict_get_int(qdict, "size"); const char *chardev = qdict_get_str(qdict, "device"); - MemCharRead *meminfo; + char *data; Error *errp = NULL; - meminfo = qmp_memchar_read(chardev, size, false, 0, &errp); + data = qmp_memchar_read(chardev, size, false, 0, &errp); if (errp) { monitor_printf(mon, "%s\n", error_get_pretty(errp)); error_free(errp); return; } - if (meminfo->count > 0) { - monitor_printf(mon, "%s\n", meminfo->data); - } - - qapi_free_MemCharRead(meminfo); + monitor_printf(mon, "%s\n", data); + g_free(data); } static void hmp_cont_cb(void *opaque, int err) diff --git a/qapi-schema.json b/qapi-schema.json index 9e2cbbd1ae..d8fa1c376a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -360,20 +360,6 @@ 'data': {'device': 'str', 'data': 'str', '*format': 'DataFormat'} } -## -# @MemCharRead -# -# Result of QMP command memchar-read. -# -# @data: The data read from memchar as string. -# -# @count: The numbers of bytes read from. -# -# Since: 1.4 -## -{ 'type': 'MemCharRead', - 'data': { 'data': 'str', 'count': 'int' } } - ## # @memchar-read: # @@ -387,14 +373,14 @@ # @format: #optional the format of the data want to read from # memchardev, by default is 'utf8'. # -# Returns: @MemCharRead +# Returns: data read from the device # If @device is not a valid memchr device, DeviceNotFound # # Since: 1.4 ## { 'command': 'memchar-read', 'data': {'device': 'str', 'size': 'int', '*format': 'DataFormat'}, - 'returns': 'MemCharRead' } + 'returns': 'str' } ## # @CommandInfo: diff --git a/qemu-char.c b/qemu-char.c index 9c1dd1326d..b593c50f20 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2788,14 +2788,14 @@ void qmp_memchar_write(const char *device, const char *data, } } -MemCharRead *qmp_memchar_read(const char *device, int64_t size, - bool has_format, enum DataFormat format, - Error **errp) +char *qmp_memchar_read(const char *device, int64_t size, + bool has_format, enum DataFormat format, + Error **errp) { CharDriverState *chr; guchar *read_data; - MemCharRead *meminfo; size_t count; + char *data; chr = qemu_chr_find(device); if (!chr) { @@ -2813,26 +2813,23 @@ MemCharRead *qmp_memchar_read(const char *device, int64_t size, return NULL; } - meminfo = g_malloc0(sizeof(MemCharRead)); - count = qemu_chr_cirmem_count(chr); if (count == 0) { - meminfo->data = g_strdup(""); - return meminfo; + return g_strdup(""); } size = size > count ? count : size; read_data = g_malloc0(size + 1); - meminfo->count = cirmem_chr_read(chr, read_data, size); + cirmem_chr_read(chr, read_data, size); if (has_format && (format == DATA_FORMAT_BASE64)) { - meminfo->data = g_base64_encode(read_data, (size_t)meminfo->count); + data = g_base64_encode(read_data, size); } else { - meminfo->data = (char *)read_data; + data = (char *)read_data; } - return meminfo; + return data; } QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) diff --git a/qmp-commands.hx b/qmp-commands.hx index 8468f1022d..51ce2e6b41 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -525,7 +525,7 @@ Example: "arguments": { "device": foo, "size": 1000, "format": "utf8" } } -<- { "return": { "data": "data string...", "count": 1000 } } +<- {"return": "abcdefgh"} EQMP From 1a69278e53a0e5060c8c6cc825449a122634ce3b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:16 +0100 Subject: [PATCH 0939/1634] qmp: Use generic errors in memchar-read, memchar-write New errors should be generic unless there's a real use case for rich errors. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qapi-schema.json | 2 -- qemu-char.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index d8fa1c376a..6f6379151f 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -352,7 +352,6 @@ # by default is 'utf8'. # # Returns: Nothing on success -# If @device is not a valid char device, DeviceNotFound # # Since: 1.4 ## @@ -374,7 +373,6 @@ # memchardev, by default is 'utf8'. # # Returns: data read from the device -# If @device is not a valid memchr device, DeviceNotFound # # Since: 1.4 ## diff --git a/qemu-char.c b/qemu-char.c index b593c50f20..2bdd1bb18a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2764,7 +2764,7 @@ void qmp_memchar_write(const char *device, const char *data, chr = qemu_chr_find(device); if (!chr) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_setg(errp, "Device '%s' not found", device); return; } @@ -2799,7 +2799,7 @@ char *qmp_memchar_read(const char *device, int64_t size, chr = qemu_chr_find(device); if (!chr) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); + error_setg(errp, "Device '%s' not found", device); return NULL; } From c4f331b6b3b5fe260128f316ee9f01997f7c428d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:17 +0100 Subject: [PATCH 0940/1634] qmp: Clean up type usage in qmp_memchar_write(), qmp_memchar_read() Const-correctness, consistently use standard C types instead of mixing them with GLib types. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 2bdd1bb18a..b1c613257b 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2758,9 +2758,9 @@ void qmp_memchar_write(const char *device, const char *data, Error **errp) { CharDriverState *chr; - guchar *write_data; + const uint8_t *write_data; int ret; - gsize write_count; + size_t write_count; chr = qemu_chr_find(device); if (!chr) { @@ -2793,7 +2793,7 @@ char *qmp_memchar_read(const char *device, int64_t size, Error **errp) { CharDriverState *chr; - guchar *read_data; + uint8_t *read_data; size_t count; char *data; From 13289fb5a716e06fb06febb880e5e116d485f82b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:18 +0100 Subject: [PATCH 0941/1634] qmp: Plug memory leaks in memchar-write, memchar-read Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index b1c613257b..4dd01e645a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2782,6 +2782,10 @@ void qmp_memchar_write(const char *device, const char *data, ret = cirmem_chr_write(chr, write_data, write_count); + if (write_data != (uint8_t *)data) { + g_free((void *)write_data); + } + if (ret < 0) { error_setg(errp, "Failed to write to device %s", device); return; @@ -2825,6 +2829,7 @@ char *qmp_memchar_read(const char *device, int64_t size, if (has_format && (format == DATA_FORMAT_BASE64)) { data = g_base64_encode(read_data, size); + g_free(read_data); } else { data = (char *)read_data; } From c287e99fe47b179e6ef6b212139821b4d78934c1 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:19 +0100 Subject: [PATCH 0942/1634] qmp: Drop superfluous special case "empty" in qmp_memchar_read() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 4dd01e645a..9d1c02cd1d 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2818,10 +2818,6 @@ char *qmp_memchar_read(const char *device, int64_t size, } count = qemu_chr_cirmem_count(chr); - if (count == 0) { - return g_strdup(""); - } - size = size > count ? count : size; read_data = g_malloc0(size + 1); From 44f3bcd2c7991cc9d096e51e38864135543ea1ce Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:20 +0100 Subject: [PATCH 0943/1634] qmp: Drop wasteful zero-initialization in qmp_memchar_read() Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index 9d1c02cd1d..b0e4b41bcc 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2819,7 +2819,7 @@ char *qmp_memchar_read(const char *device, int64_t size, count = qemu_chr_cirmem_count(chr); size = size > count ? count : size; - read_data = g_malloc0(size + 1); + read_data = g_malloc(size + 1); cirmem_chr_read(chr, read_data, size); @@ -2827,6 +2827,7 @@ char *qmp_memchar_read(const char *device, int64_t size, data = g_base64_encode(read_data, size); g_free(read_data); } else { + read_data[size] = 0; data = (char *)read_data; } From 094c8c2c67c486bcbc03c5e6327edc6ad3e5e29a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:21 +0100 Subject: [PATCH 0944/1634] qemu-char: Fix chardev "memory" not to drop IAC characters Undocumented misfeature, get rid of it while we can. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index b0e4b41bcc..2f59a61429 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2678,11 +2678,6 @@ static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) } for (i = 0; i < len; i++ ) { - /* Avoid writing the IAC information to the queue. */ - if ((unsigned char)buf[i] == IAC) { - continue; - } - d->cbuf[d->prod++ % d->size] = buf[i]; if ((d->prod - d->cons) > d->size) { d->cons = d->prod - d->size; From 6fd5b66950fc5551d371ba5017d0e0858b7c800b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:22 +0100 Subject: [PATCH 0945/1634] qemu-char: Drop undocumented chardev "memory" compatibility syntax This is a new device, so there's no compatibility to maintain, and its use case isn't common enough to justify shorthand syntax. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 2f59a61429..cdbbafe4f1 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2883,11 +2883,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) qemu_opt_set(opts, "path", filename); return opts; } - if (strstart(filename, "memory", &p)) { - qemu_opt_set(opts, "backend", "memory"); - qemu_opt_set(opts, "maxcapacity", p); - return opts; - } if (strstart(filename, "file:", &p)) { qemu_opt_set(opts, "backend", "file"); qemu_opt_set(opts, "path", p); From 5c230105cdea8ac9338bd5b4485c6ae80ec1fa18 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:23 +0100 Subject: [PATCH 0946/1634] qemu-char: General chardev "memory" code cleanup Inline trivial cirmem_chr_is_empty() into its only caller. Rename qemu_chr_cirmem_count() to cirmem_count(). Fast ring buffer index wraparound. Without this, there's no point in restricting size to a power two. qemu_is_chr(chr, "memory") returns *zero* when chr is a memory character device, which isn't what I'd expect. Replace it by the saner and more obviously correct chr_is_cirmem(). Also avoids encouraging testing for specific character devices elsewhere. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index cdbbafe4f1..831d564a8b 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2645,7 +2645,7 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr) } /*********************************************************/ -/*CircularMemory chardev*/ +/* CircularMemory chardev */ typedef struct { size_t size; @@ -2654,18 +2654,11 @@ typedef struct { uint8_t *cbuf; } CirMemCharDriver; -static bool cirmem_chr_is_empty(const CharDriverState *chr) +static size_t cirmem_count(const CharDriverState *chr) { const CirMemCharDriver *d = chr->opaque; - return d->cons == d->prod; -} - -static size_t qemu_chr_cirmem_count(const CharDriverState *chr) -{ - const CirMemCharDriver *d = chr->opaque; - - return (d->prod - d->cons); + return d->prod - d->cons; } static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) @@ -2678,8 +2671,8 @@ static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) } for (i = 0; i < len; i++ ) { - d->cbuf[d->prod++ % d->size] = buf[i]; - if ((d->prod - d->cons) > d->size) { + d->cbuf[d->prod++ & (d->size - 1)] = buf[i]; + if (d->prod - d->cons > d->size) { d->cons = d->prod - d->size; } } @@ -2692,8 +2685,8 @@ static int cirmem_chr_read(CharDriverState *chr, uint8_t *buf, int len) CirMemCharDriver *d = chr->opaque; int i; - for (i = 0; i < len && !cirmem_chr_is_empty(chr); i++) { - buf[i] = d->cbuf[d->cons++ % d->size]; + for (i = 0; i < len && d->cons != d->prod; i++) { + buf[i] = d->cbuf[d->cons++ & (d->size - 1)]; } return i; @@ -2743,9 +2736,9 @@ fail: return NULL; } -static bool qemu_is_chr(const CharDriverState *chr, const char *filename) +static bool chr_is_cirmem(const CharDriverState *chr) { - return strcmp(chr->filename, filename); + return chr->chr_write == cirmem_chr_write; } void qmp_memchar_write(const char *device, const char *data, @@ -2763,7 +2756,7 @@ void qmp_memchar_write(const char *device, const char *data, return; } - if (qemu_is_chr(chr, "memory")) { + if (!chr_is_cirmem(chr)) { error_setg(errp,"%s is not memory char device", device); return; } @@ -2802,7 +2795,7 @@ char *qmp_memchar_read(const char *device, int64_t size, return NULL; } - if (qemu_is_chr(chr, "memory")) { + if (!chr_is_cirmem(chr)) { error_setg(errp,"%s is not memory char device", device); return NULL; } @@ -2812,7 +2805,7 @@ char *qmp_memchar_read(const char *device, int64_t size, return NULL; } - count = qemu_chr_cirmem_count(chr); + count = cirmem_count(chr); size = size > count ? count : size; read_data = g_malloc(size + 1); From 3949e59414fccefadc50ae65650d676cc734048c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:24 +0100 Subject: [PATCH 0947/1634] qemu-char: Saner naming of memchar stuff & doc fixes New device, has never been released, so we can still improve things without worrying about compatibility. Naming is a mess. The code calls the device driver CirMemCharDriver, the public API calls it "memory", "memchardev", or "memchar", and the special commands are named like "memchar-FOO". "memory" is a particularly unfortunate choice, because there's another character device driver called MemoryDriver. Moreover, the device's distinctive property is that it's a ring buffer, not that's in memory. Therefore: * Rename CirMemCharDriver to RingBufCharDriver, and call the thing a "ringbuf" in the API. * Rename QMP and HMP commands from memchar-FOO to ringbuf-FOO. * Rename device parameter from maxcapacity to size (simple words are good for you). * Clearly mark the parameter as optional in documentation. * Fix error reporting so that chardev-add reports to current monitor, not stderr. * Replace cirmem in C identifiers by ringbuf. * Rework documentation. Document the impact of our crappy UTF-8 handling on reading. * QMP examples that even work. I could split this up into multiple commits, but they'd change the same documentation lines multiple times. Not worth it. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- hmp-commands.hx | 37 +++++++++++++-------------- hmp.c | 8 +++--- hmp.h | 4 +-- qapi-schema.json | 47 ++++++++++++++++++++-------------- qemu-char.c | 65 +++++++++++++++++++++++++++--------------------- qemu-options.hx | 13 ++++------ qmp-commands.hx | 55 +++++++++++++++++++++------------------- 7 files changed, 122 insertions(+), 107 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index bdd48f3469..66ec716e03 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -841,40 +841,37 @@ Inject an NMI on the given CPU (x86 only). ETEXI { - .name = "memchar_write", + .name = "ringbuf_write", .args_type = "device:s,data:s", .params = "device data", - .help = "Provide writing interface for CirMemCharDriver. Write" - "'data' to it.", - .mhandler.cmd = hmp_memchar_write, + .help = "Write to a ring buffer character device", + .mhandler.cmd = hmp_ringbuf_write, }, STEXI -@item memchar_write @var{device} @var{data} -@findex memchar_write -Provide writing interface for CirMemCharDriver. Write @var{data} -to char device 'memory'. +@item ringbuf_write @var{device} @var{data} +@findex ringbuf_write +Write @var{data} to ring buffer character device @var{device}. +@var{data} must be a UTF-8 string. ETEXI { - .name = "memchar_read", + .name = "ringbuf_read", .args_type = "device:s,size:i", .params = "device size", - .help = "Provide read interface for CirMemCharDriver. Read from" - "it and return the data with size.", - .mhandler.cmd = hmp_memchar_read, + .help = "Read from a ring buffer character device", + .mhandler.cmd = hmp_ringbuf_read, }, STEXI -@item memchar_read @var{device} -@findex memchar_read -Provide read interface for CirMemCharDriver. Read from char device -'memory' and return the data. - -@var{size} is the size of data want to read from. Refer to unencoded -size of the raw data, would adjust to the init size of the memchar -if the requested size is larger than it. +@item ringbuf_read @var{device} +@findex ringbuf_read +Read and print up to @var{size} bytes from ring buffer character +device @var{device}. +Bug: can screw up when the buffer contains invalid UTF-8 sequences, +NUL characters, after the ring buffer lost data, and when reading +stops because the size limit is reached. ETEXI diff --git a/hmp.c b/hmp.c index f6bb7675ba..cbd572753b 100644 --- a/hmp.c +++ b/hmp.c @@ -662,25 +662,25 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict) hmp_handle_error(mon, &errp); } -void hmp_memchar_write(Monitor *mon, const QDict *qdict) +void hmp_ringbuf_write(Monitor *mon, const QDict *qdict) { const char *chardev = qdict_get_str(qdict, "device"); const char *data = qdict_get_str(qdict, "data"); Error *errp = NULL; - qmp_memchar_write(chardev, data, false, 0, &errp); + qmp_ringbuf_write(chardev, data, false, 0, &errp); hmp_handle_error(mon, &errp); } -void hmp_memchar_read(Monitor *mon, const QDict *qdict) +void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) { uint32_t size = qdict_get_int(qdict, "size"); const char *chardev = qdict_get_str(qdict, "device"); char *data; Error *errp = NULL; - data = qmp_memchar_read(chardev, size, false, 0, &errp); + data = qmp_ringbuf_read(chardev, size, false, 0, &errp); if (errp) { monitor_printf(mon, "%s\n", error_get_pretty(errp)); error_free(errp); diff --git a/hmp.h b/hmp.h index 076d8cf378..30b3c20ca4 100644 --- a/hmp.h +++ b/hmp.h @@ -43,8 +43,8 @@ void hmp_system_powerdown(Monitor *mon, const QDict *qdict); void hmp_cpu(Monitor *mon, const QDict *qdict); void hmp_memsave(Monitor *mon, const QDict *qdict); void hmp_pmemsave(Monitor *mon, const QDict *qdict); -void hmp_memchar_write(Monitor *mon, const QDict *qdict); -void hmp_memchar_read(Monitor *mon, const QDict *qdict); +void hmp_ringbuf_write(Monitor *mon, const QDict *qdict); +void hmp_ringbuf_read(Monitor *mon, const QDict *qdict); void hmp_cont(Monitor *mon, const QDict *qdict); void hmp_system_wakeup(Monitor *mon, const QDict *qdict); void hmp_inject_nmi(Monitor *mon, const QDict *qdict); diff --git a/qapi-schema.json b/qapi-schema.json index 6f6379151f..736f881b75 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -329,9 +329,9 @@ # # An enumeration of data format. # -# @utf8: The data format is 'utf8'. +# @utf8: Data is a UTF-8 string (RFC 3629) # -# @base64: The data format is 'base64'. +# @base64: Data is Base64 encoded binary (RFC 3548) # # Since: 1.4 ## @@ -339,44 +339,55 @@ 'data': [ 'utf8', 'base64' ] } ## -# @memchar-write: +# @ringbuf-write: # -# Provide writing interface for memchardev. Write data to char -# device 'memory'. +# Write to a ring buffer character device. # -# @device: the name of the memory char device. +# @device: the ring buffer character device name # -# @data: the source data write to memchar. +# @data: data to write # -# @format: #optional the format of the data write to chardev 'memory', -# by default is 'utf8'. +# @format: #optional data encoding (default 'utf8'). +# - base64: data must be base64 encoded text. Its binary +# decoding gets written. +# Bug: invalid base64 is currently not rejected. +# Whitespace *is* invalid. +# - utf8: data's UTF-8 encoding is written +# - data itself is always Unicode regardless of format, like +# any other string. # # Returns: Nothing on success # # Since: 1.4 ## -{ 'command': 'memchar-write', +{ 'command': 'ringbuf-write', 'data': {'device': 'str', 'data': 'str', '*format': 'DataFormat'} } ## -# @memchar-read: +# @ringbuf-read: # -# Provide read interface for memchardev. Read from the char -# device 'memory' and return the data. +# Read from a ring buffer character device. # -# @device: the name of the memory char device. +# @device: the ring buffer character device name # -# @size: the size to read in bytes. +# @size: how many bytes to read at most # -# @format: #optional the format of the data want to read from -# memchardev, by default is 'utf8'. +# @format: #optional data encoding (default 'utf8'). +# - base64: the data read is returned in base64 encoding. +# - utf8: the data read is interpreted as UTF-8. +# Bug: can screw up when the buffer contains invalid UTF-8 +# sequences, NUL characters, after the ring buffer lost +# data, and when reading stops because the size limit is +# reached. +# - The return value is always Unicode regardless of format, +# like any other string. # # Returns: data read from the device # # Since: 1.4 ## -{ 'command': 'memchar-read', +{ 'command': 'ringbuf-read', 'data': {'device': 'str', 'size': 'int', '*format': 'DataFormat'}, 'returns': 'str' } diff --git a/qemu-char.c b/qemu-char.c index 831d564a8b..8a3540389a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2645,25 +2645,25 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr) } /*********************************************************/ -/* CircularMemory chardev */ +/* Ring buffer chardev */ typedef struct { size_t size; size_t prod; size_t cons; uint8_t *cbuf; -} CirMemCharDriver; +} RingBufCharDriver; -static size_t cirmem_count(const CharDriverState *chr) +static size_t ringbuf_count(const CharDriverState *chr) { - const CirMemCharDriver *d = chr->opaque; + const RingBufCharDriver *d = chr->opaque; return d->prod - d->cons; } -static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +static int ringbuf_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { - CirMemCharDriver *d = chr->opaque; + RingBufCharDriver *d = chr->opaque; int i; if (!buf || (len < 0)) { @@ -2680,9 +2680,9 @@ static int cirmem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) return 0; } -static int cirmem_chr_read(CharDriverState *chr, uint8_t *buf, int len) +static int ringbuf_chr_read(CharDriverState *chr, uint8_t *buf, int len) { - CirMemCharDriver *d = chr->opaque; + RingBufCharDriver *d = chr->opaque; int i; for (i = 0; i < len && d->cons != d->prod; i++) { @@ -2692,31 +2692,31 @@ static int cirmem_chr_read(CharDriverState *chr, uint8_t *buf, int len) return i; } -static void cirmem_chr_close(struct CharDriverState *chr) +static void ringbuf_chr_close(struct CharDriverState *chr) { - CirMemCharDriver *d = chr->opaque; + RingBufCharDriver *d = chr->opaque; g_free(d->cbuf); g_free(d); chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_cirmemchr(QemuOpts *opts) +static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts) { CharDriverState *chr; - CirMemCharDriver *d; + RingBufCharDriver *d; chr = g_malloc0(sizeof(CharDriverState)); d = g_malloc(sizeof(*d)); - d->size = qemu_opt_get_number(opts, "maxcapacity", 0); + d->size = qemu_opt_get_number(opts, "size", 0); if (d->size == 0) { d->size = CBUFF_SIZE; } /* The size must be power of 2 */ if (d->size & (d->size - 1)) { - fprintf(stderr, "chardev: size of memory device must be power of 2\n"); + error_report("size of ringbuf device must be power of two"); goto fail; } @@ -2725,8 +2725,8 @@ static CharDriverState *qemu_chr_open_cirmemchr(QemuOpts *opts) d->cbuf = g_malloc0(d->size); chr->opaque = d; - chr->chr_write = cirmem_chr_write; - chr->chr_close = cirmem_chr_close; + chr->chr_write = ringbuf_chr_write; + chr->chr_close = ringbuf_chr_close; return chr; @@ -2736,12 +2736,12 @@ fail: return NULL; } -static bool chr_is_cirmem(const CharDriverState *chr) +static bool chr_is_ringbuf(const CharDriverState *chr) { - return chr->chr_write == cirmem_chr_write; + return chr->chr_write == ringbuf_chr_write; } -void qmp_memchar_write(const char *device, const char *data, +void qmp_ringbuf_write(const char *device, const char *data, bool has_format, enum DataFormat format, Error **errp) { @@ -2756,8 +2756,8 @@ void qmp_memchar_write(const char *device, const char *data, return; } - if (!chr_is_cirmem(chr)) { - error_setg(errp,"%s is not memory char device", device); + if (!chr_is_ringbuf(chr)) { + error_setg(errp,"%s is not a ringbuf device", device); return; } @@ -2768,7 +2768,7 @@ void qmp_memchar_write(const char *device, const char *data, write_count = strlen(data); } - ret = cirmem_chr_write(chr, write_data, write_count); + ret = ringbuf_chr_write(chr, write_data, write_count); if (write_data != (uint8_t *)data) { g_free((void *)write_data); @@ -2780,7 +2780,7 @@ void qmp_memchar_write(const char *device, const char *data, } } -char *qmp_memchar_read(const char *device, int64_t size, +char *qmp_ringbuf_read(const char *device, int64_t size, bool has_format, enum DataFormat format, Error **errp) { @@ -2795,8 +2795,8 @@ char *qmp_memchar_read(const char *device, int64_t size, return NULL; } - if (!chr_is_cirmem(chr)) { - error_setg(errp,"%s is not memory char device", device); + if (!chr_is_ringbuf(chr)) { + error_setg(errp,"%s is not a ringbuf device", device); return NULL; } @@ -2805,16 +2805,23 @@ char *qmp_memchar_read(const char *device, int64_t size, return NULL; } - count = cirmem_count(chr); + count = ringbuf_count(chr); size = size > count ? count : size; read_data = g_malloc(size + 1); - cirmem_chr_read(chr, read_data, size); + ringbuf_chr_read(chr, read_data, size); if (has_format && (format == DATA_FORMAT_BASE64)) { data = g_base64_encode(read_data, size); g_free(read_data); } else { + /* + * FIXME should read only complete, valid UTF-8 characters up + * to @size bytes. Invalid sequences should be replaced by a + * suitable replacement character. Except when (and only + * when) ring buffer lost characters since last read, initial + * continuation characters should be dropped. + */ read_data[size] = 0; data = (char *)read_data; } @@ -2975,7 +2982,7 @@ static const struct { { .name = "udp", .open = qemu_chr_open_udp }, { .name = "msmouse", .open = qemu_chr_open_msmouse }, { .name = "vc", .open = text_console_init }, - { .name = "memory", .open = qemu_chr_open_cirmemchr }, + { .name = "memory", .open = qemu_chr_open_ringbuf }, #ifdef _WIN32 { .name = "file", .open = qemu_chr_open_win_file_out }, { .name = "pipe", .open = qemu_chr_open_win_pipe }, @@ -3236,7 +3243,7 @@ QemuOptsList qemu_chardev_opts = { .name = "debug", .type = QEMU_OPT_NUMBER, },{ - .name = "maxcapacity", + .name = "size", .type = QEMU_OPT_NUMBER, }, { /* end of list */ } diff --git a/qemu-options.hx b/qemu-options.hx index 2d44137bf9..046bdc0f63 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1736,7 +1736,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev msmouse,id=id[,mux=on|off]\n" "-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]\n" " [,mux=on|off]\n" - "-chardev memory,id=id,maxcapacity=maxcapacity\n" + "-chardev ringbuf,id=id[,size=size]\n" "-chardev file,id=id,path=path[,mux=on|off]\n" "-chardev pipe,id=id,path=path[,mux=on|off]\n" #ifdef _WIN32 @@ -1778,7 +1778,7 @@ Backend is one of: @option{udp}, @option{msmouse}, @option{vc}, -@option{memory}, +@option{ringbuf}, @option{file}, @option{pipe}, @option{console}, @@ -1887,13 +1887,10 @@ the console, in pixels. @option{cols} and @option{rows} specify that the console be sized to fit a text console with the given dimensions. -@item -chardev memory ,id=@var{id} ,maxcapacity=@var{maxcapacity} +@item -chardev ringbuf ,id=@var{id} [,size=@var{size}] -Create a circular buffer with fixed size indicated by optionally @option{maxcapacity} -which will be default 64K if it is not given. - -@option{maxcapacity} specifies the max capacity of the size of circular buffer -to create. Should be power of 2. +Create a ring buffer with fixed size @option{size}. +@var{size} must be a power of two, and defaults to @code{64K}). @item -chardev file ,id=@var{id} ,path=@var{path} diff --git a/qmp-commands.hx b/qmp-commands.hx index 51ce2e6b41..799adea1b7 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -466,30 +466,30 @@ Note: inject-nmi fails when the guest doesn't support injecting. EQMP { - .name = "memchar-write", + .name = "ringbuf-write", .args_type = "device:s,data:s,format:s?", - .mhandler.cmd_new = qmp_marshal_input_memchar_write, + .mhandler.cmd_new = qmp_marshal_input_ringbuf_write, }, SQMP -memchar-write +ringbuf-write ------------- -Provide writing interface for CirMemCharDriver. Write data to memory -char device. +Write to a ring buffer character device. Arguments: -- "device": the name of the char device, must be unique (json-string) -- "data": the source data write to memory (json-string) -- "format": the data format write to memory, default is - utf8. (json-string, optional) - - Possible values: "utf8", "base64" +- "device": ring buffer character device name (json-string) +- "data": data to write (json-string) +- "format": data format (json-string, optional) + - Possible values: "utf8" (default), "base64" + Bug: invalid base64 is currently not rejected. + Whitespace *is* invalid. Example: --> { "execute": "memchar-write", - "arguments": { "device": foo, +-> { "execute": "ringbuf-write", + "arguments": { "device": "foo", "data": "abcdefgh", "format": "utf8" } } <- { "return": {} } @@ -497,32 +497,35 @@ Example: EQMP { - .name = "memchar-read", + .name = "ringbuf-read", .args_type = "device:s,size:i,format:s?", - .mhandler.cmd_new = qmp_marshal_input_memchar_read, + .mhandler.cmd_new = qmp_marshal_input_ringbuf_read, }, SQMP -memchar-read +ringbuf-read ------------- -Provide read interface for CirMemCharDriver. Read from the char -device memory and return the data with size. +Read from a ring buffer character device. Arguments: -- "device": the name of the char device, must be unique (json-string) -- "size": the memory size wanted to read in bytes (refer to unencoded - size of the raw data), would adjust to the init size of the - memchar if the requested size is larger than it. (json-int) -- "format": the data format write to memchardev, default is - utf8. (json-string, optional) - - Possible values: "utf8", "base64" +- "device": ring buffer character device name (json-string) +- "size": how many bytes to read at most (json-int) + - Number of data bytes, not number of characters in encoded data +- "format": data format (json-string, optional) + - Possible values: "utf8" (default), "base64" + - Naturally, format "utf8" works only when the ring buffer + contains valid UTF-8 text. Invalid UTF-8 sequences get + replaced. Bug: replacement doesn't work. Bug: can screw + up on encountering NUL characters, after the ring buffer + lost data, and when reading stops because the size limit + is reached. Example: --> { "execute": "memchar-read", - "arguments": { "device": foo, +-> { "execute": "ringbuf-read", + "arguments": { "device": "foo", "size": 1000, "format": "utf8" } } <- {"return": "abcdefgh"} From de1cc36e1039faf65b1739d28bef9f2a4e230eb6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:25 +0100 Subject: [PATCH 0948/1634] qemu-char: Support suffixed ringbuf size arguments like "size=64K" Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- qemu-char.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 8a3540389a..a3ba02127f 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -98,7 +98,6 @@ #include "ui/qemu-spice.h" #define READ_BUF_LEN 4096 -#define CBUFF_SIZE 65536 /***********************************************************/ /* character device */ @@ -2709,9 +2708,9 @@ static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts) chr = g_malloc0(sizeof(CharDriverState)); d = g_malloc(sizeof(*d)); - d->size = qemu_opt_get_number(opts, "size", 0); + d->size = qemu_opt_get_size(opts, "size", 0); if (d->size == 0) { - d->size = CBUFF_SIZE; + d->size = 65536; } /* The size must be power of 2 */ @@ -3244,7 +3243,7 @@ QemuOptsList qemu_chardev_opts = { .type = QEMU_OPT_NUMBER, },{ .name = "size", - .type = QEMU_OPT_NUMBER, + .type = QEMU_OPT_SIZE, }, { /* end of list */ } }, From 543f34126b7bfc85b05d0e371e3ce0695444f433 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 21:27:26 +0100 Subject: [PATCH 0949/1634] hmp: make memchar-read escape ASCII control chars except \n and \t Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Anthony Liguori --- hmp-commands.hx | 2 ++ hmp.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 66ec716e03..4c100d7369 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -869,6 +869,8 @@ STEXI @findex ringbuf_read Read and print up to @var{size} bytes from ring buffer character device @var{device}. +Certain non-printable characters are printed \uXXXX, where XXXX is the +character code in hexadecimal. Character \ is printed \\. Bug: can screw up when the buffer contains invalid UTF-8 sequences, NUL characters, after the ring buffer lost data, and when reading stops because the size limit is reached. diff --git a/hmp.c b/hmp.c index cbd572753b..420d48bea6 100644 --- a/hmp.c +++ b/hmp.c @@ -679,6 +679,7 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) const char *chardev = qdict_get_str(qdict, "device"); char *data; Error *errp = NULL; + int i; data = qmp_ringbuf_read(chardev, size, false, 0, &errp); if (errp) { @@ -687,7 +688,19 @@ void hmp_ringbuf_read(Monitor *mon, const QDict *qdict) return; } - monitor_printf(mon, "%s\n", data); + for (i = 0; data[i]; i++) { + unsigned char ch = data[i]; + + if (ch == '\\') { + monitor_printf(mon, "\\\\"); + } else if ((ch < 0x20 && ch != '\n' && ch != '\t') || ch == 0x7F) { + monitor_printf(mon, "\\u%04X", ch); + } else { + monitor_printf(mon, "%c", ch); + } + + } + monitor_printf(mon, "\n"); g_free(data); } From 8a14952c9d2f5fa2b3caa6dc286b62ed5d26bca7 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 6 Feb 2013 17:07:46 +0100 Subject: [PATCH 0950/1634] hmp: Disable chardev-add and chardev-remove As a general rule, HMP commands must be built on top of the QMP API. Luiz and others have worked long & hard to make HMP conform to this rule. Commit f1088908 added chardev-add, in violation of this rule. QMP command chardev-add was added right before, with minimal features, and the idea to complete it step by step, then switch over the HMP command to use it. Unfortunately, we're not there, yet, and we don't want to release with chardev-add in a "HMP is more powerful than QMP" state. Disable the HMP command for now, along with its chardev-remove buddy. Signed-off-by: Markus Armbruster Signed-off-by: Anthony Liguori --- hmp-commands.hx | 63 +++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 4c100d7369..64008a92d1 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1522,37 +1522,38 @@ passed since 1970, i.e. unix epoch. @end table ETEXI - { - .name = "chardev-add", - .args_type = "args:s", - .params = "args", - .help = "add chardev", - .mhandler.cmd = hmp_chardev_add, - }, - -STEXI -@item chardev_add args -@findex chardev_add - -chardev_add accepts the same parameters as the -chardev command line switch. - -ETEXI - - { - .name = "chardev-remove", - .args_type = "id:s", - .params = "id", - .help = "remove chardev", - .mhandler.cmd = hmp_chardev_remove, - }, - -STEXI -@item chardev_remove id -@findex chardev_remove - -Removes the chardev @var{id}. - -ETEXI +HXCOMM Disabled for now, because it isn't built on top of QMP's chardev-add +HXCOMM { +HXCOMM .name = "chardev-add", +HXCOMM .args_type = "args:s", +HXCOMM .params = "args", +HXCOMM .help = "add chardev", +HXCOMM .mhandler.cmd = hmp_chardev_add, +HXCOMM }, +HXCOMM +HXCOMM STEXI +HXCOMM @item chardev_add args +HXCOMM @findex chardev_add +HXCOMM +HXCOMM chardev_add accepts the same parameters as the -chardev command line switch. +HXCOMM +HXCOMM ETEXI +HXCOMM +HXCOMM { +HXCOMM .name = "chardev-remove", +HXCOMM .args_type = "id:s", +HXCOMM .params = "id", +HXCOMM .help = "remove chardev", +HXCOMM .mhandler.cmd = hmp_chardev_remove, +HXCOMM }, +HXCOMM +HXCOMM STEXI +HXCOMM @item chardev_remove id +HXCOMM @findex chardev_remove +HXCOMM +HXCOMM Removes the chardev @var{id}. +HXCOMM +HXCOMM ETEXI { .name = "info", From f565235b71b7be66f3f6b385a5377969f5ed26f7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 2 Feb 2013 15:13:02 +0000 Subject: [PATCH 0951/1634] hw/pxa2xx: Fix transposed crn/crm values for pxa2xx cp14 perf regs When the pxa2xx performance counter related cp14 registers were converted from a switch-statement implementation to the new table driven cpregs format in commit dc2a9045c, the crn and crm values for all these registers were accidentally transposed. Fix this mistake, which was causing OpenBSD for Zaurus to fail to boot. Reported-by: Jonathan Gray Signed-off-by: Peter Maydell Signed-off-by: Anthony Liguori --- hw/pxa2xx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 373d0616ba..d303320d42 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -343,23 +343,23 @@ static int pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri, } static const ARMCPRegInfo pxa_cp_reginfo[] = { - /* cp14 crn==1: perf registers */ - { .name = "CPPMNC", .cp = 14, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 0, + /* cp14 crm==1: perf registers */ + { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write }, { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore }, - { .name = "CPINTEN", .cp = 14, .crn = 1, .crm = 4, .opc1 = 0, .opc2 = 0, + { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPFLAG", .cp = 14, .crn = 1, .crm = 5, .opc1 = 0, .opc2 = 0, + { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPEVTSEL", .cp = 14, .crn = 1, .crm = 8, .opc1 = 0, .opc2 = 0, + { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - /* cp14 crn==2: performance count registers */ - { .name = "CPPMN0", .cp = 14, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0, + /* cp14 crm==2: performance count registers */ + { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "CPPMN1", .cp = 14, .crn = 2, .crm = 1, .opc1 = 0, .opc2 = 0, + { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, From 0bc8ce9460c1f51211e797a825432e55327b70c6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 31 Jan 2013 12:50:40 +0000 Subject: [PATCH 0952/1634] linux-user: Restore cast to target type in get_user() Commit 658f2dc97 accidentally dropped the cast to the target type of the value loaded by get_user(). The most visible effect of this would be that the sequence "uint64_t v; get_user_u32(v, addr)" would sign extend the 32 bit loaded value into v rather than zero extending as would be expected for a _u32 accessor. Put the cast back again to restore the old behaviour. Signed-off-by: Peter Maydell Signed-off-by: Anthony Liguori --- linux-user/qemu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 31a220af81..b10e9572a9 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -306,12 +306,12 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) ((hptr), (x)), 0) #define __get_user_e(x, hptr, e) \ - ((x) = \ + ((x) = (typeof(*hptr))( \ __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p, \ __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p, \ __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p, \ __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort)))) \ - (hptr), 0) + (hptr)), 0) #ifdef TARGET_WORDS_BIGENDIAN # define __put_user(x, hptr) __put_user_e(x, hptr, be) From ecd8d4715ea33aa2c146a5047bacb031e86af599 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 6 Feb 2013 18:33:47 -0600 Subject: [PATCH 0953/1634] Update version for release Signed-off-by: Anthony Liguori --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 619d9ea8c8..aa6058d68a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.90 +1.3.91 From 0184543814354d37eab75132712c3874d71dd776 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Feb 2013 20:44:23 +0000 Subject: [PATCH 0954/1634] tests/test-string-input-visitor: Handle errors provoked by fuzz test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's OK and expected for visitors to return errors when presented with the fuzz test's random data. Since the fuzzer doesn't care about errors, we pass in NULL rather than an Error**. This fixes a bug in the fuzzer where it was passing the same Error** into each visitor, with the effect that once one visitor returned an error, each later visitor would notice that it had been passed in an Error** representing an already set error, and do nothing. For the case of visit_type_str() we also need to handle the case where an error means that the visitor doesn't set our char*. We initialize the pointer to NULL so we can safely g_free() it regardless of whether the visitor allocated a string for us or not. This fixes a problem where this test failed the MacOSX malloc() consistency checks and might segfault on other platforms [due to calling free() on an uninitialized pointer variable when visit_type_str() failed.]. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Luiz Capitulino --- tests/test-string-input-visitor.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c index f6b0093554..5989f8118e 100644 --- a/tests/test-string-input-visitor.c +++ b/tests/test-string-input-visitor.c @@ -174,7 +174,6 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, double nres; char *sres; EnumOne eres; - Error *errp = NULL; Visitor *v; unsigned int i; char buf[10000]; @@ -193,21 +192,22 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, } v = visitor_input_test_init(data, buf); - visit_type_int(v, &ires, NULL, &errp); + visit_type_int(v, &ires, NULL, NULL); v = visitor_input_test_init(data, buf); - visit_type_bool(v, &bres, NULL, &errp); + visit_type_bool(v, &bres, NULL, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); - visit_type_number(v, &nres, NULL, &errp); + visit_type_number(v, &nres, NULL, NULL); v = visitor_input_test_init(data, buf); - visit_type_str(v, &sres, NULL, &errp); + sres = NULL; + visit_type_str(v, &sres, NULL, NULL); g_free(sres); v = visitor_input_test_init(data, buf); - visit_type_EnumOne(v, &eres, NULL, &errp); + visit_type_EnumOne(v, &eres, NULL, NULL); visitor_input_teardown(data, NULL); } } From b890492110ccdc943554231d40b67d29fef6af82 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Wed, 6 Feb 2013 18:25:48 -0600 Subject: [PATCH 0955/1634] net: fix infinite loop on exit 1ceef9f27359cbe92ef124bf74de6f792e71f6fb added handling for cleaning up multiple queues in qemu_del_nic() for cases where multiqueue is in use. To determine the number of queues it looks at nic->conf->queues, then iterates through all the queues to cleanup the associated NetClientStates. If no queues are found, no NetClientStates are deleted. However, nic->conf->queues is only set when a peer is created via -netdev or netdev_add, and is otherwise 0. This causes us to spin in net_cleanup() if we attempt to shut down qemu before adding a host device. Since qemu_new_nic() unconditionally creates at least 1 queue/NetClientState at queue idx 0, make qemu_del_nic() always attempt to clean it up. Signed-off-by: Michael Roth Signed-off-by: Anthony Liguori --- net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/net.c b/net/net.c index 98068625d4..f9e7136a2b 100644 --- a/net/net.c +++ b/net/net.c @@ -351,7 +351,7 @@ void qemu_del_net_client(NetClientState *nc) void qemu_del_nic(NICState *nic) { - int i, queues = nic->conf->queues; + int i, queues = MAX(nic->conf->queues, 1); /* If this is a peer NIC and peer has already been deleted, free it now. */ if (nic->peer_deleted) { From 1e89ad5b00ba0426d4e949c9e6ce2926c15b81b7 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Feb 2013 17:47:15 -0600 Subject: [PATCH 0956/1634] virtio-net: pass host features to virtio_net_init Signed-off-by: Anthony Liguori --- hw/s390x/s390-virtio-bus.c | 3 ++- hw/s390x/virtio-ccw.c | 3 ++- hw/virtio-net.c | 3 ++- hw/virtio-pci.c | 3 ++- hw/virtio.h | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index d4677814ca..089ed92006 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -153,7 +153,8 @@ static int s390_virtio_net_init(VirtIOS390Device *dev) { VirtIODevice *vdev; - vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net); + vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net, + dev->host_features); if (!vdev) { return -1; } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 231f81e48c..d92e42735c 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -555,7 +555,8 @@ static int virtio_ccw_net_init(VirtioCcwDevice *dev) { VirtIODevice *vdev; - vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net); + vdev = virtio_net_init((DeviceState *)dev, &dev->nic, &dev->net, + dev->host_features[0]); if (!vdev) { return -1; } diff --git a/hw/virtio-net.c b/hw/virtio-net.c index e37358a40c..f1c2884384 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1279,7 +1279,8 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, } VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, - virtio_net_conf *net) + virtio_net_conf *net, + uint32_t host_features) { VirtIONet *n; int i; diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 9abbcdfc7c..a869f535de 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -997,7 +997,8 @@ static int virtio_net_init_pci(PCIDevice *pci_dev) VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); VirtIODevice *vdev; - vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net); + vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net, + proxy->host_features); vdev->nvectors = proxy->nvectors; virtio_init_pci(proxy, vdev); diff --git a/hw/virtio.h b/hw/virtio.h index a29a54d4f3..1e206b8355 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -243,7 +243,8 @@ typedef struct VirtIOBlkConf VirtIOBlkConf; VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk); struct virtio_net_conf; VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, - struct virtio_net_conf *net); + struct virtio_net_conf *net, + uint32_t host_features); typedef struct virtio_serial_conf virtio_serial_conf; VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial); VirtIODevice *virtio_balloon_init(DeviceState *dev); From 14f9b664b34bbd37a488cb5c762aa278c60e1fb6 Mon Sep 17 00:00:00 2001 From: Jesse Larrew Date: Tue, 5 Feb 2013 17:47:16 -0600 Subject: [PATCH 0957/1634] hw/virtio-net.c: set config size using host features Currently, the config size for virtio devices is hard coded. When a new feature is added that changes the config size, drivers that assume a static config size will break. For purposes of backward compatibility, there needs to be a way to inform drivers of the config size needed to accommodate the set of features enabled. aliguori: merged in - hw/virtio-net: use existing macros to implement endof - hw/virtio-net: fix config_size data type Signed-off-by: Jesse Larrew Signed-off-by: Anthony Liguori --- hw/virtio-net.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index f1c2884384..573c669d15 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -73,8 +73,31 @@ typedef struct VirtIONet int multiqueue; uint16_t max_queues; uint16_t curr_queues; + size_t config_size; } VirtIONet; +/* + * Calculate the number of bytes up to and including the given 'field' of + * 'container'. + */ +#define endof(container, field) \ + (offsetof(container, field) + sizeof(((container *)0)->field)) + +typedef struct VirtIOFeature { + uint32_t flags; + size_t end; +} VirtIOFeature; + +static VirtIOFeature feature_sizes[] = { + {.flags = 1 << VIRTIO_NET_F_MAC, + .end = endof(struct virtio_net_config, mac)}, + {.flags = 1 << VIRTIO_NET_F_STATUS, + .end = endof(struct virtio_net_config, status)}, + {.flags = 1 << VIRTIO_NET_F_MQ, + .end = endof(struct virtio_net_config, max_virtqueue_pairs)}, + {} +}; + static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc) { VirtIONet *n = qemu_get_nic_opaque(nc); @@ -104,15 +127,15 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) stw_p(&netcfg.status, n->status); stw_p(&netcfg.max_virtqueue_pairs, n->max_queues); memcpy(netcfg.mac, n->mac, ETH_ALEN); - memcpy(config, &netcfg, sizeof(netcfg)); + memcpy(config, &netcfg, n->config_size); } static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) { VirtIONet *n = to_virtio_net(vdev); - struct virtio_net_config netcfg; + struct virtio_net_config netcfg = {}; - memcpy(&netcfg, config, sizeof(netcfg)); + memcpy(&netcfg, config, n->config_size); if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) && memcmp(netcfg.mac, n->mac, ETH_ALEN)) { @@ -1279,16 +1302,21 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx, } VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, - virtio_net_conf *net, - uint32_t host_features) + virtio_net_conf *net, uint32_t host_features) { VirtIONet *n; - int i; + int i, config_size = 0; + + for (i = 0; feature_sizes[i].flags != 0; i++) { + if (host_features & feature_sizes[i].flags) { + config_size = MAX(feature_sizes[i].end, config_size); + } + } n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET, - sizeof(struct virtio_net_config), - sizeof(VirtIONet)); + config_size, sizeof(VirtIONet)); + n->config_size = config_size; n->vdev.get_config = virtio_net_get_config; n->vdev.set_config = virtio_net_set_config; n->vdev.get_features = virtio_net_get_features; From 32ab06bcf1352848eec42629a85e20efa4e105dc Mon Sep 17 00:00:00 2001 From: Jesse Larrew Date: Tue, 5 Feb 2013 17:47:17 -0600 Subject: [PATCH 0958/1634] hw/virtio-net: disable multiqueue by default The new multiqueue feature adds fields to the virtio device config, which breaks Windows guests. Disable the feature by default until the Windows drivers are fixed. Signed-off-by: Jesse Larrew Signed-off-by: Anthony Liguori --- hw/virtio-net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio-net.h b/hw/virtio-net.h index f5fea6e9bc..e654c13a9f 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -191,6 +191,6 @@ struct virtio_net_ctrl_mq { DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \ DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true), \ DEFINE_PROP_BIT("ctrl_mac_addr", _state, _field, VIRTIO_NET_F_CTRL_MAC_ADDR, true), \ - DEFINE_PROP_BIT("mq", _state, _field, VIRTIO_NET_F_MQ, true) + DEFINE_PROP_BIT("mq", _state, _field, VIRTIO_NET_F_MQ, false) #endif From 0eb256a2173d35c64696189adcd3599be61922ef Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 8 Feb 2013 13:19:07 +0100 Subject: [PATCH 0959/1634] qemu-nbd: document --cache and --aio options Signed-off-by: Paolo Bonzini Signed-off-by: Anthony Liguori --- qemu-nbd.texi | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qemu-nbd.texi b/qemu-nbd.texi index 6955d90327..3e57200e76 100644 --- a/qemu-nbd.texi +++ b/qemu-nbd.texi @@ -29,7 +29,12 @@ Export QEMU disk image using NBD protocol. @item -s, --snapshot use snapshot file @item -n, --nocache - disable host cache +@itemx --cache=@var{cache} + set cache mode to be used with the file. See the documentation of + the emulator's @code{-drive cache=...} option for allowed values. +@item --aio=@var{aio} + choose asynchronous I/O mode between @samp{threads} (the default) + and @samp{native} (Linux only). @item -c, --connect=@var{dev} connect @var{filename} to NBD device @var{dev} @item -d, --disconnect From fb6d1bbd246c7a57ef53d3847ef225cd1349d602 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 8 Feb 2013 08:49:10 +0100 Subject: [PATCH 0960/1634] block/curl: disable extra protocols to prevent CVE-2013-0249 There is a buffer overflow in libcurl POP3/SMTP/IMAP. The workaround is simple: disable extra protocols so that they cannot be exploited. Full details here: http://curl.haxx.se/docs/adv_20130206.html QEMU only cares about HTTP, HTTPS, FTP, FTPS, and TFTP. I have tested that this fix prevents the exploit on my host with libcurl-7.27.0-5.fc18. Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori --- block/curl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/block/curl.c b/block/curl.c index 47df9524ea..f6226b3a08 100644 --- a/block/curl.c +++ b/block/curl.c @@ -34,6 +34,10 @@ #define DPRINTF(fmt, ...) do { } while (0) #endif +#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \ + CURLPROTO_FTP | CURLPROTO_FTPS | \ + CURLPROTO_TFTP) + #define CURL_NUM_STATES 8 #define CURL_NUM_ACB 8 #define SECTOR_SIZE 512 @@ -302,6 +306,13 @@ static CURLState *curl_init_state(BDRVCURLState *s) curl_easy_setopt(state->curl, CURLOPT_ERRORBUFFER, state->errmsg); curl_easy_setopt(state->curl, CURLOPT_FAILONERROR, 1); + /* Restrict supported protocols to avoid security issues in the more + * obscure protocols. For example, do not allow POP3/SMTP/IMAP see + * CVE-2013-0249. + */ + curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS); + curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS); + #ifdef DEBUG_VERBOSE curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1); #endif From 70ef6a5b7121cb54d7f9713d6315fb8547761bfc Mon Sep 17 00:00:00 2001 From: Liming Wang Date: Thu, 7 Feb 2013 16:58:15 +1000 Subject: [PATCH 0961/1634] xilinx_zynq: Fix wrong IRQ number of the second EHCI controller The IRQ number of the second EHCI controller should be 76, not 75. Signed-off-by: Liming Wang Tested-by: Peter Crosthwaite Signed-off-by: Anthony Liguori --- hw/xilinx_zynq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 0ac33b5dab..311f791833 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -168,7 +168,7 @@ static void zynq_init(QEMUMachineInitArgs *args) zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true); sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); - sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[75-IRQ_OFFSET]); + sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]); sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); From 10442558ab1797bfbb01285b909e34c5cf038f12 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 9 Feb 2013 13:39:45 +0000 Subject: [PATCH 0962/1634] Update OpenBIOS images Update OpenBIOS images to SVN r1097 built from submodule. Signed-off-by: Blue Swirl --- pc-bios/README | 2 +- pc-bios/openbios-ppc | Bin 729908 -> 733972 bytes pc-bios/openbios-sparc32 | Bin 381764 -> 381764 bytes pc-bios/openbios-sparc64 | Bin 1598648 -> 1598648 bytes roms/openbios | 2 +- 5 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index eff3de7615..bb182dc79c 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -12,7 +12,7 @@ 1275-1994 (referred to as Open Firmware) compliant firmware. The included images for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32 and Sparc64 are built from OpenBIOS SVN revision - 1063. + 1097. - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index 5311eca691f37222e8dc3453c4b6307e4f285306..c37c258143037cd40c07ddd6daceea0746b310fc 100644 GIT binary patch literal 733972 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ℜR_43q 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%0D$wvS+58lVBCQQ~(-=W2asub0dmGH(l1 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%0DfTq5Ax&hge$5x~SkO|z zzK`IuberHaC!Oh1+DQL{>B?sq%hy}%TCO?|yvpk9e22cXjd6At^7n+fd4R?&T=&+GJr7wL1ooN}@iNUx zW*2n1UbL7!*S`1G%RJqD%G!9;+AC_iUCg%MzuFM}dtgXg(G2S;I2HZ9nOy^I*|xL4 zeH57Y%C7}JEIoFOb89whBqy-_VMnuW&G>wU@Fla(AIAO@!p2mI{!?LjChJPVl>Qi4 zmMz)EzQ+O9ublYF87HGAmqX63h?bkE)+@d(OPKj>s!R56*}7%-Zy5pYt>^tAY^%fR zFEM1=@8>Ms{ibZySzLngNb)@C3`uF+eW?VJL}`i zc^+Sby|)Q_TsQXKI(Qf{swU!3Kv~6jQ#|vazNKs#V;ZFPk$u@$${w`%ESvz)z<#ijFnL+qv-u~GBC#snOLjA;R}fEbHnTA2pQD*jxMGr~4T+H%>3 zH5TTJv5fWjO4eJO@^+k084G;~Ia~P*$EOSY_`cnh=f&WdY#BcBWSt+e


jJPN!s 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 literal 729908 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

& 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 z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF 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 Tc(EJvW-oKD&v*BDvk(0r9IB}V delta 85437 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≦ZQw(fU-MS*3 z$8-LfBDUw~TvmB-YJ~H%dBQzC)zA6soV}#}9LjT; zLU|@;Cy@;TBMMPqzbHr^9xmSdGn&~bvR{lD+uVvVCnC`L31e>}C79PJN z2l+FeDh=i6y-g*@0Wnkfsqp~3TN@oZAac(>^8xI9cn4tE8cg9w-4sp+nBA#7q*MRm zsm?=0{#%lt7Ux<%YKGoW{D4P@^nIHBv{+_A*C8{y?vKGVw}3@D@wB+J_7EHGNu@k= zHqxiETqc}B1P)~RO$o5cAC>af{iEH=B-C{&<;_oz4k+kMbh^u%*k+$fbV$5eL%R^< zVnaLM@ud7iwb4&Iuw3-pmK9+i)DN&w{cyL!Q%!S#pGLN&yBg0l)v8X45n2J@ZQDRb z)REo+%zq|2*NHU$4$hl^HTA$b@H;p!1J=y6F-sSNv7D5jir!(#ol6x#G05_0OF_9m zyt=#%;+hhk3)#S>WL^4+1(UF?E2%uxl2qOde``WrQ}bMtXigdvZSHF~X@>RvSD=Xy zxjevWZS?!E8TUt&e*%7O^w=E~4vPMnb67LMiJd9WBHdb~+FEu)Gqj#YLz+dwS%+Bg z=U}|;j`ENy>}Yd+8**X_izNfX`Li0$^VQPMmIepMr--& z4bWN7s-UK4#aVQ-nhzq6MYxc*AHpi?phJhmXz61c`JYGBl=Qr)6eZ+-J_cJY>|{NR z9$hs1u$ZW0X41ol#ZXj*4~xr&)f}mA3f^1j;^k?%W~?85jZosF9!}Fy8~ym!;Ds-U zdnJ)hkr%P`oKI6)L~cUHu_N)eFH4Zb~Nlrc`XhzUj-i`r45lxWpHzwI8(5Y zUqyI4hLqRD_=II(s9m+7#1HyosqL!wy=W!p>o`R4zlKwY2sOPXhG*?E(c}n3HEzQ_ z=dxx`obn~@`K~_vv9;lKENxRkrGu2C$bQw6NOnSJZS;d-RP{RcsE;sTGNa?y)N<-8jw}As$X9hDG7f;*-m}l5MvTN$U4Y@tfd-RoamX(#5Q@vHd!em z=Nr()LV#WL;2Ri?yEgh^DV^Z#NI*T5@i&mjMYfSjIGc`a6Rr81C`wR}ZKe=s`yv~r z_&3FvffBM2snxV)Ptu+j!m|}~UW;icQpop2J~`h6<#G(Ri{urEZBO(i|C^$K<{lM& zGNjv{F`F0o_kU$67f@f+C!B|RvnJ~Izr=dmsfqd%(Kpqjna7D?K#|FPRLo6S z14g>&_)#!@7X;@ca~RpR$ogptXIFp?bI={edYX`iyb|1ejP=__{S486~0^Rzy3gjO8K_P7$D6>pWgE`u3KqZ#jrG0E-*nM1Yr|3aJJ5hD^j$gZVB@4$ps zgFqv7ydy41sDOMNWN$|-cOA`cN99|-^!xyM+r{X-GIm0s_`ZY9w!6m{oPa&fb>wIf z{Sx25N~O}(jx}uyIp4+JF0@_p2r!VmJ$*N(q zkdwQ%r|+@@{2j%=he=gQb?;%Go(BKv-dOsy!QxM-xn8HN`czQQrFjj{#5n8 z$m{1a#})mwmtoH)IRu*#s{o5ye`xi{xz2!bJqwQ4p5vvi5^&^#{YZ@%7V4~Y z@_li>^xm&jctTZS=?QFS`cvoxw(EX{PMm-XeVyVzfGTefmVN*?3GaE|hu9~+K=MbT zI@!4kXC%8aT&1-6Bgo%f8-3w2I`k2Iow0AhZZv~tM=;bv@*nmIwC+Tq{5HI zy7YWAn>AQ+tUEIVZM0uTzK_N5^Yg7b+^)gjS;qkcf>cLs^xZk^i;X=2$C+482X*fU z-Wd)p+l-l$op2+_*O2cMk)0}-Dth@woh|_7CVZ++mjj<*J_M;VMH(^Ct|7exkLB{5 zZW!-cY2>FO-yEoozWvDoS*hRhVh*`K75x+7wOxhe`xFNUFyS(v9!_v)JL+<-2K&6BVzY&uYkAH!@vq4Cs6OX@#Y$@&g zM&zG0AH=)jF#d$1pB~`L9gYEw3m(KQ=B`qgLMOk$u~f-(W86g=;eXr!3NCefB)xqn z`Tr> z^Lx0IU&#Ce)T;zX{vi6t32U(ANAVvCCvJ}a;@qW@X8#w?@?jsAdaRknwb8%-r72S} zJ*Y-;f4`*wW8fKcvwsx1boEbS zMnY*jv$XFgF)8)xM>1WeM@P98ke)=HKSA`bLpp^l`bQF2&wn4`%S7-q(Lk)&+M;_BJvo`wH&2-{t7=IPXzlceH`k4I>kBq4? zkD4^z@@&g2_c66y@h;&o<^9@Ct=y+mO9!=S0k{gP)-#Ej!sk-qHLOIivbuy20B5zZu@L%v!09b3mKCT(6F9C!K#j3Rca zKfUm)7?4`1TUA_3sjHbfeuczO2aP->MkI$gs1K)@1UXK@CPGwm3O3=V`%YnQ`O&nA zLZ={r0G;HD09m7$2LW0U70WK!87gr3AoL5(xXWvq>uL%ox$fJ>m!m049E|x4Om0uO zugedZv?B!OQxxn>o?Zc?%3yqkbN$^TrSrReNmv_O_<_4U(imfI9eo={-hTHXsVITN z=Llxjm{bnHJFwMJk0i+XPb_gI+KdTf33qjpTS(anTd@*{$?*-YS&sfwB&8ii_~hzB z?D{U0Jdk9+$fxgw)F)vB%+J&yNtcNxx*WHt+!E_elO%nSa4oX!v^`F`Iu%1kQ0Bmy zyUBGQos5$TQk!^m+hipP61k6T@zNH^s5xFL8fYLVx0+nr(eOnWY7)%jJ2Y;jj0EX| zu>n;yn%JVAU5W>^jq{RR_K)4Z@#%L_Hj_6&s?TX-H`4Qd7$*!oJA5=DQTiD{f;~yv zkL0r?sXC`;AAa=VPoEzB1qTKJa+{@d!R$V>bp2TYcxBlS%f~FiA-oc6<=LbtFw}pm zEk-7*bR)^q^#~rPq)6u`FJ(7T8$Eh8c~Yc_iMwsJ(KlbDLn+dDaX|ITsk&GG+qsav zmuzQ9JXAQcbFqpRifgv_DlE zm-x4zF+Kg{&y@yb@ai~YFu}2G=2KAk!Lldtk$*m-TNh9 zvr?5T^#@P#yuwYQy!FV#=i{m$;6_XjA#{u_c9vD<@hRou1_-Q)j)eOwM%)$ZQ8Nf@>@w$~< ztJ%^P*pdw7|4q|r==6WnbWD?aC%rY@7wuI`sEz*mZ$r^CRC>CmeOXffvA?Tn@YokT z_SCjIZ@53!DBgCUy0uH64*C>{@0P)@kN%#lxH(93R1jskvd?1}^0A4)qG7sVeedte zQ5EB$|9!U5fo!R~mg#EKan3Gd8prkEak0uH>Uz%6Rt@*(7=I`m{Ba#{S^TPcz~e%d zM-ASsYo?K&r^q}|9*{b#HKguYjWRV`r4j6wcfJ`8tVfgu@pf9Jg0s2HHdQ&Lm+G+%v-MF!aR6o2&Yaeftc95A)%l*_Q zYK$iHKq+_B!#G50Lnxga0IfZ^mft2Ti8R$8w>=}GXeUtvzeJpb%h!Ib-S%0q z?Z=RHlItuf8%ISoXTf|Q0Hn0u_gV&wwrwLDEuT1`aWRF?lE&xUfqECb_9#A#xEmX) zZCUdiK2>8|l zX;b3MUxB4&^~B)i50DL!--e;#>=Sm_X5%^DFbpAUA(af1u1@$n*9UJ-ZZ%Bc?kSl>c{=aKw9IR(f4mkGd`|>Nqr0jnp$7(nH8NT#XN# zwWNKxRL(*E2q<@aw{lzGC-(?xQbJ8_^yM7dH$oc0Q@p4CUdE|VnTO<&((uIAey_Gsg zO5>BC10(=_HqyvZ(DxMe0Kz#6^W`2@cU7aX`7o1z6zsW>T1QDE1RUZhDJXIxXF})f zd$=Q`6XZK7G)DR~b_B+oX?}-?H+Dnl^09CiHE$`Oy2(Elv1JV%8Y|T!agLM5Thx1W zFw~)KU0<3@+s8?>q``QZhw9`P*~n_6kGw!5$4j}F)Wo6KbLSRP%H5}*RJGP=O<1xrKY8#I!cq=Ir5bc*>OEd^BhWndE4^Dus*R-t0 zczgBP;wX3Hg_N`~p}osp7NOZ^OAAFiwVo}F$%%xE%i3{eco8oPFc@}Q$qb`D6S1Py z(B%^$RX4dO!Uo)}N_h?K1H|Hnd)ga2cQ64Q0XWn9o4!lS+Q>RdnkTh>O=~8B7A$#^ zv?Zaj#f$@=358Noa^M-b?*lRpgVz+o_B-i7p;SGv)7StuCk^o!&!#uZyBk~0y90FL zIha+QwEY}uvFL1=3|k1O6b4L|R*RFgeX>-XbFw!xb?8Iw_T*&v+>_J^M++jJbEVY- zJNeWW=WxnX@N0Z>dyc6n^hw|Hz`<-VmN7+IpB!lITmEEA-}0x(KLrit7f-J8>h2;xgt5sMbLI~Ft#1M?U;rb@M`HAnj9gK9pg=Bre*r2PH#*;JfM z1jt?_oon&=;~jDX4v3#w5Xxy?k?)~3MbadTrzP>z8otKGi@pIZLqDyd)*{H(OC6}i ziy_511wLAvh!rnc0LvZsIv3|sNYSY3&1>#`a)^FXr$v8LT+xl{2~Co z!4nr@4naWXVsPRO&M21fAj?AsN&v2-NC`|4GPy+U>heqAMNq7|RH{z(@J@~oH(@Cr z`sPw;QgR(`o~=@exRex^l$A21FLW8V4w?vFewh>(2WFkq;CaCNf$1P`rpR=xM0KP% zrOY^`tcx?*ndaWQ47ss3sT7CJ1VxD{Qk7F$mbo3Kscv13mGeiFYXEgRA)hYFxDsBw zQLYqQ{X^~W3^;71wd!${89*@y zoin5t`1z4M6a33GWhRbEy6Tb~QY*9XnJJA=xB@Xy6E)9-XYu$m@=VmHRH6h6pv}}& zie|VSDpkeV=Q=5gg_1E_x|g*TxB(hzB*z>$s78XYr_(!gq+hUpAD@c`R_fzYwc&6< zs|q!_Fw7zJ1}8S^bb)ju4JebMoXkT>p^|x0Zl=wcUB=9Ui40NYnWgZn+jF5nygc;? z7UqvinZjzwu>Pc!*?McDODP*d$LFELM(Ua;EkpN}9;P)Bvi|2n=hTgHU-9qP*;WYKJv#GNcU#?>XJ+nPlx)+d^EAUv1P?>57jM{ z#*Ff;OZ3Q?xctmOof>r}Pk(k;(h)~OOZ=x^kKbjIrbj0-9)*iAgS~i@h*Q2s4oWx5 zL$cRp!758DrCTNL??y}v%$CK{{+typ)8LZ*t}%Jjqo)Fiil~!qg0X2xm2?N_?5lza zHwNV;(%&T%KU*g4M$zl$sj-5ZZjy@5Y7E)R{rKDYY*OWYNO$3HH~t>P-$VG@gTKAh zXE|1!MzSrJz5@YkwUiHIped_B2v2EONw`o;DKTAkP=-t2zDj!HA{?KEBsAT5hdp3D z0&+-klvchM`G=4oP zJj{+$m-5|s4{3*{Y#ZfJe4Dxa!8?b!l{(oI2fT-XW8Gwd#hc6b08hqKn*?~;y|ktV zVNVS;*GMBOe9Z->WJ7tLy{4R&Rl7Z^-f=|*Dt@%yiJo?WLLqwCjo$3&#isZ2AbL^s zULFc-Jz2RY;K|ID+GEMhQqfosuenbRbqru10HYWHKPd$gO|oGeIDhATh^g7+8Gr{S z;P7T>u*a2{mE5<$L=wq+3nrqShTICT5TMI%m5K-2K{c++?Ge0^Z#~zg|2l;)=%4CG zfm<;Z^65A?u+uMSaGw3AQioOB0u@Dhr47%;A#!?I7`u?V?MW_0UwLt`z>#y{ue@Z0 z=em^I=#vM?vj&UVACYLM$Ql^O_J-Tw4eV5iWNZw#M^|oiH5pym^{$dQ%0L%(bWuhA z+aR>xYsP2pgV3y`SF;i{bCP`fA2joznS^GAy_yxG*#z?3E?tm=j!zw7xgc%Dxch+_ z8Px;n#O>0p7)og^#wAltt&}GP{z>=MV#T-9H?{C7ZxD{o`I%*@2j_&~8!zFLTxJhu zIPZU+9Bq$-6u)LEYk8VQArEGjolbbLq~WIrYo$k1+qAv#6Y2|vU}UYdKQ7@P{N#Ze zHy~(z9eW8!FtkB>JYL%VMbN!T`XULx`zYNeEsGb4!L|mT-G_r6B=wanhY*SuvOQoZ zskPCqg3Nz~6Trjeze@d6@lrm&6g3#E?;m#@|Eq+*IQ+%qF9Cmv!Q+2Tdhx-aaF~Z? zCcB^-Q?$LZhV0jvbFuI`uQAW8eUPEX7d>|4e9i+aqNkl|dTd1>t-Od6Q}o!%&3akZ z%GEV`S<%WX?OM5_ODo?rgHz*+9=mlP=cDblS2n4cW4CVC09OX|vdUPry~?JQYc;&~ zszR;2rjk?R>n8Yrq^Hu4wTo-d!4BdEGp-@8HJ@=^J6A;87k6rDf1j3C>E+6hRvzfp z(j{h2jW60h$j|v``w~S@HD=p$n<+fcoRy-ubhwioGtJpKr;nk1h$gJ|B_48fwc0DU z;4j*4Q+tcHSL1ySs_BcF=F~pX_Tg@=dPx(70T!XHYct}(L!_b9oYik>FBZqtXxK|_ zcok@#X(`c*M(U)-QgiOGH4NrYUTn(Na?HX~1I^vmoNrE}2d+0KVz^g&wysskJ_mJXwGO>d+H4@~yWV_e&H;_);xIcX07Xr#m!UV9hf{CBGLAjfl z`)K>w7^PJsHoeT8uyw-_jUKd*hnp-dw<;}1nYpheqO~#FPJ*oPf{Ud$dY(3}G+My9 zjxsd7N##?S$5|VbE1hRB>O+o-%gvcveHj|pH+iUio_U$@u?S|DoAX5p=e8q9bLWG3 z@X}YSjh~O&HYSL!A-;;9WI7lgUI;0fx&43&93(B5IXeScv7EMUG-uN03XMbtwIWAb z7O)r>fY>Vw%&9bTfw^3`m=GJ1w7iD1om{h1X{eet#AYc~ zt3y{?SKGL?vd9>^ycQ&@oecCbQ0=FUbKFhCjmUVplIf&W>)NUguvKdGRL!XL+8K{^ zlv3THX{Nf1?2FB##R`=ZR!m}*Ig5oHT5K@T#X0m3;Z$MlUsORJ$YoGvmBvH{ZLTt3 z&$70WyaX`6nq$6KG;`JiAVrrz6wO>6VOS^Ux;W=pW|(MT8DMsXg_k0SKGj*5CarYG z5Y=8(M3ppKFg@UgYOo6N%-ZUVs)2B|i`s+6OgGO=Hg_(Ue&a9?GQ}=#bNSS!^bpJb9Ic$ zTpVpURsg!MVU{^dTGh_V@U1X!N!BOPsxGpvg!^iv5+psKZVl@DU12m?tIcPIk4M8f(mhqvKSCM@M_kmfd^-K#q z=CrMU$zTJvQ&%md-l?hU783$PSff!ibJ33Ho#uG@rW%x{tp#E5nMSvB&cPf%u@+3Z zkrOa+g@x3YR{~W=MYL=kYVGR)Yh;*{_p8DTd#WEfN%Xjv@_~!jm-Z~X>I!-cC30{9vy$tW4mh9 zwB3jc_f_fTfL_lD*3$~LUG&)FdK_BOtkv)QMz3$v%WrUcIRXw%WXD3fSr~z9NDnm( zf=6`G8U#ZbrxOef3D#^dKOky9s?;hBLLa$wM6H8kpL+Frz2gqQUe-s_p^c!uLdXBI zO>f_&rpG!;weoFxT3MsP|6Ql1wXqTXa9l$)82Mp^RyGL#t63{A-~=N6zECea^|Bf~ zM%x$2TKNavIB#?7WkpTfZ}aHocuq(1fA|AIo%7p#TKSZwvty?;UA$$Qk5%xBX!~uA zYW-V-G{SEwidI&foEl&BEycrm;QQ6|ExR_rxA0_z;ctx_X~Kz^IWu_BYd$|Wy{clt zic#*e<<%9Vs#h#uv~;0~zTay;oV{Y1vS4}Hl8RCDRxVgjv3yk7{N>#KjwhPT_)ErL z3jWT(UmyIX;x8@uL{s0vbkHFWO_o+i$aaZ52x+k768T$6deBLQm&2hT)5g>feGg+H|>`ii5<)%jKa`Dnj(j&c!R?z!ex`8jd`;7@*E82!H8&X63_O4^7W-=ydqh6L=X-)CIVdQAx@Su$-z;;SA9A zlkY=}bJ+~JM6^?2Ch|vT$Vrln`_P&4pyA#9*j7|lEFHFSoklNH?H_qvHyII9t^qwC zIj)flhJ_dlpK3kPPioB76)RS{N3B@m9#y_=P6bVZj^D4p*3&Q(s;dn-!@XNm527rk{OOqXRaHcT-QPqZRERF9+YB`%j_h% z1qy!iTG*UQvb$*(%$Vh+%i~g`jmgU5fZTO?Wc#^4d@*@&AsWdFYpKavQB}?JN5{9q zjX=Hz-E@O4ZUWSH8Q7Ae+G;1IR4#y;N;qjFHz%Fgcte*t;0-D5xlWep@O1nKwq>R? z6q&Aaoji1S?A$=-D@zxp$*%QdZPHTUyRXB9X`|5fa&~f849cUAahK!P;8|hnybkR3 zL&Px)T5lrzEP1JvgA2=9axo0PV-}3S$H@5pue!!2^LiP(KdpaVYT(Lqy_^-Z!hVfR zucuU3E?u#xYJ(xw{*m8f|0+Ycziqy{a#2;q2Gd%NEdJdT?fV0ca}=&-yFAS(SlFJ~ z>STgWvr_cK4Mt<`V{_H$J|m)$VJXg*vt|ucxQtJmEs??20mf9P_!_ zQ4;WU_6Di~?w&S=E=>_87LDW}TD(ENR>~#7)MFw$Fe ziMl9b@XlB}rwh|xsU+8b;2UdQ@QsR%ye_%GqE1!d#Y9IT7pCQ4yTp;Sj~5lxg2D0 z=lB>zJ+)lU!Cc0ahSoYtZeJpojqTtz_;mh8)o>vi z5zSf}E9-rY!eYJ@Gi0<&<5Xqx+NE-#G^&PtOW{`#f2u=hw3zAWQrUs!R9=P_V~nwJ z#q?!(g@IozERze8b?!mgzf5i4ybNYxFQg7Ntt6|vM|kI!b9x66b_aRg5Oo)`j87km z-Hm?@Mjn(t)~11Da6fgZ@X}uJFj;R>XKUe2=&+e8Iq9Iro50REs}^2TimDts6FpOthZ`K_+X2Zff zUSWKE#*lO^pnXMERb9;Z#+Oj%av1G+H_6rTZ#D-v;(n%{*VEX?BYr%+-hO(0h}_i} zG*nS7XXi8;RP0lFQkekfQVp3*a5lg@=J;b+Q%}Q!&shOl0gYChfwgkVc|E4hgb0oS zPvdyy)SmTc%M?1je)XaimEAUdwu4>tB+VqEkvP?yqY;~f3RglPXS>xUpx@awM)%_! zJ()baox-=n=nyVGju~-yCEVFWS@kqOu0)(S-bChApfj(knq;K_7yT4ojo@X7OJf8ZgibC`Qnd1T z{7AV5pRk1n~xohA{A`RQY`{Om>%F_aLYRp8GD?_YRM222=Kfm;{i3 z@6TYJ33{}&%L6GEsa_53b(;lO_J=LG=jekln4RL$x-hz&qMCDed~M88G-nxL6%VXo zyIw0N57zyj(KHr{>q?k_^N5w{1L^s7vW3|TuY*tu*2&o^sfyMqtEmy=nY&Kzo8Eiy z&;=fpaGd5}hbgNOxR}#WEjSpx9w!IA+oYN_VPJxK)@xF3UN6t#Mu7#~s7_ASZ~G#` zp)rAxxjDRqAYFAhMTpVt)azBDs{#(x!Tj3E^E7z=u1-#hIgY&ch7FK;@1`JW-v9>% z${Qd%uj*}>8Q%tMJMr>o1Nyu8Hx8j;BjUD;o#ZLB7W7_&yRN^*OlAD}rlL5kQvcp+xV7+p z^q*x1&DkyIXxo_ac+K!=<#;kBCKv}P>*4S(snLiUrd{ly%1!cI5RcrP zo*5Up#7~h;=moJlPd*xSCtM7WYEjNHnK_hB~$0 zqvp~51?rn-7?qBPRgA4(u3@XUl5!Vz3DcZpzYD}TDxcU2mNV$yy@1dgywsM?{-RYmf?si`70?dO zhcx&T|B~h8TeQy3R_ia$ySf)My-gLKJ>1VShy!iU7KkL@Oul-UY!AP###IJSuu5lk zI;^H%wv;tTo@+4$2u=YDnv1~VOc&utA3WKxs~(*kDpRTT+QeBeS{~j_?1C9HxpZ z-!d`J@FGTPvMyM(bbeio+v^cU-iw3eFn7UBlILEyx>PQrY*Ks2l};B0?uAkyj1JUG zvkSGevqAUC=GajsoQVBCY@Z`);~2*PyY54q8*F^cqy{CSYmovTxDT%KhEkPQ`t@qF zXe6ljRW+Wm5Jvd$)UYglK7{&v)MgQSs?;~A_Ehwq0= zn$t$EHf+5w*84Tm8D5effZZYpeE@;(TvgxQd>A5{E0Y`bv~dUa@*fskWJ>!9xg!t2 ztXlp1uQ{fwOCP z63Z)G`wkp-gh}yhuo6Es<#O?m@af{|(Z=sb#1^LT=h$0YZ7Y_Is#!6t*Y2mxaeBAm zyLc0@4hJi9cOvLDtOly`>;#wiZJmFooNHJMYj8K1{%|LThq}(4*za}v;hxGOs!j*@ z)@hkO8BEqi)#~<{a(APj?m42xwdsgHccH)X0C{%F6H^S8V9tbgK``Zo)V>QsD33Jk zMoc)rmue6bhVOPhk?%t!)qg(c+M1FH&gUy!d=t|h3VsypMrbdT z8=wGIoo2(6&T_z~i+z!g8XuO2T5j}d;24}&WCY#b7R}-XcJ1w z{s=tIjjA?Ty!onrjTL6GjogpOqh~FOaJy)v2c9;mJQ{p)4X5~Ywv1q4v4?@6tM=P{ z)-}FMgIl|(3;j!r+tix`u}EcG0=v#f;c>JFN;1;J+cafojj;xnW)=n1Sq8Zf8tY4+qc>AQ$uEJtN%+FjHc!F1)-H2|w{muj2dY1p<%SL5II<2}q= zE$|OKhWwU*yf7A}Pe$<5Bvg>?4|M>zpebb(juS@o8%0e_6cnZ>59-zomxI(Y)Am@I# zhc5DP(vE*;7e{(JvN6$?H>SuW8ki*aWDV{J}oauUs1{=@af}UfuqBL*vX7O zh=>I3od+R72n!KVHa&3=w?!yu3s+E1qaTCV0(MXYQSKLZ+`Kco?A2929_5(euAjZ-=eXApY6#r20o z{Lf&%-5fcc5#w;c(7&Ob-`VDOK7)v(lzcCsBb=i+ z@T4r}G2+4+G0c%jiv`bsbmA6ALkQ@IQIrt;7QzSr8(?ToNS4RdHgg+%y6qc*Wo?Lo z-2s#lQ{W|%pNXxl;hW|`Qf-J7JPC`1bbZ?zUIgtQU&Ng4vC(w#dD5y2EV9%Gi{e#? znRi@^qt!khtrxJQpjqs7z?ohRZbUGBedK&m9y)oQ!ft4oa2fmywSi#pr1Uu#mG-U~9!1S*H#hFnxeMI&rnaUOB$yw}eOoD96;j-c9a!Tq|)W zYJB=KS2Ask3fz~x4B{L9z{WO&$OC*j@(Q+phhN44*?6bcQfkxEYXVwo*ufoM>U>$A z8k;u8^x;_a2=safjyz^!hIp;yIU-Lzzq?+iW1U}tSF5qG{El{pSC4SYS z;9luBl8$i|AxL^?tUd;}F=v|1Z+kba24@S-Fjm9pE6|{!5o4X} zHWhX1^d#7 zDpY%?oy@PvgT~!i!}a*|{x&snAsRb?G1^PI32ll{crf;wHLuB8=ik}L$oP6SHX0eJ z#!NTfL@PH^EjtV*q|FHMUV|Ty84NfcTq>`_4mZ1~L`|FVuXSSvY>uc1vHmuPxU5Dq zkve#AV*xad)DT~UU&mnoV$$sSFO3av$QKX)jXB#jGQAHCaMS621MhYJf?11)!{dw# z1jD@<3%X%w#zH@#S)+%@3)gWtxpU$w1ToL_zu|=3r`1h>OZppDwJvhDStjzF5Bv?1 zK+J>9WLDm9V+5_4(RHswJU(?>4HKXKCXRLx7**m<702K9#g+o?{SK}ubOXdD4>zs_ z$svuPgfXHKkn#VV>_)E9xy149(QahK1n#5q=*f4fw1A@PJr=SkS~KGav_coG;Vu!y zv>(N!*{Ufz)*dUr9EPB`$qmQgB{8_BFk;SajYiRa48?jJi1Nur6Heb4Cv*%=>O-W4 z1ykQbSOB2wEdaOUECbRN)B z0d7AIc!Qz^5KYJRzEmLo$=QEsjpf4@E4jHqB^3Av!Yj0N2BGBWKk!VCnn-@TN6d=N zhx2Xq;cMhBXt~iz&2J+ZZftCLM;<-yH}+_)UQxDUW$YY&t6Sv`|4_5WWJU?O-oY~2 z7}DXo8XDWQdPCLdwfEL2^bW+|*r~VE>D>cIT9uwTB63gZ=>%tZHG+nrH+E^|Vi*3k z5=@A#R;_F}xx1WN`CL`M(a2Waj5c@Zbg*k_hl20%s7@^1up5c1A^l>d;axo1h-f7P zdI@xbK%Zk^PHFVJQ1xFix8_2W0P^b$2}q%LaWSg5O%LldbPjQgi|RqK;2H;g9q&RE ze+@AnK3#-=#Wm4;c)k!}STtggF=lqLqQQ-6h+gqhJgc8E5Ch*3#9wh#^d7jp*TYv) z4e9sl0yXObLa<%>zC3!k0mm!wRb@S%Mct?Nhdy=o?z2(geK^MZ5h(Ff{O{hE`=-p- ziD69U6BuK;E^USF0V5oUNB zKE!BunEA;m9g0$k^h5Vd7zh1yj^$hDaPRC*!Q7o|7 zHX0Y;)9~-sfn1(J?hLi}?zcNVnwh_VdF`z^ox4415jT`>t$X8mX-_jbfuG*gcsf4f zBwRiYk}w+o7qDUAwE<6RQtwoUQd);>zv|)A(;Gb$(uf;Dm|>$$9U2_x-Bs1gx=$7# z?j=GN-IE9khuSoJbQE_aeH+^5C z{UdJeQQp)q<*}A9BSa&HK6FJ(58288C44(BH^N_HzC6-M@>f_FAN5d)nl_W?D+u7x z5c$=#lR{rXF#ELAQ#$n(Ziu^&)RnIxRAU^*i7h6H^J_VKtXE?Jk4W)bA$yGdeZ9n) zAJOn8Aq*U68Pv~MP=>fPxN%^dha1|jVR6_MeT`LlU#Iclk>5J?Gq8;a+6XQ|73fp? zR4zAS_s5zj{0$z7G->1w6EUX#1YL`80SE_&(&&H6V+XfuxW)*7XT+X=LTY$q=l>_9 z^|(X5Hr0seTWTq-?fZYW7dYdnI0qHs=^ zjiVYo0l^W-zvMqB>o$c${LX*zX;uTFX6pBN?QRUpIQJjlsC5lg&-XBqr*Hss5~lN% zhnzp)U24h?a)xvOEAbC8;6&+wkKg!bNr+$lKgiQ!wsAlwHq_Q|5`sF=NQ#=m#@l0!O`0@V+i=4gC z+&}&vG4l693ju9dh({KUOl#IhD9xU&=Tvx47Vl2a)_%^z@0%D2UQiWWG-3@?;eS}F ze*XDOuJP*Am@0;xjK%Aq-uzsdTnC|egg=r0;7}XKA4w4$x)0eKe!>K6ZYRf2SX`b{yX$Ud zpc}s)delque5lr711F6BpCCR=&^ELmZorK&(pV2-^6MT>_$T=DgI?ybJ4`j$dNicL zje6tvk~l=*b}0rNVhQle2>4{*&%9Xw!Y4>SEG@}S8t*q9Z3f7qTY`TdfX8VmRD&}#&}yce1n58ofsqjum)Aw-Kf&7sjR z_IU1sb1x;zmAGGt$_>2Y;xTR(&!)~OW>X0FG3+UMRz(qY#p+ABK9{1K@Jnl+UD))i zuX)kXB`m9?7u%TNwKN(>NH!jCci3c;22yN1+K1_*9;yOi>O{zr(}2gSFPko#t>Yr zQv9MX*^(3sBv9w!I{aVIlPzO<|HSE4{5m389YWV*Q(KB9cab*Y*uZ)>8`Z0sQHFr37E~>Y{T}pnm2CF_4LXK>Lj2A%EV-6m zT;fj6a|R+xL+-EZTpK}g8y<1=u?(hn&#Z4s*&Y9DLsh6U z)iNmkZ|ay(uWumk3{zvOrGWmEYUwMX5avQbnpQBUp~agvCWo)PMPVAaDAk}nz?BU4 z{s!F0;O5_e+WIT&+&%_v`ole&7B5?9t4eIdkUBneEJ(8Km-;r3zAT zq%1f}!HKfqBn79-g3Vf#O9dAcK-18DZq=}P2TlYuq*XPPr>l#Cd&^MvQSd-n@F0Sr zK^_KTLw95QK0z>PHb4$m2L=X?-@2J=0`$!RnM7zJGa43n6ObRa!zSo0loUWn3J3az z3A#?{CxDWd+(ik^+dRxO5wi92M7?(YZw4tcXa1JMz~!ug+b6?iJiodHa4%tKn}{x# zvnpqXJ6IC9Mn(D9YrG_b)ufD|p(yHBsa3d|r2ST6FAJBsmxW8}%EBe}rQx!4qoJH+ zy_3)h{kxMx+AUV?{{0p!@kuBLbZu8*4l%w?ch;!5PX(B}4xM#B^VOj`piBwFs|KCl z^s#6iYGwi?}Gz`S|Smi8HH#xZD?B4h5!D2B=BREENpr;D4%796p zoNafCf^;;XdeMh#xHZ7>va9DEYJ4z+L~3v)i<1d9a+L{?yQk>WW_1xVe0DvNCua`w z`h&}*gVUP64)Z+F8l9py+X_3S&l{Bx=@6fqqUSYmd5xQhSDeD~_asQQqNWrKXncsb zsm{lX<808BL{GxX~HUAk9xC{6>Scp8&PXPxB*QTNp2ZTu*W~V_|Y$+Wgmh~{; zT0~~j{$G+6_f&`$2DPc^s?t4;IvG8ueut*k)~GvaDjTA(4!&%uQA>{hPP6{T@~Zn? zR8q>h&d>iQ&&GK1&V`uy7o_!00}Ed*k#&{004_2OQYCsY$4wr*Ajj*Qt~{`}xM720 zQgD{mQTEJSv`)S^>qWT3^s=BE%{jlM5rkqD(&a|#D2q%7Nh(_Pg5~?&Y>>bQgel)1 z+KVqubDKw?uCQtfA`g04oAO#&nyx%Afu~Bg76tD}ig4&=v4_1F!^=n|^EQE0AMwQ| zvUJ}7<&P0ml=U@X;8|C%Pjf(1o^1l5uT?Q^2Kb+4o*A&}`2GyNwnjCVpN04V3A+|h z*aTq3WhbCdwl*cX|6!JaYbWdVrCsyyqKuo+-`RmJl665A2F#KW6&GI_N(#)|B-zH+ zUJ;IQB^-xV0+jKyS?`~$PoC9Barh)IdmSdzs38|=eW&QtCi^+C4gQ}4(atKp2OjHK!&3y#tk_{O8R2-hj52a(PvJMQ8YePvLf_2oqeG;))v@& z9{kXNqs~=!IZvv&V4@^(0xa9C&uw^96IrReCYt1@D~6bFCMuWB)HN|R%WEvA;i50Z zc}E~qDK@4_RJi8Cvt}A=R=xtg(x@IUw+9)*U@qlf(thBOafP12IJg4b5QOObHh>AkZPO*uHYP$ zE$w8{IT&-oP$f39pUu&yBLPkpOk*uO(3oF@&JeqDH3$77FO-d+VTWx?U@qopK?=qv zIr2Xk{^nvl!p_fJ)lKAgxsXUCu3}jvMpdNdqi?tMv?gKV7empN0FFam7H&ZSfU`wk zC2`Ih5n05FWFbi{s`N*P=K^5LuqjqYtgLoN9-vc}- zZ6yTW1xVD-Lgau9V6B!ljHF4_D0^msJ`dfwB+a=H_l^F9Ks2R@}QvDdCL?#~I9ybHRO+C{pPrtY}uinT1# zy{N13BK_Lg@4Eylg{!)s{5kV&pKxa+h5J^vXEA!(54dzA$j(|s&zA+vCu2dt6UkkR zF+B+p7`~EZCE)Cp#W;3fi}8z%_v!AYVUI|ql6|0&KWF|qA>3xDBz<~wjS3(3(h=qs zTfHI;QvL>O4IgCNq*VAM5i}e2>2vc(Y;dG$32NeRE*4y(+Xm0n1eWNl&XbIIQORqT zP@&OEhAA5kB_+RciFj2+wVY9n+=og#6^*+>e*uGmY1N!#Xgd&hOx;<}Qe9V4^tO*B zmqLPLEWSs_k@y#fdQL~_Ef7m4%U~OmU9^<2u8o4>ZBFlj7BQGOkX!f%+^vU!31SW;*gE09EHiyRS z##N;f2H_uKXZzEb8hy-b7vYkGd^#5RG&gUsX{qznItu%Xi znGoS<%U5B1KxSz`Pv*6Wn6kWjmhr*Fg;Fg&;-a+p#?Zf z9^rYzFR=-(Ok=B-LpAkCiY1nzzmD@1g)r%5Xd#dKn6?}n5AUqRBtIQtsT*Lgr*_s= zVbT#wobTO$6PDAsdTcoq+ATGD;|ZoRmd2C`;@VjAs81xR8fO0G=p2sV#uYLfAP><5 z+t@nF949;KYE*s*_xtr}^Gdk$Hm_00x>w*-GVLHQ$U=E>PeDEU&OU#>;S`L3Ss+!? zDWlsAA>{loDNg zsue{azf!Npc(_ju)=>XS{JDOC;z%zGuB7P!T{Aazw0T&L0a(ita5Q)d(O&h zPrxttSr|!DEN~W@bCw^)rLu7=wnJf-K=7<|F)t2x3BMXuRYB3`4G|XX>A>=VO*9f;EoQ8&Yq2G_+SP0Lhjk4XU6k}Uyhou$Mr7$yFbvh7)OOjf| zJ-j(nS^KWQdJD6Ph7}2c23Mr+;hPmVa=$eeN)K#y)#S}^S^5P?1vSp6u^!3wiwhmoC-^ovk7@^AC=6C(o>k2&IgcEX9jnn9 z*SN&3QmPw&pw=%`gMN1q+ zX7owMReQ;kvraJCz`3CF#0dHEi80(d3vZVpeCdh2%^+MdRCRl*E0Th4sZ%bh2SsfM z*Ps_J&K3p>EV>50r2@w+8iL-~P%;a()NKriuWTBQd(qZn?J|xR!zRx6IEl%^FlO4h~S+^KIi$R`?f%g$ue9Ythx3!i)AvWEHFwaJ{v@SWO~Od)_t_ zeu$v)NuH1Mv2Yu@?W|qLy=|z@S|EGKpgD88ttg9VM?MQ{ES4ebpgpNA7Q%cB;GD=y zb~;Tt=jU!}V(G;MRci;)la$)csthUf1@)QpIPMDIDZ)`P&v;P3 zwMlnVJigLwvJ^;N4fCCcxlxJG{1`pRd0>=*#(Ew)CN7d#t|vq)%u3VeVZ7tq=Bpnl zG%*7|U$1u@fXM{SmoP5|4CYG?9DX?P->`|=e?E3{kTh{V))d#dSo(aud1dJ-?<4&p z3nf0PJ2{GN7`hV}@?U_72nLey1^Oa~fdjdhYLiA=Mu;UZfY4415mtPX4H_?R-uwW< zmc0Ny=ZUa-zYxSvl(tg{_g{#CDo$y+{ZSZRjC(;`aKiRqh=mM?sB?Ujgpvf^2bN(M z3Pi&fqW>7eCEf+|a=C9c5f6J{Gk85t=hiL03olRfu19BA=cHWlNg^i=vDA8?gw}CA zGR0hey`H~e0ZQk@Ud)M8l!7KG+_jJ>d=W}er?KcoNQLe!rcIrIZ~>?08R#tr0B6)i zC>&ot(**7tXMb9cakHO!E-uefZhBBwz>N#zF4mo*;h`-Exhf=s-+hPdvKJ$}`aY4H z?DR6@2XP%YCaY-~ET}NYa4@o7U_pu=E{RT&pGQYS;Pzy!EMa&+E9NBp4U>zj+dR%~ z!<#%lMt*!UyW@Q1;rO&mD1ATq@u~PAd3e1463*1nCE#&`i*<1q4=-~!#QM40#Rj?C z%Z9m&-4wb+YWbyTAFs)AM<@%Ikw1AUpLlSXTnUW#GM&RjE<>Z4(#sN;>CH<|3KKo} zWTl=l^C%!R(4-E%o?T&Ci_oy#$SnA(MxY{*S8=M^X!j@4X&5fy##6<}H;#@Q?MxkjU( zkl~YMa1G+27}Q~7M4TN`dyz_D-v|(J&it<~;a1U^kG-AqZjExk)!0i0SdH^lIyK=Q zA>DjC9rmC8fpiO1x@nktZ@})&$ochLiQ-O+aa~}!7CxzCQ*-1N}5s=W6v~- zgPN4^=Vu3Oa3lCKol7?2B;P=ya}(H&4%|a- zQ$HTX#U`h?Ck1eJ&x`xJ!G{?zzCNAL08*Qvq9~ahm7R-&u1!o9-OT(CTK#O+J+|dO zdY#B-w9XkFEU_7ao?z+CdYdDakq>{V{)(or>wxBtn-zL4~_|Jef&*6m07LW_r z}!2uR(2T#P1nJ+7hCSnxc>?3%5 zd8>(j9^N5>3&MvG&i-Sou()t-#e{003?@Lq!)3u;Tfy#`p0e;H4-c1x5ApEcvT*k{ zjF;)M;LtXd#KYNxxO_=sJiI~)5$^DGu)%GpZBK7c2b9npYkqlEV6ux@eB*32^AK0Wh<*ukllq zczEsdc@4i*b`LBbunLdtfHdP4b>!aIG@J9*o~K(gJBqW!?AF{t6CWs_DiTCzD%Jf% zY67VUn2AiT(pM=n3Y-w2LzN&QjLV~N#lK!%T4|$XiLuO}gO&j0hLho)7&=Z3v+T`i z&8JEd(NB4wfq8AdVg%`Eumd|G7IS>Oh&8H+T!GfuP|j453|R(uK{!*wYnP#enJe{4 zGYaZe04P#N583IdazL`V3k;rvONEHqIsGD9QtK|KR>b2ziT15?wzRWX#v3m8TrP}= zksaVu5=)h9TYD!#HP#v~qa{FT@#VWo^yH0(tOqP$DbhX<%?vrDUAbpwY7MIwa^lqGRy!7<0r(pU2dT;hMk=;qqXW!S$L zvEC~FsDQfZq0(|W4)9qifm{idM=Q>(YFPLWL19E_JsK(dmZXbQHAjSBjiyH#MN>P_ zU__UKZrdx;*`sZWrMuBHEeNs{vf*vJ&QM%^r%ynmJtP|qc?SbPy`7jEqdmR@IoZ&O zrBNOWorkoWp;TB{xS6ZJ6NAQr7~#X07t(BJ(XyN?B<$|lO|V>MiF2xJQN6a@EhOx* zYtYOVVF-mLaxx z$7l6Lvy}u@4Hx4x62hOCDBdwIRf3}MFOnUwN#}+ zM{dLf*c50{0)BKeKM?TkjRw_`Rw&ufji7O*U#<1rH-U=6Y5z@##(qfnCNQ9jAL_?u z2%icsM}gE#Pe}^sNfU+wda0cA^W_wTs%EbwQxb@Bi+Biu?`BlRnO^ealN~iEiJxLj zJTYgT>7(GBi6YawbAGovDK}2hBS$IE(=MB3E=@5mllHdhIxNZfWRmJQjB7(OPe1&{@czM1_ggaIZu=K6y z7*-AU+yI^?Z>W4;#;Kvl$rZMdfByaOk zxgYebQ$}RrdwF=WEIiG_%kenB20RzJ%i#SyyqHePw~L3z z%ixnde4s3Rh{7+H!Aj16$K6BWzB2ew4;tjfk+Sd@4^NbZ_w(@L`XV}qfZq|SVjAPx zVe?N|p{!#tV2rUSgZXcarG?|}<-SNSOiN>UvH=SAL%lGwjP-n-hXlT^w>m;T7XP~5 zQXQlG`DLbfOcCq2uj@fa$j`jrfNFYekVU_tU$pYl{$e86@=AiPk5@|0S{oEdR3lo; z!3*LO%=Jy2x%k<)^x9Lc%bfyRPJ7DyYk1Lt6;<<1eeV3rJBo9c>8(6maqewHY!K;o zTwcP$^Lf?etTiHkOZ7E2)yF8+8ZXZWbQR~fHo+oyW3Icliuvz{eoMwH{MMx@kxr&J z)q+H=UDv>dBUK3L3gTIXd_kDVPtmXVVE&W%Y?MjY zfH3Txb}zII5Sk=e`7Xa#-$U}7yjO3XeEx9^LGBO> zB_N3#-2{(Mmhc#O=!W3_1Wh^6`6E5y(e4xYgdgGbcFvyr^mPpzlLEIwzEQB-+K4T? z`+#KAP|vr4V>3ox?&7!$+@{UEmhv-Upcmhv3apfIws@xnlG1Ql z>G><@cr(d&VygMcPOYGuVbKTByp{4s<+D~2Yp0V!CFvrjP&!-bW2fs<^oizG(0qAw zQ`Lj!E&QP(_#JC_#g|W&uJ8#smCrg&r7I4;s zV*ffBU&?MN#&$MAN(Q+sh1={c#ut>uP;lL_Zr_{?ghtWCg@Us-$h8-?}w^_)DwLL5S{nR_+ zskrazK7K_xU97q1yZW8Dm89np{USpFN@iL+0<7Z^D8+UR5dwU&=TmS}*=Fr<;e`wI zF1Y6(Z~H!?x76&ASz=ESFHOO~_EEjXvBt@Qk7CwaAluPL^@|FDO~f~-c+~-@Hr@=a z@naZ@R6N>-|FKHxy+mt%0wSjhrk!5K!_ehGaq{p1uyGBJW^yuZFqSHT`$x$XO*oG) zaZta=u_KFD4~QLUL9QgPA>S47aP+%H@rA|jO8#^31RvKooTF-0)xM<5QuL@rR4`IR zml`lkJ09k+z&HDo<73e$itE9A0%9M8WzdtNeBmcCo&<3)zsT=np6?aLM_9k~YftHI zw#H9&3Hcch-RfIs+qPDS?|Vw$P}UmO#OVFjb4H#hNw$PUbuAbcZaI1Z7p!7kPwN{R z%Ge}YEuJbC*%35^*+wIy?OOWe+2JDH4K?}fSn_+cHu%2oS-LaHbFmw^91ZNAV`0A_ z;&|B+$jw{C<1GmsAj~5baOm}-{aDAA8X8HhI;G=k@|XMd#Wi+!|O=*!c-Q93Mzr@{mKp_T+X^l)?k&%{U-8=KaV*~KkFx_kKz3eItm+wwUBKF zSg>J2+cWf{jnhz6E53o6$d9o^xEYOtZs}5`DaZ+>nR+S?9*L~g*2S2t@K-ReaQ_6d zq2QD)$1%=a-SZPHC3X$7zMnvTZo!7lPhbuuYe;5g-D39q6ur;qhbd=#$I(BWed}O8 zggb5xvhYt~52mhuQAdPi`?YV!k$nl>JtEJ~q>$Y1ywoK+yLdKu=p`nyxi!R`KSTDn zazDakmErao|Ig5UsBE#dO;<41C_L0Ee}+bMTZr)Blj&Z*spo4%Kfdo~@;V*?3GhDU)H^!R~dqA(_bEMxxK=@BmIBX?Y2h9 zzlZnshzF9f}I~Ee^--KBUj6 z=2eq3PsK%*yD+M~atJ3iV*>0HD6J0b%jZcERFm3;GJ2t;Vxh#YCW;G(SoE+yZAC(0 zIW8&OPr0OjK>7p1T_F7ndS$pN-7aPx#(7kj0HpPG>bhK|gPAFzW+quQtvBzOM~P6k z^SsgxOE)gu`LYnooLpHGE}&?nTObSJjR?OtA;W{h^$kfk$+Q>IV3N%DBF@b(l7)h0 zOXNkpu6watfK8NzJ57=^Co96|NdMdp;h&on?gf6~oL#)ISR}M2hIxc_enPkx$P!&B!>f8lcw?7vrw&WMKxnNFNq<1N z@@$!Pk}3RS65KW4cME@A7v&F%>XRbiY#DJZj!YDUn8QON-Lc?Dj;H)9uzKVK|73Wn zf&auZpa_%NLwh4bF6)(6&srm^LT)Hnt%HJaxeB+|`Guby7}QzlCrSMDg26nsWM#o{{dHY0{=h) z$b6J?6E|BYaeo&3oTa;JR13Hd_8^wNXz3jybL+kVPK32zmPT2C-Iox=9Vbg$B}#97 z8~1Z$upRvE0L9~z8X=YWZ#_MAQ1mEGs7fw^+5QZXVrPwq+n`r`AjJ{Me>v+rN%{#l zCf)d5H=aBOO5UNnZaiyDE_1cX!mmMj^&L~j3(~Fc^s?U9psc!D)PwZ^MOOjd!v~ z54VfMSr3M#+X1q1AV3rk#qr*C;~6N%gSbrf4Q#MH*el^+%JT-Qd0bV`>!|ey`&f7g zwJfs9WzLn1e>fq)AL^5COuED!WTVKC*<`K*+TVj44-HDV0qH`zD7;VNeP~#Qr&;Rv zP)PRqg}=`yU1!gm(B}4aNpG0B--LdpuV4CmS?EoDkcTw)Iq4fFaC}mXBoiJE7cxOWkVt$tO26TTr0bV1Ze<}RC?*jTV3PipKHlgIN{}w; z2ATgYo4*uBU(R~eE!;6h_wyb?$7!_q$_-4sjy0ZQ0MUDBUrCg7ArSdRsGc;;+V#6LPH-IR0(K=Ejl zh~0Iob25u=aLyTRJ?3S-Z$s)Hm6<&XEq#I1J?7*LAH~y5nwYZ=5H7IgF-g>8S-}RG zx%DWdo22N=~QnoRvJx`u+qBd@{)f{selGxC#}n@i?yzfCy2w9(OZOmcsp%4qrYz zjBv-}T`ZObp2w4{kNdIz!2Q^ZB=-py)Ba4Zk9oNpVnOb9;c)=qeWF*ORZRoB`96xj zB*>z_rfYuw%r6rd{&UGKp?^W%Po#Rjik-Y43rVprm%-_-=wIkiFiZSJV8Z=1bxkvz zlvB=B;A&$>Z8YJ^zaL;TrS`A7bC#-%u@~;We*5liZcZb;B`i=V7sUGiiVXqfSK7;} z0S;%a!2bMSL4q&D;(tZ=QAz^#B;!+X(a1Z0#m%B&fg3o}@1lo1OYMsJ-o;gIF%dax zNVtk-6g7fq6gB>?Eb6=1eHj5&&wBukG534m#*ui_}0@MEDiXE@AI*+5`6K+7WsM*_zKvD_v0JS$riIJmT)&(thps&FyZAEU$lcaYhr2;po1t)(`l7Tj39i4u|u1 z=1vX^6!|P!{|9-Qwjd(e5A?d}{i2*5ZG07{S8(5uL>29 z9t3xhp1Vj-?!O^DcafgENdI@V)_;rid`Qu~%>5yGaRCnZo2-M}A62m!h2x#NBzFTn zAHjs$BcNjb(8jP0HmwoM8qn2Hf z(6X4z`*n+nI3d!bI9+x@Ygh>x#_t+Di%K3u%z@^&m}1kHrlSQ zg^b4e&!x$WPYRuiZjMnPIt9TUJDHLGS|5@oM>W(N#uB9H5HPA{XpP33XC`?`+pJKF_m6)8&tF|E^vIKlwajx**OrJO+56Fjb% z0F^FwoN+PeGmnE1w089zFR%sgg^}*zi*PUL?hx}G59VR4`Jq0Ct$jwTVYxfCv4yP{ zd$ORRiuE6lLV*@C&!;Xei&tyym!qZiuBkTVs1jj6x#<`pX4hirosWO#OtCFwFzU$) z9PM_WE`N&gfhEQojmGm__7Gt=JC+`6v^t*0u>_|<*Y1a%Xg^Bw?O~~laKU(ZK)9tQ zE?{laY1G-vjN>Id`no|Umr+mk|2bOXV!Rr4LdHqe#=34*$m4OXPy1ds(Ig5f+)qk% ze#GMl@HFrCeQx=)5TDu#S0i21v1$ueFfh{ObCYC^(b%onIVvp(JXZQqegUTl#D#tB z?KdMV%EPS}LgeC;wRjo#%B|Uqf_Gq~tJi zIFVlu*9&jcAs2z;lO1@4*_^Zh%bp0LP}5<0O(Vs;;|%%Wovqz7VPO~^hdd5p3O)`k zS#kjtmK-hbT8|xMQcuTdCKR3G=sI&$4j#{4I?dG8|%|R--{UBw$YKL7du!)<2IkT z^Pb(K8T1yqoKg>H#^P#@mFzxQ6c>8eN|301s(T!#FSU7*y z7g;BCgI~KBUTI97f_wM`;YyZO`Jcd6Sy2sU1BJ1yvC8!iTQY&HEk1d37GC-p^3(|HBV?F3&9#p z7!f(Ylr3uAq}WpuZ|SDEb_aLLilzgcql7M&Q;s5xkkl+kEp9}-caq^jQyIX$?haT$ zO8Z=xug*0}g%GPa&Bez(uM1om#8Z6+UAdmBgRhGvT!OLTE3`>dtQWb&V}gB^p3m*rqK7`o;4K`L=~( zWnD&H!%Ip=D^pB&NaBrfe(h!$C8$Jkd@_XoKXK8GuyQv42^0@DpnDjJG$r1L;&?cZ z*NlG(W@Y6p#`3))!6}3{{a2W(2%qfwcpF3GdO1#kG{x#U$*5cTzq-haPxfJIk}knV zz9cS5iTHI{5RJyAyFYBbMo zmT1+yTlv-azi`MVBRUmwi-p%z2yC;5nNy9$qk38TDyUUj8V%yK}3TVJd4;^qk1VL z!LODtyAMYd<)B~Yu6jAeVMyLIE(V$#6C|1_@pppU#^j?=5OEuer}q;^e2&xH+~xo5 z*)@(>Gi?b_9`rNQjn=EmFUxJuXjKW+%oeR1PcZShPjGs{lu)&HXr8;KqZVF?vUDFU zM7lA*M)CPYb>lcGbPp&|lQXkIeL=eUCba4yaXHeiVG#>f`5cw&D+vN5wI4%6YQU=6D_H@pK48B62dX%J|6z ze3ON;UWu{jjat2wPU|&ak@xi!_v(^wO8rA!?&6|e+{fdN${R`(H23;Xs)|(WJR7wI=n~;-NO#VbX zNyZ(RLO+%iei{;QA|*3!DaB~w$1UT9ag^n}gaG}dSyHH{q6FQ77!(Nqq1c&gub*#@m4qV6QQ^Ni9dDWr0!=SbrQ6 zaOhs*UW_y`*6&5Hltt%>(?zpYXDKDKV8|EAl*FR;T=S5;kNM}JhOnX?K-)%WWL`mE zsLUNy!4RK7eBl9x)I6hk>0cs*9iL?1U%JSX`y?|6_k7Im{~D9v9(2xUHA;4D@p7|0_*`~lz@OLag zRlM8FVhb>(c+XAwftCbwitTKfQA$NZY1KfK-;a4{Q1$_!G zyPq~))|p%vSnq2Byr2&IfyVKEoG(ykSf%)G=lr1KDI($RCi5<$a+ll_bTNjq z58^Dj7~|6Wz4YQG^!$qrZ;g!sTk<}zEh#Zd!+Yy}MK)ywSywIYeaI}}4aL@~VIB{@ zu<++Gy3G9{E`(H(P@5+KTw|9t%+l~XKImmbKFHGF(8^(~!Wx%gNa`1Nl`BFN!wU!v zEkT;UC+L~zdUod$jBOukEV%^2@FAxblt`h+JZ%WT#)rJ}?QrXFL6-WoQLjth%Z|?i zr|5oZ^$ol!h?de7j?6792^i$%@=k3aSm=QC#ap50P|O=K73LlfVn`PBmv zlCzf$_5d+5os`}_*8d4e6%%b)UIh;=O8nEPh9e#xQO53%{S;onR$1Lg1pD*VkY~4N z8Q72us0&2H%ZfQh=V6aVcF>AqaHb*15QpaY1mM5jE=q_Q+gpjbsp zJ@3#;qj~;^E`eFiVn6IF^4n)JWIS!|hZh-WHa-dG=dN`lIn;chFz;;NeXU&QWJVA0 z2vt68YT~IyV_J1wfS=RHvUElNp)(D7Ubh0FdP+b_0y3jvGk6wuG>+qhBTjZ_Gi;0! zJ|tW<6_JD+YKoA}ig-*tQo!dp9^D?4v_~19uuXh68mc`WZ~}5f5Pty!E2|LVn~v`y z#P})`W?>}5+pJTkWR8y#6po8276pVKl%~%{hncS_t<`9pJyxS=d{R=>I8|Y8faOsh zf2C1B-ilFq>;M~R#SrVnlJHUt6j(j`aVFb=$psGJ;#!GSP^ljDGj|q&P)dYXVLJF@ zNu=EVMd^toap|voUI&lo1XyYn#(!tLCtzGucr|i3VC*Jy#B=}!tnQ^}2C(?ZvlQ<^ z8+bYw6A15WzVZyO#(rY6tjhu+Oss}-(G+g7Fq-R<3%k0Kl|Oicg=It&kFeC9RF5q2!DYC zM>$+(+#vUr;U5qB*FbQ`^Kt{`H~~LCD_q&Bfe$iVWA3%+V#kj_@Aw!Cu0^$u$ATGf zYQkfeAMpvEK27-Wm6W#@;;|Mjy*9$ruPo(Xt#ixvjoapwm9Libw*tN>3$&qpwVZy$ z%kpVq{Klldw0yNu7H>oOYDcK=T4+gu?^3OU(u?nC^-(*#``W!5ckSJLn*@%Mo6Bf^ za`BavUyCr`I?$`B`jYg@31u0*fRC;Ny;{FOSB7thCD%b2tgHG0*wN_KhI)cPr+X`- z(>s_qh~n$2`XqTqfZ)s7sdwyY-!*6Fo^5-U7m1^u909+{`hcI_S*$2Nx{2HCL7%Xa z2aXc<86oCA5A+!+iC@w;!AJgb`i#&u``YKoDq5azjz&VJFU61hq|QTgoZy%7PI7aZ z37q}q&Cy72-yOMzp3Na^v^@R^E}6ar|AZiOolp2vMe&)5g8s7ZWI}MyHJ$kk?x>1V zI?&Twl-};HCV+n6pFPnp<9W}T%S=p>KWEAHfhE@u8Nd&nkM3{c2=q?G4J8*4KGj?# zzDfSd_y8Zd0QEO9LGk!X%0F?CB?#XnE>DOT<7j45ih#@M1ALb7O>$E_z7l+sAP*O! zJDM~g^7sg^;H@zl@jVtLrC!IX#mGBb&F+;n$q_w7hef|b*S(4#@yL;DIRNgPxT|TC%{M6qdw|JsNcFl*0&z=Qy(nB$LptD z{_6(!U9~+jXLoxi4I9gC`KkBF^dWY7=8zuA*HKM3d1yK}%tLXdBvhy`#7zb8Y!f$!1=KViZr`OzTcyNn-` z2dTf@*1o%a@Al0F{iQfIh4dx(8zA48fFBJhLXJxgb1nxv{KLc<<%L+(K=1n$n-73TM;Vb46t`!&hMCkk1b9tRi`1 ztgM*X5z+@YR3cko(btRTuCnXqcd10V(rJ-ZXEo?N`sOwtrd{yFXsMZ_fBFoZkr7GS``5OQo71A|K zi&joYH4S*11^J@&Yy?HqaqHnm2v!p;xw#81DDmRY8#i;+t!J~*Qf&&%r^6Hm_sFRy+cU^HifH7JEQeBNDX`S%sR>%!Vl<9wVh0x+ z^%a=bf!Io99*b$|Ek|XVtNs58(@Zd#Ua3vZfr6IaQ&V<;83cN^LTpZfZT#=Bq|Y=B z3yz$UW*rnU(`2!&=(s%Co`XBv6QFo}au(+CkSA{_RKr^oE-MrE334%Q+b3ice2q(_ zBfSZW(~WL19H6&Qlw znB}H;e3E`JK>H>%`?WvUj-Qe71Su+K9_Qw+?JuBKyMd_f7jT8tcA%S|m0)qW#%#qU zIkwG(YN!J`rrDfoq?NhPmihhEFYwW=W81M)IlGVi_!L}}JUO!fF1#J0Gn<#*hNIzt zo){);faG?rK}l~n>PC%YckVG}vhh2pw_@%ckcOM%EOjrv)vgSfJ_w5}fC6bIu^Vmb+zAQcDruP=<$im=>!+shLnW2|Ei5QW&ayj<*7>E@*g26f zqZpx-V&w=hs|SLHkq{sQ^D0<@&ElNPsbdaitK_gDDMw3>dOYU`co{3-3bfY;m&im(W^Up!Ms(hTYRU4XvRiEP-Y2 zKZ=r{k33l*tNGD@?RV{l{go-ad99rCv(RqHb_?w1HsEIeOiMsS&_>&COeDR2^5c`j z>J{-+=jLvq$A%fsWKKFNCP|>SRVwjB?wSW7qe48PNqj7c=LC&Kwmm7aj^eXy7{Lz1 z%STyx5;^$f zEO$YeMJap%uUdrXt1fx9v21=mJtabMTzlK0IalvgWfp`e9G_&y0xxs#MSEK?zzycadK(8Z$UU+80f+#hBG+#hAxz2NpjoI2S@E=JIOc>ern*BBZ*a5^9NVhE@- z7?Dj?wIt9wkuCov9>)UTvimsS_z}$Io!nR@(21;}r;c<&zuGSduBv6}e=iu*!J%X) zWb{)doETw_l=+mGWjmqZUlf)2B#%C6#g};KS zBVKl2)U;@T;_=D+)W(6DG=KwS!|+LM5A6J~!Qj0X6S>7vj@`yzT7KaFqz5*uV}yzu zC|w5`xCELKxWReCjbR|#04N|e`qMKE=a)=u;*f$Q{9b=c9p$=;vvSPNEawwf*gMb*^uGL ziB)5GLwh{r`e0DNkRS3ANEuJWOjB zc1$!;TY7p-(lH=hd%t}QPTX8YVf5uP<#3FqPP5CyMT)91o$Wh!%HKRa3*G<$__PZ{ zC7E8_0PDkKAgUsxQVWXVW zWS09_d?i`3+=SgNzm%8VA^wgoVABinP<$pIF7gz@j^9@ZKLDdQ87;1u@H#c&ZZ~B# z%O$mX%9=mR+Zt4qXg6d1KQk<#Mh|f}^JXmJBs2{; z`Rht@na!d^nZ1M?649EFZdAH4T=0O~Rn9iWEi0{fT=o`PPo-phoLqd>Ec-t=XUlKu zK-bcWtMWgOrOcTk)>c4WYX;X{aN(St+xK-ADS}qP(gW~IR|RAOIjLV4I&1ZcRTbbP z#c&+pip9TZ9H6&O{j@q* z3y#4x+FX=1K3UN;=+adaJ__UO12Q|dFT+>nvczx8wL;;g=USW!eY0Khx&lw{dHG=k<|xUZb|su8q?Pm;&-CUo|yXy(df{v}ZJa z^|*IGUknHLLnEfZQ0fT$#5BxvC$hWu8x6)mzsUPsCwFP0<9!;#`hgzJ$==y-c$Nl3 z6oXIXZeQMo)1EkTy~SP#1UXj<;GjXf6I2F=d1^a-w2O7!iOM<8%@R2O+#o41M+vTG z)&vMXN2V3ow=oXBdMC!g^Kd258(Isy^GR6GT^To=Y8Fvt3TV_7r~9I~p(~4tDxP!B zJW3AfI5)~mZ@~yQ{w^cvI4{k@cY${>@wp4jF0i!!E}TvVEeu>)7SWw-?w6re7-ar0 zBWZ{wU&Uz%bzVbG#4>AxbU>UP_%a6Q3tTMd#-MfN%f>96sqL|tUo2+4s_JR7F;>w8rzp|gle>u0LQ1YJP* zYp}MB6N((DWJt(5}h#gPe+*JQZT?xgJZ-b6~W!0sLo2zG}D~7ln?Q-&fJ} z|5Idy3|Z`JSmRwZ_=%GJSBIh#uY^KkE{>>VvJZ&#(CF7CN>NbA$U9o&Y`fMI0*mC8 z(q%y5CelHXn(g7OMPtYWt;5S8wko+okJb}Hysa=+jZPi$!C)R|sDg`!i|X`M%KvJXPcHH&Ko&V!S%+UPfuS?8~y-?{q_^_cFxAO`sved^}J9Llt8Xm{SD5>+Ha@!aa^gZKb!30L|jVAf=$!f+* zH=00e!+ISjG$*o??$&DT*PBVHjAd}4Kbrs#@+(C=C<@+e@-Q!4<0o;#oKqIn=yh56 zK0YPEo);Ek_Zib1o3bp4uoV#jD)r#FZb10urkA=uK;2%71M)oH8j}!k(6M03Kj~C? zGaLodm&pD6^$Y%&Io0#hkx=i1mLP?Q%<>gh#vnHsAKq?ne-V%0-pMkxGhzN6+V*NH-9 z+T)SE?U9Xp+ixQ{d{O$B%e2Rs_dDn-pe{vONAvXx%^0_uB7SR1y5bhR%vNy=p7%9e z@U#Q7#Rov+HUc5O;3~!kut44BVzCDxTHE~G6mv>uo0|hv(!i&_NAmQ5;dRUpGVg=N zOf^{;OJNC}olz>}R}q4;{{5$KdY&g)PXgFva7O z1yJ#$5)_y#xXJ(f!AFsaV;79*NXs(qNo}lcE39n!l|Jn$wAKRyV2aI~r3DGs9 z0;xS9j5>`1F-0QGaBJ{-FWtC z0OQg_QM=lA?b&-h{o={E)BtQy`jbq19Bp@>Q~FKje;ku&rH9z(<~LY6=$2UO4?5if zPK>1RJ4Ii&FMQXHK^A-h-CU<%f@rMk383zjtm(vSflnB%HJvFLA7#UccSL%bbt#^F zUGSta!FV`Ek@)gb9eT20a6|tWeF`nf$&ycE$i7AZD{vYHu$Ncqv9+G>8Pg_9o-G}q zWH~F^#a$D93yjt==l>ph)@!1qM#e7lHJlVav!j)#(>$8S~rE_6UE4k6?}8_OyY&3HY0cze)J3`~I@0>yM9p se~jOC^YrTP5w6_e=f3*=_(s>^QKM2UyxFxJBZ9ukIfeajv+Lvk4P*oLBme*a delta 81236 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�rwy#LZ_nrHlM6HYcu`D$P}Y~I>daZ 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 Date: Fri, 8 Feb 2013 21:22:14 +0100 Subject: [PATCH 0963/1634] error: Clean up error strings with embedded newlines The arguments of error_report() should yield a short error string without newlines. A few places try to print additional help after the error message by embedding newlines in the error string. That's nice, but let's do it the right way. Since I'm touching these lines anyway, drop a stray preposition and some tabs. We don't use tabs for similar messages elsewhere. Signed-off-by: Markus Armbruster Message-id: 1360354939-10994-2-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- hw/kvm/pci-assign.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c index 896cfe8a59..da64b5b86f 100644 --- a/hw/kvm/pci-assign.c +++ b/hw/kvm/pci-assign.c @@ -936,8 +936,8 @@ retry: /* Retry with host-side MSI. There might be an IRQ conflict and * either the kernel or the device doesn't support sharing. */ error_report("Host-side INTx sharing not supported, " - "using MSI instead.\n" - "Some devices do not to work properly in this mode."); + "using MSI instead"); + error_printf("Some devices do not work properly in this mode.\n"); dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK; goto retry; } @@ -1903,10 +1903,10 @@ static void assigned_dev_load_option_rom(AssignedDevice *dev) memset(ptr, 0xff, st.st_size); if (!fread(ptr, 1, st.st_size, fp)) { - error_report("pci-assign: Cannot read from host %s\n" - "\tDevice option ROM contents are probably invalid " - "(check dmesg).\n\tSkip option ROM probe with rombar=0, " - "or load from file with romfile=", rom_file); + error_report("pci-assign: Cannot read from host %s", rom_file); + error_printf("Device option ROM contents are probably invalid " + "(check dmesg).\nSkip option ROM probe with rombar=0, " + "or load from file with romfile=\n"); memory_region_destroy(&dev->dev.rom); goto close_rom; } From 1a9522cc6ea04968e1169f0195952d0029d5dbb9 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 8 Feb 2013 21:22:15 +0100 Subject: [PATCH 0964/1634] error: Clean up abuse of error_report() for help Use error_printf() instead, so the help gets presented more nicely. Signed-off-by: Markus Armbruster Message-id: 1360354939-10994-3-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- hw/vfio_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 66537b7eb5..a934f1308e 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -1806,9 +1806,9 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name); if (ret < 0) { - error_report("vfio: error getting device %s from group %d: %m\n", + error_report("vfio: error getting device %s from group %d: %m", name, group->groupid); - error_report("Verify all devices in group %d are bound to vfio-pci " + error_printf("Verify all devices in group %d are bound to vfio-pci " "or pci-stub and not already in use\n", group->groupid); return ret; } From 312fd5f29097890179793d8bbb59ab18afbe0ad4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 8 Feb 2013 21:22:16 +0100 Subject: [PATCH 0965/1634] error: Strip trailing '\n' from error string arguments (again) Commit 6daf194d and be62a2eb got rid of a bunch, but they keep coming back. Tracked down with this Coccinelle semantic patch: @r@ expression err, eno, cls, fmt; position p; @@ ( error_report(fmt, ...)@p | error_set(err, cls, fmt, ...)@p | error_set_errno(err, eno, cls, fmt, ...)@p | error_setg(err, fmt, ...)@p | error_setg_errno(err, eno, fmt, ...)@p ) @script:python@ fmt << r.fmt; p << r.p; @@ if "\\n" in str(fmt): print "%s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt) Signed-off-by: Markus Armbruster Message-id: 1360354939-10994-4-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- block/gluster.c | 2 +- hmp.c | 2 +- hw/9pfs/virtio-9p-proxy.c | 2 +- hw/pci/pci.c | 2 +- hw/qdev.c | 4 +- hw/qxl.c | 2 +- hw/vfio_pci.c | 110 ++++++++++++++++++------------------ hw/vhost_net.c | 4 +- migration.c | 2 +- qemu-char.c | 8 +-- target-i386/cpu.c | 10 ++-- target-ppc/translate_init.c | 2 +- ui/console.c | 2 +- ui/input.c | 2 +- util/qemu-config.c | 6 +- util/qemu-sockets.c | 6 +- 16 files changed, 83 insertions(+), 83 deletions(-) diff --git a/block/gluster.c b/block/gluster.c index 0f2c32a3fa..ccd684d360 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -217,7 +217,7 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename) ret = glfs_init(glfs); if (ret) { error_report("Gluster connection failed for server=%s port=%d " - "volume=%s image=%s transport=%s\n", gconf->server, gconf->port, + "volume=%s image=%s transport=%s", gconf->server, gconf->port, gconf->volname, gconf->image, gconf->transport); goto out; } diff --git a/hmp.c b/hmp.c index 420d48bea6..2f47a8a9dd 100644 --- a/hmp.c +++ b/hmp.c @@ -1365,7 +1365,7 @@ void hmp_chardev_add(Monitor *mon, const QDict *qdict) opts = qemu_opts_parse(qemu_find_opts("chardev"), args, 1); if (opts == NULL) { - error_setg(&err, "Parsing chardev args failed\n"); + error_setg(&err, "Parsing chardev args failed"); } else { qemu_chr_new_from_opts(opts, NULL, &err); } diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index d5ad208d00..54e98759f0 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -521,7 +521,7 @@ static int v9fs_request(V9fsProxy *proxy, int type, } break; default: - error_report("Invalid type %d\n", type); + error_report("Invalid type %d", type); retval = -EINVAL; break; } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 905dc4a219..2f45c8f02f 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1132,7 +1132,7 @@ PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin) } while (dev); if (!bus->route_intx_to_irq) { - error_report("PCI: Bug - unimplemented PCI INTx routing (%s)\n", + error_report("PCI: Bug - unimplemented PCI INTx routing (%s)", object_get_typename(OBJECT(bus->qbus.parent))); return (PCIINTxRoute) { PCI_INTX_DISABLED, -1 }; } diff --git a/hw/qdev.c b/hw/qdev.c index 8258757a1d..689cd543e9 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -114,11 +114,11 @@ DeviceState *qdev_create(BusState *bus, const char *name) dev = qdev_try_create(bus, name); if (!dev) { if (bus) { - error_report("Unknown device '%s' for bus '%s'\n", name, + error_report("Unknown device '%s' for bus '%s'", name, object_get_typename(OBJECT(bus))); abort(); } else { - error_report("Unknown device '%s' for default sysbus\n", name); + error_report("Unknown device '%s' for default sysbus", name); abort(); } } diff --git a/hw/qxl.c b/hw/qxl.c index a125e294aa..2e1c5e225b 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -2036,7 +2036,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) qxl->ssd.qxl.base.sif = &qxl_interface.base; qxl->ssd.qxl.id = qxl->id; if (qemu_spice_add_interface(&qxl->ssd.qxl.base) != 0) { - error_report("qxl interface %d.%d not supported by spice-server\n", + error_report("qxl interface %d.%d not supported by spice-server", SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR); return -1; } diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index a934f1308e..ad9ae360b2 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -289,7 +289,7 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev) /* Get an eventfd for resample/unmask */ if (event_notifier_init(&vdev->intx.unmask, 0)) { - error_report("vfio: Error: event_notifier_init failed eoi\n"); + error_report("vfio: Error: event_notifier_init failed eoi"); goto fail; } @@ -297,7 +297,7 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev) irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask); if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { - error_report("vfio: Error: Failed to setup resample irqfd: %m\n"); + error_report("vfio: Error: Failed to setup resample irqfd: %m"); goto fail_irqfd; } @@ -316,7 +316,7 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev) ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); g_free(irq_set); if (ret) { - error_report("vfio: Error: Failed to setup INTx unmask fd: %m\n"); + error_report("vfio: Error: Failed to setup INTx unmask fd: %m"); goto fail_vfio; } @@ -365,7 +365,7 @@ static void vfio_disable_intx_kvm(VFIODevice *vdev) /* Tell KVM to stop listening for an INTx irqfd */ if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) { - error_report("vfio: Error: Failed to disable INTx irqfd: %m\n"); + error_report("vfio: Error: Failed to disable INTx irqfd: %m"); } /* We only need to close the eventfd for VFIO to cleanup the kernel side */ @@ -447,7 +447,7 @@ static int vfio_enable_intx(VFIODevice *vdev) ret = event_notifier_init(&vdev->intx.interrupt, 0); if (ret) { - error_report("vfio: Error: event_notifier_init failed\n"); + error_report("vfio: Error: event_notifier_init failed"); return ret; } @@ -467,7 +467,7 @@ static int vfio_enable_intx(VFIODevice *vdev) ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); g_free(irq_set); if (ret) { - error_report("vfio: Error: Failed to setup INTx fd: %m\n"); + error_report("vfio: Error: Failed to setup INTx fd: %m"); qemu_set_fd_handler(*pfd, NULL, NULL, vdev); event_notifier_cleanup(&vdev->intx.interrupt); return -errno; @@ -526,7 +526,7 @@ static void vfio_msi_interrupt(void *opaque) } else if (vdev->interrupt == VFIO_INT_MSI) { msi_notify(&vdev->pdev, nr); } else { - error_report("vfio: MSI interrupt receieved, but not enabled?\n"); + error_report("vfio: MSI interrupt receieved, but not enabled?"); } } @@ -580,7 +580,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, msix_vector_use(pdev, nr); if (event_notifier_init(&vector->interrupt, 0)) { - error_report("vfio: Error: event_notifier_init failed\n"); + error_report("vfio: Error: event_notifier_init failed"); } /* @@ -609,7 +609,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, vdev->nr_vectors = nr + 1; ret = vfio_enable_vectors(vdev, true); if (ret) { - error_report("vfio: failed to enable vectors, %d\n", ret); + error_report("vfio: failed to enable vectors, %d", ret); } } else { int argsz; @@ -632,7 +632,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set); g_free(irq_set); if (ret) { - error_report("vfio: failed to modify vector, %d\n", ret); + error_report("vfio: failed to modify vector, %d", ret); } } @@ -721,7 +721,7 @@ static void vfio_enable_msix(VFIODevice *vdev) if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use, vfio_msix_vector_release, NULL)) { - error_report("vfio: msix_set_vector_notifiers failed\n"); + error_report("vfio: msix_set_vector_notifiers failed"); } DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain, @@ -746,7 +746,7 @@ retry: vector->use = true; if (event_notifier_init(&vector->interrupt, 0)) { - error_report("vfio: Error: event_notifier_init failed\n"); + error_report("vfio: Error: event_notifier_init failed"); } msg = msi_get_message(&vdev->pdev, i); @@ -767,10 +767,10 @@ retry: ret = vfio_enable_vectors(vdev, false); if (ret) { if (ret < 0) { - error_report("vfio: Error: Failed to setup MSI fds: %m\n"); + error_report("vfio: Error: Failed to setup MSI fds: %m"); } else if (ret != vdev->nr_vectors) { error_report("vfio: Error: Failed to enable %d " - "MSI vectors, retry with %d\n", vdev->nr_vectors, ret); + "MSI vectors, retry with %d", vdev->nr_vectors, ret); } for (i = 0; i < vdev->nr_vectors; i++) { @@ -891,7 +891,7 @@ static void vfio_bar_write(void *opaque, hwaddr addr, } if (pwrite(bar->fd, &buf, size, bar->fd_offset + addr) != size) { - error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m\n", + error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m", __func__, addr, data, size); } @@ -922,7 +922,7 @@ static uint64_t vfio_bar_read(void *opaque, uint64_t data = 0; if (pread(bar->fd, &buf, size, bar->fd_offset + addr) != size) { - error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m\n", + error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m", __func__, addr, size); return (uint64_t)-1; } @@ -979,7 +979,7 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) val = pci_default_read_config(pdev, addr, len); } else { if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) { - error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m\n", + error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m", __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function, addr, len); return -errno; @@ -1021,7 +1021,7 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, /* Write everything to VFIO, let it filter out what we can't write */ if (pwrite(vdev->fd, &val_le, len, vdev->config_offset + addr) != len) { - error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m\n", + error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m", __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function, addr, val, len); } @@ -1138,7 +1138,7 @@ static void vfio_listener_region_add(MemoryListener *listener, if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != (section->offset_within_region & ~TARGET_PAGE_MASK))) { - error_report("%s received unaligned region\n", __func__); + error_report("%s received unaligned region", __func__); return; } @@ -1160,7 +1160,7 @@ static void vfio_listener_region_add(MemoryListener *listener, ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly); if (ret) { error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " - "0x%"HWADDR_PRIx", %p) = %d (%m)\n", + "0x%"HWADDR_PRIx", %p) = %d (%m)", container, iova, end - iova, vaddr, ret); } } @@ -1182,7 +1182,7 @@ static void vfio_listener_region_del(MemoryListener *listener, if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) != (section->offset_within_region & ~TARGET_PAGE_MASK))) { - error_report("%s received unaligned region\n", __func__); + error_report("%s received unaligned region", __func__); return; } @@ -1200,7 +1200,7 @@ static void vfio_listener_region_del(MemoryListener *listener, ret = vfio_dma_unmap(container, iova, end - iova); if (ret) { error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " - "0x%"HWADDR_PRIx") = %d (%m)\n", + "0x%"HWADDR_PRIx") = %d (%m)", container, iova, end - iova, ret); } } @@ -1257,7 +1257,7 @@ static int vfio_setup_msi(VFIODevice *vdev, int pos) if (ret == -ENOTSUP) { return 0; } - error_report("vfio: msi_init failed\n"); + error_report("vfio: msi_init failed"); return ret; } vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0); @@ -1332,7 +1332,7 @@ static int vfio_setup_msix(VFIODevice *vdev, int pos) if (ret == -ENOTSUP) { return 0; } - error_report("vfio: msix_init failed\n"); + error_report("vfio: msix_init failed"); return ret; } @@ -1448,7 +1448,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr) ret = pread(vdev->fd, &pci_bar, sizeof(pci_bar), vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr)); if (ret != sizeof(pci_bar)) { - error_report("vfio: Failed to read BAR %d (%m)\n", nr); + error_report("vfio: Failed to read BAR %d (%m)", nr); return; } @@ -1471,7 +1471,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr) strncat(name, " mmap", sizeof(name) - strlen(name) - 1); if (vfio_mmap_bar(bar, &bar->mem, &bar->mmap_mem, &bar->mmap, size, 0, name)) { - error_report("%s unsupported. Performance may be slow\n", name); + error_report("%s unsupported. Performance may be slow", name); } if (vdev->msix && vdev->msix->table_bar == nr) { @@ -1485,7 +1485,7 @@ static void vfio_map_bar(VFIODevice *vdev, int nr) /* VFIOMSIXInfo contains another MemoryRegion for this mapping */ if (vfio_mmap_bar(bar, &bar->mem, &vdev->msix->mmap_mem, &vdev->msix->mmap, size, start, name)) { - error_report("%s unsupported. Performance may be slow\n", name); + error_report("%s unsupported. Performance may be slow", name); } } } @@ -1572,7 +1572,7 @@ static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos) if (ret < 0) { error_report("vfio: %04x:%02x:%02x.%x Error adding PCI capability " - "0x%x[0x%x]@0x%x: %d\n", vdev->host.domain, + "0x%x[0x%x]@0x%x: %d", vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function, cap_id, size, pos, ret); return ret; @@ -1627,7 +1627,7 @@ static int vfio_load_rom(VFIODevice *vdev) if (errno == EINTR || errno == EAGAIN) { continue; } - error_report("vfio: Error reading device ROM: %m\n"); + error_report("vfio: Error reading device ROM: %m"); memory_region_destroy(&vdev->pdev.rom); return -errno; } @@ -1657,14 +1657,14 @@ static int vfio_connect_container(VFIOGroup *group) fd = qemu_open("/dev/vfio/vfio", O_RDWR); if (fd < 0) { - error_report("vfio: failed to open /dev/vfio/vfio: %m\n"); + error_report("vfio: failed to open /dev/vfio/vfio: %m"); return -errno; } ret = ioctl(fd, VFIO_GET_API_VERSION); if (ret != VFIO_API_VERSION) { error_report("vfio: supported vfio version: %d, " - "reported version: %d\n", VFIO_API_VERSION, ret); + "reported version: %d", VFIO_API_VERSION, ret); close(fd); return -EINVAL; } @@ -1675,7 +1675,7 @@ static int vfio_connect_container(VFIOGroup *group) if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) { ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd); if (ret) { - error_report("vfio: failed to set group container: %m\n"); + error_report("vfio: failed to set group container: %m"); g_free(container); close(fd); return -errno; @@ -1683,7 +1683,7 @@ static int vfio_connect_container(VFIOGroup *group) ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU); if (ret) { - error_report("vfio: failed to set iommu for container: %m\n"); + error_report("vfio: failed to set iommu for container: %m"); g_free(container); close(fd); return -errno; @@ -1694,7 +1694,7 @@ static int vfio_connect_container(VFIOGroup *group) memory_listener_register(&container->iommu_data.listener, &address_space_memory); } else { - error_report("vfio: No available IOMMU models\n"); + error_report("vfio: No available IOMMU models"); g_free(container); close(fd); return -EINVAL; @@ -1714,7 +1714,7 @@ static void vfio_disconnect_container(VFIOGroup *group) VFIOContainer *container = group->container; if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) { - error_report("vfio: error disconnecting group %d from container\n", + error_report("vfio: error disconnecting group %d from container", group->groupid); } @@ -1749,13 +1749,13 @@ static VFIOGroup *vfio_get_group(int groupid) snprintf(path, sizeof(path), "/dev/vfio/%d", groupid); group->fd = qemu_open(path, O_RDWR); if (group->fd < 0) { - error_report("vfio: error opening %s: %m\n", path); + error_report("vfio: error opening %s: %m", path); g_free(group); return NULL; } if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) { - error_report("vfio: error getting group status: %m\n"); + error_report("vfio: error getting group status: %m"); close(group->fd); g_free(group); return NULL; @@ -1764,7 +1764,7 @@ static VFIOGroup *vfio_get_group(int groupid) if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) { error_report("vfio: error, group %d is not viable, please ensure " "all devices within the iommu_group are bound to their " - "vfio bus driver.\n", groupid); + "vfio bus driver.", groupid); close(group->fd); g_free(group); return NULL; @@ -1774,7 +1774,7 @@ static VFIOGroup *vfio_get_group(int groupid) QLIST_INIT(&group->device_list); if (vfio_connect_container(group)) { - error_report("vfio: failed to setup container for group %d\n", groupid); + error_report("vfio: failed to setup container for group %d", groupid); close(group->fd); g_free(group); return NULL; @@ -1820,7 +1820,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) /* Sanity check device */ ret = ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &dev_info); if (ret) { - error_report("vfio: error getting device info: %m\n"); + error_report("vfio: error getting device info: %m"); goto error; } @@ -1828,23 +1828,23 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) dev_info.flags, dev_info.num_regions, dev_info.num_irqs); if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) { - error_report("vfio: Um, this isn't a PCI device\n"); + error_report("vfio: Um, this isn't a PCI device"); goto error; } vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET); if (!vdev->reset_works) { - error_report("Warning, device %s does not support reset\n", name); + error_report("Warning, device %s does not support reset", name); } if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) { - error_report("vfio: unexpected number of io regions %u\n", + error_report("vfio: unexpected number of io regions %u", dev_info.num_regions); goto error; } if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) { - error_report("vfio: unexpected number of irqs %u\n", dev_info.num_irqs); + error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs); goto error; } @@ -1853,7 +1853,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); if (ret) { - error_report("vfio: Error getting region %d info: %m\n", i); + error_report("vfio: Error getting region %d info: %m", i); goto error; } @@ -1873,7 +1873,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); if (ret) { - error_report("vfio: Error getting ROM info: %m\n"); + error_report("vfio: Error getting ROM info: %m"); goto error; } @@ -1889,7 +1889,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); if (ret) { - error_report("vfio: Error getting config info: %m\n"); + error_report("vfio: Error getting config info: %m"); goto error; } @@ -1941,7 +1941,7 @@ static int vfio_initfn(PCIDevice *pdev) vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function); if (stat(path, &st) < 0) { - error_report("vfio: error: no such host device: %s\n", path); + error_report("vfio: error: no such host device: %s", path); return -errno; } @@ -1949,7 +1949,7 @@ static int vfio_initfn(PCIDevice *pdev) len = readlink(path, iommu_group_path, PATH_MAX); if (len <= 0) { - error_report("vfio: error no iommu_group for device\n"); + error_report("vfio: error no iommu_group for device"); return -errno; } @@ -1957,7 +1957,7 @@ static int vfio_initfn(PCIDevice *pdev) group_name = basename(iommu_group_path); if (sscanf(group_name, "%d", &groupid) != 1) { - error_report("vfio: error reading %s: %m\n", path); + error_report("vfio: error reading %s: %m", path); return -errno; } @@ -1966,7 +1966,7 @@ static int vfio_initfn(PCIDevice *pdev) group = vfio_get_group(groupid); if (!group) { - error_report("vfio: failed to get group %d\n", groupid); + error_report("vfio: failed to get group %d", groupid); return -ENOENT; } @@ -1980,7 +1980,7 @@ static int vfio_initfn(PCIDevice *pdev) pvdev->host.slot == vdev->host.slot && pvdev->host.function == vdev->host.function) { - error_report("vfio: error: device %s is already attached\n", path); + error_report("vfio: error: device %s is already attached", path); vfio_put_group(group); return -EBUSY; } @@ -1988,7 +1988,7 @@ static int vfio_initfn(PCIDevice *pdev) ret = vfio_get_device(group, path, vdev); if (ret) { - error_report("vfio: failed to get device %s\n", path); + error_report("vfio: failed to get device %s", path); vfio_put_group(group); return ret; } @@ -1999,7 +1999,7 @@ static int vfio_initfn(PCIDevice *pdev) vdev->config_offset); if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) { ret = ret < 0 ? -errno : -EFAULT; - error_report("vfio: Failed to read device config space\n"); + error_report("vfio: Failed to read device config space"); goto out_put; } @@ -2086,7 +2086,7 @@ static void vfio_pci_reset(DeviceState *dev) if (vdev->reset_works) { if (ioctl(vdev->fd, VFIO_DEVICE_RESET)) { error_report("vfio: Error unable to reset physical device " - "(%04x:%02x:%02x.%x): %m\n", vdev->host.domain, + "(%04x:%02x:%02x.%x): %m", vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function); } } diff --git a/hw/vhost_net.c b/hw/vhost_net.c index 8693ac27f6..d1df0e2447 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -214,7 +214,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, int r, i = 0; if (!dev->binding->set_guest_notifiers) { - error_report("binding does not support guest notifiers\n"); + error_report("binding does not support guest notifiers"); r = -ENOSYS; goto err; } @@ -231,7 +231,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, total_queues * 2, true); if (r < 0) { - error_report("Error binding guest notifier: %d\n", -r); + error_report("Error binding guest notifier: %d", -r); goto err; } diff --git a/migration.c b/migration.c index 77c1971b77..c4589b16f8 100644 --- a/migration.c +++ b/migration.c @@ -85,7 +85,7 @@ void qemu_start_incoming_migration(const char *uri, Error **errp) fd_start_incoming_migration(p, errp); #endif else { - error_setg(errp, "unknown migration protocol: %s\n", uri); + error_setg(errp, "unknown migration protocol: %s", uri); } } diff --git a/qemu-char.c b/qemu-char.c index a3ba02127f..574d3d292f 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3021,12 +3021,12 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, int i; if (qemu_opts_id(opts) == NULL) { - error_setg(errp, "chardev: no id specified\n"); + error_setg(errp, "chardev: no id specified"); goto err; } if (qemu_opt_get(opts, "backend") == NULL) { - error_setg(errp, "chardev: \"%s\" missing backend\n", + error_setg(errp, "chardev: \"%s\" missing backend", qemu_opts_id(opts)); goto err; } @@ -3035,14 +3035,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, break; } if (i == ARRAY_SIZE(backend_table)) { - error_setg(errp, "chardev: backend \"%s\" not found\n", + error_setg(errp, "chardev: backend \"%s\" not found", qemu_opt_get(opts, "backend")); goto err; } chr = backend_table[i].open(opts); if (!chr) { - error_setg(errp, "chardev: opening backend \"%s\" failed\n", + error_setg(errp, "chardev: opening backend \"%s\" failed", qemu_opt_get(opts, "backend")); goto err; } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 5c108e17ab..aab35c74d9 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1333,7 +1333,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) numvalue = strtoul(val, &err, 0); if (!*val || *err) { - error_setg(errp, "bad numerical value %s\n", val); + error_setg(errp, "bad numerical value %s", val); goto out; } if (numvalue < 0x80000000) { @@ -1355,7 +1355,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) tsc_freq = strtosz_suffix_unit(val, &err, STRTOSZ_DEFSUFFIX_B, 1000); if (tsc_freq < 0 || *err) { - error_setg(errp, "bad numerical value %s\n", val); + error_setg(errp, "bad numerical value %s", val); goto out; } snprintf(num, sizeof(num), "%" PRId64, tsc_freq); @@ -1364,12 +1364,12 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) char *err; numvalue = strtoul(val, &err, 0); if (!*val || *err) { - error_setg(errp, "bad numerical value %s\n", val); + error_setg(errp, "bad numerical value %s", val); goto out; } hyperv_set_spinlock_retries(numvalue); } else { - error_setg(errp, "unrecognized feature %s\n", featurestr); + error_setg(errp, "unrecognized feature %s", featurestr); goto out; } } else if (!strcmp(featurestr, "check")) { @@ -1382,7 +1382,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) hyperv_enable_vapic_recommended(true); } else { error_setg(errp, "feature string `%s' not in format (+feature|" - "-feature|feature=xyz)\n", featurestr); + "-feature|feature=xyz)", featurestr); goto out; } if (error_is_set(errp)) { diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f0388508bc..6cebaa1982 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9806,7 +9806,7 @@ static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) ((opc->handler.type2 & def->insns_flags2) != 0)) { if (register_insn(env->opcodes, opc) < 0) { error_setg(errp, "ERROR initializing PowerPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + "0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2, opc->opc3); return; } diff --git a/ui/console.c b/ui/console.c index d880ebff07..0a68836d50 100644 --- a/ui/console.c +++ b/ui/console.c @@ -194,7 +194,7 @@ void qmp_screendump(const char *filename, Error **errp) if (consoles[0] && consoles[0]->hw_screen_dump) { consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp); } else { - error_setg(errp, "device doesn't support screendump\n"); + error_setg(errp, "device doesn't support screendump"); } if (cswitch) { diff --git a/ui/input.c b/ui/input.c index 259fd1808d..9abef0cd78 100644 --- a/ui/input.c +++ b/ui/input.c @@ -269,7 +269,7 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, /* key down events */ keycode = keycode_from_keyvalue(p->value); if (keycode < 0x01 || keycode > 0xff) { - error_setg(errp, "invalid hex keycode 0x%x\n", keycode); + error_setg(errp, "invalid hex keycode 0x%x", keycode); free_keycodes(); return; } diff --git a/util/qemu-config.c b/util/qemu-config.c index 47c81f72d3..db6ec03a78 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -29,7 +29,7 @@ QemuOptsList *qemu_find_opts(const char *group) ret = find_list(vm_config_groups, group, &local_err); if (error_is_set(&local_err)) { - error_report("%s\n", error_get_pretty(local_err)); + error_report("%s", error_get_pretty(local_err)); error_free(local_err); } @@ -153,7 +153,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) /* group with id */ list = find_list(lists, group, &local_err); if (error_is_set(&local_err)) { - error_report("%s\n", error_get_pretty(local_err)); + error_report("%s", error_get_pretty(local_err)); error_free(local_err); goto out; } @@ -164,7 +164,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) /* group without id */ list = find_list(lists, group, &local_err); if (error_is_set(&local_err)) { - error_report("%s\n", error_get_pretty(local_err)); + error_report("%s", error_get_pretty(local_err)); error_free(local_err); goto out; } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 3537bf3d45..1350cccce3 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -720,7 +720,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, int sock, rc; if (NULL == path) { - error_setg(errp, "unix connect: no path specified\n"); + error_setg(errp, "unix connect: no path specified"); return -1; } @@ -854,7 +854,7 @@ SocketAddress *socket_parse(const char *str, Error **errp) addr = g_new(SocketAddress, 1); if (strstart(str, "unix:", NULL)) { if (str[5] == '\0') { - error_setg(errp, "invalid Unix socket address\n"); + error_setg(errp, "invalid Unix socket address"); goto fail; } else { addr->kind = SOCKET_ADDRESS_KIND_UNIX; @@ -863,7 +863,7 @@ SocketAddress *socket_parse(const char *str, Error **errp) } } else if (strstart(str, "fd:", NULL)) { if (str[3] == '\0') { - error_setg(errp, "invalid file descriptor address\n"); + error_setg(errp, "invalid file descriptor address"); goto fail; } else { addr->kind = SOCKET_ADDRESS_KIND_FD; From 7216ae3d1a11e07192623ad04d450e98bf1f3d10 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 8 Feb 2013 21:22:17 +0100 Subject: [PATCH 0966/1634] qemu-option: Disable two helpful messages that got broken recently commit 8be7e7e4 and commit ec7b2ccb messed up the ordering of error message and the helpful explanation that should follow it, like this: $ qemu-system-x86_64 --nodefaults -S --vnc :0 --chardev null,id=, Identifiers consist of letters, digits, '-', '.', '_', starting with a letter. qemu-system-x86_64: -chardev null,id=,: Parameter 'id' expects an identifier $ qemu-system-x86_64 --nodefaults -S --vnc :0 --machine kvm_shadow_mem=dunno You may use k, M, G or T suffixes for kilobytes, megabytes, gigabytes and terabytes. qemu-system-x86_64: -machine kvm_shadow_mem=dunno: Parameter 'kvm_shadow_mem' expects a size Pity. Disable them for now. Signed-off-by: Markus Armbruster Message-id: 1360354939-10994-5-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- util/qemu-option.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/qemu-option.c b/util/qemu-option.c index c12e7245ef..5a1d03c331 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -231,8 +231,10 @@ static void parse_option_size(const char *name, const char *value, break; default: error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size"); +#if 0 /* conversion from qerror_report() to error_set() broke this: */ error_printf_unless_qmp("You may use k, M, G or T suffixes for " "kilobytes, megabytes, gigabytes and terabytes.\n"); +#endif return; } } else { @@ -771,7 +773,9 @@ QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, if (id) { if (!id_wellformed(id)) { error_set(errp,QERR_INVALID_PARAMETER_VALUE, "id", "an identifier"); +#if 0 /* conversion from qerror_report() to error_set() broke this: */ error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n"); +#endif return NULL; } opts = qemu_opts_find(list, id); From cfdd1628666f1342925f9c77cbb63b7d6d049dae Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 8 Feb 2013 21:22:18 +0100 Subject: [PATCH 0967/1634] vl: Drop redundant "parse error" reports qemu_opts_parse() reports the error already, and in a much more useful way. Signed-off-by: Markus Armbruster Message-id: 1360354939-10994-6-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- vl.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vl.c b/vl.c index a8dc73d61d..73122d8716 100644 --- a/vl.c +++ b/vl.c @@ -3334,7 +3334,6 @@ int main(int argc, char **argv, char **envp) } opts = qemu_opts_parse(olist, optarg, 1); if (!opts) { - fprintf(stderr, "parse error: %s\n", optarg); exit(1); } break; @@ -3350,7 +3349,6 @@ int main(int argc, char **argv, char **envp) } opts = qemu_opts_parse(olist, optarg, 1); if (!opts) { - fprintf(stderr, "parse error: %s\n", optarg); exit(1); } @@ -3521,7 +3519,6 @@ int main(int argc, char **argv, char **envp) olist = qemu_find_opts("machine"); opts = qemu_opts_parse(olist, optarg, 1); if (!opts) { - fprintf(stderr, "parse error: %s\n", optarg); exit(1); } optarg = qemu_opt_get(opts, "type"); @@ -3755,7 +3752,6 @@ int main(int argc, char **argv, char **envp) } opts = qemu_opts_parse(olist, optarg, 0); if (!opts) { - fprintf(stderr, "parse error: %s\n", optarg); exit(1); } break; From 49295ebc56a303a60c6ca2ead6f548eae3521150 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 8 Feb 2013 21:22:19 +0100 Subject: [PATCH 0968/1634] vl: Exit unsuccessfully on option argument syntax error We exit successfully after reporting syntax error for argument of --sandbox and --add-fd. We continue undaunted after reporting it for argument of -boot, --option-rom and --object. Change all five to exit unsuccessfully, like the other options. Signed-off-by: Markus Armbruster Message-id: 1360354939-10994-7-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- vl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/vl.c b/vl.c index 73122d8716..1355f6959e 100644 --- a/vl.c +++ b/vl.c @@ -3135,8 +3135,10 @@ int main(int argc, char **argv, char **envp) exit(1); } } - qemu_opts_parse(qemu_find_opts("boot-opts"), - optarg, 0); + if (!qemu_opts_parse(qemu_find_opts("boot-opts"), + optarg, 0)) { + exit(1); + } } } break; @@ -3623,6 +3625,9 @@ int main(int argc, char **argv, char **envp) exit(1); } opts = qemu_opts_parse(qemu_find_opts("option-rom"), optarg, 1); + if (!opts) { + exit(1); + } option_rom[nb_option_roms].name = qemu_opt_get(opts, "romfile"); option_rom[nb_option_roms].bootindex = qemu_opt_get_number(opts, "bootindex", -1); @@ -3780,14 +3785,14 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_sandbox: opts = qemu_opts_parse(qemu_find_opts("sandbox"), optarg, 1); if (!opts) { - exit(0); + exit(1); } break; case QEMU_OPTION_add_fd: #ifndef _WIN32 opts = qemu_opts_parse(qemu_find_opts("add-fd"), optarg, 0); if (!opts) { - exit(0); + exit(1); } #else error_report("File descriptor passing is disabled on this " @@ -3797,6 +3802,9 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_object: opts = qemu_opts_parse(qemu_find_opts("object"), optarg, 1); + if (!opts) { + exit(1); + } break; default: os_parse_cmd_args(popt->index, optarg); From d5f1f286ef8c7c96614779a40af724d7109175d5 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 10 Feb 2013 23:12:44 +0100 Subject: [PATCH 0969/1634] block-migration: improve "Unknown flags" error message Show the actual flags value and include "block migration" in the error message so it's clear where the error is coming from. Signed-off-by: Stefan Hajnoczi Message-id: 1360534366-26723-2-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- block-migration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block-migration.c b/block-migration.c index 9ac7de6d78..573319a305 100644 --- a/block-migration.c +++ b/block-migration.c @@ -695,7 +695,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) (addr == 100) ? '\n' : '\r'); fflush(stdout); } else if (!(flags & BLK_MIG_FLAG_EOS)) { - fprintf(stderr, "Unknown flags\n"); + fprintf(stderr, "Unknown block migration flags: %#x\n", flags); return -EINVAL; } ret = qemu_file_get_error(f); From 9ee0cb201e6bfe03549a649fd165a85cfed34d05 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 10 Feb 2013 23:12:45 +0100 Subject: [PATCH 0970/1634] block-migration: fix blk_mig_save_dirty_block() return value checking Commit 43be3a25c931a7f61a76fbfc9d35584cbfc5fb58 changed the blk_mig_save_dirty_block() return code handling. The function's doc comment says: /* return value: * 0: too much data for max_downtime * 1: few enough data for max_downtime */ Because of the 1 return value, callers must check for ret < 0 instead of just: if (ret) { ... } We do not want to bail when 1 is returned, only on error. Signed-off-by: Stefan Hajnoczi Message-id: 1360534366-26723-3-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- block-migration.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block-migration.c b/block-migration.c index 573319a305..a91d96be5e 100644 --- a/block-migration.c +++ b/block-migration.c @@ -569,7 +569,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque) } } } - if (ret) { + if (ret < 0) { blk_mig_cleanup(); return ret; } @@ -609,7 +609,7 @@ static int block_save_complete(QEMUFile *f, void *opaque) } while (ret == 0); blk_mig_cleanup(); - if (ret) { + if (ret < 0) { return ret; } /* report completion */ From 2c5a7f20112615ce13a3434ab90bee1ed8d44ebd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Sun, 10 Feb 2013 23:12:46 +0100 Subject: [PATCH 0971/1634] block-migration: fix block_save_iterate() return value The .save_live_iterate() function returns 0 to continue iterating or 1 to stop iterating. Since 16310a3cca7320edb9341c976f7819de0a8c27e0 it only ever returns 0, leading to an infinite loop. Return 1 if we have finished sending dirty blocks. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini Message-id: 1360534366-26723-4-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- block-migration.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/block-migration.c b/block-migration.c index a91d96be5e..bcd0039025 100644 --- a/block-migration.c +++ b/block-migration.c @@ -582,7 +582,12 @@ static int block_save_iterate(QEMUFile *f, void *opaque) qemu_put_be64(f, BLK_MIG_FLAG_EOS); - return 0; + /* Complete when bulk transfer is done and all dirty blocks have been + * transferred. + */ + return block_mig_state.bulk_completed && + block_mig_state.submitted == 0 && + block_mig_state.read_done == 0; } static int block_save_complete(QEMUFile *f, void *opaque) From f880defbb06708d30a38ce9f2667067626acdd38 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 7 Feb 2013 20:26:52 +0100 Subject: [PATCH 0972/1634] block/vpc: Fix size calculation The size calculated from the CHS values is not the real image (disk) size, but usually a smaller value. This is caused by rounding effects. Only older operating systems use CHS. Such guests won't be able to use the whole disk. All modern operating systems use the real size. This patch fixes https://bugs.launchpad.net/qemu/+bug/1105670/. Signed-off-by: Stefan Weil Message-id: 1360265212-22037-1-git-send-email-sw@weilnetz.de Signed-off-by: Anthony Liguori --- block/vpc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index 82229ef5a0..b4ff5646a2 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -34,6 +34,8 @@ #define HEADER_SIZE 512 +#define VHD_SECTOR_SIZE 512 + //#define CACHE enum vhd_type { @@ -204,11 +206,13 @@ static int vpc_open(BlockDriverState *bs, int flags) /* Write 'checksum' back to footer, or else will leave it with zero. */ footer->checksum = be32_to_cpu(checksum); - // The visible size of a image in Virtual PC depends on the geometry - // rather than on the size stored in the footer (the size in the footer - // is too large usually) - bs->total_sectors = (int64_t) - be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; + /* The visible size of a image in Virtual PC depends on the guest: + * QEMU and other emulators report the real size (here in sectors). + * All modern operating systems use this real size. + * Very old operating systems use CHS values to calculate the total size. + * This calculated size is usually smaller than the real size. + */ + bs->total_sectors = be64_to_cpu(footer->size) / VHD_SECTOR_SIZE; /* Allow a maximum disk size of approximately 2 TB */ if (bs->total_sectors >= 65535LL * 255 * 255) { From 84eac31707a8f103cc9a0b38ab62a8832bec1153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 11 Feb 2013 18:35:39 +0100 Subject: [PATCH 0973/1634] libqtest: Fix documentation copy&paste errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The [qtest_]in[bwl]() functions/macros don't have a value argument. Signed-off-by: Andreas Färber Message-id: 1360604139-16797-1-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- tests/libqtest.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/libqtest.h b/tests/libqtest.h index c8ade856fc..110e2ecdaf 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -109,7 +109,6 @@ void qtest_outl(QTestState *s, uint16_t addr, uint32_t value); * qtest_inb: * @s: QTestState instance to operate on. * @addr: I/O port to read from. - * @value: Value being written. * * Returns an 8-bit value from an I/O port. */ @@ -119,7 +118,6 @@ uint8_t qtest_inb(QTestState *s, uint16_t addr); * qtest_inw: * @s: QTestState instance to operate on. * @addr: I/O port to read from. - * @value: Value being written. * * Returns a 16-bit value from an I/O port. */ @@ -129,7 +127,6 @@ uint16_t qtest_inw(QTestState *s, uint16_t addr); * qtest_inl: * @s: QTestState instance to operate on. * @addr: I/O port to read from. - * @value: Value being written. * * Returns a 32-bit value from an I/O port. */ @@ -279,7 +276,6 @@ void qtest_add_func(const char *str, void (*fn)); /** * inb: * @addr: I/O port to read from. - * @value: Value being written. * * Returns an 8-bit value from an I/O port. */ @@ -288,7 +284,6 @@ void qtest_add_func(const char *str, void (*fn)); /** * inw: * @addr: I/O port to read from. - * @value: Value being written. * * Returns a 16-bit value from an I/O port. */ @@ -297,7 +292,6 @@ void qtest_add_func(const char *str, void (*fn)); /** * inl: * @addr: I/O port to read from. - * @value: Value being written. * * Returns a 32-bit value from an I/O port. */ From 5dd6be069bf832f888005d28cebdec16720dedac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 11 Feb 2013 17:41:53 +0100 Subject: [PATCH 0974/1634] qtest: Use strtoull() for uint64_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 32-bit hosts, unsigned long may be uint32_t and uint64_t may be unsigned long long. Account for this by always using strtoull(). We were already using strtoll() for int64_t. Signed-off-by: Andreas Färber Reviewed-by: Anthony Liguori Message-id: 1360600914-5448-2-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- qtest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qtest.c b/qtest.c index b7a3821ca7..4663a38e11 100644 --- a/qtest.c +++ b/qtest.c @@ -282,8 +282,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) uint8_t *data; g_assert(words[1] && words[2]); - addr = strtoul(words[1], NULL, 0); - len = strtoul(words[2], NULL, 0); + addr = strtoull(words[1], NULL, 0); + len = strtoull(words[2], NULL, 0); data = g_malloc(len); cpu_physical_memory_read(addr, data, len); @@ -302,8 +302,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) size_t data_len; g_assert(words[1] && words[2] && words[3]); - addr = strtoul(words[1], NULL, 0); - len = strtoul(words[2], NULL, 0); + addr = strtoull(words[1], NULL, 0); + len = strtoull(words[2], NULL, 0); data_len = strlen(words[3]); if (data_len < 3) { From d0bce760e04b1658a3b4ac95be2839ae20fd86db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 11 Feb 2013 17:41:54 +0100 Subject: [PATCH 0975/1634] libi2c-omap: Fix endianness dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The libqos driver for omap_i2c currently does not work on Big Endian. Introduce helpers for reading from and writing to 16-bit armel registers. This fixes tmp105-test failures on ppc. To prepare for a QTest-level endianness solution, poison mem{read,write} and always use the helpers. Adopt the expected signatures. To avoid an unused variable warning, assert the STAT Single Byte Data bit but, due to it not getting cleared, only it being set when len == 1. Signed-off-by: Andreas Färber Message-id: 1360600914-5448-3-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- tests/libi2c-omap.c | 76 +++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/tests/libi2c-omap.c b/tests/libi2c-omap.c index 9be57e92c4..b7b10b5cbd 100644 --- a/tests/libi2c-omap.c +++ b/tests/libi2c-omap.c @@ -12,6 +12,7 @@ #include #include "qemu/osdep.h" +#include "qemu/bswap.h" #include "libqtest.h" enum OMAPI2CRegisters { @@ -48,12 +49,35 @@ typedef struct OMAPI2C { } OMAPI2C; +/* FIXME Use TBD readw qtest API */ +static inline uint16_t readw(uint64_t addr) +{ + uint16_t data; + + memread(addr, &data, 2); + return le16_to_cpu(data); +} + +/* FIXME Use TBD writew qtest API */ +static inline void writew(uint64_t addr, uint16_t data) +{ + data = cpu_to_le16(data); + memwrite(addr, &data, 2); +} + +#ifdef __GNUC__ +#undef memread +#undef memwrite +#pragma GCC poison memread +#pragma GCC poison memwrite +#endif + static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr) { uint16_t data = addr; - memwrite(s->addr + OMAP_I2C_SA, &data, 2); - memread(s->addr + OMAP_I2C_SA, &data, 2); + writew(s->addr + OMAP_I2C_SA, data); + data = readw(s->addr + OMAP_I2C_SA); g_assert_cmphex(data, ==, addr); } @@ -66,36 +90,38 @@ static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr, omap_i2c_set_slave_addr(s, addr); data = len; - memwrite(s->addr + OMAP_I2C_CNT, &data, 2); + writew(s->addr + OMAP_I2C_CNT, data); data = OMAP_I2C_CON_I2C_EN | OMAP_I2C_CON_TRX | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT | OMAP_I2C_CON_STP; - memwrite(s->addr + OMAP_I2C_CON, &data, 2); - memread(s->addr + OMAP_I2C_CON, &data, 2); + writew(s->addr + OMAP_I2C_CON, data); + data = readw(s->addr + OMAP_I2C_CON); g_assert((data & OMAP_I2C_CON_STP) != 0); - memread(s->addr + OMAP_I2C_STAT, &data, 2); + data = readw(s->addr + OMAP_I2C_STAT); g_assert((data & OMAP_I2C_STAT_NACK) == 0); while (len > 1) { - memread(s->addr + OMAP_I2C_STAT, &data, 2); + data = readw(s->addr + OMAP_I2C_STAT); g_assert((data & OMAP_I2C_STAT_XRDY) != 0); - memwrite(s->addr + OMAP_I2C_DATA, buf, 2); + data = buf[0] | ((uint16_t)buf[1] << 8); + writew(s->addr + OMAP_I2C_DATA, data); buf = (uint8_t *)buf + 2; len -= 2; } if (len == 1) { - memread(s->addr + OMAP_I2C_STAT, &data, 2); + data = readw(s->addr + OMAP_I2C_STAT); g_assert((data & OMAP_I2C_STAT_XRDY) != 0); - memwrite(s->addr + OMAP_I2C_DATA, buf, 1); + data = buf[0]; + writew(s->addr + OMAP_I2C_DATA, data); } - memread(s->addr + OMAP_I2C_CON, &data, 2); + data = readw(s->addr + OMAP_I2C_CON); g_assert((data & OMAP_I2C_CON_STP) == 0); } @@ -108,42 +134,46 @@ static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr, omap_i2c_set_slave_addr(s, addr); data = len; - memwrite(s->addr + OMAP_I2C_CNT, &data, 2); + writew(s->addr + OMAP_I2C_CNT, data); data = OMAP_I2C_CON_I2C_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT | OMAP_I2C_CON_STP; - memwrite(s->addr + OMAP_I2C_CON, &data, 2); - memread(s->addr + OMAP_I2C_CON, &data, 2); + writew(s->addr + OMAP_I2C_CON, data); + data = readw(s->addr + OMAP_I2C_CON); g_assert((data & OMAP_I2C_CON_STP) == 0); - memread(s->addr + OMAP_I2C_STAT, &data, 2); + data = readw(s->addr + OMAP_I2C_STAT); g_assert((data & OMAP_I2C_STAT_NACK) == 0); - memread(s->addr + OMAP_I2C_CNT, &data, 2); + data = readw(s->addr + OMAP_I2C_CNT); g_assert_cmpuint(data, ==, len); while (len > 0) { - memread(s->addr + OMAP_I2C_STAT, &data, 2); + data = readw(s->addr + OMAP_I2C_STAT); g_assert((data & OMAP_I2C_STAT_RRDY) != 0); g_assert((data & OMAP_I2C_STAT_ROVR) == 0); - memread(s->addr + OMAP_I2C_DATA, &data, 2); + data = readw(s->addr + OMAP_I2C_DATA); + + stat = readw(s->addr + OMAP_I2C_STAT); - memread(s->addr + OMAP_I2C_STAT, &stat, 2); if (unlikely(len == 1)) { - *buf = data & 0xf; + g_assert((stat & OMAP_I2C_STAT_SBD) != 0); + + buf[0] = data & 0xff; buf++; len--; } else { - memcpy(buf, &data, 2); + buf[0] = data & 0xff; + buf[1] = data >> 8; buf += 2; len -= 2; } } - memread(s->addr + OMAP_I2C_CON, &data, 2); + data = readw(s->addr + OMAP_I2C_CON); g_assert((data & OMAP_I2C_CON_STP) == 0); } @@ -159,7 +189,7 @@ I2CAdapter *omap_i2c_create(uint64_t addr) i2c->recv = omap_i2c_recv; /* verify the mmio address by looking for a known signature */ - memread(addr + OMAP_I2C_REV, &data, 2); + data = readw(addr + OMAP_I2C_REV); g_assert_cmphex(data, ==, 0x34); return i2c; From d7cd369402191814a1bb339a730f3af411e9682f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 11 Feb 2013 17:01:45 +0100 Subject: [PATCH 0976/1634] migration: restrict scope of incoming fd read handler The incoming migration is processed in a coroutine and uses an fd read handler to enter the yielded coroutine when data becomes available. The read handler was set too broadly, so that spurious coroutine entries were be triggered if other coroutine users yielded (like the block layer's bdrv_write() function). Install the fd read only only when yielding for more data to become available. This prevents spurious coroutine entries which break code that assumes only a specific set of places can re-enter the coroutine. This patch fixes crashes in block/raw-posix.c that are triggered with "migrate -b" when qiov becomes a dangling pointer due to a spurious coroutine entry that frees qiov early. Signed-off-by: Stefan Hajnoczi Message-id: 1360598505-5512-1-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- migration.c | 8 -------- savevm.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/migration.c b/migration.c index c4589b16f8..b1ebb01145 100644 --- a/migration.c +++ b/migration.c @@ -95,7 +95,6 @@ static void process_incoming_migration_co(void *opaque) int ret; ret = qemu_loadvm_state(f); - qemu_set_fd_handler(qemu_get_fd(f), NULL, NULL, NULL); qemu_fclose(f); if (ret < 0) { fprintf(stderr, "load of migration failed\n"); @@ -115,12 +114,6 @@ static void process_incoming_migration_co(void *opaque) } } -static void enter_migration_coroutine(void *opaque) -{ - Coroutine *co = opaque; - qemu_coroutine_enter(co, NULL); -} - void process_incoming_migration(QEMUFile *f) { Coroutine *co = qemu_coroutine_create(process_incoming_migration_co); @@ -128,7 +121,6 @@ void process_incoming_migration(QEMUFile *f) assert(fd != -1); socket_set_nonblock(fd); - qemu_set_fd_handler(fd, enter_migration_coroutine, NULL, co); qemu_coroutine_enter(co, f); } diff --git a/savevm.c b/savevm.c index 4eb29b2ae2..0b6724dddb 100644 --- a/savevm.c +++ b/savevm.c @@ -140,6 +140,34 @@ typedef struct QEMUFileSocket QEMUFile *file; } QEMUFileSocket; +typedef struct { + Coroutine *co; + int fd; +} FDYieldUntilData; + +static void fd_coroutine_enter(void *opaque) +{ + FDYieldUntilData *data = opaque; + qemu_set_fd_handler(data->fd, NULL, NULL, NULL); + qemu_coroutine_enter(data->co, NULL); +} + +/** + * Yield until a file descriptor becomes readable + * + * Note that this function clobbers the handlers for the file descriptor. + */ +static void coroutine_fn yield_until_fd_readable(int fd) +{ + FDYieldUntilData data; + + assert(qemu_in_coroutine()); + data.co = qemu_coroutine_self(); + data.fd = fd; + qemu_set_fd_handler(fd, fd_coroutine_enter, NULL, &data); + qemu_coroutine_yield(); +} + static int socket_get_fd(void *opaque) { QEMUFileSocket *s = opaque; @@ -158,8 +186,7 @@ static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) break; } if (socket_error() == EAGAIN) { - assert(qemu_in_coroutine()); - qemu_coroutine_yield(); + yield_until_fd_readable(s->fd); } else if (socket_error() != EINTR) { break; } @@ -205,8 +232,7 @@ static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) break; } if (errno == EAGAIN) { - assert(qemu_in_coroutine()); - qemu_coroutine_yield(); + yield_until_fd_readable(fileno(fp)); } else if (errno != EINTR) { break; } From 58fa4325228f61d58317f48364259b31e9b92d15 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 11 Feb 2013 18:05:48 +0100 Subject: [PATCH 0977/1634] qapi: Improve chardev-add documentation Signed-off-by: Markus Armbruster Message-id: 1360602348-4727-1-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qapi-schema.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 736f881b75..bd289aeb51 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3152,6 +3152,9 @@ # # Return info about the chardev backend just created. # +# @pty: #optional name of the slave pseudoterminal device, present if +# and only if a chardev of type 'pty' was created +# # Since: 1.4 ## { 'type' : 'ChardevReturn', 'data': { '*pty' : 'str' } } @@ -3159,12 +3162,12 @@ ## # @chardev-add: # -# Add a file chardev +# Add a character device backend # # @id: the chardev's ID, must be unique # @backend: backend type and parameters # -# Returns: chardev info. +# Returns: ChardevReturn. # # Since: 1.4 ## @@ -3175,7 +3178,7 @@ ## # @chardev-remove: # -# Remove a chardev +# Remove a character device backend # # @id: the chardev's ID, must exist and not be in use # From 03ec2f83087de34924489eeae0ea6fe7785cc050 Mon Sep 17 00:00:00 2001 From: Kuo-Jung Su Date: Mon, 4 Feb 2013 17:56:25 +0800 Subject: [PATCH 0978/1634] hw/m25p80.c: add WRSR(0x01) support Atmel, SST and Intel/Numonyx serial flash tend to power up with the software protection bits set. And thus the new m25p80.c in linux kernel would always tries to use WREN(0x06) + WRSR(0x01) to turn-off the protection. The WEL(0x02) of status register is supposed to be cleared after WRSR(0x01). There are also some drivers (i.e mine for RTOSes) would check the WEL(0x02) in status register to make sure the protection is correctly turned off. Signed-off-by: Kuo-Jung Su Cc: Peter Crosthwaite Cc: Peter Maydell Cc: Edgar E. Iglesias Reviewed-by: Peter Crosthwaite Signed-off-by: Edgar E. Iglesias --- hw/m25p80.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/m25p80.c b/hw/m25p80.c index 788c19608c..461b41c4ac 100644 --- a/hw/m25p80.c +++ b/hw/m25p80.c @@ -184,6 +184,7 @@ static const FlashPartInfo known_devices[] = { typedef enum { NOP = 0, + WRSR = 0x1, WRDI = 0x4, RDSR = 0x5, WREN = 0x6, @@ -379,6 +380,11 @@ static void complete_collecting_data(Flash *s) case ERASE_SECTOR: flash_erase(s, s->cur_addr, s->cmd_in_progress); break; + case WRSR: + if (s->write_enable) { + s->write_enable = false; + } + break; default: break; } @@ -443,6 +449,15 @@ static void decode_new_cmd(Flash *s, uint32_t value) s->state = STATE_COLLECTING_DATA; break; + case WRSR: + if (s->write_enable) { + s->needed_bytes = 1; + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; + } + break; + case WRDI: s->write_enable = false; break; From da888d37b0b85fc23e4ea55ab8b0c482d4918afb Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 5 Feb 2013 12:28:33 +0100 Subject: [PATCH 0979/1634] block/raw-posix: detect readonly Linux block devices using BLKROGET Linux block devices can be set read-only with "blockdev --setro ". The same thing can be done for LVM volumes using "lvchange --permission r ". This read-only setting is independent of device node permissions. Therefore the device can still be opened O_RDWR but actual writes will fail. This results in odd behavior for QEMU. bdrv_open() is supposed to fail if a read-only image is being opened with BDRV_O_RDWR. By not failing for Linux block devices, the guest boots up but every write produces an I/O error. This patch checks whether the block device is read-only so that Linux block devices behave like regular files. Reported-by: Sibiao Luo Suggested-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi Reviewed-by: Markus Armbruster Signed-off-by: Kevin Wolf --- block/raw-posix.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 8b6b92608b..4dfdf985b0 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1257,9 +1257,43 @@ static int hdev_probe_device(const char *filename) return 0; } +static int check_hdev_writable(BDRVRawState *s) +{ +#if defined(BLKROGET) + /* Linux block devices can be configured "read-only" using blockdev(8). + * This is independent of device node permissions and therefore open(2) + * with O_RDWR succeeds. Actual writes fail with EPERM. + * + * bdrv_open() is supposed to fail if the disk is read-only. Explicitly + * check for read-only block devices so that Linux block devices behave + * properly. + */ + struct stat st; + int readonly = 0; + + if (fstat(s->fd, &st)) { + return -errno; + } + + if (!S_ISBLK(st.st_mode)) { + return 0; + } + + if (ioctl(s->fd, BLKROGET, &readonly) < 0) { + return -errno; + } + + if (readonly) { + return -EACCES; + } +#endif /* defined(BLKROGET) */ + return 0; +} + static int hdev_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; + int ret; #if defined(__APPLE__) && defined(__MACH__) if (strstart(filename, "/dev/cdrom", NULL)) { @@ -1300,7 +1334,20 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) } #endif - return raw_open_common(bs, filename, flags, 0); + ret = raw_open_common(bs, filename, flags, 0); + if (ret < 0) { + return ret; + } + + if (flags & BDRV_O_RDWR) { + ret = check_hdev_writable(s); + if (ret < 0) { + raw_close(bs); + return ret; + } + } + + return ret; } #if defined(__linux__) From 33ccf6675faa3c56f30399e184064fd126904515 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 12 Feb 2013 12:25:15 +0100 Subject: [PATCH 0980/1634] Revert "block/vpc: Fix size calculation" This reverts commit f880defbb06708d30a38ce9f2667067626acdd38. Jeff Cody's testing revealed that the interpretation of size differs even between VirtualPC and HyperV. Revert this so there is time to consider the impact of any backwards incompatible behavior this change creates. Signed-off-by: Stefan Hajnoczi --- block/vpc.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/block/vpc.c b/block/vpc.c index b4ff5646a2..82229ef5a0 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -34,8 +34,6 @@ #define HEADER_SIZE 512 -#define VHD_SECTOR_SIZE 512 - //#define CACHE enum vhd_type { @@ -206,13 +204,11 @@ static int vpc_open(BlockDriverState *bs, int flags) /* Write 'checksum' back to footer, or else will leave it with zero. */ footer->checksum = be32_to_cpu(checksum); - /* The visible size of a image in Virtual PC depends on the guest: - * QEMU and other emulators report the real size (here in sectors). - * All modern operating systems use this real size. - * Very old operating systems use CHS values to calculate the total size. - * This calculated size is usually smaller than the real size. - */ - bs->total_sectors = be64_to_cpu(footer->size) / VHD_SECTOR_SIZE; + // The visible size of a image in Virtual PC depends on the geometry + // rather than on the size stored in the footer (the size in the footer + // is too large usually) + bs->total_sectors = (int64_t) + be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; /* Allow a maximum disk size of approximately 2 TB */ if (bs->total_sectors >= 65535LL * 255 * 255) { From 30d940875dcd1adfbfd7fe7ccd3e543408519662 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 12 Feb 2013 14:34:04 +0100 Subject: [PATCH 0981/1634] trace: use glib atomic int types Juan reported that RHEL 6.4 hosts give compiler warnings because we use unsigned int while glib prototypes use volatile gint in trace/simple.c. trace/simple.c:223: error: pointer targets in passing argument 1 of 'g_atomic_int_compare_and_exchange' differ in signedness These variables are only accessed with glib atomic int functions so let's play it by the book and use volatile gint. Reported-by: Juan Quintela Signed-off-by: Stefan Hajnoczi Message-id: 1360676045-9204-2-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- trace/simple.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trace/simple.c b/trace/simple.c index 74701e3272..1d5d8e4667 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -51,9 +51,9 @@ enum { }; uint8_t trace_buf[TRACE_BUF_LEN]; -static unsigned int trace_idx; +static volatile gint trace_idx; static unsigned int writeout_idx; -static int dropped_events; +static volatile gint dropped_events; static FILE *trace_fp; static char *trace_file_name; @@ -267,7 +267,7 @@ void trace_record_finish(TraceBufferRecord *rec) record.event |= TRACE_RECORD_VALID; write_to_buffer(rec->tbuf_idx, &record, sizeof(TraceRecord)); - if ((g_atomic_int_get(&trace_idx) - writeout_idx) + if (((unsigned int)g_atomic_int_get(&trace_idx) - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) { flush_trace_file(false); } From 4a0e6714b06453078e02029e1432fab052927691 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 12 Feb 2013 14:34:05 +0100 Subject: [PATCH 0982/1634] trace: deal with deprecated glib thread functions g_thread_create() was deprecated in favor of g_thread_new() and g_cond_new() was deprecated in favor of GCond initialization. If the host has glib 2.31 or newer, avoid using the deprecated functions. This patch solves compiler warnings that are generated when glib's deprecated functions are used. Signed-off-by: Stefan Hajnoczi Message-id: 1360676045-9204-3-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- trace/simple.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/trace/simple.c b/trace/simple.c index 1d5d8e4667..375d98f70b 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -40,8 +40,18 @@ * records to become available, writes them out, and then waits again. */ static GStaticMutex trace_lock = G_STATIC_MUTEX_INIT; + +/* g_cond_new() was deprecated in glib 2.31 but we still need to support it */ +#if GLIB_CHECK_VERSION(2, 31, 0) +static GCond the_trace_available_cond; +static GCond the_trace_empty_cond; +static GCond *trace_available_cond = &the_trace_available_cond; +static GCond *trace_empty_cond = &the_trace_empty_cond; +#else static GCond *trace_available_cond; static GCond *trace_empty_cond; +#endif + static bool trace_available; static bool trace_writeout_enabled; @@ -397,7 +407,13 @@ static GThread *trace_thread_create(GThreadFunc fn) sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, &oldset); #endif + +#if GLIB_CHECK_VERSION(2, 31, 0) + thread = g_thread_new("trace-thread", fn, NULL); +#else thread = g_thread_create(fn, NULL, FALSE, NULL); +#endif + #ifndef _WIN32 pthread_sigmask(SIG_SETMASK, &oldset, NULL); #endif @@ -418,8 +434,10 @@ bool trace_backend_init(const char *events, const char *file) #endif } +#if !GLIB_CHECK_VERSION(2, 31, 0) trace_available_cond = g_cond_new(); trace_empty_cond = g_cond_new(); +#endif thread = trace_thread_create(writeout_thread); if (!thread) { From ad55ab42d494c5f4ebc5199c5c9db473b7d5fbf9 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 12 Feb 2013 10:37:14 +0100 Subject: [PATCH 0983/1634] migration: make qemu_ftell() public and support writable files Migration .save_live_iterate() functions return the number of bytes transferred. The easiest way of doing this is by calling qemu_ftell(f) at the beginning and end of the function to calculate the difference. Make qemu_ftell() public so that block-migration will be able to use it. Also adjust the ftell calculation for writable files where buf_offset does not include buf_size. Signed-off-by: Stefan Hajnoczi Reviewed-by: Juan Quintela Message-id: 1360661835-28663-2-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- include/migration/qemu-file.h | 1 + savevm.c | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 68deefbcfb..46fc11dc99 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -81,6 +81,7 @@ QEMUFile *qemu_popen(FILE *popen_file, const char *mode); QEMUFile *qemu_popen_cmd(const char *command, const char *mode); int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); +int64_t qemu_ftell(QEMUFile *f); void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); void qemu_put_byte(QEMUFile *f, int v); diff --git a/savevm.c b/savevm.c index 0b6724dddb..a8a53efc9b 100644 --- a/savevm.c +++ b/savevm.c @@ -673,9 +673,14 @@ int qemu_get_byte(QEMUFile *f) return result; } -static int64_t qemu_ftell(QEMUFile *f) +int64_t qemu_ftell(QEMUFile *f) { - return f->buf_offset - f->buf_size + f->buf_index; + /* buf_offset excludes buffer for writing but includes it for reading */ + if (f->is_write) { + return f->buf_offset + f->buf_index; + } else { + return f->buf_offset - f->buf_size + f->buf_index; + } } int qemu_file_rate_limit(QEMUFile *f) From 6aaa9dae8059633d52ddcd0622de1a2700fc58a8 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 12 Feb 2013 10:37:15 +0100 Subject: [PATCH 0984/1634] block-migration: fix pending() and iterate() return values The return value of .save_live_pending() is the number of bytes remaining. This is just an estimate because we do not know how many blocks will be dirtied by the running guest. Currently our return value for .save_live_pending() is wrong because it includes dirty blocks but not in-flight bdrv_aio_readv() requests or unsent blocks. Crucially, it also doesn't include the bulk phase where the entire device is transferred - therefore we risk completing block migration before all blocks have been transferred! The return value of .save_live_iterate() is the number of bytes transferred this iteration. Currently we return whether there are bytes remaining, which is incorrect. Move the bytes remaining calculation into .save_live_pending() and really return the number of bytes transferred this iteration in .save_live_iterate(). Also fix the %ld format specifier which was used for a uint64_t argument. PRIu64 must be use to avoid warnings on 32-bit hosts. Signed-off-by: Stefan Hajnoczi Reviewed-by: Juan Quintela Message-id: 1360661835-28663-3-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- block-migration.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/block-migration.c b/block-migration.c index bcd0039025..43ab2028c0 100644 --- a/block-migration.c +++ b/block-migration.c @@ -539,6 +539,7 @@ static int block_save_setup(QEMUFile *f, void *opaque) static int block_save_iterate(QEMUFile *f, void *opaque) { int ret; + int64_t last_ftell = qemu_ftell(f); DPRINTF("Enter save live iterate submitted %d transferred %d\n", block_mig_state.submitted, block_mig_state.transferred); @@ -582,12 +583,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque) qemu_put_be64(f, BLK_MIG_FLAG_EOS); - /* Complete when bulk transfer is done and all dirty blocks have been - * transferred. - */ - return block_mig_state.bulk_completed && - block_mig_state.submitted == 0 && - block_mig_state.read_done == 0; + return qemu_ftell(f) - last_ftell; } static int block_save_complete(QEMUFile *f, void *opaque) @@ -629,10 +625,18 @@ static int block_save_complete(QEMUFile *f, void *opaque) static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) { + /* Estimate pending number of bytes to send */ + uint64_t pending = get_remaining_dirty() + + block_mig_state.submitted * BLOCK_SIZE + + block_mig_state.read_done * BLOCK_SIZE; - DPRINTF("Enter save live pending %ld\n", get_remaining_dirty()); + /* Report at least one block pending during bulk phase */ + if (pending == 0 && !block_mig_state.bulk_completed) { + pending = BLOCK_SIZE; + } - return get_remaining_dirty(); + DPRINTF("Enter save live pending %" PRIu64 "\n", pending); + return pending; } static int block_load(QEMUFile *f, void *opaque, int version_id) From dada5c7e92434df7c0ec152fe9a8f0e3de67b632 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Tue, 12 Feb 2013 11:17:10 +1000 Subject: [PATCH 0985/1634] xilinx.h: Dont qdev_create from ethernet_create() Pulled the qdev_create functionality out of xilinx_axiethernet_create() and pushed it up to the petalogix_ml605_mmu machine model. This makes the ethernet create+init process consistent with the AXI DMA. Renamed function to xilinx_axiethernet_init accordingly. Signed-off-by: Peter Crosthwaite Signed-off-by: Edgar E. Iglesias --- hw/petalogix_ml605_mmu.c | 6 ++++-- hw/xilinx.h | 13 +++---------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index bdfc6ce365..8fd55a0328 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -129,14 +129,16 @@ petalogix_ml605_init(QEMUMachineInitArgs *args) xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000); /* axi ethernet and dma initialization. */ + qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet"); + eth0 = qdev_create(NULL, "xlnx.axi-ethernet"); dma = qdev_create(NULL, "xlnx.axi-dma"); /* FIXME: attach to the sysbus instead */ object_property_add_child(container_get(qdev_get_machine(), "/unattached"), "xilinx-dma", OBJECT(dma), NULL); - eth0 = xilinx_axiethernet_create(&nd_table[0], STREAM_SLAVE(dma), - 0x82780000, irq[3], 0x1000, 0x1000); + xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(dma), + 0x82780000, irq[3], 0x1000, 0x1000); xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0], 100 * 1000000); diff --git a/hw/xilinx.h b/hw/xilinx.h index 725f2f4898..d255ca7fbb 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -53,17 +53,12 @@ xilinx_ethlite_create(NICInfo *nd, hwaddr base, qemu_irq irq, return dev; } -static inline DeviceState * -xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, - hwaddr base, qemu_irq irq, - int txmem, int rxmem) +static inline void +xilinx_axiethernet_init(DeviceState *dev, NICInfo *nd, StreamSlave *peer, + hwaddr base, qemu_irq irq, int txmem, int rxmem) { - DeviceState *dev; Error *errp = NULL; - qemu_check_nic_model(nd, "xlnx.axi-ethernet"); - - dev = qdev_create(NULL, "xlnx.axi-ethernet"); qdev_set_nic_properties(dev, nd); qdev_prop_set_uint32(dev, "rxmem", rxmem); qdev_prop_set_uint32(dev, "txmem", txmem); @@ -73,8 +68,6 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - - return dev; } static inline void From 7ce4106c2125eca8f7f61f460456a49074c13e56 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Tue, 12 Feb 2013 11:17:11 +1000 Subject: [PATCH 0986/1634] xilinx.h: s/xilinx_axiethernetdma()/xilinx_axidma() This function has nothing to do with ethernet. Its reusable for all DMA clients. Dropped the "ethernet" in the name accordingly. Signed-off-by: Peter Crosthwaite Signed-off-by: Edgar E. Iglesias --- hw/petalogix_ml605_mmu.c | 4 ++-- hw/xilinx.h | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index 8fd55a0328..82d7183ae5 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -140,8 +140,8 @@ petalogix_ml605_init(QEMUMachineInitArgs *args) xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(dma), 0x82780000, irq[3], 0x1000, 0x1000); - xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0), - 0x84600000, irq[1], irq[0], 100 * 1000000); + xilinx_axidma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0], + 100 * 1000000); { SSIBus *spi; diff --git a/hw/xilinx.h b/hw/xilinx.h index d255ca7fbb..09bc2e4913 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -71,9 +71,8 @@ xilinx_axiethernet_init(DeviceState *dev, NICInfo *nd, StreamSlave *peer, } static inline void -xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer, - hwaddr base, qemu_irq irq, - qemu_irq irq2, int freqhz) +xilinx_axidma_init(DeviceState *dev, StreamSlave *peer, hwaddr base, + qemu_irq irq, qemu_irq irq2, int freqhz) { Error *errp = NULL; From 760794f784f66e262a9ca32821ba202cdf3a3e4b Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 4 Feb 2013 22:53:24 +0000 Subject: [PATCH 0987/1634] s390/sclpconsole: prevent char layer callback during initialization Starting a qemu with an sclp console and pressing a key very early can result in "qemu-system-s390x: hw/s390x/sclpconsole.c:60: receive_from_chr_layer: Assertion `scon->iov' failed." Lets make sure that the init process is finished, since the iov is allocated after CHR_EVENT_OPENED by also checking for scon->iov. Signed-off-by: Christian Borntraeger Signed-off-by: Alexander Graf --- hw/s390x/sclpconsole.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index adc0ee83f4..effe51110f 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -44,12 +44,9 @@ typedef struct SCLPConsole { /* Return number of bytes that fit into iov buffer */ static int chr_can_read(void *opaque) { - int can_read; SCLPConsole *scon = opaque; - can_read = SIZE_BUFFER_VT220 - scon->iov_data_len; - - return can_read; + return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0; } /* Receive n bytes from character layer, save in iov buffer, From bd9a8d852c857fd19c4626acaac1d4979f816f3a Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 7 Feb 2013 02:20:50 +0000 Subject: [PATCH 0988/1634] s390: Keep I/O interrupts enabled for all iscs. do_io_interrupt() would stop scanning further iscs if it found an I/O interrupt it could inject. This might cause the pending interrupt indication for I/O interrupts to be reset although there might be queued I/O interrupts for subsequent iscs. Fix this by reordering the logic: Inject the I/O interrupt immediately and continue searching all iscs for queued interrupts. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- target-s390x/helper.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 043feb2739..9f9088b040 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -617,7 +617,6 @@ static void do_ext_interrupt(CPUS390XState *env) static void do_io_interrupt(CPUS390XState *env) { - uint64_t mask = 0, addr = 0; LowCore *lowcore; IOIntQueue *q; uint8_t isc; @@ -642,36 +641,39 @@ static void do_io_interrupt(CPUS390XState *env) disable = 0; continue; } - found = 1; - lowcore = cpu_map_lowcore(env); + if (!found) { + uint64_t mask, addr; - lowcore->subchannel_id = cpu_to_be16(q->id); - lowcore->subchannel_nr = cpu_to_be16(q->nr); - lowcore->io_int_parm = cpu_to_be32(q->parm); - lowcore->io_int_word = cpu_to_be32(q->word); - lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env)); - lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr); - mask = be64_to_cpu(lowcore->io_new_psw.mask); - addr = be64_to_cpu(lowcore->io_new_psw.addr); + found = 1; + lowcore = cpu_map_lowcore(env); - cpu_unmap_lowcore(lowcore); + lowcore->subchannel_id = cpu_to_be16(q->id); + lowcore->subchannel_nr = cpu_to_be16(q->nr); + lowcore->io_int_parm = cpu_to_be32(q->parm); + lowcore->io_int_word = cpu_to_be32(q->word); + lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr); + mask = be64_to_cpu(lowcore->io_new_psw.mask); + addr = be64_to_cpu(lowcore->io_new_psw.addr); - env->io_index[isc]--; + cpu_unmap_lowcore(lowcore); + + env->io_index[isc]--; + + DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, + env->psw.mask, env->psw.addr); + load_psw(env, mask, addr); + } if (env->io_index[isc] >= 0) { disable = 0; } - break; + continue; } if (disable) { env->pending_int &= ~INTERRUPT_IO; } - if (found) { - DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, - env->psw.mask, env->psw.addr); - load_psw(env, mask, addr); - } } static void do_mchk_interrupt(CPUS390XState *env) From 91b0a8f33419573c1d741e49559bfb666fd8b1f0 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 7 Feb 2013 02:20:51 +0000 Subject: [PATCH 0989/1634] s390: Fix handling of iscs. There are two ways to express an interruption subclass: - As a bitmask, as used in cr6. - As a number, as used in the I/O interruption word. Unfortunately, we have treated to I/O interruption word as if it contained the bitmask as well, which went unnoticed so far as - (queued-for-next) kvm made the same mistake, and - Linux guest kernels don't check the isc value in the I/O interruption word for subchannel interrupts. Make sure that we treat the I/O interruption word correctly. Signed-off-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/css.c | 4 ++-- target-s390x/cpu.h | 2 +- target-s390x/helper.c | 5 ++++- target-s390x/ioinst.h | 3 +++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 3244201fc7..85f6f22a7f 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -87,7 +87,7 @@ static void css_inject_io_interrupt(SubchDev *sch) css_build_subchannel_id(sch), sch->schid, sch->curr_status.pmcw.intparm, - (0x80 >> isc) << 24); + isc << 27); } void css_conditional_io_interrupt(SubchDev *sch) @@ -111,7 +111,7 @@ void css_conditional_io_interrupt(SubchDev *sch) css_build_subchannel_id(sch), sch->schid, sch->curr_status.pmcw.intparm, - (0x80 >> isc) << 24); + isc << 27); } } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 01e59b99f0..fa8dfe0737 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1001,7 +1001,7 @@ static inline void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, uint32_t io_int_parm, uint32_t io_int_word) { CPUS390XState *env = &cpu->env; - int isc = ffs(io_int_word << 2) - 1; + int isc = IO_INT_WORD_ISC(io_int_word); if (env->io_index[isc] == MAX_IO_QUEUE - 1) { /* ugh - can't queue anymore. Let's drop. */ diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 9f9088b040..76268317a3 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -628,6 +628,8 @@ static void do_io_interrupt(CPUS390XState *env) } for (isc = 0; isc < ARRAY_SIZE(env->io_index); isc++) { + uint64_t isc_bits; + if (env->io_index[isc] < 0) { continue; } @@ -637,7 +639,8 @@ static void do_io_interrupt(CPUS390XState *env) } q = &env->io_queue[env->io_index[isc]][isc]; - if (!(env->cregs[6] & q->word)) { + isc_bits = ISC_TO_ISC_BITS(IO_INT_WORD_ISC(q->word)); + if (!(env->cregs[6] & isc_bits)) { disable = 0; continue; } diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h index d5a43f4a71..7bed2910dc 100644 --- a/target-s390x/ioinst.h +++ b/target-s390x/ioinst.h @@ -209,6 +209,9 @@ typedef struct IOIntCode { #define IOINST_SCHID_SSID(_schid) ((_schid & 0x00060000) >> 17) #define IOINST_SCHID_NR(_schid) (_schid & 0x0000ffff) +#define IO_INT_WORD_ISC(_int_word) ((_int_word & 0x38000000) >> 24) +#define ISC_TO_ISC_BITS(_isc) ((0x80 >> _isc) << 24) + int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, int *schid); int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1); From cc2a90432d9cb7546a2c4360ad7200a2fb3af31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 12 Feb 2013 23:16:06 +0100 Subject: [PATCH 0990/1634] net: Avoid NULL function pointer dereference on cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pSeries machine and some other devices don't supply a cleanup callback. Revert part of 1ceef9f27359cbe92ef124bf74de6f792e71f6fb that started calling it unconditionally. Cc: Jason Wang Signed-off-by: Andreas Färber Message-id: 1360707366-9271-1-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- net/net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/net.c b/net/net.c index f9e7136a2b..be03a8dd14 100644 --- a/net/net.c +++ b/net/net.c @@ -287,7 +287,9 @@ static void qemu_cleanup_net_client(NetClientState *nc) { QTAILQ_REMOVE(&net_clients, nc, next); - nc->info->cleanup(nc); + if (nc->info->cleanup) { + nc->info->cleanup(nc); + } } static void qemu_free_net_client(NetClientState *nc) From d037d6bbbcdda6552254286b6da090ef0dc0d98a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 15:54:15 +0100 Subject: [PATCH 0991/1634] chardev: Fix manual page and qemu-doc for -chardev tty Broken in commit d59044ef. Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Message-id: 1360767256-610-2-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index 046bdc0f63..9d7131aa0f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1956,7 +1956,7 @@ Connect to a local BrlAPI server. @option{braille} does not take any options. @item -chardev tty ,id=@var{id} ,path=@var{path} @option{tty} is only available on Linux, Sun, FreeBSD, NetBSD, OpenBSD and -DragonFlyBSD hosts. It is an alias for -serial. +DragonFlyBSD hosts. It is an alias for @option{serial}. @option{path} specifies the path to the tty. @option{path} is required. From d36b2b904ee921b380fad559cb824a40eb587bcb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 15:54:16 +0100 Subject: [PATCH 0992/1634] qapi: Flatten away ChardevPort Simplifies the schema and the code. QMP command { "execute" : "chardev-add", "arguments" : { "id" : "ser0", "backend" : { "type" : "port", "data" : { "type": "serial", "device":"/dev/ttyS0"} } } } becomes { "execute" : "chardev-add", "arguments" : { "id" : "ser0", "backend" : { "type" : "serial", "data" : { "device":"/dev/ttyS0"} } } } Bonus: nicer error messages. "unknown chardev port (1)" becomes "character device backend type 'parallel' not supported". Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Message-id: 1360767256-610-3-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qapi-schema.json | 11 +++---- qemu-char.c | 82 ++++++++++++++++++++++++++---------------------- 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index bd289aeb51..7275b5dd6a 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3095,7 +3095,7 @@ 'out' : 'str' } } ## -# @ChardevPort: +# @ChardevHostdev: # # Configuration info for device chardevs. # @@ -3105,11 +3105,7 @@ # # Since: 1.4 ## -{ 'enum': 'ChardevPortKind', 'data': [ 'serial', - 'parallel' ] } - -{ 'type': 'ChardevPort', 'data': { 'device' : 'str', - 'type' : 'ChardevPortKind'} } +{ 'type': 'ChardevHostdev', 'data': { 'device' : 'str' } } ## # @ChardevSocket: @@ -3142,7 +3138,8 @@ { 'type': 'ChardevDummy', 'data': { } } { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', - 'port' : 'ChardevPort', + 'serial' : 'ChardevHostdev', + 'parallel': 'ChardevHostdev', 'socket' : 'ChardevSocket', 'pty' : 'ChardevDummy', 'null' : 'ChardevDummy' } } diff --git a/qemu-char.c b/qemu-char.c index 574d3d292f..e4b0f5304f 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3269,15 +3269,17 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_win_file(out); } -static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) +static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial, + Error **errp) { - switch (port->type) { - case CHARDEV_PORT_KIND_SERIAL: - return qemu_chr_open_win_path(port->device); - default: - error_setg(errp, "unknown chardev port (%d)", port->type); - return NULL; - } + return qemu_chr_open_win_path(serial->device); +} + +static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel, + Error **errp) +{ + error_setg(errp, "character device backend type 'parallel' not supported"); + return NULL; } #else /* WIN32 */ @@ -3316,38 +3318,39 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp) return qemu_chr_open_fd(in, out); } -static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp) +static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial, + Error **errp) { - switch (port->type) { #ifdef HAVE_CHARDEV_TTY - case CHARDEV_PORT_KIND_SERIAL: - { - int flags, fd; - flags = O_RDWR; - fd = qmp_chardev_open_file_source(port->device, flags, errp); - if (error_is_set(errp)) { - return NULL; - } - socket_set_nonblock(fd); - return qemu_chr_open_tty_fd(fd); - } -#endif -#ifdef HAVE_CHARDEV_PARPORT - case CHARDEV_PORT_KIND_PARALLEL: - { - int flags, fd; - flags = O_RDWR; - fd = qmp_chardev_open_file_source(port->device, flags, errp); - if (error_is_set(errp)) { - return NULL; - } - return qemu_chr_open_pp_fd(fd); - } -#endif - default: - error_setg(errp, "unknown chardev port (%d)", port->type); + int fd; + + fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); + if (error_is_set(errp)) { return NULL; } + socket_set_nonblock(fd); + return qemu_chr_open_tty_fd(fd); +#else + error_setg(errp, "character device backend type 'serial' not supported"); + return NULL; +#endif +} + +static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel, + Error **errp) +{ +#ifdef HAVE_CHARDEV_PARPORT + int fd; + + fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp); + if (error_is_set(errp)) { + return NULL; + } + return qemu_chr_open_pp_fd(fd); +#else + error_setg(errp, "character device backend type 'parallel' not supported"); + return NULL; +#endif } #endif /* WIN32 */ @@ -3391,8 +3394,11 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_FILE: chr = qmp_chardev_open_file(backend->file, errp); break; - case CHARDEV_BACKEND_KIND_PORT: - chr = qmp_chardev_open_port(backend->port, errp); + case CHARDEV_BACKEND_KIND_SERIAL: + chr = qmp_chardev_open_serial(backend->serial, errp); + break; + case CHARDEV_BACKEND_KIND_PARALLEL: + chr = qmp_chardev_open_parallel(backend->parallel, errp); break; case CHARDEV_BACKEND_KIND_SOCKET: chr = qmp_chardev_open_socket(backend->socket, errp); From 8a8f5840082eb65d140ccfe7b128c92390cce1c3 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 13 Feb 2013 09:25:34 +0100 Subject: [PATCH 0993/1634] block/curl: only restrict protocols with libcurl>=7.19.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, ...) interface was introduced in libcurl 7.19.4. Therefore we cannot protect against CVE-2013-0249 when linking against an older libcurl. This fixes the build failure introduced by fb6d1bbd246c7a57ef53d3847ef225cd1349d602. Reported-by: Andreas Färber Signed-off-by: Stefan Hajnoczi Tested-by: Andreas Färber Message-id: 1360743934-8337-1-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- block/curl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/curl.c b/block/curl.c index f6226b3a08..98947dac32 100644 --- a/block/curl.c +++ b/block/curl.c @@ -309,9 +309,13 @@ static CURLState *curl_init_state(BDRVCURLState *s) /* Restrict supported protocols to avoid security issues in the more * obscure protocols. For example, do not allow POP3/SMTP/IMAP see * CVE-2013-0249. + * + * Restricting protocols is only supported from 7.19.4 upwards. */ +#if LIBCURL_VERSION_NUM >= 0x071304 curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS); curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS); +#endif #ifdef DEBUG_VERBOSE curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1); From 9893c80d81587ac25d8ea4a82651371b54e7df35 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Tue, 12 Feb 2013 11:29:31 +1000 Subject: [PATCH 0994/1634] cadance_uart: Accept input after rx FIFO pop The device returns false from the can receive function when the FIFO is full. This means the device should check for buffered input whenever a byte is popped from the FIFO. Reported-by: Jason Wu Signed-off-by: Peter Crosthwaite Message-id: 1360632571-25638-1-git-send-email-peter.crosthwaite@xilinx.com Signed-off-by: Anthony Liguori --- hw/cadence_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c index cf2f53c81c..5766d38f13 100644 --- a/hw/cadence_uart.c +++ b/hw/cadence_uart.c @@ -343,6 +343,7 @@ static void uart_read_rx_fifo(UartState *s, uint32_t *c) if (!s->rx_count) { s->r[R_SR] |= UART_SR_INTR_REMPTY; } + qemu_chr_accept_input(s->chr); } else { *c = 0; s->r[R_SR] |= UART_SR_INTR_REMPTY; From 71652365c53115d2090d294406ec0bd3b7c63953 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 13 Feb 2013 23:58:12 +0100 Subject: [PATCH 0995/1634] Revert "Update OpenBIOS images" This reverts commit 10442558ab1797bfbb01285b909e34c5cf038f12. With the updated OpenBIOS image, -M g3beige fails to boot quik. Signed-off-by: Alexander Graf Signed-off-by: Mark Cave-Ayland Message-id: 1360796292-27078-1-git-send-email-agraf@suse.de Signed-off-by: Anthony Liguori --- pc-bios/README | 2 +- pc-bios/openbios-ppc | Bin 733972 -> 729908 bytes pc-bios/openbios-sparc32 | Bin 381764 -> 381764 bytes pc-bios/openbios-sparc64 | Bin 1598648 -> 1598648 bytes roms/openbios | 2 +- 5 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index bb182dc79c..eff3de7615 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -12,7 +12,7 @@ 1275-1994 (referred to as Open Firmware) compliant firmware. The included images for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32 and Sparc64 are built from OpenBIOS SVN revision - 1097. + 1063. - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc index c37c258143037cd40c07ddd6daceea0746b310fc..5311eca691f37222e8dc3453c4b6307e4f285306 100644 GIT binary patch literal 729908 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

& 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 z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF 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ℜR_43q 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%0D$wvS+58lVBCQQ~(-=W2asub0dmGH(l1 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%0DfTq5Ax&hge$5x~SkO|z zzK`IuberHaC!Oh1+DQL{>B?sq%hy}%TCO?|yvpk9e22cXjd6At^7n+fd4R?&T=&+GJr7wL1ooN}@iNUx zW*2n1UbL7!*S`1G%RJqD%G!9;+AC_iUCg%MzuFM}dtgXg(G2S;I2HZ9nOy^I*|xL4 zeH57Y%C7}JEIoFOb89whBqy-_VMnuW&G>wU@Fla(AIAO@!p2mI{!?LjChJPVl>Qi4 zmMz)EzQ+O9ublYF87HGAmqX63h?bkE)+@d(OPKj>s!R56*}7%-Zy5pYt>^tAY^%fR zFEM1=@8>Ms{ibZySzLngNb)@C3`uF+eW?VJL}`i zc^+Sby|)Q_TsQXKI(Qf{swU!3Kv~6jQ#|vazNKs#V;ZFPk$u@$${w`%ESvz)z<#ijFnL+qv-u~GBC#snOLjA;R}fEbHnTA2pQD*jxMGr~4T+H%>3 zH5TTJv5fWjO4eJO@^+k084G;~Ia~P*$EOSY_`cnh=f&WdY#BcBWSt+e


jJPN!s zEtT-Jj9_MlLGy`hhpzO&+f=Kp@X9(_*o1$&;CAyXlfe)goL&!3vN;bHci zAGFxralbip3pB}kQp!3JCRI$RGSV<E%2h%ky|^3jAsO?cK5$JiN%XP2^l+%jG<~ zee%9E&*;FqR2>at5;=3ZjS7nRf3hoiCEZGTrL z&4r;Ai%dH-s`9JQjZ)adBOc$JJ2Ma4T@!ovW9`|TOp#dz4zFw|4o9^Q(K(X2Um8(A z!q9Ac(!9Hmbd}=UV8fX$+QiRMavMJTW=YLRWTYWQ?yRv{(o$|#PP;H1O&+->)baP! zb%$NIs$0GV54_XzOz4Q1UHs2F-wr-4OO2$B18QT6+A#8oo(OME9;qL5@!wcEo)~7v zmppRym{g*EO!^1xp@7$^uMl&0R9&-tG;Mz-c>U2CE%+wcr z|IUF6pi5wAWx6fUOKaM+3%5FQrY$}1<$bL;a)x_?Co_qUCSR@Dm;SeZ3*lQyA4|n= zS9<&&f2Lo(JSH{wHQ|t8Z)FqGpzv(fFjGQWOnOF{DLT@5r5XIt*Ug!vC8VXv;)7!z z{<)Qt>^coUi)ih@F7SYz`y#XQR362<0pe4hoO0q>$1m8cghq=8%!YR;&)#Fv7RMi1 zv%b}D9|(PWcR?LXsY5=u`8qoK>If9p(Yvp&Z!_SHTL+QD|7O;y>p({l=e5uk8`k5e zvfk7;tPhM&K5${EV*q_8c2{(^vGEfeZg%b5jjrqYpiWBu1p7ET#JDbFI)|GJ`)IxB z4|!S#-lefw=5rmb=Dg{*o69u*)*{(LPM!^~K(6)aEH$>Wis__|w|cQ%Js)LX<^AKi zAFt7q=cU(!Gqcn8{F9BPm0ok^0@?Vd-x1I~iI=*uK9Hdu$u)U@-{fCgdR!*?f6?K` zn$yn5*viM)UScz?999CpElICF)SSNOX@iYn&Bb?HdUyML6@O3L^=c!&-84$}g$6Rw z?JkxW{Sf?EJ05iXC_7z0kRL1EnA=W2X7nK16>l83k9+aBj}86vb@5ho3i*W6ZuV`_ zj@AlzNZiB6n*zP_Bp#BVC&`V-$C4eBFMbI*CVOe}HY?wa?u1V!V?&yM`k^^<9I!2% z!&n@?0nd&ZY_srf&B3_c=5vb|nbNQAGnXx1XKmGO=^4MWvSa!><^maR`j^$;lN&9Z zkb&J;|AqcW7CrHB^CIjSijk1~uGMRt&A;N^LRbjSvSmn)T(s0H-#b_5_0H9#^z`SO z)2p^=u96quW#`J_)A^t4tFLdZ2LDa_=Yj1k>4C)4xWSYAGUpnzuJi z6`h~1KEX`zUv%XP>T6o);P1&*JFS0_;{hLy0M-V2JJX(5+s=B`%Kd%Ry9M1R+DJdJ z{jk=Qc>|Ymh>{x@uX4GIO#ajD@bceCy|aP{R(NEG(ma=>6A>7nbaO2 z#uhO|_`jZX3h6aGpUU$F(t6Svqz&w=%^;5scA*nAe7q1OJt<2y%J z=Z_~}l`Oh$OtSoX?!z;F#VFRkYLd9cymP$h{BH=qg@>Me+sA`FJZ$_m{V+8iY!x%g zznptFY9jFdE5YL?_|3e}H$OCq^^LoD)PBcXb`RI5Hi?5be#>F-93QvzQsP;2&M@DH zR8<(=Ibp8a>CS4?hiLKnKPsTN-m@n8byl{)T`jE5p6+7Lph~aMIg-4uo#$uwVTJgR zWKn2qEO15t&ed4{j4T|z&yQc$iB89_Lm6mMa@@na@V_dz``u1HyRl2--vX^cUxSeu z{i`dDpR|ayh`O!6kKjk&f6>?XJ~*oH8ISfPe-Jys(w+4g?8i6Y*LL04SVZS-1|QyI zuXDc8%9QXZkKbyKql+-}DFocLe5%&BK1x^{K4SFsy;UH5hqKYWYNn=A3VRh{Ou z?YogLG(L2PXeT_6wKKXKSLV27SN!usHk6-{;yHv?Pm z7cCec=LZ6h3_u>U=WmZ6WXu7J%Rhy;18=Q&vdN=gAQzrc99YgyvX-wycf;RG<8 zJ*}*B7VrgTofA06a;J@9tp5Ydr#rJbvn($I?W*YQ(0W;yKA7u?Tp%*mQJ=Cm?I~@`MSNHx#X&V1|IVc^vHJ2ZHB{ zk=6%mHas98Ty94XAn)-5e9MTnX=NwAk7vr%mI*w3z~e{AlO^fQUc>y!4l~%swnPsU z-cgP-68LJM_vstqczU>OYS+1aO%KOCp6MSeyF>xblw<;u6RiAD1nd(TWCZb2Y;$1` z$9z|{?q^Q%k=`;39s{0B?zHp(%-~UXXzoN0$hcZt<}hApaJcqf6YArCOdFGb)JGd1 zSiizQjW(_W*ZchFygpx>(s(#MR}CRQDZCjt`&QTChr#-(|1bWbrPUzocelRL-OZHssr(k~`r_G&#U@_gIoqpq zY74RUu!(8ijjm_mi<=4BPt<(K_l7Zx&Z0|aV^_V?)<2rK0^Rt3jYoF;y69K?A*&}_ zy(=i+5ZM;gH`RGX9DHo8lKlOM`n0Op#pi3xz29*NI;D-8D`}guHS_jc9}wCe+cB8_ z5%Zk;8T<{u4~%ape)a^mjWI5kKuGPUM*2fmMi|2Lzp=7?NlnD|Bd&h4N3k7#*3(%@ z8$oPMv@tCh7(eZTXHO)b`QjMoGejK&$0whf5^8vgn5Cn5zQm5R#A_?}M3Va|w3d0W z$Tixv&+e_AB4eOK!P83ae;j_a{!QuDrf)CtC&Z*h4{XJjLM(drKP>NvcCc@a|4Lo% zCuhw8X8AZG(IUo<9l=|Jrt1#uM&a(RS!S91rDC0|sk&30^eSTxV@r4I;05c1AGvMRXZKF%bBAy|VZOGB`PO|{R^Ehv8LdUh;%mPHzF8du z90_9Q4rp(>0H*zH&K(v96Qj29Jv8QIDA^5%|MThT%(s$n{IMrYJ>U2<0c%GNkOpP< zC6x^sUWV*}?SV8z8X^sohDpmviH(gegFZuANm@x-MOsBVnshX2HEA{JSkkeiQPL=B zEom)joHR~4iF8uSB<{4BZKf{2(j>4YPi5@&$(@0pCGQ{bGi)ds-Y?+&LVS%EVB=cI zcg^s9op(sG24u)5k=-65zqjQ|?59omX5MJJDEoxg2HrnS%3W@Z3!iMt-Vwde7wIeO zD_x%UNr$7XPc~9l)`u^7_FBp=C@9-VS*<@RJEx%Re9B%#*{*`JTPXX8E4!_rEVP%^ z{;u`QO_+xMwr|h&VC|PJ!{Pg;4jB~0IMF7sj&pIF|z?qln#EN48hd+ul0!h;(!LQ?stl>|A7$EnmkDerIA7&&$Be zQu#>N%o~0LI%wwoqG|D8E$aL_`*e;r)tA&1-@fD!-@fHHAnO|Z#fM6s$-blh^IiSL zOB16+bD~K%=67W$jxWY0okZ5DHC3rmllNJF>&xxlVVT!%Wr=73-|P;LCXm5;;qld~ z-np7Y97M_InpaQH_izB3fHz9dv9<*Kmb&4iMaa9M*!})808o}7!+*#=+r`N!7N=wD##$=>p!XWz`r z4VCdee&*s)B1<#wi1k(5WnQAK0S-ytB4%VyuPLChbiU-n(_;Q+xz(x#5#O zg3Ik0Ip-7Sk6ItW_7>pF`hUfwIl~g8^5;Upe`Fq$jCJW9__|XzM%Fdvx-NT5h1M(& zj`f=~p8qbt!My(C$$0;BwP4S>_NeX%Y?%NJ6#ExWTnBGn8mMfU8>p0Q6W`AMU?Vib z|9Zw96N<6O8WpIN>?U58*OMf>QC~#wNW1d*qJ81oOs}uv5pS*^o@>9afKK?XaIK@x z0$;_yQv5^Uxb^IWxkUHfpW>_dx05~CUZy=&JNN9NewwdhTVbD~O=b6bu$WL>*cWJX zrYqOItCO{m{YdtTtgmA0&OpTZ%1#oEB~0yetS{Vy{#WwFw{iu~c1XriY$I>ok8yXa zbj8~B@C@#NJa@C6)8;9DR3{IwtoTDlZKvc1UQs+-yxE=^-R(oiE^f2B19hnWG3PNa zEya!Ub4|+MH5Wt1DNe-T75M9))mc$Q9M@b{=zFC<^Q~2Nc7-HQ?fn4A z{&m@#9~7T#PYb3suge#iK1&vga0V*^uF03`g@hS*hW^*OLEe{{MPED~1y8zpX$!Ec znN^&TzUTQ9U*+}!viQyTEU&;{q*DGOvWubL`1Xt*%9+t_jXQg`<6WawPWvo+Z|_5S zs~we)iUFr3pd%wMW^%%5QT5;P&Z zfOPd=Qx=^jK1S=CV%+Qh8ZK=W4M`uC;4XzW#6=$9*fNlJg+%>7I8>o0N;L z56?{hz5IAiTq?apK|A=j<>r6`dEcp?XgB`JUB)y%^|ud-FC~j& zcPG1JcMlz8YKKM&d}s$1-JKd4t}n}&*+Ux*ezae@JNZ`B`O#h?KiUPS_|bCj+x7bj zd}xtfeC?Mrm-3;lnQ}B-;72PPL`d)SoO}>{vl^J&bpV+yZz~UKf4qVFy70*ulN`bs zn;+PifY!fO`is7mpRIgsg{RiXwkh&U?VZBQcL3x5wo|J=zSp>`;tXQ*o`J4*{6pbk zUG^6(mbY42WYkvc8x3CoN36_Lmz}$VwyKGjyN&#E%X{@*?hlhSw}L;sfp~&*f9&z> z>bY9CsQ*^>KImsnaja!PwR{Yt>-=T-h?mNDi}+TZv6{;7!LLeV6PaIRP|g%Ss{K0o zHYLnothavQ)(7h^R*P48^k{Y_O!ceuX=RLdI(&oT%(r-IEqpHS=odNn|15>im8ic7 zb7`K=!_isA+)W9ufL3FTvPu8NM%VTpkG{FL?_NtIVYO#vl%~r6n>Odt=G)O0zW4fi zMqmFf`%wLJ{GhZiR&cISG(CZO;8*X<|64p6+P*J#d+vL&HI*A;J1XVpj{Vl_J7-0o zb7KQFnG-Gd&GjW1y?KA4#`2*1daBm3y=;%5usV0CO)cB@zR#7WH!d<>er zxHCFyKsB=6%Wk}F_IwcY?ZLP5SCp|aD6pT|I1qK&Z@GBn-+Cy+JbK^BkM>)gHM7p> zNSME@5^w7-1AXPk!mCV^aN$^mm4W86zW1&X-?|B#M1VRJHwjttD<_a8tv;~xAT|ed zDB&lx`UtpoRm*tJ{oMy|ybXN{n~&z8b+Uh9bfbSk>of3$E_Bpcz}6r$AtPG*{ZPYw zD$dVmmhU^6H~bOp{cGQ!bN9u}=S=!#*KMmK^s`C)`*QV_wI;sk_}=>TPq3pPo2CB& z+2gi<49R}6==H~%)8Su1)0bMmbo`{>ao?1rSM8Mz>H+z>3y$bV?4N!4c<&f@6NB8- z6YbePm5EJYeE5%&zoB(MHfhd4Xe^PH{0aNzul^#Gs(GnCeRsmbE_GR5bF%rL zLdkp14=s9@x2=&5mHFt)t$z^Q)^gU_*2_GxTzDI|8u$<^eND_7vR*2`$U! zqcdGv>w=2QXlb&|k3HmfXT@^H@8%{f{z-e)eeVz7s&f!p3k7Gp2L2BH^IH~IF4A1W z?@y6;-^;Ik1%Ar!TOUwln~MH^$|LL@Sg~&Q5Hiq1ub=XJdAppIk33oN!li0UeE%`= zt%|&#@_SDHN4|rni}tO2w{w)0pJN^UkKliFEEyPQ#BTD{15DW(emp+S%GT4vwDHmo%>?88RB&XkjL#_Ec2JAnO+}Q#%}d1@MeklUu}2Z|Mh72 zKlXp!@+dIuw?6-u>8_1lyv3Hfcva2F=|;Y!)~0Pr$1UgCv?<6GOMPRKbFUsFy-@95 z9{2R-nkmyw@15=6He-78r`+G(pU=l1)Lgd=H`<5I>k4*XA)1ljeC`&@`x$S`NO+pt zg8;Ur7JjYS1(cb}ogI?dPY8~h2dzZ~dhOei+3Km{a(sb#{kNI7T@Lnp><=)0dS;k(EKGibN145bI#HU=5zG%pw>c5 z51rVWSPR*oyP5jVm7IY8zaQEOir;&B%NHIJ??{-EJ>rYRHCy2QU$ovE)4-G7*e`fU zG+39t@mcX5QqFGspp6NAHl9x8W?(9v9r@$dmdlw>_-?_x3wF%o$xCD1tWmtT>u`r( z_s!FX!RwvR6nvg|1pD#v&z%=y-$c5J$5UvdkEfh)d*R+4>`oq_?Gqo`Ip#ig!9sod zWFJmEWZ{JTXV1HP?d$y6DSYyTrCo>9-3fEK#UF2sCtkO>+lSZKWNhqa)~gd&XW&<| z?}-0f{?Nf5b%t@v-ecSIE9QMAHXQtNb#8)lbMQ;P?e&A$wcFG8gx}DRY29OeWP53e zdhIzb@bXF4guXLawtnA1?d$0NNsl*IzT?SKm*-ZZZ{Gwou z`^cmJ+{YvPuW`d(1`fBKy2jC$%iVfiu*MBv-;0m^+q1SS))RL({ZSi7gE{xkI27JZ zpZ(d3)X|T}e^N${-6A|jMn(>vIn5jE%&WXPjJ>UX<@urTBWhTm*I~oY&a{3S+J88; z4g8?}+Ha*?6?w(%43SDdiqcLga~LEoNzS%0>4UPJSh-_6dr{n-n5Ip9xI&!ED%JWR zxEH3bKh}1q_`#wR=E|(nJ})-;B@bX1@!G3pKi8hipzV-kCXFxJHbOofc{^CR;5oX< z7tk5aLiuSpU8-Rs=OxG&rJs4fxh4W$uC?d?>z52M=S!ACKG)vBjmh%Ko3$@3dj>YE zNP{`PNOlTj$d~jTXZbg)UE7Cs2ATK^BUCQE%eNVLN3gLhTv_o!x5g*=0Gc+tT7spG zPi2hk4DG%k>qg`@;jQ>;v?B-}mw(8;9G;I0dVwx{n4foXET=vq3s6V+jGZW8Q&yVS21;scXeHB`S(wKRg^t5eNt!XHLuwFw035% zJ!Wb9r#|^K*#5;B2W!e6wbitL33;=Ubz%nJjR0J@zv*YaaLlO@l9?sVm-O$`(1+~&cUxG9R;xcb|0Aw-xD>kcpgD6M@i4xWV;>~< zVJTyE=Y9TSn|KK}^ECxFf6p&b`(@Co)=I|ys@7-D49hOPL2%M}Qt&Y4e2!LvQ{lSo z^iGRYi%lD`po_G|EGgsSUG6lM9FvN0H)bvT#?&bt(0jKgdtm%Ogt8^4lpXBKo*`eR zg7R)(37HTc$9@@l;RVle7C0b$p&vD(QNb)>E_>R_>C9Pv?WC{r>kEnh)MdZ+j${n* zVb0R=rU)AE-{0}BzvBz~Tf~Aip8gIyrN85m(KNR4<_ykd_4U{8M+UVo>0hwv+#pE#4hO@)1}x2PVN;Rad%5d>z4Sk{QeZ1hWT2r zZ>;SIJcdqmMpt}Jv@>(!&fHN_(Mgwh9q)BUgfqup%oJBn??u})khg3LD3O1@l?KFsCQ{}equ5p>wI*E$M<}+J>nLNhwuQ&oAj-ivzb+B|S=N2nh=03cLch)Z{eIwszr`VxiOf0GP_{%4AZXl7mz;{cI6T5I|w%-9~PElZpJ#Av-L1{b}u-u&p{uhEh8-sG5?W%`x@{p z=SNCNi5AmN{ZCka1U?W`XruHVkDq+DQ2*bAZZbmpKj+CeSY02vtu9-?Rl2Hh$+Dw#*#&?_d{Rdb6YCdU;1y1=K|jUf7*9aT$;YvE}xs+;dAj^Rw-Uz;DU=Y zaq+sK&P{P|;Yi^#wwEWdYl|KN@x|H0*b00eyaN-p#w5%+_O6Ax?Ekd!xJfSu@4FIa z%$7nv!~d6Rt}O25PS!x9eL6GpB0ML6-0WxldCuxL>GK4;Eeb0rb=;DuPol)Jp zI$3MHI%Q+n{YS)gDWd*cG?r+_>I{B-8Q`&g8|x*%-h*$qf%B)@9r7|mkCkIQ`*nzR zC#w&n6RmAyHuhz7utIv!*kse7-U`vuW4jrfqdU&!9nRBJVZE(~fKR!V7sU5mT$hh0 zYb{15kj!c0dGNjCQCB_b>FWNC9^biWhO4*VITzw2t+g^`_O7)F^BL^tIWNA8wa*&( zz3)-M-|A3lE2AVub9LFP?B1}oO#naeWVY1}?0#L*R@v8E5Aa*p8`DGabgXZN;H&q7 zJA6NHTOg*`RcARnLip5J9&YX{A8WC8$A~xgA8qR$6M8lJif*xHCyjgSrPHzJy=na7jJh*g7-dj1LEBCS8w_8+y6n@ttoUMs~+t@f9J=!>9 zy7x}@jMy{vN0Y;lSs1@$cltaN`Kd~Ah2$TVTqIl0IW=0p)DP^etF3N_4r}}6@e1~P zEp1xa+v>pC$=Dv)H@EXJd8?ZTx9>k$_Qr_dBiIY>nimiD=Uxi^Nd|K8A6eZCH-|5R z8~r#-bFQ|~Gv|0Pn|zgn*$mq^_AebTt8p-^?0`?@*AL(&KRD)WvOAxh_e+>OLa-|A zpZeCYM1sTVJ}2QT^e)?NjyzF_UgoQu#sJDiOWJ`H+9ezBqhcVDdJzM$|ze*egP zRzAg^(%{D0k8e-tCYEBZ;b;bar8*VEG{c&Moz&V5+}Og{R0aY&?u(qFIC{Z!H+Q@D z;@=mJ_R<~vNW3vmch(2Z##~ICajHKh@l6hj4%{9Ya>g06fMHZP-cURVUHu=&r_j}f zW3xv7pRej{Be)6e{pCU79&iM{fBB-uF8BeTM#*^^XS4&l>k1gVmfQyn-8w}ZH}`L| zk#1yYfziX&N?VGe;=KxgFiENM=TwlI_|&Hwaotd*lDAXD={`BKV;Ts}lT?DApq zWiDSvKH~Bb@|7-MNxsVEtH_Ub`O)O7UB0@ZSau5!7F%eaK3sOnv&#gxQ=Ub6Htv*X z<9Jqk%ClOYac-oq4cd;YZQ2^o_~QION&i!>p8qHDf5P=GL4K;sPc5v2Z|f<4P2n@j zHn@7P;oS`CYAAfqH#2yCUEwpnnd!c{j`B14ztOeVNPf1<&nEx0%Rf!N+vU5-A9ne} z;K>qDP*e$@9{}`Q#bn8NS_(r)!taw?2UFjPtFcQQ79DcW9i9r3xF$ z-SmBcWJ(vMR)5Qm(B?w8{qFYqZ&JACf#vFaj{C_6T!~8#OZ7!RwO(| z^>}c|PE%bqjR8{=HyP>+ry5N)bxh6s40cZDJM-0j`ag98@Eh#gr+VSp8P&^}W~4jb z*hf7j={;|TQX}6SGi}sAj-M8pG^W$q>8@`Em+e|GZB%^Bw2{#6T-HSR=R*^)_0zua z$HG#)hI%YMrQy|!yx90WvpmI>2~lsDGc2Wr^-))t=jRnZXjz~wXY zjhsJ(HR8?=hsT^}i)dX&)=3k)gnbuqvz9wnuh#mR`a1RoYzOSYvmZ}?;|-&i*O@AO z_>N$gTS(oO_GoX;s&cbX{FvvrE{7(0H(%r7`K=wpOf%2s7vg~Ww}mr1y!$@=n?oH7 zdf)R-JfHV^w*WkfbH{r7s5{J%JPqv98spJf#!^SKr+?U4D&A1EYC&mdfj$?gdKDJv^FvW)P>o9zEn(I{8-LcaOcXZ+c_?yN^ZZ zCFvdA^;+Z7Yu~>+{R;JFdfz{4-|sw9KYfSleOqf1>srL_^|H3@-34yDvDtpeNi7{8{>k`%J5zp^SpZnatbhzqj zF3A=L&mk-X4 ze?wOJOmX_&?t0+TP*^W@*7Vi+(Vq00y>ZD?s<*GcGoMY~E?XfnSHDbLk{!Pxf99j< zdw|>R#ICQwHyAr4GUW#8;J^r8S)SMPdZOLFpk4Q|eM*)l7Cm}VcDH2eysXwKehZC? zZnegXc9X`^Z6G#hVL2k&fL?f z3Ei8M<*#XPOKs@(ho0#1`4&*|Vwtud=(fjDX)3$fjyv@J*PZvm}FB z-VJWW@vBwa_z`2zYAePTC0%N)?g15CDX+bdy{e0~EFxK(dd9+ERUi7OT@OmY$xXEx z_9lT}v~B1l#@6D&z^v4B;as$>Sg}Cyo6X(i-Zg8y)D@{2IqigEc(BiRBGzrp-)uzZ zUTa|%!f(w7FY8fT%;6;X7d~>A&y}tQAFR?^1kB}k5mbHXa*B5qRGmDNUMGF7WO_IE zXzlTh5e{m;5~j@BWF&_Q2i;h(GqxS1PVHO4TXF;JT*JeFl|B2-`w!_ync8ZAU#Okb zNHd0U_;mJDaC7zNc|o@=+vJtq)#;r{(O!~Z6YGEvyb&J5KJ0yxE26t}mMc5a!Kg}j zS(jZTKa5gnkA2wIA7RrvseaKXyQfQ=ZZEQ|)bZY)er+;7&A*+awu%ev`6k+Q?cpzS z(%P`7PkL;`wKIa}KkjX(%hO}kAMOjcXQ3M0nDA#GgU!gE$1cRX!ajKTciusZ4|cpm ztsKR8!?fesIM~;reaTgfbFq9RPO+t(wD8p$Mj!g^3!J8{Tl?CoxWtWBcDL6ZY}Hn! zYpdpyZJk)9x%ApPuj@Y*zK8Fvty1G- zzoeHAG)Jej({Op*`TGrya}LpKk3IB{EzSpZR)0G36KmizzA@1tcc!><$)Ed#6D7!o z^da*yeV8mCC5=5=0naWtHlAML$jD^*cQ&)Z!{0{H6bPwOl z^9Q$<<4a~H*?u;9un^oc!#o?|#GQB5gtC~hH8(4x%@cV^ug+A+t-qH+1u%pKko6$ z&ow%})n9IsZ|_T-jl)hBgXXng605Z9!0hze_d<$km$&ig99)$6(-tQptYf@G=2V=E zNOEXmb1KO%HFV-o{@ z$S&usk^cyFDt3vFSV*R(?%0Xs;Kb$ygYX|&oO_$K_9Aek^x|SOO0bRp3b~iE;3z%_ zw(o+q58JAAANev#wvVbV*0aHUUrkx*pFury|A)!@$ZH+a8D~H5OVJn1rQ91QcooMZQVKe;Qr zU@3ednx#L#Z`{1#cNQLVNIiHg^Wee%9z2!-k7dAP8Sq$U;Zb|>G7FEf=?x?IrS5EM zPW>>uz`~_`^1kGrs&mpit_UUH7`ZR`>K8+)FU$y~23{?AE$aubqU?gy9N)gjfD`;K zl5Cp1FE!bmlbm;6C^eUJ^G(<2Tvu~}A5D*F&D#qcVejFn%l?IIkjBx5^;yQJ>)*wv zdB@oU8>8?2nvsmPIJ{Xt30Gl@CPsXBL({)gmC(FHU;X|A?;TrAx@XND4;M8%nU)@9c z*R6327V=fJ-$L`m_3HhWXJv{Ha|L?As*Q#V-q5AzUT@0^K8h8C9Yrx;biUEXd7;g{ zwm;MTVArH$Po7^BE8DOCtvo{#+qzO*ty8#k>p*wjv#|tT*~G4OyAGErfn?s zd`zW~?ixt99w)AC?rpW9bql-07Hh9!Ov$BoJjmM2dEAs1z_%ygCVh_(x7lc1Dz_9l zQT7`3T{NY!xUrQeo(go-JNAD4b#`I)8I6-+?EV+!JDookzFo`{^{HNL;I_Zs`citL z5ZCBaNwT$f9XKvHpYpy`xR}RR=HsZ!5I-y)9pG@bxajZj{SXhdczbHu)bI;K$pL1s zY#p*^DV9Uc2zcvAFXmCI^1{&4x!hS3xiBO=Tuq*Ky!rej&V-?-&B?$F`JnoeE;gOY z_s)Hxtm0sWT>Y+KQJ1Z@dpDYMWYSwSj~-k;li$nr{J5R1M*C5*E^usD&t|Q!$Xjcz z&sef&Gx_Dork5&ey6yQK-Gc+(m!{XgB%JxR!$Y+LOg`U?jQ75tX&%am z2`Tt22gmGP#!b1s*b7a~;A1DmH&Q{f`IbTQ3&_1>>DYr=Rvy^kmcSs-Px9^scTM6|7!ENm47(F*n{I%nyT-<#X3&@Yag)B_4!;@ec`C{Y}{5;tu@-}xSVIB4y{d98pH7Yz}-g9nRqkEB;UZPG&?Z$`EVrbj)~OrOt6*X^yR?Rv>m={G)Z zu8Bi)#I?niR0iGp)aUflZtWQd6?;p(LU*%CrlSAHlP0?$9XC;pTlWEKOo~+uZiLeJ zdEec009?dgaPbQJyaAX5fk~NrFCWlqY@N0Y?TvLX8-40~*@>{bBmWU6J7g;O#z(z= z#!<=`rsl`+Y5l)v;~&@m^r{&qHG?~pBAkC#>~CV({?(8S{E>09zugNLH@?*qyuRn* za%nTLK*moOKi-@+z`MiB@ji_Q`7WpWpvhng-myB(fPtsr15CTQmh`yBA-J+OMbcpt z)p*iHoIRz!)6R=%sc>GdWM0te($^7Nz4Uh1iZ?Q9X)*WEf?B;*)xgDv3cQJ@PzB>d^enCts>_gy7=T<DSEdcbMB+$~IB&eEx58b3KChvg6K(?<`_H zE|NUKovAjR%QIl@KgzT3@m)9Heb0UOSE`ri3y2;43T4#STlp?Tik{_vnz~9I%}1H9 zaQf~Z%b)Ir?+~Zl@~lg%Si{Ygy|gD9Q*1tH?1euS#;Tt^5JUfhtImO5sYmTV*JU+% z9(hV1F7?`ao4#&edLwiCLx*$hQB8|uqd*={%>(CnXK^kK&f%Y9ajs6~KcoAfLfWGP z_QDbTAd%Isy`WP6lecnra`242f5=fQ>%-f1kAZ_v;#1&5%%QkRjf&TU=a#?SJQx19 z)bcm02N%HW3CV?v_B`Aig~o;F&_bo-fn~%)73@or{}kQ4YL7=_x_`m(!o#+m#u*-d z(q5|3L>KKNe%2@3?c=Mbz|z$PEd2{EUSjFFL_7f42me&q+F0&xP0c*Rcvw5Aw?yYr z8isI|65{shcNL|y*2l*jgPwc#ur0v*GCya-_8IwZn#1A^4TA@c zr*Essi-(kuexLSg{}kM|Fz>MV+s^lM_&)KceE;1yjlbg=YiE((JT>{$pt1BX{wLLe z{FmJ-4icCIR}F&( z*mF&$w$wxWC!EZ^mpId9(cRWgr+u2D{F8)yXD)ZGq}!>*t$Om37vZa@ub*=wWj?A3OU3@7uX! z_--`cGtSw=o8<>5ec;o+we8NXbl>vbX}*=+Q83BdvZ0$}z&I3xm%+zMBlwskn~>|f zS?}&}&z|DhdSAQFT0vWy->aqDCcll$edq9I;eN$D*4-&w3E0m*O>AtZ@98_W!?$Mx z$4|AbCpVzSsNOwavO0gteCam&cy;nn%(jJG?~7*W7xGPAcGN}DF3Ypjr%jSeCgO)O z?Sju_rwt0$PKyvr|7pG}CWg@8eJ0!RH^JJ54xT;1Gm9U&y#?Plq?d3973V5Rt&J$X zlzW_5bC63*Q;DlflfSPD;a?M)R({+}iyU7xt%S3cZ(x&O(nO4+F7_t_+v3r55sHM;u>dMHgkj?Q*Ch7RK^$=l7N2Q7ZG_mh1W7*#69jPP5& z^0Lio?w3E4+qV3z-1fVM z!7E1P4zH-o9a%9i_x6fAb3H45o;$kYncVReZ{<#?t`_QQp{~W$wV1jVQ`chZT1;Jw zscSKHEvBwk>T0E~R_bb{u2$-5rLI=$YW**)E5mxP`ZVU$EYIc$Y_Xh=Y=^)6-tEh9Yt+N99ln#Br z-Pa$h70i)hDv=#5Jw@%RptXlM)8 zrrQ$I#nz01{~)WBs1M>ro~^WKYhAYDq|0}bf7kXWTYi)4_l$I!xSx-Eb{oZi;;il% zjbX)aInQ}Ld#JZd|M;!?chcS|O#R87@)3FGS@p4#80YB@&Mv{DIae6K=VdVCuJ*>A zT?TCa{P$-F{22m&hQOa8@Mj4883KQXz@H)TX9#=(0=f52RF_Uq_%a#n9VPr!qSTlk z68*?}&wOO`7dNJONbwN9yR>wkDSt0x%zIt@c;)BEzxJo^^vwGhLm}DEmkk}pcd^px z#-HsnCfn`3PP<|mQhk@@r|(XZ=)1Ge`CORqCedD956^qLyuST0?U{fve0!DcxH|7O znIVnnH)#JzJUM?`kJ$l=xsOj%8E>`XW3p8wDqAi z>Xm-InF#qvzFg@aS#ALzF^>PVz6Aj9k0~ddpxpoJ>(=S}XS{N2KCRr)XKw<|%T^i; zm(=(7c4BQ+n#JBaGdF&{lyY}Anp#`#;l6TxWmMj)k8+pVa=ZJ=SwxNJ>-@&OljEu{ z_uk0|`8}QMxwn#ZFKJcoy^kIt|8A~lU5NB!o@KoM*KTtEcjVqLpONcXJC*-m<$V|F zA^v9!w!U|AJ!`g;|A2H^?!9bL?){;Y$d4soPWkR!&j#Auurk-Pv6f#0zd5;{pH1Z# z;8&mP*{O6HzoWUH?U7v1WAyE@Os?nWeE0Lixt>i?elz(c`Mr?qd9aG#Xnxf3U|X(d zbBNz;evj~@j{n`jZy~>x{I>Ah&X0QjcTcWoOPC*RZdt;wi{J5F&qIvwA<8}ULayf* zA$|?~=+7^n;CCX|^YB=H^Z7l%k3KyT;1}oD#!vsho$J|J%8znescS3Gw{GKiIM?$_ zp8v9zAASEN?fnDa{sZ6s1OM;H@JsNkWZWoi=XxG3<40c~<^7|t{6Fly3w%_?^#?weyB84=E*Kyx>RbU0kih0a2pAF`0TLk) zc?b$fHoKc-Ws_a^0YMQ_QSnWEwAxy0TieoBTiV*zw%F2YDYjIpQj3a;k1DOGKv2=r zd;i}vGk5nUgld2P-;enJ{Joo-J9FmDIcLtCIrH4R&i-E_{>w7t+XY<$_xtN{Z^TJz z#D9I*vE#Qm_VQ-jYjJOI?5GdVUAXtjFvUOVUVcc?!E^Z${Nx7mUWR7^c@uqb55qkK zwkIxIT~W4r>(;HSSrqZrWhM?*u$t^F>g*`iOJ^na;mx+}( zPMOkJ&YZ{ZeeAJ&A9wnl(C^Ca+qbusH#Rnw=dQ`EEUxtXeEcTIUNvNblcMt0SUFJ5u_>8G=b04SATznX+y zvu2IJ1DYf7b8}fPF2o^LAG;48%wKQU`w4r?mM!F@hc!Bl!|+4~NK1kXbcDo3r2!Sz zD3I_n*{F?Al;u{`m-k!^f?K!e`Wv^hvS`_g-P>1ypCHcqxWonW8Wp27))UC}Th@Z!*5|fH%diM6N&xNm9O7@Z=~>S(DxMu_Y+T*gcm&l6y`er2M^O*a!_01IZfkC^<+FajNPntv0z)2=58A_3&d!7y zQ0?r^#%No#@lCeBzP`Qz<=Of!%m?(hzWKq+PvHr9ajh2o>OoJ$pIY6Q_*1^}MhFW2 zYt~#W=n8b;izoDj=X1~5Q9Pp%eJkn>W(NND)?0Fmz^@$D;`f)cEmYv1Jy<#9>eHtj z_8i5kaprQ6sv>QDR-<0`)T8)~y8&Chbqn|n0dzay6t}mmhFtZBNnXZQY~Q}R&*44w z(G`u57u)|r&YrAi&z_KFPdzE%O#vmj@M?1Vx#yn4b2sRdfl!IboDpA51O>e_5nmzc zui3J?=Mm=jAMyK3hX4;^2sw}q<%dCv^5aPgpg38;5mfT5+@dwCZ*FcpH@7d$KwOL> z0I?Ojfl3!CVk_C%78J8j+jd32Pp&NI>T9Gvwlewj=c=b)KEY?pmNk9KR$n9WsYXdZ zewDvb>0|XZWe}hoZ~~OGtzZj-fxQ7A&s@K~<*;a=YjW4@TEi+}?%TIN#fUEHM_P)c zOYydKB=tEyrVWc;*Tvi^9R!}=Ci-H-dk35e*SV0;^6Qu{Ud-h~3 z_-1rXapU%WcwSz5=_@@6PdH2f8;gO3|Bc%jJA1wSEcl-Mtb9p+ptQ_&ScDGe(z6uT z2e<_z@pR!I^dz`@kr*F{$Ok=bAXAW@&_M2C%8X0W&CNXvVPZjUkuHZKxX!{Y;`m2# z2|r7~iQYK+S31sLNl2{HFXJCFNylLys&s;bs(_c4ekkC?jqnJ?#V7hi$r1TVONlN? zaTWoYmhl`F4XE|S|(7vWQIzq>m>d`k zhlt{m%EOZ){ow8PMazdoNmq!sfgsEkS2->b5dWO^UeDpixN_$qr~SmS7(=de4)m@= zxEjw~JSRB^PI?5-luR3xFVhC~6641M1NVsWg^mDGE34u zvyaSo2Iylfd*F%~UQQy0r z1Lv(h79QrHrqh0UyS)2d;~ZSO5x6wz5Vvz+UJ2y|-e3>j2H^eJ#i6GM?`#j={lNP} zC%h=)qP@}6dr^CHFBk5#_Y*KXHW#;{Z9M9MJQX+Ie7IBz@LRq3Y~-3K;Qi_ zHzu5Gk>0O2?jZ=j;j|Cn627hs;U*cr?m>j_k>TrMPp9BSJLSEh8sXDqczqv)t5g`a z&~LO1-#E!>&v{CQZ%P3!a74Vl-!cim8N3GK7Zr%+%}+S(gB1N+N}9ugRC6M>lCgLo z6pFMqrDClt3!E8V6%8bsVw6?+N)hbxA9%xN290nI-ildu_M!?z+7_f0A#GhYMXqfi z?P)K}4eK)Bn{M3u^vSf3yf8ORg+pDO2!0b>nEPBS(}dq~VeV5oSvPvr6Era^CLP`; z(wqZxH>2+BW%uqu0(^{2|-W&N!M0mym8rQ>~mvMl{`y!dWd%F^F*!sIybD!Cx>n>P(9b;i89t-lr_Xfakq1H>}FA&y9PZYY{;o>;+}Q zpInAh24s*ufwc&O=131H6Z{l3D>KNRfYi$=vpt|pQ0nEBr5S)HU?L1zy6lg*OuNd1 zo(cM8+7~haPhgTvd%y$A1V2Uj9)>)>&ty;mRlcV>!zr%H_eNJ~vffYa51Q?i?i{>3 z)81vhpYmZ>`DEM7A@v+}Nk5ol9hCrp^n*F$+%)jZ$R+(?&h)O*q#w*#)K%Ii>n!I| zH=p+@b(V9v7v_d#z2|gUfBk`k@#WWCTOncIed!L`846k|d-LNXd z$8OyFlyy6Bpcm$bW!(-WGd=41WLXBDe^e#_q$~q*V)N*0EkGD=-*I#b;9UVdFy!0h ziDrU|-{uU!6Oi>c@EH#%6XXbi=Kc)86Id(K26-Ua;D3@c9*h(Q8cXsE{r*DMITDNp zlF593p}(-K5#&xgWRmERVbIy)dGMBwzW>17xPW8AMNjYL&cW#E!ik-K{Mh``l2XCi z6Yj(rbH%%RP6yx7xWyV2<{p_gMf98lbHzB;OW);lEZ(Zzes8%&L~$>orCbm(_pKcv zc(f0y0RL$&UGJ0T4$zMP0jEyjAG~#E2b}*>KY~X4pv98b7iT#K<~>MZX+MLG@(mfq z5|Zai7Z(JYP&4V)NI`2Xk-|WsDG>-RkA^W*q&g@I=Le{$h^V5A+?b!wq<|Ptwhy8) z>=s0+d6H|!{CxHkc+xzc)6;`TeRWrOXMIXMEL0tv9;MMmd*qTQ#=Gr}o@ zNT|u9@v$8>Ug|F)V>A1+a|915>kAmimm%(vVJ@e1^EP2(uFkQZwSmS6N8x>1SzSAT zAMn~iX_;&S;AawB(&2mJKDdGUKVb)W(pt@4kq(CR^j=-HKS~FkLtZ=zOWPhy-DZc2 z7&+~Otqwp$sK9_@$Gqbu`-#C9bc8Y{`~Sg_&T!fH55BrH{HVfs5Wsh%Cn|zU{(C#a zmHa>J3|I1FMZV*OrCBQ1s~w?$bq09iz(44TilCGyw=-Cct#YZ`?{Gg+!vFHSw6Y>05Jlt9kkB~CV9P**3?}m=W z918O}uPu_8;xcp4iY4C51UMGnr}a02Mtd&#kPers@53E{h;ZCa`>B08!`DhU?+lmi z=hTwU@MGzP@Ib$^GrrXCsq;F+W&NFc)R^&D^e>z-S&%S$)J>-Vc-@HmR_EXst2)!B z_<)lBG+ZaVdvSl`Sa|=Hz7JenkG>6S_!q5r+E1GSx~S6*_e(N<+U!p7&UpVD@z+K9 z4qSwFSK4Q2Qu_=SVU7L7+0KFHZE`T;*z#v3(` z|3w1eT7mmQ+=Gt41Q~m%2meX9#a!xm%Rzi`HQ=6tyT|e7Py9##T$kadF>n8Fl!3;$ z3vmzbMj0?KX47yR-6%r>{Ape?pc`da1^yS|#-Qx@U*Jnu3io{6G~z$*7YTr?5Vv*Q znJb1u0>+B)oJ8U7kc0T*D#ksuJNOe%ApyO93a6O6Sq55nxCHl^-64n41DzKc-W~jj zr;=eJo};>1hVhUgubX9{eYkVFS%w10unhNE-603~(p83gWOwikc`T9@2O&z&)@VWuX14E4qU}@l<-C_5B*$Cw7M%N`^R| zb-2y$kU{C_@CV!{FN<$J)`yNnYd5t z4mn5wT<77Q&>j3edRPJ(R(G=u`H-Q!n`IaS87jM320B+ud)IxtLk{qzs|9y0?vuMw zhSA_((H;CZ1`RTF+f6d)5THA6r3X3)*=;w;;DZ{v^HwtSfDGMsD;YG%&~3MpL7b0* z9NqFH89u+n*a6LwU4?t}|KIfi9gL*=b3L$8&_lPanSWOF4;@gu=(hW_qKD7rkQ#t3 z(AeuW1V<>xn{Y6w>UeBr#}llz9Ekc zg~yk3mYYY0qAc|IhCDJ9A79Q{ZXOv*ve4rj^2jju_;Sv2^T<$|g&yCKM}~37m-ATgTglJ|GIZOm zWatkWy6sjn41f&Xc9RUBg$p{!>CXGJpaYTtIvCWQ_h(2CgQ16RyFWvEI0bs>w)-=r zhk?*Tx80v1J>)_U-FA~6!2iVVyp;?mK!$F+l?*<}&~3Mpp(kYMwp+jbla_D=r(&q*~Ry{@$B85H|e1V-XzkUx0Jzz4BdB28G1m5?)#7opI^{` zcpt>-`{er|R^z=8^j`4Qc(=uAui=SzThRL=*6fw(SJ7)u&cc0$dY;+oNoifdhIGPn zak|3CJJHrb9^!jVFUj{BQ^j-eE|-e|UxH`QIdJU*OzWZhjGPn7#!on}d}2i<_|ORg zoFN!FlKzQ@2;#MTm2BidHnMUg8#t0xjvP5~*sKqQJFC$i$bf4~50C5R#?vQZw8q1*r=LKsLEBnJ*0Sc%WT zN)V+G9=KU?bvI&y-w_XQlFFi_A~nrI3WJ z{uqB@QE|!G(s6FZOqx7pYSpyqGpZL|d`W#%WO++6y>itRSKWI17w-JxJzx9!H@~&< zd*6TP;UCODcKQ!D{piO(nN_!>;mWJOyx{x`XU#@16mE>gFH2l`<4reTeeHc;z5mOP z{Pbr(fAkl>y!%(1AN%!hw#>cmx4(P*iQjMi!?q{?_@{-pY@d7GpPzbq$6ua#_MCHf z^7Ch3d&3QXeQwzBg3*85^_}NmcyaejFTb+q)z@Bs`umo$vd-RnLe|-SF6-=_ zEy#P0bKrv=vhMbw4O89igWXt#c#=t=4)=*3h~7Zv6K@qGXveE($LLY96U6b}qrjg7 z{y(6B6Y&;noH(OFh%|tnctvb4oSpB@PQvfJoy_{Oei$0`X9L(NEC;@B5F3nN$T*dq zhO^8=;P=mj{c~oqv)NEKj19+I|ITH3Yy>>*D3*`&0Hd*{@5lGxi|`%r68wT&DI14x zdyZ!l@co%`>`_<1XHH@Pyu~7jx9x=SwworrZ6<_p? zN9<$vFLne!yJ$0<3)eKQho);j&Cq&kCuqI26SdyjNm?K6WUa5(PwS7*0PPelM;oXO z(gtg}+Ns)U+UeR5?F{Wq?JSLJmUgx_R2!xZ*UrT!PaC0))JAFfT7foN8>9KPLai8| z5^bzjs*TgiwDH;m?L4hqo2XT2lkk~>&s42So2E_IW@yz~jW!dXSz4_&TbrZRX%}eo z@R_eI&@R*#YKydsw2QUH+7fN4c8Ru3tJeZrgBH|6T3Bnsr&)_=mukzksMeyjYB4RY zU8W_pq?Xds+6rx@)~2n}F4wNmR%=&kYqYDhwLRu(*Wz=Xc3qG8+Inq$j|+P&)NaA& zR_&!87xh@I-J#vlqrOK_ySqoEN3(V>K3~?p(j(R*q21pjtv#T9UHc|J-@@nH+D2_- zk88E>Y2Vi#)*kM$Ui+c8smDz{Zq^>b=V#i_dfcJ?0-s-MztSGV=hxbAv@P0iwclxv zYg@(VNsT_+#plo3Q`*zo4(%`6GupG-PVKMSbK2juUE1^73)+j?ZtW%QW$hJhkM^qe zn)bT(cYNN|-qQAJ|Iq%ay{+xj-qGIG-qZGL?c#GtdtduN`%pWqeWZP?{YyKd{adp& zN5@HYy@#&rKHboJ>L=*E^b_^o`bl~p{baqb-cL96{`vs@6g@{Ds1MQy>$&==`f2*< z`VjpL{Y?EVo$Ho+}osx%xbP zzP>=eP+zDo(l634))(tb^riYG`ZB#<59kegP!H*0y-{z{oAro(slHr~>MeS!9@FFc zWqLwS>M1>~uh3WOZTc$xa{UT@wSJ|(M!!m5t6!~OqhG79)34L7*Kg3*>o@8*={M`Q z=(p;(>9^|}^dIRz)__KcW9# z->UyX-=;sQe^39u{*eB#{saAo`le5j|9748|55*wzFq&b{*?Z-zC-_u{*3;tzEl6J z{+#|deV6{c{(}CZzFU7ue_4M;-=n{(zmCt}@p%iMf8g^rKJVc39zOf^1NuR|T|cD1 zuYaI_s2|op(m&S!r61A%t>b4beaxr%=K6HseBT1!g}xJfi+mUPF7_?<_3@qT>+4(Q z^ZN>YMZRKRiEpg0)Hlvo<~!9l!FQgo+&9rz;j8pb@=f+l@lEwr`KI}%`)2s6eKo%G zeKUQte6_yWzBygwAOBzFuk&31`Q|D47G~sI;#=yw1o8#&3E~sRrwN}3KFjfG!6$~# zW%wlVN#nD^x6-!?pDXaW5}&K^xf-8qeAoKc`L6R_@4Lab-gl$#Cg07zTYR_rZu8yl z`vN|9;&V4XU&7~Je7=IuSMm88K3~V@oA`VSpYP!FU3|We&%^lq5T766^Ami2iqFsS z`2{||!sju3euK{z-*0`t^F4vj?|oZ++wghP_ebA$eE#fv%J;Nyhwm@GXME54cKZJ6 zd(QVa-!9+tz88Ei`gZ$X^1bYP#ka@zs_!-5>%KR9fA_uVd&{@i_YdDceQ*2r`QGup z>wC|)-*>=w(AVxej9$ix zMsMRJqmOa2(bwo_m_~nNfN_eEV+=F~8H0^n<5c4`<8)()afWfGahAai%Q)K@Y78@m z8|N738hOSDW27<4$Ttd%(Z(3VZv>16BWQ$-u+eBV8O=t-xYSr~M2!}s)rc8!<1!;* zB#o4jHdYubjW%PIak+7YvD&!OSYupetTnDSt}(7P)*06s*Bc9sMaD(O#l~V|iLunU z#8_t3|F6=&!B}tHXxwDnY}{hpYTRbrZfr2VVBBHcY20PpZG6%Al5vl5ukmH$E5?1s zSB?9PuNe;*UpKyCeA9T)_?Gc)<2%MimBgVfC+i>tJrJC8p)J>mh zm_5xC%wFb+W^eN(vyXYQ+1Ko6nr44E;Zx+N?3pH)oo&%vy7{ImfIsFEHnt^UV3?0`o$1p}EMs z$h_EGY%VdEnwOZ%%z86mHkd&(WQNT~v&n2WBj%;%ax-eSn5|~ajGLF42{UP?%(S_} zTxqtMtIW&IE6mmAmF61rDs!!QwRw$st+~#;&b;2d!CY_NXx?PrY~EttiuXm|Zf-EY zVBTTgY2IbtZGO@Gl6jALulZ&3E9QOXSIzs)ubDf{znIUM&zd{UznagPe=~QP&zmop zFPgi}m&}*VSIj-;tLAIw>*gEg-_1A8x6HlfKg@rcZ=3tfcg%Oq_ssp~0rQ~QZXPn< zH@BL9Ft?dcntwF^WNtVAY(8Z^{l7~81M@@ku=$bsvH36ai1}~RHXY8m#(Qv``?$e- z@)LM3ej@M9PjaU(+~ocF0DcP3;RE>~KA7k7Q~7E9bUuWi!O!Gpan3D%HXq7|@!|X& zelE}BBiy`<@iE-b3waSQ<|TYAFXiKS86VFl@bh>%pU5kCC7;A6^C^5Puj14AbUuSu z^BR6WpUG$OT0Wc4;dT51K9|qq^Z5dPAz#QB@r(Gyd@*0bm-0*aGG5OEynzRKh=+M2 zZ{p27lI0Hx;`}n6;7Ok1X}*H5_>cIH`A_&G{HOe9{O9~p{tNy~{wuzjKgNH} zf5W%%-}2w_$N3Zd_k1h=1K-A<Fg|HY5+e{-8V7PB;~hoxIS%dmP{Cs@6#6RqCXNmd{0WUH^$&oZt4)&T1i zE5{mW4YCGXxz?%HY1Zl15bF%o6wjQ&7ZT-gDV*S?oo%Oi& zg!OxCtMvzKoAspiN9#}4cI(g9Q`Xbg4(l)0GuE@#PV2AMbJpLiUDor~3)YL)ZtErM zW$P7dkM*kcn)SN%hV^&rP3tXduk{b>pVr&fKIkA1S;*Y0PVc7J<-eTto9 z53~o_gY8`VRQojhbbE+>hJB`emd$O;KHDB@53`5c=h)}kdG-i>cw+rmi_88l5 z7urR3v0Y-1wM*@Bc9}iio?xG6m)jHV3cJ#tWKXuI*i-E)dzwAno?%zpHTL=TOna7H zYtOdl*md>=_FQ|OJ>OnnUuZA17ugrt7u$>NCH7ML5__3lZwKrKJ7|aOu-#}k+0Ayu zzSLfhU!ZQWTkV(~w=c63cG6DSX?ume(r&X?*_Yc_*sJX;?KSpQ_FDUD`x^UNd!2oq zeZ75yz23gjzRAAXzQw-PzRkYf-e7;hzQexLzRSMb{-XUQ`yTsV`^)xM?ECDm+V|UE zvmda(Zhyo6rv0G(E&JQ{ckGS!ckS=l-?tyKAGUvB|IprK|H%Ha{S*5U`=|EL?4R3@ z+P|=WY5&UJY(HlI+Ww8b#s01RJNt3_3H$fF*41PH}RafzBXjFn%%iROdA3bZ3ZjhI6KKmcyON&J<^= zQ{_x^raLp7YNy6I-9D`XQ^|Ev&^Y?0#1VybV5$pX>^*LW+&oY>MVDnPK(p(#GJTunUipmPRdC; zE1Z>1o3qNf+_}P8?Of@sajtUKI#)Z_IM+Jsoa>zHog19>&W+AZ&dts(&aKXE&h5?y z=L^mq&YjL(&fU%zoi91}IQKeVcD~}==X}+<-}##Jfb(_d8_qYK2c2&@-*&#^Y;?Zs ze9!s5^N{nf^8@FH&L-za&X1j+IFC3#b$;gj+%Q@ow+p)#>P0vDq`G2;D8p8JU8aSnK5U*zC9QORRC*1fT}agctScDUgj96C($8lEe84Shtsr~Tm2)sp7W zb$HVEaNVni3g~$LAM0y4-l>l@|AXTW$+C>2HGPz&bek+oX;tk4V^JpT(;O^D z*|AS^u((a?shHl|1^pEBUhb7gmmA4GAHX2rd-*b#f=(8f*2N_eriiOY7Z;_|`#=8U z)tSHInt61=mq4b1cfnSGOgACB{p9XD)tos&Pa_RDDODpXvB~$4YE8A9G&gufKk>CVAJlUH~52ON79!?};2?-bzjHi>VG13|; z2!&Tff??JgUg-uUq@Xp>5@x_-DxO*u53_JiM zMlKJth$rmA!>MEjPGJRah{l4;JLK{}QjwN$Lm(M0XiS7JOM~$$78Ll|cp}}}ieKJ! zrAnp}6icQ8sW3}~Gw_C0*kxp;B?S$U6csv>Y1NF4T1F1+u zG|Yps*2YLvI)Nx~q!zi-SUyK7!k0tb-YnL*42%=0bet!`sdS<>9I|>dY>PJFAFx_k zAkJiMwQ7D$9xbBF~)Y~uf$t2dj2Voj-;GmjUJ_VdNVlS^SF;Reijiu{Geys&se z@i;cMEBPZKSQK-M!H0)<3#vZS8s?M|>dmIsEl9%1ppn{eODwSp;b=5e+nX&|P*a77 zzo^Z77r2rC5O7i4XKz*)TNzI9+CUJ77)v&@78qreO`cpgD_jQb@pQ^X9hMBI!mTS95+#TGDJ3OeWk4_t`Qg7>&SZ79`0ygRtMr(h(f(2(uPc zTqGHWGYlp1qj+G&Qi(uo5;ckLCDK?R$cj)R91X+v*_b$fFE7v(PL4tCw}?g=Zb>5p zY<^`Tf_%yuC&NuGU@9H#ibxD7FcoPe>r;euGBD`jge#lx+! zbW<~zeu6_rG?^4nu1coDEu(w06|rET0VPa8XO(PdED-`RFOW4vn$X@;Dg2D!DrmPg zmUZD&A{09SU)!5;*ELVTf)^Jane$*c8l}Ejz{p8+2o#D0TEj{BYG7fE04#J}@HW(; zOPk^7kI>@^r2;c2zV|qkW48M0fFfDI&7*U!XvFK zpgLGQWf}qh*Rl#G6m4X^p!bagmG1&@(qiV=E_c z(q}W8<3y54#G)jMh@!B0d|FF9wTh46Y<@LR!qH zi?Ih9I5I6ow#6i3Dwd6U5%Lza251<8^rje3$Mbn}B*oEoTH-Nk*CU7oDks>?!cbzG z+EXN15Nu4h1}V^%%7$BE9xZS^A`SgYY$b~{!$CyD6><3_#m55)Xig3bTf(X47)Bb@ zg{bDphN+mq!dMJrGjjLB@4Gk>?8ZP;I32is8f2lWQma@KMPv)l0)^WTyKu|xpJAr5 zN5~|xJa^bSg25GFbcL=0y?8-G82xt#kRq~7j9j4+5|lI(X-GFRjI1bYD@G2?Y43q^ zM?HR1PCwWt`xf$-)CDtg$pthHl_4?29Yd)F7@S4oDTeOP%@j?srWCwR0s}-0eW=q4 zi=MSHEz}5dLWN4XqIV-B!N68HPuXFM{!T$6BC?=0(h`q`$=AVnl#3;+$y+=;w3HVV zUtri^0-t zkSwvFr&$b7=kwudNlX%kX~sAlQ*VYbF{}xr*(_U5ni9s1JW~U$=ceFI0wEzAwXSdi zL(W(lofJtcA>_GZjg7Dt;kag_1XweN@S-6QUWA10Ku?X`6@}hRU@$*NYe)4;?_x2y z6jHzhAu_tgRlH+9sIqqQqGcFCR85;Z51NE>W5HlL4u=fo4vn@I&_4{5=gB^YM!p_6 z55>YsDq|zsC=E)LtM4Ex)dp%$^jWx?ZFDK{ham}pT2T+8eeq*Xyr>)n zV&E)l?NcI(*;+gX&GSf-LmyDmf1cV|$3_q$2=ldAL18CLl13@*iY!uf>B=x`n(&*y zRBdvA<&K$R3BDo#y|oc~@^T8HuM-10ck(#`1Lmy7V&d5d)MaQ2%Us7ffzMtrYZg}y z8@iNpaW@%r3%9=zO&7#m;V@)&gBW_DwYzyBL|_Gmf|T(S^1FjJnn!r^d*MoGF``?x zB9ch)0*?L=ZCZ7*c}gu}Mvnmy2_|}3VNS3QS!zjurcwVr0m-gKdM{Nuc^K`Xs9xfc z*ndrWbSjLQ&u9$d18j6dGRfM4a8{qrKu2ZAwB*ld9#tScvKTYEM!>=tXfSjM)D`0i zd!{6eH&ldd1S>awa;)h5XmFegS7IElI@IKtU`vQb2WZmhpRo!;y%#N;B<0ZAjkE;X z&~0KI-WX1Jvtw{Y*Z?NO;pHrakt20z@bKXvS~9}PpaC8FC8eE75IuHgsn`pjr zSle4TAn}g}(+L_hL|0MA0VkgA%*X=NP(%$JMfZ;KrwZiAghth%9;f1nv@8qHOd%_m zw>0E#l$x;~6v1daL8F`$29`1WD61TVuxPlEMkEQ0XVenXYF=PzS%T8)SY(PvB;9+Lm_;kH`>LBR|o(@)Zrr~WdzP~)+Nuox|oxv+7b zi?yzh>s7G?Ms;GH1`BLzEG^QoUZsku2Isxq`KL%$1V}fT{4$?dCBzszB^J5z`Q?Fl zoE%yl4AD_wVu|%WHF%P(nffD|;Wq}-QLOF7|0kt(GqIJC5JpMO;Yd?6Mp9T`!w3v^ zC71AE^o%cEdU(_Z1aMm(Ka@edSc9;3dCfK4W<4=g*yy*X-p}c zFfFr;!7qUeUKEDOsHIjc&?K-dONF7u8n{EEOCwdWE+yJSA{~da(dG)Ubcsf{0U=mf3jEBP^)`)2s2C!IYO~u5Mm6o3AITB48)e4YK)S zZMQWP!%W5tBVoi!FV%@$xE-32MwJ$_Mw+mOiP{kg2`8o0D#{wtSk$6kNVaP#M**!0 zWa%IVNOC!&E+ma5xll`h4fR9>XIIf)IPp;MbUaW%WrE19;S}bOD8E?2#@r5TE-7fZ zCALCnK&8`UD%?clcB&RAQ7m<*F{O9AS`kjmB|Nvexldj@B})i3SQmo10M;Hjbc(T7 z21=^Ls!J1GF0UCg$D5Qy8Igps0X1b5NKWs)D8j~yON!?eVli0Oos1Q#*v#-MELAkc z*u1IpYC7|-shZ{`Ha!}P$5(N3&t7m%-BB6mPOho)qD-DY*&A(%B!kc>8bT6tE7Gf{ zz?iIxO7+50Vk#sCV;;=uRaG@!tjY6hz0sO^RkOYEg;;x-9*KKFbv09KXYiuYg(Y67 z5KkGB7rto5WGXy)C@;9Usw=1<(gpU4NGKe0jVq82Veq0XO%1RU7z{+i@#YvNHY!Ex z3mzG65lcNTc<$s5!#LDt;xh@FPO4m zo{JU4CI#7}%0z1~D^YkAO=5&22Oj94$Uec4924VeeO)XnomgE1PBD)Q5@ z)UgtGXD1K|hr@-%<4f4&sZ*!TgK2d1PxD|?o+77{4d|yEKqiPGAFYRb66e)U>6p1j zn8y@a-u9r?)YaB-(S?W=lX=tTPQ~t)2Vv^u*`1`QnOoIC3?O4&6E##b*PC(fbZ@L7 znhs;xBh{hNG$b&NB7^l}ii#xVU_ji#J7-<+{0qGqvT)hNJ;G;`R>ZKn-gPdTn0Qly ziB<6wZEVJyVLe^=rj7_O4J^+EBCWK{fd=5Xx4r7^lfLIn8mOOtE^abl9FepbhL2mEWafq7;Hu`LIGzy zXG8#tIkS;@PityH(KzV%2RnEf%xdIrH2*@W+* zx(UDsM$uNufw5^*>#&vF)(KiOZQ3+mSX9=br_2JC*LD3HZQ{1D>HzjPxGa1}2o<{{ zgbLgdLPeF3vZAr$Ir?hZgHeD+LX#;_R#ZHWSJief2GP%Tf`LSd+N0srjV2^5)e}gF zEBxH~Q@yrDy=Es+EwQG5MQlMeEM~#H4jt5-E@0ETfQi=FDKABpGKC+US6egH;|v8X z(_3Yoq=1X*K5Z+Ar2tQ^$@4E_xM9alVbq~G;E<0d#4f;Q9H#)z?0jjFyAR+l8_0Qd zbGVIG+Ow+(Xr#kKIJiKY=QJ3k{RT0d7P|*oyalso&YrVyHqD37o(qsC6QT(c)``XT zg=p-emB!JyQ5EnJa;S>-L~|A__hQ`1T4Ex9sDU1?3fSbur?V-zr{b={y=E-^E2V$M z_*XsWbT%FLnj%E%5V!#MT-@^rSSXMS#}Rg6nfO1R{ulYh|3dMf$gC+U5&s2#k)U2g zm^2-PC}PqBsl-5m4Q)uLQZ#p^vmO$J4dUV=+W!YWni@NocY@F&P&S!1fvA)#B7uTn zIuxLAA{CUY6IiGce934T5tIROyrf_#X2t0inm4OB_J=SROMZkb_;5h!L@6v@|w>H(*Nwn>6`i zA)RBV7!l0HXahj-#Hwhxr6C-mZFwyEjAGO16cr|qYBi}bnOR1Hcf=|yZJTwu%GH!e zH#8j4VPE~O8+1T z&MVQn7rOLltO>I{OcrT@4<+c7tQL*o-MtuT_yr^owm#%=f#`p?qN;nLK@sC{dWB}qER2Vz% zIGz@!GZ2}~nVmwBxC+bRnEg`*u?UCr1MU(YttQCCSTy8W+9Qd?h)Zns@l0`G5^{$k zOM;eIuzn3Gu(PH1x@pBD0JFeR10l703`J~|X0wWcrJILN!YQ%bY#9I*Th@M74VZY* z+67NxXwS?1{+XOvR0F?;!vz>l ztc+m5uF}N%JrSbwRd`5S!OA;r>WeMktnyOLV*A!pWlCdiuHn4Uj~ZdaLv(&k{=+(U z5q7-Xf1E8@f)@$Eg>uYD=FX`lmy$U{D9>c7Z4vl$QaubByZSI%AoupJRW`%hNDm=A zY3oYrO=Ype$TC_$Uq-fyBR*I)#NaI{*1|nmw9u#A&REt38PUchkxZ5}j;Q{F&XT#l!)0pHK zaYk2qyaqZV!sdzdR%|-;SqX6}Vi8+127hB<6h{>RE@L=+Wow5nTQqoT@!Y-q2oFy# zp<_^a@??-yE7o#7{X3d2mX+M*OH@F^la2$O<4a5ZZu1t0Ah6lbrdE;1=y0xBI?V~Z z8ha#sUIgtipgIAZHmLGr&30iRLFb|;@bhs}2!|;!-U;9&YEqt~4s)zbp;q9Qo1kxb z{3(0#qL_|zq>8-4QCvxu2#e044u^R_8%q)HP7x{)3sb@691cH;1Hnx=%pu}f+Xitu zc|@yLP*wK4D-O|pYC7Ir<+KrAA&%5u7vKw3HbT-xduMhz~>tHTmzqL;ByUpu7S@r&^;Q+qg~?Uh#SCttt&wu4lRth zj;(dt{U%^N@X@J)&4|9w7i0dhR65=Q3jS>Js6EOPDY41=v zel4Da6T-7^5dey23h{oG**L(=q%{zgei!2XiwGcjK8W~$cqF)7r9XoBDOl}x={OL3h@W1OxCUh_tU`E5qC$kJ+-D>viSQDH&lG2@WS(Zk&k}Kq^j6r0ILB8}a0pAp z*CTGpxTW-1cn@G_kGh(4SojdaLknd1QG|z$l;I~39-ba4coR&0Jy+eZLZp6yf-zZ)Nd_^2o*9E~Z$FUm(eKaq`>BVJHZ z5peNmAwC*AwQhU~;$vb$PeoCL{cW*?n?~g?#9|P(MFnjte^F=@m7|EtT^uS9;Rg{e zX%Xcs+Jx}fbjwJW#%9DzCkZ_iZAW-qQ0TsB7s6#LW%vz*$46y&Kf)6%iGKv)^F~?3 zqnPF^R)9EmsirVL7By#vehvhT^hK z7C(Xb`RWj#56K^7i$@#_Jf>w&xYZGg{<#DbG#*-JJcK0gv$ z>Bb*Gd;z|F=EgT6ej)HJg}(*yg}`^?I}l$4d^f%a@rxp&eoFQueDS3+O!dE*zK0>{ zjHR+K!R{k%tEHPn*~jJrwsaVF0HWzoSn6mj*})~l)bVgyWs>C{I|=Y*c_K5}^Vmg* z*ULD*uGTo>X2c2Jj3*8aq6vz67`qm6A8v+~hg368875OV5gzHm=Nx*t51l(qiZ(KK zqYI<2%qY1x6AZUGCP=n6mddZ=*2b(9@jWWuV@y=UNe7hf8`DbhQUq1JO~g$V?^P)D zRLWIcE0S@)iuWj%@kuJK7Zi&8brh%fsQYDly-Ih#e5UNPH15K26cFe8qb?k3#_xu< z`-kD#8|B%F_SpyV9PE0k_EY+R2gmf{#BdZfD)d_Vga@aW7e{R!xcv445AU=dyNNU} zbvll802#*Rz!%~D6aF0er9rCKaU_?I(rNzCJeS%9Tvs^@WJ|H$_vyw|~>qtfV0a>`!DZJ>O(an@Vpqcl3Adpkgse-oaN z|G^#jB63*CzXLGAs}Y=}osD~gV7T$ch!$~ZEfscca@=8nQQp!L^fM#}-W^f2SH_E0 z16GDQz`HX1IeD}fM&BWcwMJKsxDEWva*mO=3N$+8&9D`1tE^7u8JLcHkT;FC z|5CzU$CDi(z4(YMLy55Ye3|#2Y#Nnw{CzI%U_Q0E@zfuvyrct>K8(sCytbrI{Q>bu ze&Rt-x4x+?q_fU2qT|nLrLWfsLZr9x%2tR5*~xf3h0L%KK_i9uM#{HR$Tne8RyN{C zyo7wnH};SU`w2fP@#9KPpOO>LqvY%abLo`=F2dzRuUz!Q6CP0fQLjb!5j-#Dj%_FG zSG=H$!p-0(bY9UA3#}45JFibRUC2I3;`wt3r9$FRf1vc5!GSLQIXGk<4n)aD&#RL- zW4Azt-DtCUE-!2dr16rE72zA%)xb+hyz`(}%1>!w@-LKjUq>2LS0wZJM+vtT!*SX6 z&wEtj`E&3pfC!F)(c!O3*_O`RgEaV>@?kO$d{7oe`IGaGsQh~&=MgD~d`AMk!$Hz1 z=MsnN-G3POMrk`F57~h57ebeLkw%(Fply^_DZ1cY0y`kNDSv57-m)Bd*nVjpaXsO; zN&NC^k|EU+$H8p;6XRv_JLMaZE`Gx$lLn`#KWO!78 zUMNe)FX}?lcliqci#)`i^yB&xx6X_A5${OjHL#0`A<1i^4=~U=wr)wavMwg>ka5Eg5_M&X|LcaZ%$sI31=NMaOL~Z_Hb%363xJs zy#v0o8NEsdj%pX1$~vi+#1&)o;n70Eo* zo~RCi*Oh*%PsQGmw6|bxpgg;d_=uX$@kzjcg9P%5=GMSl=%{m zY~8*6d!?;{FV%&lw>nF23i5TfH?K}y`2|i+r63}BDIJLVfgdG0qMb14Atxy3PblM* zy^364k+Bvl^;v?{?kS|BpM@28_l6>-f)Gwa0-N%G~p6ZwMshzs* zQs@)*;g*Zqxf`CiQ_-UOQv8H(Ah}|VLO)aEk|wor(Y}C7{1skXM9pKSKB4fSZ=!|v zFXn(#_W@3G0le_To&Q$(6zqhCB#kMn$mR*B7rxekw9EfiKGH&neEV_f@HOPQJ>&4f^c#ME%fL=EeA`Y8_~6Qs;%YNILF1 zU)3g=Mm8kNSCm=9tJ*HpNJrv^j$NCh{>z_JRN<~gRVf<~>3P6|%$antm#cxZJlJ6xap!X zO4rjjDETN&<{3k_IsG9I9Q8osUw18cy3&Ch>nAHhF0DN>5BX`*Yq7`|l8d2g4nO^{ zqKkB)`)crggy@H`h${6mW605Tgpct#?K3#xrd!TMpl;1^wq!$A>uou+zE zRu{BB0LvD3Eo>KYM!Kv6O-~x;vJGAuH9!+~-zM=uq$7=9SsHE{`nQfWsw9mX*bVWn zsm3!`KGDWjUW(Ukke$@Hbw{!(K4M*icubOcMO>xPnhWHOX7al}(pw&)MdkG5cl99i zH)QkgS8_fAUU`s*o+R%f!Ka}y8WDZ_`F@Ef#;-)b3ms&1tYjrx(96mUjYXYkbWs;B z4Od<%M>H$PeV;9tvezG?P{> z(`Y?HrL|_#LMkoCO$!D_DVv_TR;JDLBW<(LZ#GSpYvwFBEt*YxROM@S(^|7>J5|~` zH!T<_9JNmP_?fD1-E}kAO(tztADNHVXrwIBY+9a76Xg?fwr10+R2r2}q^X?)5EBI~& zhYloMmVXxcC>^)2d?NKLwW`d;^Wk^iAlwQGS3aNm3<>v3c!{Jd{Ae}d`^zV)x~!d* zO{?WHP4H;W!et-iFL%clwQI9!2<)XLfR5ZvuH2YUXY)jf(G~q z+WB();PRoqQOqrT=qF*5q^l`w6^v|m7s^0SnjbtUVF)`pGj+o23nVk_A*D= zKo#i9HCuf3TJ0CqskR_&ZX@wrDST{F)pcE-p4K01Ff@}2*H%3ls$LZ6=e9r>?6M*cUBl^@67gU#X%C$x@TM>asZr>|)Qn}t3u z=p|{E-U5Bi$GuuUFMu5idnMR?PCLa(&+eSdjgt-0P4f}b8`dr9ZGe)t@*%WtAnJFL zq$B8VlKDE&L464sAPd<~hW0Sf2JAeO=wlxdukyi>Y_X?u0kt10lMi!6f~vZ@V7Gwx za~ygvasl2Lnv(eB|A0R{ht9K81}GJ}nXBra?2+2m1$$(9=YprOul0~22QqEL4LJo2 zxYSNXds48%&B%LLrRT`+s^E1gLJ09asXM`+_zlBT&GCqb@Cm~pF2)H&PtYXYt6QwU zK(5UCOS6=d@|6OI=9Dy!CjTRJji;+WdQ!Xc&cmpTq8=zO{wDFY}5z z-j$_E`z+X<%hbc%yJUF;ojN50Y?;Q&v(`!abMH}n+;rHJm}k8WovoH>-tv%cg&%~B zqD*m#?qsT*^md)ehw| z5rZdFJou(LQ+rU(?pqiNgAXlqD^*3yvT;=N%fh*Rr+-8kZi=Y z9oIf;A5e6WkLb}&bc8-OXKjW0VOM7IqZzvzf;`|&`P_16Y~el$cX?=^#G_itQZ9Ap z%Hh^m;bzd=DC>vxPGOfP`ERd$)DB1{x9&TaE3HI!G%$Nw|!7OQrN9qYIknky0W|Z+`7xiuI!QE!e&ukSJyOm zar3!)A)kx2I~neVf;PfR=3BPc!w7KbZfL9@$Bm0XYQ;A#`|kUl7R1&aOP7$mp1kLBvUV}y$73RqB?J|h~RYNTaM@xR7NNhd=_zlNp95f z!u^nGr_(;K8Sq}Jj+9(f#zo~>+(pA=83~_osk~%&E}X_s6epV1+a+Aoc@Dllqt>Gq zHG>|>HITk#M{|VrQYJO`AsZ$iKx^aFc4!PjG^t)GPHjYtbE=g+_JKX|Y`e7ZiRm#ST*v3_pD9XHcavpo~Wlc@Z3f8^RA|S zk&7RYv_&5`LeUm7E|KX+6mL&`Njp4SoK09fM5cG;JH`{AjPJ-hdxY`{i&Z;tWhNgw z>o8;o50cgELn%&h8Y2)~`1u_9qQ(L`YoyxfV&y-^-X-lSQ+Fu$;*{D;fPQFCVeur) zDZo?M3E2SYwG6zGPV_~asY1E(q&%J5jT_JCbQkarBQM!#PV#KpuUh2^uO^$D3i7W`<8Ofq}@ zfbf$Xc~Ea1{D3KOGwmO35_4{G_V*G~@~B#*`dFMJbN5~@QFU51$xRbqnG|(&$p)3L zSBEs=*DiTTre*9Gdb)&oQX4!(yob^zm87$c$Y(O$Yk+E!NEZ0AT8y4f4Wi(fWJj>8_ z$PW;nXww^E>(yDB%T_CzrlcwSDd{5LRpE9pfLpDJkZ#SC-8;8EK{=PNSG@tJ*B+ENMKfYN7%H*_~HN78nEWH#TqVh<#+NtW&6b;u7r zXXZ>OANgBhw-Z#GqP@L$)SNSC@wrRMH(iZgLxU>_-)Yg;5E*(Bl0etEIVuvDDg3%X?i&j942eoNBDTOd+#yeUTV465;% zTQ{P-Whf`;Q#ol}Rlst)&>d(KO}d2+U~{D3An9os6X68Mo;`co`ll4w@e+l@& zH`4E|(3|9hF9@zhULS6Z`6U>#!uCQr0KrF4J%k{S91CUgiXU#EGj*YSiC20HXoJ3x zAG}Ck9$s_|J}L0$ca1OC^IaM6gBk&O_BI4_5&ayM@g!B&zH&W)&NMX#@bffkJ`j3D z;X)4LA9_^DQ-$y%CEo@iC^1;2^2+C80f% z=O@u8{dGlO>J{fw@v|cC8Mv_0k!yEUjt*^Wl9a!5`x3fW?JkV+X4=Xyxn`KL9j^2M znKF0?XU-TRjCr#-j}+dhbP5`-ZHFJC^oTes(pVzXJJ>Yx(;B7V@25I*+8Z~}6Sx^W z#dr*_dk}9@fn)aCsXvFl?t+SkeKnFUXfD5vcml4*PmNU91m8vQK#+bhj(le0b}0|d zo!$PnaR+eP&`(1rnf?tji7^A^S2y*)9r{`5iSmiHfsM$EJnno|j5Quqd2tq$e!5QZ ze?#(bM7yCmm#kkkj)$wFc~DbG;&iCfGSIH_$Orv(uHVjap%2&YIAKsm)NG zWcoMM35_+pb<#YHcmOw3C!QDROq(-nH1v`68^Fy8B!iKNIEU1ZG|mxgq&Xt(Y&!SX ztj6=CpX?bb(Du$pkVa(@ei>oHRbg?y#f1}XH=H@!CFZDdKe2h2lzCj993u)pcaLWb zLw*@Hvy6D)>9$Fs$4yHAkb~lxvCX5dZ^qk1BKQ_d0lx2|&TU7kz)#1`;(?H|{Rr7U z>bLj^l>jpG^BuBeX1x>lKN8)9ymL$4)OdEzop?K&l+ zD^r2ferXDPa)yd=&ZQ4Zys8q?x`Lwg+58YG&U$=uwTe|DdeE>!=)RY_T|ts z=59h~%au-Cxu+qW`l77d>7nj-HfbtK^hx&R>m`p4a_^ON-96;xn*qv;I( zTEzb!_TE0auB*Bim2H`v5JBAA(^f5lo)F)Qaw|EKEjz+iY(Zorz$Au<))0qS(mA$H zd?cMnN4A_eAQCmzqlP+-3o3Q*@E?9}=nt2gK99x;rWN2)mFt2b?nQtLrkGaYn%flZ zaWRQ+^nSlN=URL1BgqLL_l@yhqcOJjK5NZ2zt&uHeXn&f=5^0W{JzArt3;Q3u4>#K z@bByt{rgqS<3hE@6>5Z*hBaAOMF_u2`g?_TjiXG&CvyehJsj&|yRLBxHV?ZAeHdv& zPpe%2u#k;$6+r8!$F(XeGMHYR&dJ-lV~`CpF-+}tRgb`4QJM)@@LC2dw$*F-FXf~~ z>j};q(iWU9C2pg}vA&TysSPwTkO#2R=L3G03y#%`p4mUZZ*8whX%-*YYqmrFNrU}H zU#{PRZ}Jn4AEYgeWf-_c*R?^KHwV681z;FAqwQ+xrx0I*rWM^!;G4QD>D$k-AuY#+ z*j5x8Dg2&x?emQonC{9Am_O>B1WvPQ^6vY7z)8Dc9p!Z2dnV|=7*6ul*ny`V&rapT z!LL52bjfQNwi!XBqy+;N)k-6ZW{x*_uC^|}f=BCTeGQ6F{sTh~gh z%&Ksjwx97xOZ|wBkdAnKAB=jM(TDM(;|Y~naKp!u7Sm8h_IG}V{6fyYF%72-^xs}@ zZ3s6U{j~ut=)lpUo|qqw<~%(dHDB8r@M3aHJy8|pZCde`0`xgr&1Lb1bqrseG_~|+79Xwx(}Fdokw?SKHUM}{rTzkE8WH9y}STj$no>jeWQ%Y4>YTu zIc_b!0=jYY7;c`zw`Gb(*V=r{584OEjMj{+eX)&HK0mX1M)mCGFogG7wX20_$-3AK z_^MR@=F1^yNm?75-U9oRImS`sC-Q=HBp!B3zb0j2yT);BdBJ#=n`TP~daGNlOc{N# zNzi2*ia30kN+Hd($|Y-P4#Yn1Md(2E0(c##&tl#XPH$vxcEIXMi3c2MOC1C|qzr|v z_B~G$YUCY;IF}n2uCEHqy!ZsjN?*;n8u9(LI(H+of(QCh&M~dI z3O#^7*H7~GN($j6g%KQ-6X^&~SlS1_*=JdOLHjq{kE-pS_0k3$vNj!k%TTl04*Nm6 z*Kxhxb82CI{yU5p$e?>_lNX_KENbrsq>;Xr8+WRcHo(3Wii>%% z5A>-s$(L%BiPIWJ-HCpHA7ddlcBbuseYKjN<7O_c*bdTg%rYKN!y%|cI#02$C&~Z5 zg4tI_^&_@`@h{TcSEp~W9pGfyaJ;CjdvWO`kKI(=>^rguZsr5z6WqY#aEmR0j^KCk zl^XBjl+H@MFKoThv9>eq!Sml{G$!=zY`1Z$>^JmE9hdXsWR!5@fwm@oaSS+0um|9N z^AVTN#**3U@XlEF;Vke^#x!L{D zv+(gNrkiSy2B&objg7dv^6l#N1U(#^OoD$1diyiVo8WeS^;hTP)+7#j++M)m6ylP; z!Tv+BoC*Ecsw^DO6y9GG=d;i~T$axmQ==V79AtLi4X^`#TUjdPJ9Ru{Kg$sOBg-8h zKaLL@Wq%^!OAK#_OY*l_={6LnCp5^z09m)^sioCCi zW!P{jltGix$3J)}mf=Cci8HWrgB#s=>_gQW&$b!on%rJ~e)Ca3DoJE)>>+EnP=^n- zC{4EIM3-2%IWVMSg%7dJi~re`&lPlT>LJU=hibt8gr=d-d8kEspg-YntebWYP<+-y z$26YlNQaM0bLRnkf1be(^oLq8yfI3eblRA)gd}HPX zM@He08aY?vK)Vaa(fFlJVwVSYDqjb-27Qy1`a$-8bPfmS-{3@k=EVW?#}-B`7(- zhL=W*J`b2a>0hL62pIOmXye53F6h^_{kZMa~+ z&SlXyq<*Q#Wp#vs4zTxeQ9Pva5_pzgGCa_80#7S`PfOhFhmP|Ne!SniTMl@>%We~J zj?l8Q*u6hs7 z+8F4|l(StC>vPEk!wZ{O6z@sH`)kH;bpmh9c8GV>@M0c2ffsh}^!wo|!|U~%tXG_V zsiP%Meyqh_6rYpdx9{yPW~^?;EtkH1FFJSm|D7^?EdhTn|9{EkPRIP|y(h7M6P$-A z4{Y<>WjF(wAAydNHig?S28X(P>^`GV<_g*($_;SNK0+L{MYJ`AR@LTV&aLr;@taNW z9HXSo(6>q5H*K)cOX%;!&j6?36`p~2slitE@1f5Y8X1Fe`R~i6O|xg!j&wX!y#Rg3 z2hRc@+AFNrosYoHX1KIKeZ(W@5RbOWBj-_W4%pZ#Wedh*v7ZLFFXJ{==lyd7kFzcK z$a9MO(Kg~95ufv@`6}|ky5Nxre2u9t*arRJxXSS`e9gNd(+AI?4g>Fgp5ZKU@%r?7 zT@Y;RgC1=KE%3?q1^pn$F5KE+`G&3V?dk#vD`~yLZ$9*?yuZ_-X8-2V@ffe*MjGZ9 zzlqCzGk<;uG&ZczIMPnUfhUO*I<>qHX$W=xEgvBb>Iu9*dc=HgfQvTea5;KH%kWW8 zk4EI(q11lFsI}o(7qYD*Qtw0rQDF^3AsKZ9@PC(erVe!dzuh&YyA_Ay4c>u*`> z$FYPn2yaftEB#T)> zzIUAp!tl*7jz1_IP=HsbBbVpY8{3t4_W&N>lz%PsB=RFYZG`Dr25EPE6R*od@-4>} zTATQHw<@ok|9;;N;A#Ur&XkaAczKMW+2QYAQ8>17)&dUeEB5DX&hfEKEbn8Cqx_gl zR3EVg*J$j+9?hE&sADRwEyl7U^~(w3dtk_|(SOX^v+QRzBJR-!#!LGYbIAEV+SX$z z#vEt+css*!9WU?yG+rM&q5Q15s`<(GF6r?7*hwv))ZOX}aXXFctofVkK3tn*Zdz?! zX)BF-Igas=*u!IIm5#Hg_aHB}x1wBE!v?k~Eupa!{DYor6LNmX(PvwaGzD&wI)fda zLp*4QbSd-iH7UK{Yew8k{GQ?)VW20vu6Fk@WN?=}uk?gJ4B9T#_hW~M7inJk`**B? zn{g1O_R)Xu7}UUi=C6ilQ=)Le-u@4kdGwK4hps*0o?oQe263DVZjNKGjVncYh8F04 zg!T#l$u*DCPRO8NHUqnbKYQsle-4?}7ayUY0IoIg1X{&8z(t!`N9L z+n*n6S6sAxtlMFftl$4wQNt-W$70x)mNEv}eEnG+>z;Yw>+AD2XCr(18${P1gXxiH z?qR$u1zNx(K4k@PbRhg3-k>4#?N{)98uVs#e8!E1uxv{Git-})!Ew6oUOC_7W9B>D z8VJ8GANfSwOiSFPeQkU_GN<$h&B`x%qwFjr^b7AgAIRT=unFZ;<}ll1+?0j+PMXd> z6FP#v2_w9f0GsZHFt~ry%FQ2`zDSew`KCU+?pLVIdz~YXiJ!g^Hd7kFX%ohb*)MX6mf;r>C7=PY2S z@nD@IRyoG9O=|u)S=N!4+PT@s&)^N33|D_t>c@fXG-%Q1A08=7cWm)=nheH2GB^8& z=QSP6m>;)nLfU5NlDa~;=nHFd`0eERL+~zr$t$Ku$jmT|KX5-NS8fVlPgIrhHKly{ z^&v<{9g@MRwQX5L9#ppxk3X8)i?Z9>wdz(4f$?gIhbb%1Nz zyyf1CmjU~#dp2*qd-J_)qs+tGR)+Ug_jI&xzH?#N4uusym*PUua(wjB+vEM78;6;1 z7}kA`c}BTVs6IS5`$VLA64{V9^sSVSI%7ZVi7Ps$!!WUjcGDegWm;`Q$`#0r~?H0)H zbjx<3$P9S`-e5UzzjO1wD4)cKoTS|n2mSuX0878b=LzuQ*FLn8Uo5Ar(E5gRIfM^+ zW_vG`$;V$(naCsCFi+q&({m269EN_558(&{T{gJ=QXfAa>lxvVF8mYQExd{F97f9G zj$AFPpRhKN*zJlfxvtEcGpidK*JK*ktY32*;W79>h*4Lovp;cAaS8k~-nB>=-dli; zBM#=Y!ua{gEMZpSy7)XM#ntb9;-bQ28!+F^`02UXPe5*rLnxTx8n0A1<`19ol!I|= z3&79_!s`@Hd}Sqc1pO?Cdl-km;HpZt!^b-`%}}$J2aee^jK}sNzgLo;j_2r{Gx%F= zNUUuz4v}ahAs+fure72XnW&eukfjeYer`Sv(S^X_EFGiu$7v^LIbU)*ATXl+YxjZt zaf`xIZ_;KQR=eeISrgU@x!dqPg=YeBr?vg%!n}WgoxK(MlCpwtKZZGpbXV|@8{2pV}bp6Rm)3xROCjsx% z(zeGm?}%gdjOxPYyTiQ`aL^OVIR;MZJG0g<_>+R-rjMd7XzR3lsjEP5HT<2g+fhHs zZ{!Q>y*b2bJ4$e(lc;{-Po@+nVLhMpbHK;3%iF+XLwa2kE&!LiH;&W*UfL#hHwoNA zJ%%E?_Z$+xaAYguA;%G*l(BSjv$_&43`69%EH}G#_w}KUU|Qwfmbx}iUwZM zz$+T~_o9KYeNdD(_Yt;VmZ82L4&vl^9&I}uW4k_VTga7P2c=zcY{JF;e?)(%|Nqa$ z>VL-Z9L&Z382^7S63Mu*{j&(zE5Wa5;1vzLqJdX5@QMch|D}POweeu%mB-FNI<^^j zKRGT-ZM1vij$c3+#*B^~)Nv5*cWOM%u?&S%#_)irPfg*OnVbFd6rNfSSiPHkKvnp zeK;n|d1JHDL7WPSLzRo0xHjg~+l-E-Wja^3xW}A(hkUv$Zap*EK8q*0z;;74adm<$I|-xc`|rD=4Sr_c}E?FIu<@)W7O;Mi;xj|k@@u% z3P+s^Otb0f^}U_L`QD-4jQZQm&|of`!LeJo+PQBx6ayV{t*BeK&-BDyZgXxO&x^z0 zDP6yj=b@amI-mK{i98ZMGUOR(fz#PN^VZuY~&(Lkty|OxJpuYImf)<9;STX zD!0GB9`om&QosBq=hjg_JT!?n&)i=n_i*I0^*kA0$C3W>YyeY9m@Jm6;#~i}{%r0K z5H~V6`>lF9+=Gh06vVHjoWk8IN+I|UBcAQrx{X=rfx)uY=gE^nx(dcA)0`)LGATFW zx^cy_-evG4>o>=5O48+Ww!Z9CWe`^-aj1B51EqXU&h9*w3F22UUU#PrTHSQ2HHc4Z z`utwp`BCcW&kkyyoZ1<{R1@arPTub2af}A>HO50%j+37Q)W@k~L41bsXg2f~3s_en z`aE?eh+m2Pj@7C0mk>{VZrg~hV#QT`I9i=Ld#W->S7C8D8Cv4l-gi2y)Hw1Zaa_yk z;!+xim6no6Plb73MRGASl;x=+(vp`I8#{~6HnFfx;-D^%w<39Vg&2pmL7qBpI4XC^ zcAmlggW8BP`+n-Y#xGBAQUD&rnkzM~bMX=5F)uu4>9N$TGplWfr_+XeiN;Cm&hq-{ z28*jOyjZT%g+f8zpWf=??$dgu5i}F469~!Nvtqe-L=;=|W4frX6 zpI*)^50uz0eEOKfZTw2S@p~p2ht(UB4^Ll2IPU&3=$>n!@`&!n;T1z}DuwDlB~>H0HGip#;WPGNd! ziy}SoNjr|;!0*37&wqoy{{}z)8~n+)>9lC;BR?~uH0guMyI*IM(l&>ziKZ`KiR!LG zef6Erhc}py{R z))#z+b_P9u2Jx&1oQ`k`Rx``dX;!1uGjzaqG<7X_s0)NqHtIJ_2UowlFPD}2;Peqq zfBLAVm%0adr7e9bt{WwscTgU|1AYU1jqA*|PhW^}5g*&}dS9j52zYK>XT)ifpRHB+ z&(_7XM=BPk4NWaXd(CR2{aITxM!Mlc9=P70?{`2q#`n#Skv_`=bmwGee?;WOe&_Hm zfrVsIccA6xv(t))wk~xz?BKIItQ~=TK7A2+QLwmLl~vcTW%RFBvE7nUyWl=y?o)9( zhHFDxLuvh0MrpaTy&UgclO%nnvEWWV|3IW;<8BM+3a8pL|EpV^NWVZAV^mdlON3d_k z?U!NxIk-D|a@~6d(Ii^{&cSTW_3bY8ER0LqcgPp6^EbI}qCNa|waT;RDrC73$g*Ib ziA~>Jo@Xql+DG>4*lyH#ZOt-9+&bwT-GNlseQP%J7N5J+*=Wc{NkE5o=d}W z&Un7L9**l^!*I8@O>7$Sx;U;iTr&F ze+~Nq9BO!sS`gC8-z4hBq1igXB#M!vOJs$@e5ZH)`Lwf}c>%Y&zmpU9Vt*+V) zw~Wf#*3b25JnMnI&>QZ-Mqjbz{T=O!EuyrC1etGO>i z*GhKPy2D{^F}Xf>)^K(hEZ{vXs#t92mb&tDR|C9g*AOrHbYlcAjh^MiTqQXfwbkCuuo+G*of}2itX$R?HYa>Fs#G4k5Ttn1u#1;?G>#H zwTyMuVy)&aT$lX?m;iCp2dzD<ObZKAMz%8h1_p4oBF~rOLqaj67*kA+Bdqi zR^QR)6X~E2JtMFS2h`spXB(X{-$K7aI;?Btj7spuIy#Xa@{>>Jr_|0}15|D2Oq=p8 z>kEN{b&s}Vy1E8%OF<9Em7$k2hZXLx0OR*-)TlmC_Jz(Sl-JvPj2_@_uS~|Txf+*W z@+JG{(p{UB5cnaT)7PK_S(z?D2edsMi!Y}``)uj$9N0tq1dYG3^1^fii*$t9h$9^O z3wv{7n}h>6ZK0)IRlgD8^%saN>im>$x;G*6bmO>a{InLC;dvDL-4Siw^ zx7FeO+gig5c?2iZ!3Ic!_=%5v`8eR*Qb5=N#IwzFf%x>kQFMExZ~C_*ij%x?43e@j zJ?jDq+o?9s@inGJiy4o?_i3bsXliPQOA@vX8SINyiOVi+)qGv?zXbF+VUO7X8dX!!yf zK2Lg7)+eit-YMt+-w9qCEba$NX)a!c#pr z`?ttvr$e?08q(m&hO30mOsqGb*DGS)T-tqUq#ZXtQi#87`f_30t!%yaW)3Um1_$e9 zNQ`5$mx9k{-R*h7cH3G6h!cLon=dwXd%eW%pds;!t!cI_|a?995e$5keGmjv+% zZQ34jx8t|dMX_hU8x#He5l#1B!H?i>!|#=91D+?7iM$HGR$nC2WQ>lJgEEBh7fIjF z1+udA_s%y|qC7wc0qJdg0d4oL zA?%9lD-CSyE)I!ZewqCv^l`od`7j@u0Jz2c)K{24XtzlpK67V(=I*z?_wEb^RtGWc zpTR+Dr5+q#+1rUx`M#W;!KdRSwa(*7AMYzYibwKu3_OD76nIVeUgQP+z1Y$;-pEtd zUDQA80=9QpKk&^m_|##|6Z%HhQ+J&QJieKJ(Rvv)NrUj-UxOBL3U5g7@>+0pAiUY~ z8hFV!>vMtUcgemH=Xj%BJi|?!3u996edUD8Pk-9`6moJ zSik(M+f~Ld_n5s@a!g`w_8esJ@Vvs>!J|n)+w$-?D9-x`Q{mDL1X zD%a1ctlAa#)XMpNdoc`QW%_Hw3#36lP>zq4)TUf|+SjQu#YI2!`;bxW*}@cmat`Gt z%e$|cPo~|nZ%rPh|2b~)&V6 zDjRM7sg#yS$|d?iTFS#Vg4mqn12j(ocELSxtIQ5jb{IxEzm`=w zpFCys&M7_al@@&>p7i~1=+c$nQ!|EVLdzn<*Bu02{%$tDL4#q`CGkB|4Vnk=4V`Ge z$dyUei}Rh&z+`CO)CbeeYbznVTn~g}AI`T~7t#mhBOG-UmT4)U;8E%V#5ujhd|H`T zHl+?YZ}km%WPS+Vl;UOHdp>~oJappoUr3x?J)a=*&Qn%|KRFY@&X-Fccg!J zkDiC%d@lVPb;vq~ybA9IPd@%KitUFsM_B2T0iR#OUC#f$Giz_wd0WfChwG6e%rl>UpJpm zUAVKR$v1zq9Q(bzD-Z@gm^ZF2$Q?&m+Rk0F%;&h`*SBikiyugDLT6(zSFnBiUq70( z3*XkQvph%tJ!2>{E)T730iJ?>xnJKP{rs=nc-Pk_1N%zn^}@o9xb}g~A6xH$_EcwI zwvhWT;C0%3nDa+ZZdV<7+lLOEy@vMh>=}FPjfNpLdz&^L#BfEdPZ*W_ns&B0ZoV11 zb>&%fo6_C&EvFp&6k80!cy>LJC?kerr{bV3NtuV;kmql}Hl?gVX5#q< z_!ODJpX4vj7nZYF45zLJF`TBiY2f6E_Xn=Qdu5A;o4GhD|7 z&^qi(>inAprSspKfoC{K3%u_9E9a9Afp_r_<0#)pov$QL4QJVueDeE%QGePuqN%dKF)UXh36FZlV>QCM#J;Tc*#Fnxn|$Wj}PEm>i%lg zSs0f%#|^mI$Cq)ZI;>MXh;Q&B_SCHX;4rPnZ#rij_0Ko^tj_kR7d{*_n0KZW^yq!= z4z&yN%Jfo3&IfIjG;kn}dGFI8Uh`Jphi`zpfZ`&jP3ag}Lyp~FzWH$PAs>MW?Q`1Vds$M&P7xz3CiX}*N~@V=tS#yp@4 zmK|TmLWc5mUxnPFt4ftcy7yph_Mq6px5vRxB_7=SH``9n zR5Ne5V#!#xdht6WNuH(M27C+i8z;}~!a?jAtjsIz=LyA&@|)miD(1(BL!QR-2sat1 zH|6y{%=7H7AKaHOb@%AnvWslbVQpCt%UHS_4Tn8a|6jbQGH`C?HardKeQ})mtJRT< zEBLtYS{sLcPt$c5u~a~Cez!q!a{kBR^l@7)4z{3ig*aW0#kIJ&fv#5TtABS?;~LTf z`+V3@A6D>TCw*AgO)l+}58LO%F8Hv54>Lap8pDF`!*jF$L|cblu05=FDR~RKpwC*0 zHslwwmfx@w&VRac#Wsz6BacE@`VO7z9T*n6q)~kh8n^xwGz>PTf&1%Ft@IA!OhB{Q ze>wnK%kWfiPDNs*t@}?i%ELc_Z~8&Ewwb?m&be3ab^RWbLLc9Q?_e2mZCw85I%~HE zdXBaPSvjxPInXP1@jdznq@{ntUA9~|AQx4$9{yg|;%to`56$+#9vBj{KZR@0kj564O~}r$z-Ds;QBoJjWgp|OHB23v7?Uwp|mpNnj5vtkk8*i-mF9xoM4KD$C@;yeQ9@EN)PpTr!=o zy!thn7@y8IYW(+W6wmiFlocx=2m0kK*YCGzxYRGNkMHf!RaF@drVp_L#nqCm1D(%K z(it2YL@P8~FR7%S`F@Au)%7E6)Tlh)5886HJ>F}v`6AvOR(D`LQ0Bte&H_DYCtgjq zX~i}nC;KMT6WSJ(whVBweY^&^d_RuzqO9-?DAHh_v%TQk3RC)`GCv7YEz9+h#T8I8KOjOHu97pZ2Ec`R^N!^UM{N;v= z=&^z%t}C*U~@`TIC%@*zF(@xbk2ES~l!aVXni8iq6P zv3FxIk9`TH9<|+nVcsEsY|jSbl6xU$MuPYh)6$6VV`EUt#LUqkeg)&Xk>frNm}~rG z5MRxBwl(kbW9>5+gZPZc&sic#|16?Cf3=DD`>>|}apu{xnEN&|xq=0Zc1lN@zS88XF6F7AEWYX>%~_X6oLPXHNw2?TnB2c|3bAh}$}t@7vWc z+Xh$}uwcmg&Sft(ND~Kc2C1zW`S3 zvQGOuQZ7Px*fRU%4o3Q1z!B1-J<*OxQ_@!j1yV93&*gDto$au;y+UKV%E$E7`g`7XA4f-YEP1@kND~xFz@0fSW z4P)9t`MX7I><5>U{Qbb>ezskCU|-z#50M|jtIg3+o_V}F+U_2=YSrVjEAa-8?ANhh z<@bjpk*)pm-$zwu)m75e7#*uH}m-XiRBICak?&-jq87WI_SmOKrCC5HI|pl zr(@YJPrj6FST&1bHD5nlIsc*6^-mO`4_T)Zz~FdS?lJh`xY7}s%j$TJ2XTBb+|gBR9^grlyd&A@N)L_CX*MKB(+h`y12E7B64>kWK+1N=(-4BiL9a|X22 zpoib29nz!@E`wj!e)nyfV=AK?50?0Gz)hGAwgvpdH#q)XohtpFrkF1IapjVB?8c-$ z&qt{v<;9O#tkAF@ZZ{b!m4BaRtHjUES-&3RR{6d?_5FQ0txNw$CFq-!|~)W@qy1u zp3f?Q^EzgoME+uWI>ixBp$rVNEdN_N&O6%PKTiP< zbmQ$0FqDBjFphaa9TE34)f(q)UGm^4;4W!iNWL7yH^TV+ujjO`q)eQnVIDhJ&Sw$k z-++^Nz3m}P%Gfk`u(4@O21uLz-(Y^UyLn|Q1K44;E7qmt^;;(boZy4Lo@1+}9yW;U zyRnA2Z>XsL{YPzzSL%AmPh8X^aY-0-Az>%YhQ}?ua&GoV?PgbaCt!eszg_!*Ht%?& zz9k&#zYg7ozll%qKo5iu%Y=kOZw!B?+Tei0^?7~({pvhntrN7rFvRNLH{ zc{QqO|K%`njcI;7OMJ*b&wC5LCqQ!sZR9~ zrrdTCVaJrVgLxMErp?g)7PEV2o3sf}>i~GY65I5W_CTHng`;g!E~aOnXWhZrMu~@Z zDQ|=mE+Gr?n=YjN$Zzyz{CBH<3qR0_D-W)`NVv%=-=hHx;fa6D9^(FwHg*r0yzaMJ zd$1YrDe#JSNKbsq0&`z12Tqp%kuuw@2CW%9R}=@siOhdR*5O z@KviYFGsJ!2l6dhHqB(MeKI?$HcQ*Sy9YEolrDeMPUvex9j-g5zn=wf&UP68>>>S4 z{`s5bYIaQ9OuqbWLmc>_Fa6O`l>>0%V|~B4QrmLud$_Xg`{Y%ESMEk-`&RlH(=krm zr3L5DxlOG{|7WwxM*TI`&dvVMmcY(aaobd6LVl2r@RiOD=eluqsLkKoB(B^I`D5qb z+o7Mf1@Mwb$VXh{kNPBj>LXF-tkAg|FB{~hUK0B8bGbO!!0NOg_oz&MjAQ943_fXJ z%9r6*<$*R5+LK#L!Y~h8rc>Gs`4%5hySUDXn>Ot7lIhSVa+A-p#_`89%B#Qv7j^LC z%gJ`Mn}a1yhm*L77wZVz`UI(;t{gVmfydRIY`aLEM|;9L39M z>7>kVyfX=t!Fo;Ht(wPdeWrhaD>>`$f)!=9AG(J^h@gpNC%4Tww#trx4dIC;1#q>wQc-?Dlqq$1|DB@*|e3vP{-lDY)@%*HV z$2!k$jGy-p)N@%R`)SW#WZbv^?63Y6fzjV&V0L6=9sNnd$5u z)VR7Z4)$m3Q(kBf!?OczU{5kG(J)#({6!gY<&gvD$%zyGc{g z#S6#7bofsET?dDWzl)2#KP1s}7Z-hhXKoI0hlZEESaBV+RQ@hnc*Vc#_mUBj|H_h! ziTBlI7b~u#-mbe?u?cVF!~FMEhEG;(y2AHJ#fL89^7j`jDmEdhyeILddA_{AT1>VU z`gix&uWK4!*W}hxzQDc>&RKrp0{V`*n`M6Le?7-AV(msH-`jVy&E3CP>B7-R!p$?e zP3o&&tSJkxAH+hzT;C@1n=dxG_?t;Y?)Q7K!-pvmo4a_i$Au^S6P%-#-xo(*ywbpB zTD(_7?ES@~WpTJAt7LNmFP?UB`>^M%pIg6+EL$&5mxXibht-iU#(L<%%@sxfd>1C;Wz&NAgSl20F7UniKGoga_Cz?2jj-^d3n!jYnG2Xhl;#WX zk)e;kyalw^Z@QT~;^MpDG8c&VI>-)m?yDyw7!^wC| zn&Rq8CxNWVh$_ZI7+aHD4nrLTbOeuBrN|joTnyt4M-aaR(Q$gwBMTMtI9iek<92n` z=TLoV*@>34NL=)5Dc0v0=tZY@@4Dc-E%-ia-|3A+&T<|tL6IVE;%b~y{2WJ_1HQ)dcq2{YY4XH-pSb3?P=Jj` zOD=0VuGJ35M266gTi2xX|6Bt=p2I!;0^6`YBgZ&qa6x2d<3Og1Ry>%=_Gj{$?$(TH z4JVNG7c&DJGaE9vpZ&Pesa~J)8V|k_Fu%SYr_abO_k4RR1|l%6xI~_TTyOtgX>&wN zSC+{WtfPA=nFJS?;Brn~eM7V~D#Mp@0Lgo(7Sa*MV!IkK+tL>_KhZ9WmbEEP(c$WM z_4oC6_rRg&u!aWBIBmsc28W8p{(({kJBPS5C_o`?dpEDF?M>22`T?QCGPDHrjxg^C z6KYX>aKvgL36t;#kJGj)Ri^=-&?gw4_HsO-Uoea!>d1$r+QrU}W*19)Zeq3N=jDTg+pBp;C@`*T{>&r4Od(;uezUVv{%*Tc>lCE+A zIQZ3haPW8Y@FDFyIP_yfIGIxj_!64%1qm4NIuB2484P5e2QyLzQwm^a)b5+>VT&bd z5=w^cEI$|PQN}jTLsuQxX9`?fwjupa>+7~7eH&nRs4lsmk>fMu!RYl=^deJA z6Sc)bScn59Y#9y_|L>VI2kC1lZ!eck4PU~SA%fC%lfTh ze1m_lU*s3{EBaiiaI9BJ+rt+E_$q~$c_e-_4dR(55e9lvKTDp>_nWDb$f;|=i39u+ zo?|zHbG!a_e9cW7K9lW3+9FR6x!=q$a=xx`TICvr}2oM=GP0?PnrzJkPbTV_PaeE%cE{Y_m$ue zI*ILTe*N(3(S`A`+)7#PiOVMOvb=g*LH>|e(hz#k4ZjzJL0W-<9Z^S2M?HBxj3Z2B zo?p+s`n>QMy?T0%kHIZmkKN$fgo10~I_!pHDznm?Uw_>&6~@o6yKa~{tS9!c_N(tg1Y7-ErFoX{2U3nl zUAa~JmGZh$?U>)R=g>b=<}G-bmOKcI>BPw&!jNymh)#$%Q}#Pm_8T%M;J52<(2G*T zMi)MaFbuo?jJ_*c;;>hbS=f#^?1lpthPO*AwhJ5;N8+#>CJYWTIk+3nTG*u^?6QU} zsf@#_sw@n0y0lf(7KXfcVb||8d^H*-?c`t15B9HXTK(qw#y2;w(Vp^Ph3*%SIf1m( zA?yQwOUf>FFhg7jgU@w3j(xF~f1!)DJA>VWxd(XO5bD3z)FF+Go75t3i05B&{5rak z^;;#L#9yr~tQzX=$_?<$u;|7P0I;tIU3>qN!f(jSacv3j0G~~Ob9^F>?K+7E-@>o( zRgbX*V%GM{jRzFBv|W&2GM`Wa&F!f3uHX$_ZUIhT&PG6QIQH|aolagoH`@#Q5FRqX zQw=!k3gPq#EdTWVqD$~4aT@}8jE0Ay9Mi!awv?CU8T7ffgzYNYzH496KFKTeAKeHT z%oV5}nGIGhZ=4oc1rBSmL`L%EWq1qHO$0nar{n>8jBdPuIgL}Xj;UL&RS|h$m+~7t zJ6}hA$yyfJC&OqLgk63NIH{MnmeFcogjTKL1}%r1J`w!Oni=|r1pYR|f5*>&A2g^B z`k(}UgggE#FByK)33c@{_+L%^7>$H}Lj0gD`q^BDe>;9JlovmRe#C}XDi2@z4clIM~)Q}EH3 zARlZ@>9F~ieahKKS7wx5v8@>zdjCAHrCsNRM;B;+OD^Fsbu}K5Sm- zJWxi*+5ZA`woo^Yme?O?yc}9iFIbzOC~Fz~o}MRD#66Bay_pY1!g8$=%s zLPL0B-2ggTe}ZPs>W%%enreO;i*xOOF5y;Blth-cS`kQtsI1o2?mEUnVWn6OJ;;+YhBGB(n z{5BfWj~NZ(;7=H5I`TYHN5DTfcLnuxk>3=@eV5VQVex1qCFnv9p$nO1+=2Y!n{q5v zhb>7Po*Nd&<8=gB;u0MNctwu0hKI6+dN6*;s+^;FaQ-j~onNNrO zpiGixo27YOS(-XcBlupY_Aa)LvK82$;vnC{md9qtvL73ZH6BAd`qwIv7idTObt+u{ z;m>u__V908d_%xwX9;TE@gS zY^}en3+jmV!Qa%!KI9SG;m?2v(qwn zEejjGVEqB`I(^m34DycO(obOcnIIhB4CmTBuQR~-wWi>Oaxa)>lKF~q031m^QO0-Y z`#7iYx(U^_<1L265-Z-d!UY(5S4C7~eIVuw_=#S39C*hAUP`Jnziz4QY^%mX*&YqR ziyeZ0=f}C$nB^j|R|UFbzmK}7F8JQ)WJ6lU2_9Wz&FwJU_aD`asBF}atalB0HN8=% z%xkW5o44-!tj2Mjxugdk=AYL+((yObd48tB58w(liqqD8lP8&ne0_uRB>YZjTF{PO z--L813s_U53uolA4xOubJ<9|3Mc20wM)u!@K##M3`}!*;D|}t+$928--93N@Z@f2x zHto;;ud}l8O9812PP}gz1`;hJOhXxPu3hx{tE4OY{(}U{+Z$?>uG~!#(B>Likuji; z`dn@jso#~uao@6^CVInROMeOQ&;k3Cq$_22>H3W0$L($QKD63kUXA5fy~TVXcZ-Lm z{!fpzrrgepRt6=&Y#;$=FM8B#J7R}M7sz4vc8}l zt)9_0@A05LQC6`p=vaOO=IKlNO&k)3H{)EJ*Ukrz-jLBSw^x_8vd|;r3>|_i`pwZ` zU138Ye@!U=aCffA_1c;4&LONmxhc+1(N&e2uwH4SbI#JX-3c8Wz*7kJZ*C1})CM%L zX0VS6#)Mz@o{Vcq)@8E!UArI`ZO!3w_AGZykj6n>6N)vF(Hq90d&q=+=6zUofN37v zL2UKfZ(h|r7ruYR!&tuV>mMlFlZ-O~FsnYW*P-FK)lJU@IDCAFBGyks`kpu4TQ@4> zWp8AAAN4fP#*(@4bRQ#SZNeMbJhV8D6-hZ~e#0IFmSaTE;rBFUQ+;E$4)vtJA2NC) zhUF?`ukYOK_cL?R8=HUTXZ8!Q=`UQw{&e__Gm|)Xy%x`TJXdf=c{QG99V=T4TmIq> zJjb;RHl9X)z;+t}+YY;JKMNZ#YFS;4e3Cn6TJhe72YJ^HI-Buu3}tl%o(4P_q=$X7 z?9g^tKe4>C{PUdqcOi^*8_$&C9zO2PX5WNsq1P}D@N0&#UcCz6;PYL;$2(u{tTp{1 zj%Aj5X1&{paGtTlb>^JEY)s)jjyG(#VFu3_o>TbU4!FxYcD>~U-iM(B$ha1Cc_t9g z7I`Old?$49&S^Xd=N^Qub$F0=>lB`g2;YjQ2j8G~7kK4)qid=m_XWHw@J6~j&*D9U z-&J^8@HF6AiE!}5b^Dx?c#!s9;MvfD z2jAaA`t7H6401R4V4cRgW!EV@=jLXA`?A^ZVJ)loAuZ=a?l0j1jy<4vKWOh6!*de8 zZz~?YYw!S9FJRW5$J$!R%5!))e#(7=;)|N_Zo>nZwiKQ^JV>`?8|1kPos2?;c04Cx zYX|Y*{XB3!kMK#vf36nKaon$Q8TJXCeIEMyJi-oB8< zGX{BqyL*M)b>(pUJnz{{Z8%#3yj=ocm(F;)i{YI8{&v7!f$V2c_FGl6KPFQ{G?!^7~|7q)8q+?|QaGg5iB>X#w&S3%3Z*^A9MV{K-he6!yMjjy!N z3%?fMzsNWpCj@`&Q?l>P@gI)QJP#Sr*XFp2jF+Hq$i6?vf+CEYag34Uc^q4emb4gt?{YH7{)wKP^AA&$mHWko|e+fj0HM(?7pV!1L4c@$VUa_N(J4`>;9o zt9jnuH>Y*~;WuE<-^k**iau^N9@qr)=mPAJdu_f|LYb{V-d)0T26@*5AGZ~L<;2`< z4{Vud0lpjM|9hi4xA>*YIGY}EU#fvW*rEN=i@^O|;QnqCo^5yvc*amS9mNB@+s?vQ z9b7a&XTN(4@E7r%!UGw;3;2IRS=_c2&q449dM}()zS+-bU;Xb=b5W)Od`{skwrjV4 zX4k1*{uK5xzs)7rs_MBV(HqaA?S;9}>pS{fgHigXb?w@&V;h5GUTkwTKqqWd@SF4c zYzMI2#JXPQ0wK4wJJKW4Zmip>I5<|6GI-Y6>OViFYz};a}naBH=YxIqB`hT*E=Dc;}{jSH1P`~R9kd^O&a_+43k=LGl10r?2x_=k4-Z8OlH?gN(g z`>F;F=UQifmVwRBt}+{VqR2FMmq2_UZnP?^X?gG8A08zPe%Cpf=b~F%z}po(Gk7i| zF7b!3aljr;1eW~(4)RxF$NESt!k~{;&*4YP>Efm3ytNwekU!>eF8V0^a>FIyJBkNo z`qo22Aozzc$na7;HcT@KdB9*~FTas)63+=dhw<}z$LCx7`%CY+>s^e8&D;tVR~T>fy(E4uo7^?F@wm_nzNX}95N zb}+W^c(A?;jPM*8jgZCifZK^@D}pK+T|cUf&8c%{ZV{ zt5#ukb2ly&&CxjG{-oNS%O}toM)U&q*f6Q#aX#TU2hAs?@u zPYTI=;)uYYr9*!$YHYy|Z%gPf@}@TPbMHupb zO(Oqan#VQf_i*+kFJKZsx`uw9e4{So7y$c)vSu-@b*1!)Pa%xsA(sKOlfH=eGmlDL zx#rN~>DNpv4)&vy>AOqV8I2WNXBZWjhsrP;u7q^2D~e5It7c-x;DHBlEXeTrvl$sJX@u>(Ty zP?poHU>L-81h8C-RkZ+|%{4SlDZUMt@b-TgaKoS|MmY0XClBkGN&d9xR??9H;{eyTo;l3GZvOh?jL_2!9mc#5rnVOPq@} zSe66AE*jtTJv@$flIBrOuIOf8% zZtlg;yOfZA%+g=iF|eOwu~zSJ>{akCL$zdKayJj)e_V}p<0d!0f7FgLiHG#q7L_?r z=!3j@+LH`N`8}ZFq|5OIp>f@<=HT`0bqQSV zVq~i3kJH1;r^k~NV|qBBp2jVIUiN zsYYqiZgI|7KmEs>8$`xvZMBZc`n5WM5q+<@vp*vald}~l$vvHenJ#PqM)R$d>DsSZ zfE);22>7LJ%rnZSd0o4^|CUAk26QSgzrGtg1$BSheqaywxFzzGc{FHww4Q!i>Z9L6 zpyus*`acO<)m3zG^nVH$htdB@SiKM1;OoA61S-A_D;-={(fQ#GzV1Y|>EO0HIED>M zx!JJOh4u71UN)41FynaxT)y(MyWh#Sf%Tm5SIQR(#tZ$wgz5PVtj9N;abc^v&^p*t z?8ll2tKT+E`#3VCJVibXn+Hk*L)~oM9u&XdlJarbm#s8gy!?avdrhA$vHbgcH*(HU z=cik|4kT~-T4kW|v?Ea|bunX@j77P1@@0Q~(tag>tQOl%; zasEQa1KRK#<%_>%9|6kI=8Ld*yg6p?#vB;WITrCbD-cc@TXa6)11DHM27CJV$poG9 z?`&!%ct#m#S$yQYjz{oJ5f5#8zuo)`;Wk_@9=u14-(aRVTVL1lnVCyX}HZ{bsTx*Yf zmvjoNw6UAN&#gn;v_s&f&J;ZdYZc1Y9YmXek8K#vsj-fgb|v1lE$+eQT%c>)EPW2L zoKQH%H#OmVBFI=LG?@tjNI|WY? zM~C8&HrQf(ESKd(P>A6{e~mJe7vY27;A7)(86UL@BeE>-+}$a?NH331uWNge{?N73 z`A=W zVat0l*U2-zEx$y*a-3ZEOWzTZ%r!3NmOEt#I1Gm1}fA^#nJ&dxaBDP{Vg z;=HGXcZhcimSr*XK&{~ zUV2nNH67~S(W*FZw6K>uK`R^3dKFfZd9# z4&-~K3h}bg4$9L}cFC(Wve4QbZ?*agYf7R!Ko{*mu2#a??pnXJO#-E~jrug$d~@4H z7rxRW4E~A>@7p`nCy1op+3f2nz*_{{Dw}H^Jm?xvn_D%E{XO&})<^7rDa|3ArQoQ7AbCD+d;ymIrpK0UD`6LeC$K{ zXLxTG-XCRRnC_La`P+}DBRCcINT;%0|5IbamD5+q9jaGPpCyf#dH^qntE>9=?T6ss#syVA^J* zl^^&AX~(9E4x!lU+e}Z;QS`Pk>nB2AT0Zq|SMuoblfP+O2a9mp1pDmLb`J8GdS^Iw z4_k@e)`Z^&G>qX~)4;wpeHq{EzcO4N;AFp4!VxFDENO*sfWJ!p;4_1G;Ba>gaBPF{ z{7wFtH;+Reelr|A$UC%Sw!yG2mReF>SR0)((Z7YTK(K2E_0=}Zub4dJ9`$eFoFCR~qE!wHrD)?~a(wDuo@~QTAtMDab zD;=7K>Ad`{&>`|k@*8@gTn-<A?r5N#deMN^lIlKu5onoE~EpW&(M|E2Wwl!r6TP5pFQhZC zr;)|IqK^pcF{5|D&ZO;}F7VE(=v|YlE3}yyFLxxbzM%F^dk*~=f3sbW zx7aoDu&p(3|H2u-OyfzfDq<3bo4Yo#ZSt-QmM`!fEJLi9R?k>jNoiS=a@UM_D|_^( zgkyP=dJOdD-IIv0#)9G`zC@XTPU(N?qxlw{wu%f|pJ2}s*S<1N>X#Ax#;%$7C!`^L-mzr=ykZ;RhE-pl z2KZ)L%I42FhP{aYziPOV<`BX}e&F|fA5l29t%r~?${*#U9Mt` zz+RdF(}r;50oT;ZIARp9t<|!Ka>8Z)gPWv1@^0%dNZu@~ug_TCP&U$39}(|Sp$x9P zINRZR@A9%6mJ#%)qj%S#{GL$T@OCi?9;ug|cuyPu>DpCp>zf;gdbjmM$dk86>H}$o zzw27$6330kJMnSROXoW7t9=^L(qCiwLDn-mAfoSBB@f%)jlm-K5X!*3W5 z(@Ixt3UDkN-tS_lv~Q5BbTHIVe={0N*j+n_fl=ydLiMC&U)wwWu3_*l;jb-U-vwT) zlWk7gw)oSumMhA`hvD3x;Oce$mhzh9NjUmA___O>^22+4sYB#PboY7H&HQvY+;k8X zJkoXSlyp%Cd{H7VT|Ps9%oiW0zXi7sBOQdxcn#~TkVotHb=Y{a*b(aRjw493Qy+FzgJb>%xwZ}v`Zc_X|lO2L* z`T+4ACA?XVs`R(>eHdT!{sexno*l7UZ2iT10WN<0l-Z%(VU^gIS*>?Ip9Nm@8KU>F zoPs8N3inh>UrlWIRc>uk*}l$Jz&rfcckac22nWePxD4(ZbkxVi^YGt<50G+-Je0U) zy;%DM{(yu1G+)M#B+Clhq2M{r+XF9?w@j=9mM@mKa$R^Ct3snLld)SHKzFGDLFitd3%IEA((df4el0VW`6rb5)avy@tAiw!Y->3k&Q$Zb6)V89u0fxbA zt@>}mioTX)ME~^Z^n1SC!q>4q=I>5Dhq!4xWBO2c)GxxK-v$j|k3o+tbA;9LK#U(^ z$2Z1&q>kNQC2|NI*QR~P39D1UpYT+^kGMMN|A<$7T!XP_6zpqE- zrM}36@}<82$Cst;FF2p6_PmiV(bfCTTr=>%cwirt~q$o8p1_bYYQbLC(gH-VZcV zw$mHCcdcTn9}_?R{&s}BHCz>pv$K$G?C#s3h;8N{V6Q_QrPFFTGY&(bzU+VCs_@**-D zk6bGt;-X0JGW)uByQcSfAa~2K$1RXDzJ9N@T|i&TjEf}wdrxcn+n5iyuUV7jcT=DD zPD@<0V?tySIq#jscLDN29+4li-wV5uuwxnqnWKB5ON`;O4ASLNaOEXZdb-A6`EdZ` z=L7Tu=xZrIE=KwJfcmclKOfjSpPvsDuE`H>`{tT<;puU8|xzNtK*>(L-@HeoGH~yg7#v( zE(E&}p8=fglgC_Ate*UC=E;3Kg}0>MVgKcJa9{SCddDKef+$^ZUM-gwYl+I`t%5#g z7La-QuFit34NUk*2Y&dtUYsZQvS62QdCS(jH-our!_$7b2FT^77tZ<%JGZ?I z`2yYhd|ynqg?c-YL13^I`wC=*vR3E3mos9|QT+F`wez4aj`#RB`&OYV@X`uAK$d2wTcr02&jVGq(KF`O*Z^bIl= zHi7q)#=EqQwV*SGF!0N=w`Sbpce*+n=d9vdR8vK1;1+E!=S*L|Ep))}ARYT^B3m`W zX5#WdK74tE{saa##kQm`hf8jUaQfTL8@f41$0zGq^3VM%(vP$}Q#BcfMp*~Q z`hM4_;aE(xdlE3f)02|+TZDEUU_-cr(l6W1d~~?ZGG1V8uK?n%2aYPd@wX(zC9w5` zlm6rGD*!M&J=NKK=kEH!eR(W0rDWizhxH}Snd%vLa^X7xr~LG^26%S3c7Wj1r5uQ^ zxB+R8VoYp~KVtcMb_8(dmwMnjJzvKqJ}KMG0(fFLk*z1tcTW_a@dMnDEnkN>WXqQV z*%ELnTb}iv=_udqWRoI3(2Xc;Mvn3a_>t6gzS&@`{>*0q;P8z0=X&eAuze>Im`JbPP;b@b2w)>5z`>PqpW7yTK zX+!s0{@;H%<|%*^J>TCN;P83xa3K!%cmI+3`E~ye2cz}m{i6Y%V?(%+%JgTpc>e{& zLqB`aw{iNpKLMxtb^qA_&y3SgzOOhWV@z1Fg?Qxuo;tk2+aBaU`btvP?w<+a6yKh7 zjBii#p4|Sfeq3dbtyu|#fO!pY(GH-`JyS8xJ2K``Y+=tqJ94u^-}P9Z&3oJi zfeIVXqdn*FUOE>QGU$&K@N7kxrSY&vTx^CHbvOsG^c``KyRg#m5tqYv zF@#gO3oBw=g@)Blz-1RF)!*Ek+b!%>ycYP1fWufy0lv@SD>Niw*|#X{2=I-7HQ>XQ zWckwmdUpKq8-LJYVKTNA^j)G4K$gNt0#t< z?RXoXy+vn_gM0GD`o5g_Z7Xk(z4x@@?t@)A8}BV9U`6)cV*$>y9%uIeZve%jeo+8? zN+0tO{-h7`dwge+*AC8nN^ejP^wqF#!fN6YHhW^ZU%sj^LH;WC=5bqI64$iyRICYbje9u7H5uT#M4lu*AzLwHcv!Bi?Dt>t zaDu1EGGnq8>xf6%7V01n#d^Hh!;fTrSF8)*%&v-T2RU5YMgg9DvBbp0!~DnJGT6KG z!Nm~H;W-K*hvziwhTS<-o%wF78;Z1Fl*tE>_s-6X2{>d1Y^gXC<9VRc*^=;`Xs0|t z`$f5V;84uh19~2U!Wmx=1a|O12ezy25nSAK2?Y3qJw0$(Kf`v|105btbpF5yU`)OT zj^Yf59B*V4TfrjWP8kn-U4|Ei5(e*Bhl z94j{ucXGMG;Cdl}EsI?2oTI^c1)M8FUR?xGq~0e7x2|?<=#^a zFlOu`a57cMV+}U$hn9`hvQIi8Q%wd(Ja+ER)VAS2_KcPC-5K2Ui7j2ZLF|omu;>$t zt_kbbX$))&biIKW5@uS|xHe`o?-}Y7CAn%egT8i8zi!eREatlNyYg5mZZ;d!k$ig# zadB!Vqko(ATJwyM;MQ73Y0|;W5Kjo98s$nvBLl`_oQ`+u$nieNddk_!?V`PVjQM)U z-oVE7E(qlT8@>8UgB$P7+~X`?Lz3sK3jf#pJWlW-ad!wU6HH!hI!0nyD8ovF8OKAG zN4ZNg5(7@U;bL%}O^M$^HV*D-T;C};-%4}Xg;QKKl!G0myqqA~8S6#(`A@=6Pj-D{ z-41^4*xL&W9C{E&&|kX!R%rRwo@^(4Xq>JgO;gaaSfc-j9^KfG%s~zZecKgt(E$4Q z?2k(y{4l=9tbA6|n$SnBM&A|v+q=*Y_IrKN&KsQ6bnF+$X~^W_X-Ws;G$P-xV!TJn zzn_bjGVbJw?OV?w;dtB7BxI_@Q-QF2pX}AyOCKm<(!SQP34}p*@|Nh&x0-yfc{|(e zW~mtfs}4z1c)LNiFz(`wq^kn`QeKI#gy+nvtl!84I>lI)$B~xZ&)9fCShN0BabAh; z=x@Q}kD=$p`o$)rle)_`Y?Ser%IJoUGJG<2GXq@6XW{cTvW6H9x6Upcl&Yvy_C@f>UJ&Av`J%M;QJ8;wt!yuvFR#5z`aW^S zl*#>4`LbNjOYw3h@&H#s_SeDmPAO7O=C)zt+rf2B?NA1uL!c}K^ z*>6AG0hZK`qrH=J(eQTUM>>x=LELw2egFL^?q>h}^-#6MSsP+M%Yl}S{(5vT-MY#B zX9RDw-}0ODw0>P%%Fn+@Jm<9_<{s>7T!Y{P4f`!EKcLfD8?yyZjkZ#kmbGTK6R^XILqO@4Zmh@ z7-g`-^5#{p2_3{&sSd=qx9M1;;JOagQL)guzXE60j{*iZC;H9kI&pvgM}U*#n{uYe zPQe-NL4O>!813nS%}&lmln41ednAK5bT9ZC)Sfx^DZfL0QfmL4#|g$oBkFQNJjWIO z<>E=$O&UDI)*c*@x18Y%oAY)oIGY!+N!lm)p^w{j%IuVQS}g3Gv)vJ~nTPQ5?Uq<~ zR%Q_geLvh}=U2&CnD!eUW;-AKi-#wHH|^qe{Eq$IhkGo3n(;hejROX5fKTo9;W5B) ztxCm+@bd6+e8O*Ve3?%}+QLt3_$N>%#TH(j5rP>UU{2rn3Gg7{zw$e|0-EJ=C=aV3 zIf893632UdI0o;>;mi3l8-Dn_(qma=9z1-)=}hILzxZIAz(gN3|3`aC)P~(3VOJD7SWY3{=A>+Zfx(B?q&T zy&RG6!zl|x-iyv|>_8NIJKFcjRFt(_g7X^un$hjf-q=H`CvG4`-iP*91>3o7d7LqL zlO~ z8gkHNPH7EB<}ypl`qAR?!RQuzg>~tvMv_XYjypqVJ*d zJVG@F{T?mTjF-77!Nv2)NT0g(_1#OJua!LSO7OnM6$F{H^SH%Vpu7UVJ1Z($FMO_) z1%qw}qqaK_OFleuO8I8}?&lxLCwzdLvrV*TfnR+)hh?x4jyt-o-S=owaq$de`W4)@ zklZ(YZ{6b+AD)XIwfcZ{93QR?r0)5~UhCf8yqxkW2uu)`!M4N&4!nE7jUK}^%}!MCzRX4q3t;c ze})E)+R*4WrNeT>_7VFU;$LCYUau+TS>|;??~ef+>VWc#4!{%ZBlk^R^81flsh?U3 zft3hd92Lj?s)r;WM=c-K?tCm|h}&+U=jtf(`OWEAcOqLeY=?PI**uDag8z55ZS3kQ zN8RK1GFI9=KXkAVFXP)S{Iy9j$fxLI*vlRLZc8k;;JQ)rC1!1YnuOlIbs|nL^&0X- z?Lhj`(dcQ-Ck?|H4*ySk_ZMqNaUTHq5KQ6*OGS;N(gZ1v>NHf!g=;XusiFoFNQvSQ z5{N|AMgnYut=MpT?{#8SR9T7}tT?z%FyQbfb%kxNgCn6Ts(6U1Jn(?3sG<$6c<@6i zQOOT|K=Fx!6r|hVZ)SGS9{WOwsy^jA(%yT{?Ck8!x3jae|GyH;dl)w8<4=XJT8tZ9 zTHG_~b=U5NXzuR5x7LNf?Y0Z+gD2ikm-p$E>mKs=2kP&<2jtT`Km( zc9=5zWZ!rprqBJdFv@yZ?g4u8ob-ojtlt|G)Oo};JaIm0%XQiJd9b#<;|JG8T9KzU zuSY!?xAY>fCG3ruM_6n;mgUQ7zgDN+TJmuIv^UgzOila4ZrYu7+M_E^TiWEzN6d5M z3*9tZK3MX4x=fShJ%65I*uDEMr!Dz?xtsoLW%~VX{a+$%(W9{DAjB{m;U&h^V&bTkPad))5M0=R+Kt2yW zkK5&aVcGBN=Qlg}-sL;zG0f8-jm&$dk?*7_WsNeo`aOPddo5cZzW1DY#k;R_*-p*B zn@`?{bTp>V|55H-4w>I_tTDIcvCls9!1DNs>z2pQtd8dZFU4>;hFmYFJ`r}qRKN;9 zmd8tPWN_Phw$mWFZTRN%G47=p)jtP2+q8YrUS|CG#JYOznaJPZx#Zt`v4+pCz2%EH z-tzfd>;8XjWB0!tti0cDdNO=?gO!mCdUQJya$n^@G#m(#Ux z)$iM%j<}KEw;ea~`*!1gCDJW@h^SvXo~!Sw$^FcJJGdsU!P>k${_B0Quemew5#@Wk zY2Op+bZOrc?b^Om%V)nnTk6q{yW{4{nYry{8Gq~2Fp2v?9@-TDqt0LX@%Udp5q30& z{V_z7R=s7T@TSyssuF?M~6n+`aqW z@}S0V_v=8Zx1VV5rmWk?hkg>1wCz~$73+4{4zIcSOPe=OzsoX@+kN4IEdM8VY>%^9 zJKMcH552lVI_sy>Y4N-EHrk8!PRv**cjVm*TjuUBmIpsl(<<%g+(DJ`XH|tWTk7qVRmRuwJYshjLws z>GQoLc`f~po%NZ)hi-4-v7Qaz;d*GUgpc3%Vur^vlJf4vo!jos>o*PsL&;0ji7am{ z|M5dnp8k5%2+KO#<)ti}E{(Qda_Cq~Bg`^xf2<~!TX*~=!^`=aBZGD&$46N+PCx!F z@-d88>h`9{@1-%^5ozp+|F_jTKB>F+#{Ftp*t)C_wR)NHGJe0lW*Iy0)pcB2WLUYs z`Nb&H`Wjx=nT_#%f6Q;^!0EDm^I&o=j>pQgV?sw|4A0Lc5oX7vN-j(N%&6KE%+grc!J1ezs zVVwKDomH3raLVVcRFkz^?u@&7$}yvd*G%eJma9Jw6zkB#QI~qRGb`u2d)Cpzw@lI* z)`2(6%V&>tc^NvyeOBA%=VITwK0@b-NHaViKJuHTz4?b-+T|ETJ)F_{Ll2KvNbB;} z*1RX<=gY{;`;zN)quMTYp1DlBx?bwRr7^EqPPw0+=Xbu)>R_pln_IeT2Kk8b+0JD> z@9IZ?{%=jZy0m|F=cLWt8S6pzUCTQ8O4f(2AGtg}eBGoxnV(-?n&ZoUa9O^OTvEsX z{H6@g{n~xS^pV*bKBylhKmGCMbIv7~@R6s-Tk|_{)yYhW7ZGAy*!J6$ zu%UYzN+c)upyuH73ROMLXXnr6x4s!x9Y^U+3?{l$1z zVXQx;OpmoPl{gpOc=K&HezBCH#)}iR?K*|WE+3?I(Wh>@{xdfZ;??yrp3+_VK#vX9 z@vLiE=dNgt$hw}}iE9pran7gQ$J6y8qr)0) z!ebAVe2*V`srKv3a*OXR{$gCeGP7lFcggpW)q^tr{;fG~-KTE((z>Y!xx{ivo1AyH zS$WUsj&|(!$i~6+t8TpgGtIm9x$~Iy%v2k5WUTVq87duI(yICU+Dj ztxY_@rKs_|F4XZ)JXdmfvtPo1ojwQc3&F*J9ZP~RoFGDObV!G&OJdxY%{{2ULW7(CFWf_!u8TBo^@)%4x&fFWXYwgFo zx-{!D$ZcyWYdDwb-_yqD*}!%};DfCWXT9ytEkE(2m~ZYE^!}CU`hO9&xBu}bUzW$; zdm~5XrFb*(;FoPXYs8p#9K$Q|>*8)7Ixoqask^uH`HYSlbF?b|-@VX}X?5$VH4$9L zMc*{f!}JrE_4cXO?#K3j{8ZGR^Nu~law&b3aPN+rls-Vzug$HlWq+isA5q`B>&E(H zE6>Ha7(eN6ms3o6Pt(Hv3ya%!we|9;n3@^!R^Pv@dt5*MSc?thF$xGIsay@9btMYi* zJpPlKpW^b~KHtN-R?1w)zk686;~ZaZQ;xK@Y;A3)vR&=_RFRi5-TVJyGU1ow;@0Tk z#AB}4ZJVFJZ@zif^}U~exJ~a*{e5g|vW}JX-ZPBXR;Nhk|Cq;Ufwq(rxeITZ$2|0( z_tvxrHMe!(=*F7AT$lR(cx(^zea=}=^Z&n|p8j6Xxx@j7mQmhwbd*J$+jrwrin_x4jQrn4h05 z`x#GXKfIUwkb8e`K!9HpH0H9?!v~C zu#GM3*y>5xHC@=Gyz?LJ!gBk5VGN@W&0pJv-7pE;)P>zX3Hw+VwsR7;VYd1m+dBx` z(83N6!meszOM|ehTiA~VVH;amZgX1xHeA!fULAyew1vGs2)nk19bYpD+tk9=4Z=Rw z!ZuFAu4?5tp4;L!->X_Vj{oH#td-+h5?TgzfLb7UG3L)%nDe5q8n?+54j(S=!-z=WLu)J8>q4S7LY}ey{q& zyk~8uJcM#|(J%fhf}*c5KJj`CujcqTo)ga)ix*k`)$Vw7|NS{S`l0n5%W;k|`k~Kk zkKy(ha(PXC@*L+>zzRPiPS&MS>@k;=L&T}iYl`oE`E&X(i1IH* z`IlBG|I*ti|57f8QU8p_@zVZCE6TrgM+Eops_n*S+!%KxhP^qy9{a8DG477dWt{j# zp0ADm@$i`3Qmz9L-XGU3=G}C$fA+ICnJ()>nJ)hK`yuf?@^UivX-`J^Pp(k@lW(K^ zCo@l@=v?jE5#6h}>V0=yOBp?^`iXR-KAgNGe*Ioo7rOkmC@Yln?FwkrU*z zEz9}Z6VKIg{qg4LJLf(~_6hrIwR3-dPuX`J?~DDEJlE3iU%XuW=C@_4ZNKg0i*0_f z>`wlq_36$zS5}UX#yrZtO!PZTU+JdhvoHOy?O(2nbj$METee%@zpSQN`iB?JFK+4j ziuL>W`|H|#2ItXA+;?5sDogBRMw~oXcIsR4eX(5fmPY~><38~IP|TxyV_deY;Z>%8 z|CQYZ1y`QGR0hWgGQY26`rUo{arU>I13gspe>&1!6~pNAvIEw~s#W%nbH2~cmidmK z-B|ba`u&-ubDsS;TsHe+p0RBDeUUf0_PI~%<1L>tO&&WeWnA6m=A36-UDDEyefG># zUKjuD?JHcb8SO+1eS&BNp#hF|_qAFn){zP|=@ zkk70qKfN^aw>IVx>)ol#ch7CjrCHyCTI%+x^>zNO9`x@=&Gf%|sv2j#E8{OJ_l#v) zSqJ-jMf&mYtoNC9dj>Pa}3`b))5yPn%{xOEs!-(G~UYLj8BwLX4lkZ`Zba7w7LET@lG$ap&UV{EoYJ zFK%0S^ZcwZ=Hdv;oV;`SwK8_kX!PO3gLpYEKYtKI$?@`Qd*kcgJ);Z$`*eKiKC9Z7 z55)hB_m1VC&&A)lNbjE>=px1cF5ZV*ybG7l&W=VG&h8nl9u4Q)#hdBl{c85`=;94) z;`b#nbe}HX#t2v)!-dPgx^5KlE*p)W`A8S3jmw`Oi=mcxdHIbRug_DC@5=kB`<9n~ ikpbm%@rHHre>mSRUjDzZ#K}JwZ-~N-ZtZ`!^!^u)chpq? diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 index 79e816ec437dd69bb7b9747b477b55ac675e62df..6bd8e45d86e00919fcf3d4de697f1946ea2a3905 100644 GIT binary patch delta 85437 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 Tc(EJvW-oKD&v*BDvk(0r9IB}V diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 index 14624e9cc77fd5129d42e2d3ede134735ca49fc2..7c06fcc5aaa2274b01d65b26ec5339d190036e44 100644 GIT binary patch delta 81236 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�rwy#LZ_nrHlM6HYcu`D$P}Y~I>daZ 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≦ZQw(fU-MS*3 z$8-LfBDUw~TvmB-YJ~H%dBQzC)zA6soV}#}9LjT; zLU|@;Cy@;TBMMPqzbHr^9xmSdGn&~bvR{lD+uVvVCnC`L31e>}C79PJN z2l+FeDh=i6y-g*@0Wnkfsqp~3TN@oZAac(>^8xI9cn4tE8cg9w-4sp+nBA#7q*MRm zsm?=0{#%lt7Ux<%YKGoW{D4P@^nIHBv{+_A*C8{y?vKGVw}3@D@wB+J_7EHGNu@k= zHqxiETqc}B1P)~RO$o5cAC>af{iEH=B-C{&<;_oz4k+kMbh^u%*k+$fbV$5eL%R^< zVnaLM@ud7iwb4&Iuw3-pmK9+i)DN&w{cyL!Q%!S#pGLN&yBg0l)v8X45n2J@ZQDRb z)REo+%zq|2*NHU$4$hl^HTA$b@H;p!1J=y6F-sSNv7D5jir!(#ol6x#G05_0OF_9m zyt=#%;+hhk3)#S>WL^4+1(UF?E2%uxl2qOde``WrQ}bMtXigdvZSHF~X@>RvSD=Xy zxjevWZS?!E8TUt&e*%7O^w=E~4vPMnb67LMiJd9WBHdb~+FEu)Gqj#YLz+dwS%+Bg z=U}|;j`ENy>}Yd+8**X_izNfX`Li0$^VQPMmIepMr--& z4bWN7s-UK4#aVQ-nhzq6MYxc*AHpi?phJhmXz61c`JYGBl=Qr)6eZ+-J_cJY>|{NR z9$hs1u$ZW0X41ol#ZXj*4~xr&)f}mA3f^1j;^k?%W~?85jZosF9!}Fy8~ym!;Ds-U zdnJ)hkr%P`oKI6)L~cUHu_N)eFH4Zb~Nlrc`XhzUj-i`r45lxWpHzwI8(5Y zUqyI4hLqRD_=II(s9m+7#1HyosqL!wy=W!p>o`R4zlKwY2sOPXhG*?E(c}n3HEzQ_ z=dxx`obn~@`K~_vv9;lKENxRkrGu2C$bQw6NOnSJZS;d-RP{RcsE;sTGNa?y)N<-8jw}As$X9hDG7f;*-m}l5MvTN$U4Y@tfd-RoamX(#5Q@vHd!em z=Nr()LV#WL;2Ri?yEgh^DV^Z#NI*T5@i&mjMYfSjIGc`a6Rr81C`wR}ZKe=s`yv~r z_&3FvffBM2snxV)Ptu+j!m|}~UW;icQpop2J~`h6<#G(Ri{urEZBO(i|C^$K<{lM& zGNjv{F`F0o_kU$67f@f+C!B|RvnJ~Izr=dmsfqd%(Kpqjna7D?K#|FPRLo6S z14g>&_)#!@7X;@ca~RpR$ogptXIFp?bI={edYX`iyb|1ejP=__{S486~0^Rzy3gjO8K_P7$D6>pWgE`u3KqZ#jrG0E-*nM1Yr|3aJJ5hD^j$gZVB@4$ps zgFqv7ydy41sDOMNWN$|-cOA`cN99|-^!xyM+r{X-GIm0s_`ZY9w!6m{oPa&fb>wIf z{Sx25N~O}(jx}uyIp4+JF0@_p2r!VmJ$*N(q zkdwQ%r|+@@{2j%=he=gQb?;%Go(BKv-dOsy!QxM-xn8HN`czQQrFjj{#5n8 z$m{1a#})mwmtoH)IRu*#s{o5ye`xi{xz2!bJqwQ4p5vvi5^&^#{YZ@%7V4~Y z@_li>^xm&jctTZS=?QFS`cvoxw(EX{PMm-XeVyVzfGTefmVN*?3GaE|hu9~+K=MbT zI@!4kXC%8aT&1-6Bgo%f8-3w2I`k2Iow0AhZZv~tM=;bv@*nmIwC+Tq{5HI zy7YWAn>AQ+tUEIVZM0uTzK_N5^Yg7b+^)gjS;qkcf>cLs^xZk^i;X=2$C+482X*fU z-Wd)p+l-l$op2+_*O2cMk)0}-Dth@woh|_7CVZ++mjj<*J_M;VMH(^Ct|7exkLB{5 zZW!-cY2>FO-yEoozWvDoS*hRhVh*`K75x+7wOxhe`xFNUFyS(v9!_v)JL+<-2K&6BVzY&uYkAH!@vq4Cs6OX@#Y$@&g zM&zG0AH=)jF#d$1pB~`L9gYEw3m(KQ=B`qgLMOk$u~f-(W86g=;eXr!3NCefB)xqn z`Tr> z^Lx0IU&#Ce)T;zX{vi6t32U(ANAVvCCvJ}a;@qW@X8#w?@?jsAdaRknwb8%-r72S} zJ*Y-;f4`*wW8fKcvwsx1boEbS zMnY*jv$XFgF)8)xM>1WeM@P98ke)=HKSA`bLpp^l`bQF2&wn4`%S7-q(Lk)&+M;_BJvo`wH&2-{t7=IPXzlceH`k4I>kBq4? zkD4^z@@&g2_c66y@h;&o<^9@Ct=y+mO9!=S0k{gP)-#Ej!sk-qHLOIivbuy20B5zZu@L%v!09b3mKCT(6F9C!K#j3Rca zKfUm)7?4`1TUA_3sjHbfeuczO2aP->MkI$gs1K)@1UXK@CPGwm3O3=V`%YnQ`O&nA zLZ={r0G;HD09m7$2LW0U70WK!87gr3AoL5(xXWvq>uL%ox$fJ>m!m049E|x4Om0uO zugedZv?B!OQxxn>o?Zc?%3yqkbN$^TrSrReNmv_O_<_4U(imfI9eo={-hTHXsVITN z=Llxjm{bnHJFwMJk0i+XPb_gI+KdTf33qjpTS(anTd@*{$?*-YS&sfwB&8ii_~hzB z?D{U0Jdk9+$fxgw)F)vB%+J&yNtcNxx*WHt+!E_elO%nSa4oX!v^`F`Iu%1kQ0Bmy zyUBGQos5$TQk!^m+hipP61k6T@zNH^s5xFL8fYLVx0+nr(eOnWY7)%jJ2Y;jj0EX| zu>n;yn%JVAU5W>^jq{RR_K)4Z@#%L_Hj_6&s?TX-H`4Qd7$*!oJA5=DQTiD{f;~yv zkL0r?sXC`;AAa=VPoEzB1qTKJa+{@d!R$V>bp2TYcxBlS%f~FiA-oc6<=LbtFw}pm zEk-7*bR)^q^#~rPq)6u`FJ(7T8$Eh8c~Yc_iMwsJ(KlbDLn+dDaX|ITsk&GG+qsav zmuzQ9JXAQcbFqpRifgv_DlE zm-x4zF+Kg{&y@yb@ai~YFu}2G=2KAk!Lldtk$*m-TNh9 zvr?5T^#@P#yuwYQy!FV#=i{m$;6_XjA#{u_c9vD<@hRou1_-Q)j)eOwM%)$ZQ8Nf@>@w$~< ztJ%^P*pdw7|4q|r==6WnbWD?aC%rY@7wuI`sEz*mZ$r^CRC>CmeOXffvA?Tn@YokT z_SCjIZ@53!DBgCUy0uH64*C>{@0P)@kN%#lxH(93R1jskvd?1}^0A4)qG7sVeedte zQ5EB$|9!U5fo!R~mg#EKan3Gd8prkEak0uH>Uz%6Rt@*(7=I`m{Ba#{S^TPcz~e%d zM-ASsYo?K&r^q}|9*{b#HKguYjWRV`r4j6wcfJ`8tVfgu@pf9Jg0s2HHdQ&Lm+G+%v-MF!aR6o2&Yaeftc95A)%l*_Q zYK$iHKq+_B!#G50Lnxga0IfZ^mft2Ti8R$8w>=}GXeUtvzeJpb%h!Ib-S%0q z?Z=RHlItuf8%ISoXTf|Q0Hn0u_gV&wwrwLDEuT1`aWRF?lE&xUfqECb_9#A#xEmX) zZCUdiK2>8|l zX;b3MUxB4&^~B)i50DL!--e;#>=Sm_X5%^DFbpAUA(af1u1@$n*9UJ-ZZ%Bc?kSl>c{=aKw9IR(f4mkGd`|>Nqr0jnp$7(nH8NT#XN# zwWNKxRL(*E2q<@aw{lzGC-(?xQbJ8_^yM7dH$oc0Q@p4CUdE|VnTO<&((uIAey_Gsg zO5>BC10(=_HqyvZ(DxMe0Kz#6^W`2@cU7aX`7o1z6zsW>T1QDE1RUZhDJXIxXF})f zd$=Q`6XZK7G)DR~b_B+oX?}-?H+Dnl^09CiHE$`Oy2(Elv1JV%8Y|T!agLM5Thx1W zFw~)KU0<3@+s8?>q``QZhw9`P*~n_6kGw!5$4j}F)Wo6KbLSRP%H5}*RJGP=O<1xrKY8#I!cq=Ir5bc*>OEd^BhWndE4^Dus*R-t0 zczgBP;wX3Hg_N`~p}osp7NOZ^OAAFiwVo}F$%%xE%i3{eco8oPFc@}Q$qb`D6S1Py z(B%^$RX4dO!Uo)}N_h?K1H|Hnd)ga2cQ64Q0XWn9o4!lS+Q>RdnkTh>O=~8B7A$#^ zv?Zaj#f$@=358Noa^M-b?*lRpgVz+o_B-i7p;SGv)7StuCk^o!&!#uZyBk~0y90FL zIha+QwEY}uvFL1=3|k1O6b4L|R*RFgeX>-XbFw!xb?8Iw_T*&v+>_J^M++jJbEVY- zJNeWW=WxnX@N0Z>dyc6n^hw|Hz`<-VmN7+IpB!lITmEEA-}0x(KLrit7f-J8>h2;xgt5sMbLI~Ft#1M?U;rb@M`HAnj9gK9pg=Bre*r2PH#*;JfM z1jt?_oon&=;~jDX4v3#w5Xxy?k?)~3MbadTrzP>z8otKGi@pIZLqDyd)*{H(OC6}i ziy_511wLAvh!rnc0LvZsIv3|sNYSY3&1>#`a)^FXr$v8LT+xl{2~Co z!4nr@4naWXVsPRO&M21fAj?AsN&v2-NC`|4GPy+U>heqAMNq7|RH{z(@J@~oH(@Cr z`sPw;QgR(`o~=@exRex^l$A21FLW8V4w?vFewh>(2WFkq;CaCNf$1P`rpR=xM0KP% zrOY^`tcx?*ndaWQ47ss3sT7CJ1VxD{Qk7F$mbo3Kscv13mGeiFYXEgRA)hYFxDsBw zQLYqQ{X^~W3^;71wd!${89*@y zoin5t`1z4M6a33GWhRbEy6Tb~QY*9XnJJA=xB@Xy6E)9-XYu$m@=VmHRH6h6pv}}& zie|VSDpkeV=Q=5gg_1E_x|g*TxB(hzB*z>$s78XYr_(!gq+hUpAD@c`R_fzYwc&6< zs|q!_Fw7zJ1}8S^bb)ju4JebMoXkT>p^|x0Zl=wcUB=9Ui40NYnWgZn+jF5nygc;? z7UqvinZjzwu>Pc!*?McDODP*d$LFELM(Ua;EkpN}9;P)Bvi|2n=hTgHU-9qP*;WYKJv#GNcU#?>XJ+nPlx)+d^EAUv1P?>57jM{ z#*Ff;OZ3Q?xctmOof>r}Pk(k;(h)~OOZ=x^kKbjIrbj0-9)*iAgS~i@h*Q2s4oWx5 zL$cRp!758DrCTNL??y}v%$CK{{+typ)8LZ*t}%Jjqo)Fiil~!qg0X2xm2?N_?5lza zHwNV;(%&T%KU*g4M$zl$sj-5ZZjy@5Y7E)R{rKDYY*OWYNO$3HH~t>P-$VG@gTKAh zXE|1!MzSrJz5@YkwUiHIped_B2v2EONw`o;DKTAkP=-t2zDj!HA{?KEBsAT5hdp3D z0&+-klvchM`G=4oP zJj{+$m-5|s4{3*{Y#ZfJe4Dxa!8?b!l{(oI2fT-XW8Gwd#hc6b08hqKn*?~;y|ktV zVNVS;*GMBOe9Z->WJ7tLy{4R&Rl7Z^-f=|*Dt@%yiJo?WLLqwCjo$3&#isZ2AbL^s zULFc-Jz2RY;K|ID+GEMhQqfosuenbRbqru10HYWHKPd$gO|oGeIDhATh^g7+8Gr{S z;P7T>u*a2{mE5<$L=wq+3nrqShTICT5TMI%m5K-2K{c++?Ge0^Z#~zg|2l;)=%4CG zfm<;Z^65A?u+uMSaGw3AQioOB0u@Dhr47%;A#!?I7`u?V?MW_0UwLt`z>#y{ue@Z0 z=em^I=#vM?vj&UVACYLM$Ql^O_J-Tw4eV5iWNZw#M^|oiH5pym^{$dQ%0L%(bWuhA z+aR>xYsP2pgV3y`SF;i{bCP`fA2joznS^GAy_yxG*#z?3E?tm=j!zw7xgc%Dxch+_ z8Px;n#O>0p7)og^#wAltt&}GP{z>=MV#T-9H?{C7ZxD{o`I%*@2j_&~8!zFLTxJhu zIPZU+9Bq$-6u)LEYk8VQArEGjolbbLq~WIrYo$k1+qAv#6Y2|vU}UYdKQ7@P{N#Ze zHy~(z9eW8!FtkB>JYL%VMbN!T`XULx`zYNeEsGb4!L|mT-G_r6B=wanhY*SuvOQoZ zskPCqg3Nz~6Trjeze@d6@lrm&6g3#E?;m#@|Eq+*IQ+%qF9Cmv!Q+2Tdhx-aaF~Z? zCcB^-Q?$LZhV0jvbFuI`uQAW8eUPEX7d>|4e9i+aqNkl|dTd1>t-Od6Q}o!%&3akZ z%GEV`S<%WX?OM5_ODo?rgHz*+9=mlP=cDblS2n4cW4CVC09OX|vdUPry~?JQYc;&~ zszR;2rjk?R>n8Yrq^Hu4wTo-d!4BdEGp-@8HJ@=^J6A;87k6rDf1j3C>E+6hRvzfp z(j{h2jW60h$j|v``w~S@HD=p$n<+fcoRy-ubhwioGtJpKr;nk1h$gJ|B_48fwc0DU z;4j*4Q+tcHSL1ySs_BcF=F~pX_Tg@=dPx(70T!XHYct}(L!_b9oYik>FBZqtXxK|_ zcok@#X(`c*M(U)-QgiOGH4NrYUTn(Na?HX~1I^vmoNrE}2d+0KVz^g&wysskJ_mJXwGO>d+H4@~yWV_e&H;_);xIcX07Xr#m!UV9hf{CBGLAjfl z`)K>w7^PJsHoeT8uyw-_jUKd*hnp-dw<;}1nYpheqO~#FPJ*oPf{Ud$dY(3}G+My9 zjxsd7N##?S$5|VbE1hRB>O+o-%gvcveHj|pH+iUio_U$@u?S|DoAX5p=e8q9bLWG3 z@X}YSjh~O&HYSL!A-;;9WI7lgUI;0fx&43&93(B5IXeScv7EMUG-uN03XMbtwIWAb z7O)r>fY>Vw%&9bTfw^3`m=GJ1w7iD1om{h1X{eet#AYc~ zt3y{?SKGL?vd9>^ycQ&@oecCbQ0=FUbKFhCjmUVplIf&W>)NUguvKdGRL!XL+8K{^ zlv3THX{Nf1?2FB##R`=ZR!m}*Ig5oHT5K@T#X0m3;Z$MlUsORJ$YoGvmBvH{ZLTt3 z&$70WyaX`6nq$6KG;`JiAVrrz6wO>6VOS^Ux;W=pW|(MT8DMsXg_k0SKGj*5CarYG z5Y=8(M3ppKFg@UgYOo6N%-ZUVs)2B|i`s+6OgGO=Hg_(Ue&a9?GQ}=#bNSS!^bpJb9Ic$ zTpVpURsg!MVU{^dTGh_V@U1X!N!BOPsxGpvg!^iv5+psKZVl@DU12m?tIcPIk4M8f(mhqvKSCM@M_kmfd^-K#q z=CrMU$zTJvQ&%md-l?hU783$PSff!ibJ33Ho#uG@rW%x{tp#E5nMSvB&cPf%u@+3Z zkrOa+g@x3YR{~W=MYL=kYVGR)Yh;*{_p8DTd#WEfN%Xjv@_~!jm-Z~X>I!-cC30{9vy$tW4mh9 zwB3jc_f_fTfL_lD*3$~LUG&)FdK_BOtkv)QMz3$v%WrUcIRXw%WXD3fSr~z9NDnm( zf=6`G8U#ZbrxOef3D#^dKOky9s?;hBLLa$wM6H8kpL+Frz2gqQUe-s_p^c!uLdXBI zO>f_&rpG!;weoFxT3MsP|6Ql1wXqTXa9l$)82Mp^RyGL#t63{A-~=N6zECea^|Bf~ zM%x$2TKNavIB#?7WkpTfZ}aHocuq(1fA|AIo%7p#TKSZwvty?;UA$$Qk5%xBX!~uA zYW-V-G{SEwidI&foEl&BEycrm;QQ6|ExR_rxA0_z;ctx_X~Kz^IWu_BYd$|Wy{clt zic#*e<<%9Vs#h#uv~;0~zTay;oV{Y1vS4}Hl8RCDRxVgjv3yk7{N>#KjwhPT_)ErL z3jWT(UmyIX;x8@uL{s0vbkHFWO_o+i$aaZ52x+k768T$6deBLQm&2hT)5g>feGg+H|>`ii5<)%jKa`Dnj(j&c!R?z!ex`8jd`;7@*E82!H8&X63_O4^7W-=ydqh6L=X-)CIVdQAx@Su$-z;;SA9A zlkY=}bJ+~JM6^?2Ch|vT$Vrln`_P&4pyA#9*j7|lEFHFSoklNH?H_qvHyII9t^qwC zIj)flhJ_dlpK3kPPioB76)RS{N3B@m9#y_=P6bVZj^D4p*3&Q(s;dn-!@XNm527rk{OOqXRaHcT-QPqZRERF9+YB`%j_h% z1qy!iTG*UQvb$*(%$Vh+%i~g`jmgU5fZTO?Wc#^4d@*@&AsWdFYpKavQB}?JN5{9q zjX=Hz-E@O4ZUWSH8Q7Ae+G;1IR4#y;N;qjFHz%Fgcte*t;0-D5xlWep@O1nKwq>R? z6q&Aaoji1S?A$=-D@zxp$*%QdZPHTUyRXB9X`|5fa&~f849cUAahK!P;8|hnybkR3 zL&Px)T5lrzEP1JvgA2=9axo0PV-}3S$H@5pue!!2^LiP(KdpaVYT(Lqy_^-Z!hVfR zucuU3E?u#xYJ(xw{*m8f|0+Ycziqy{a#2;q2Gd%NEdJdT?fV0ca}=&-yFAS(SlFJ~ z>STgWvr_cK4Mt<`V{_H$J|m)$VJXg*vt|ucxQtJmEs??20mf9P_!_ zQ4;WU_6Di~?w&S=E=>_87LDW}TD(ENR>~#7)MFw$Fe ziMl9b@XlB}rwh|xsU+8b;2UdQ@QsR%ye_%GqE1!d#Y9IT7pCQ4yTp;Sj~5lxg2D0 z=lB>zJ+)lU!Cc0ahSoYtZeJpojqTtz_;mh8)o>vi z5zSf}E9-rY!eYJ@Gi0<&<5Xqx+NE-#G^&PtOW{`#f2u=hw3zAWQrUs!R9=P_V~nwJ z#q?!(g@IozERze8b?!mgzf5i4ybNYxFQg7Ntt6|vM|kI!b9x66b_aRg5Oo)`j87km z-Hm?@Mjn(t)~11Da6fgZ@X}uJFj;R>XKUe2=&+e8Iq9Iro50REs}^2TimDts6FpOthZ`K_+X2Zff zUSWKE#*lO^pnXMERb9;Z#+Oj%av1G+H_6rTZ#D-v;(n%{*VEX?BYr%+-hO(0h}_i} zG*nS7XXi8;RP0lFQkekfQVp3*a5lg@=J;b+Q%}Q!&shOl0gYChfwgkVc|E4hgb0oS zPvdyy)SmTc%M?1je)XaimEAUdwu4>tB+VqEkvP?yqY;~f3RglPXS>xUpx@awM)%_! zJ()baox-=n=nyVGju~-yCEVFWS@kqOu0)(S-bChApfj(knq;K_7yT4ojo@X7OJf8ZgibC`Qnd1T z{7AV5pRk1n~xohA{A`RQY`{Om>%F_aLYRp8GD?_YRM222=Kfm;{i3 z@6TYJ33{}&%L6GEsa_53b(;lO_J=LG=jekln4RL$x-hz&qMCDed~M88G-nxL6%VXo zyIw0N57zyj(KHr{>q?k_^N5w{1L^s7vW3|TuY*tu*2&o^sfyMqtEmy=nY&Kzo8Eiy z&;=fpaGd5}hbgNOxR}#WEjSpx9w!IA+oYN_VPJxK)@xF3UN6t#Mu7#~s7_ASZ~G#` zp)rAxxjDRqAYFAhMTpVt)azBDs{#(x!Tj3E^E7z=u1-#hIgY&ch7FK;@1`JW-v9>% z${Qd%uj*}>8Q%tMJMr>o1Nyu8Hx8j;BjUD;o#ZLB7W7_&yRN^*OlAD}rlL5kQvcp+xV7+p z^q*x1&DkyIXxo_ac+K!=<#;kBCKv}P>*4S(snLiUrd{ly%1!cI5RcrP zo*5Up#7~h;=moJlPd*xSCtM7WYEjNHnK_hB~$0 zqvp~51?rn-7?qBPRgA4(u3@XUl5!Vz3DcZpzYD}TDxcU2mNV$yy@1dgywsM?{-RYmf?si`70?dO zhcx&T|B~h8TeQy3R_ia$ySf)My-gLKJ>1VShy!iU7KkL@Oul-UY!AP###IJSuu5lk zI;^H%wv;tTo@+4$2u=YDnv1~VOc&utA3WKxs~(*kDpRTT+QeBeS{~j_?1C9HxpZ z-!d`J@FGTPvMyM(bbeio+v^cU-iw3eFn7UBlILEyx>PQrY*Ks2l};B0?uAkyj1JUG zvkSGevqAUC=GajsoQVBCY@Z`);~2*PyY54q8*F^cqy{CSYmovTxDT%KhEkPQ`t@qF zXe6ljRW+Wm5Jvd$)UYglK7{&v)MgQSs?;~A_Ehwq0= zn$t$EHf+5w*84Tm8D5effZZYpeE@;(TvgxQd>A5{E0Y`bv~dUa@*fskWJ>!9xg!t2 ztXlp1uQ{fwOCP z63Z)G`wkp-gh}yhuo6Es<#O?m@af{|(Z=sb#1^LT=h$0YZ7Y_Is#!6t*Y2mxaeBAm zyLc0@4hJi9cOvLDtOly`>;#wiZJmFooNHJMYj8K1{%|LThq}(4*za}v;hxGOs!j*@ z)@hkO8BEqi)#~<{a(APj?m42xwdsgHccH)X0C{%F6H^S8V9tbgK``Zo)V>QsD33Jk zMoc)rmue6bhVOPhk?%t!)qg(c+M1FH&gUy!d=t|h3VsypMrbdT z8=wGIoo2(6&T_z~i+z!g8XuO2T5j}d;24}&WCY#b7R}-XcJ1w z{s=tIjjA?Ty!onrjTL6GjogpOqh~FOaJy)v2c9;mJQ{p)4X5~Ywv1q4v4?@6tM=P{ z)-}FMgIl|(3;j!r+tix`u}EcG0=v#f;c>JFN;1;J+cafojj;xnW)=n1Sq8Zf8tY4+qc>AQ$uEJtN%+FjHc!F1)-H2|w{muj2dY1p<%SL5II<2}q= zE$|OKhWwU*yf7A}Pe$<5Bvg>?4|M>zpebb(juS@o8%0e_6cnZ>59-zomxI(Y)Am@I# zhc5DP(vE*;7e{(JvN6$?H>SuW8ki*aWDV{J}oauUs1{=@af}UfuqBL*vX7O zh=>I3od+R72n!KVHa&3=w?!yu3s+E1qaTCV0(MXYQSKLZ+`Kco?A2929_5(euAjZ-=eXApY6#r20o z{Lf&%-5fcc5#w;c(7&Ob-`VDOK7)v(lzcCsBb=i+ z@T4r}G2+4+G0c%jiv`bsbmA6ALkQ@IQIrt;7QzSr8(?ToNS4RdHgg+%y6qc*Wo?Lo z-2s#lQ{W|%pNXxl;hW|`Qf-J7JPC`1bbZ?zUIgtQU&Ng4vC(w#dD5y2EV9%Gi{e#? znRi@^qt!khtrxJQpjqs7z?ohRZbUGBedK&m9y)oQ!ft4oa2fmywSi#pr1Uu#mG-U~9!1S*H#hFnxeMI&rnaUOB$yw}eOoD96;j-c9a!Tq|)W zYJB=KS2Ask3fz~x4B{L9z{WO&$OC*j@(Q+phhN44*?6bcQfkxEYXVwo*ufoM>U>$A z8k;u8^x;_a2=safjyz^!hIp;yIU-Lzzq?+iW1U}tSF5qG{El{pSC4SYS z;9luBl8$i|AxL^?tUd;}F=v|1Z+kba24@S-Fjm9pE6|{!5o4X} zHWhX1^d#7 zDpY%?oy@PvgT~!i!}a*|{x&snAsRb?G1^PI32ll{crf;wHLuB8=ik}L$oP6SHX0eJ z#!NTfL@PH^EjtV*q|FHMUV|Ty84NfcTq>`_4mZ1~L`|FVuXSSvY>uc1vHmuPxU5Dq zkve#AV*xad)DT~UU&mnoV$$sSFO3av$QKX)jXB#jGQAHCaMS621MhYJf?11)!{dw# z1jD@<3%X%w#zH@#S)+%@3)gWtxpU$w1ToL_zu|=3r`1h>OZppDwJvhDStjzF5Bv?1 zK+J>9WLDm9V+5_4(RHswJU(?>4HKXKCXRLx7**m<702K9#g+o?{SK}ubOXdD4>zs_ z$svuPgfXHKkn#VV>_)E9xy149(QahK1n#5q=*f4fw1A@PJr=SkS~KGav_coG;Vu!y zv>(N!*{Ufz)*dUr9EPB`$qmQgB{8_BFk;SajYiRa48?jJi1Nur6Heb4Cv*%=>O-W4 z1ykQbSOB2wEdaOUECbRN)B z0d7AIc!Qz^5KYJRzEmLo$=QEsjpf4@E4jHqB^3Av!Yj0N2BGBWKk!VCnn-@TN6d=N zhx2Xq;cMhBXt~iz&2J+ZZftCLM;<-yH}+_)UQxDUW$YY&t6Sv`|4_5WWJU?O-oY~2 z7}DXo8XDWQdPCLdwfEL2^bW+|*r~VE>D>cIT9uwTB63gZ=>%tZHG+nrH+E^|Vi*3k z5=@A#R;_F}xx1WN`CL`M(a2Waj5c@Zbg*k_hl20%s7@^1up5c1A^l>d;axo1h-f7P zdI@xbK%Zk^PHFVJQ1xFix8_2W0P^b$2}q%LaWSg5O%LldbPjQgi|RqK;2H;g9q&RE ze+@AnK3#-=#Wm4;c)k!}STtggF=lqLqQQ-6h+gqhJgc8E5Ch*3#9wh#^d7jp*TYv) z4e9sl0yXObLa<%>zC3!k0mm!wRb@S%Mct?Nhdy=o?z2(geK^MZ5h(Ff{O{hE`=-p- ziD69U6BuK;E^USF0V5oUNB zKE!BunEA;m9g0$k^h5Vd7zh1yj^$hDaPRC*!Q7o|7 zHX0Y;)9~-sfn1(J?hLi}?zcNVnwh_VdF`z^ox4415jT`>t$X8mX-_jbfuG*gcsf4f zBwRiYk}w+o7qDUAwE<6RQtwoUQd);>zv|)A(;Gb$(uf;Dm|>$$9U2_x-Bs1gx=$7# z?j=GN-IE9khuSoJbQE_aeH+^5C z{UdJeQQp)q<*}A9BSa&HK6FJ(58288C44(BH^N_HzC6-M@>f_FAN5d)nl_W?D+u7x z5c$=#lR{rXF#ELAQ#$n(Ziu^&)RnIxRAU^*i7h6H^J_VKtXE?Jk4W)bA$yGdeZ9n) zAJOn8Aq*U68Pv~MP=>fPxN%^dha1|jVR6_MeT`LlU#Iclk>5J?Gq8;a+6XQ|73fp? zR4zAS_s5zj{0$z7G->1w6EUX#1YL`80SE_&(&&H6V+XfuxW)*7XT+X=LTY$q=l>_9 z^|(X5Hr0seTWTq-?fZYW7dYdnI0qHs=^ zjiVYo0l^W-zvMqB>o$c${LX*zX;uTFX6pBN?QRUpIQJjlsC5lg&-XBqr*Hss5~lN% zhnzp)U24h?a)xvOEAbC8;6&+wkKg!bNr+$lKgiQ!wsAlwHq_Q|5`sF=NQ#=m#@l0!O`0@V+i=4gC z+&}&vG4l693ju9dh({KUOl#IhD9xU&=Tvx47Vl2a)_%^z@0%D2UQiWWG-3@?;eS}F ze*XDOuJP*Am@0;xjK%Aq-uzsdTnC|egg=r0;7}XKA4w4$x)0eKe!>K6ZYRf2SX`b{yX$Ud zpc}s)delque5lr711F6BpCCR=&^ELmZorK&(pV2-^6MT>_$T=DgI?ybJ4`j$dNicL zje6tvk~l=*b}0rNVhQle2>4{*&%9Xw!Y4>SEG@}S8t*q9Z3f7qTY`TdfX8VmRD&}#&}yce1n58ofsqjum)Aw-Kf&7sjR z_IU1sb1x;zmAGGt$_>2Y;xTR(&!)~OW>X0FG3+UMRz(qY#p+ABK9{1K@Jnl+UD))i zuX)kXB`m9?7u%TNwKN(>NH!jCci3c;22yN1+K1_*9;yOi>O{zr(}2gSFPko#t>Yr zQv9MX*^(3sBv9w!I{aVIlPzO<|HSE4{5m389YWV*Q(KB9cab*Y*uZ)>8`Z0sQHFr37E~>Y{T}pnm2CF_4LXK>Lj2A%EV-6m zT;fj6a|R+xL+-EZTpK}g8y<1=u?(hn&#Z4s*&Y9DLsh6U z)iNmkZ|ay(uWumk3{zvOrGWmEYUwMX5avQbnpQBUp~agvCWo)PMPVAaDAk}nz?BU4 z{s!F0;O5_e+WIT&+&%_v`ole&7B5?9t4eIdkUBneEJ(8Km-;r3zAT zq%1f}!HKfqBn79-g3Vf#O9dAcK-18DZq=}P2TlYuq*XPPr>l#Cd&^MvQSd-n@F0Sr zK^_KTLw95QK0z>PHb4$m2L=X?-@2J=0`$!RnM7zJGa43n6ObRa!zSo0loUWn3J3az z3A#?{CxDWd+(ik^+dRxO5wi92M7?(YZw4tcXa1JMz~!ug+b6?iJiodHa4%tKn}{x# zvnpqXJ6IC9Mn(D9YrG_b)ufD|p(yHBsa3d|r2ST6FAJBsmxW8}%EBe}rQx!4qoJH+ zy_3)h{kxMx+AUV?{{0p!@kuBLbZu8*4l%w?ch;!5PX(B}4xM#B^VOj`piBwFs|KCl z^s#6iYGwi?}Gz`S|Smi8HH#xZD?B4h5!D2B=BREENpr;D4%796p zoNafCf^;;XdeMh#xHZ7>va9DEYJ4z+L~3v)i<1d9a+L{?yQk>WW_1xVe0DvNCua`w z`h&}*gVUP64)Z+F8l9py+X_3S&l{Bx=@6fqqUSYmd5xQhSDeD~_asQQqNWrKXncsb zsm{lX<808BL{GxX~HUAk9xC{6>Scp8&PXPxB*QTNp2ZTu*W~V_|Y$+Wgmh~{; zT0~~j{$G+6_f&`$2DPc^s?t4;IvG8ueut*k)~GvaDjTA(4!&%uQA>{hPP6{T@~Zn? zR8q>h&d>iQ&&GK1&V`uy7o_!00}Ed*k#&{004_2OQYCsY$4wr*Ajj*Qt~{`}xM720 zQgD{mQTEJSv`)S^>qWT3^s=BE%{jlM5rkqD(&a|#D2q%7Nh(_Pg5~?&Y>>bQgel)1 z+KVqubDKw?uCQtfA`g04oAO#&nyx%Afu~Bg76tD}ig4&=v4_1F!^=n|^EQE0AMwQ| zvUJ}7<&P0ml=U@X;8|C%Pjf(1o^1l5uT?Q^2Kb+4o*A&}`2GyNwnjCVpN04V3A+|h z*aTq3WhbCdwl*cX|6!JaYbWdVrCsyyqKuo+-`RmJl665A2F#KW6&GI_N(#)|B-zH+ zUJ;IQB^-xV0+jKyS?`~$PoC9Barh)IdmSdzs38|=eW&QtCi^+C4gQ}4(atKp2OjHK!&3y#tk_{O8R2-hj52a(PvJMQ8YePvLf_2oqeG;))v@& z9{kXNqs~=!IZvv&V4@^(0xa9C&uw^96IrReCYt1@D~6bFCMuWB)HN|R%WEvA;i50Z zc}E~qDK@4_RJi8Cvt}A=R=xtg(x@IUw+9)*U@qlf(thBOafP12IJg4b5QOObHh>AkZPO*uHYP$ zE$w8{IT&-oP$f39pUu&yBLPkpOk*uO(3oF@&JeqDH3$77FO-d+VTWx?U@qopK?=qv zIr2Xk{^nvl!p_fJ)lKAgxsXUCu3}jvMpdNdqi?tMv?gKV7empN0FFam7H&ZSfU`wk zC2`Ih5n05FWFbi{s`N*P=K^5LuqjqYtgLoN9-vc}- zZ6yTW1xVD-Lgau9V6B!ljHF4_D0^msJ`dfwB+a=H_l^F9Ks2R@}QvDdCL?#~I9ybHRO+C{pPrtY}uinT1# zy{N13BK_Lg@4Eylg{!)s{5kV&pKxa+h5J^vXEA!(54dzA$j(|s&zA+vCu2dt6UkkR zF+B+p7`~EZCE)Cp#W;3fi}8z%_v!AYVUI|ql6|0&KWF|qA>3xDBz<~wjS3(3(h=qs zTfHI;QvL>O4IgCNq*VAM5i}e2>2vc(Y;dG$32NeRE*4y(+Xm0n1eWNl&XbIIQORqT zP@&OEhAA5kB_+RciFj2+wVY9n+=og#6^*+>e*uGmY1N!#Xgd&hOx;<}Qe9V4^tO*B zmqLPLEWSs_k@y#fdQL~_Ef7m4%U~OmU9^<2u8o4>ZBFlj7BQGOkX!f%+^vU!31SW;*gE09EHiyRS z##N;f2H_uKXZzEb8hy-b7vYkGd^#5RG&gUsX{qznItu%Xi znGoS<%U5B1KxSz`Pv*6Wn6kWjmhr*Fg;Fg&;-a+p#?Zf z9^rYzFR=-(Ok=B-LpAkCiY1nzzmD@1g)r%5Xd#dKn6?}n5AUqRBtIQtsT*Lgr*_s= zVbT#wobTO$6PDAsdTcoq+ATGD;|ZoRmd2C`;@VjAs81xR8fO0G=p2sV#uYLfAP><5 z+t@nF949;KYE*s*_xtr}^Gdk$Hm_00x>w*-GVLHQ$U=E>PeDEU&OU#>;S`L3Ss+!? zDWlsAA>{loDNg zsue{azf!Npc(_ju)=>XS{JDOC;z%zGuB7P!T{Aazw0T&L0a(ita5Q)d(O&h zPrxttSr|!DEN~W@bCw^)rLu7=wnJf-K=7<|F)t2x3BMXuRYB3`4G|XX>A>=VO*9f;EoQ8&Yq2G_+SP0Lhjk4XU6k}Uyhou$Mr7$yFbvh7)OOjf| zJ-j(nS^KWQdJD6Ph7}2c23Mr+;hPmVa=$eeN)K#y)#S}^S^5P?1vSp6u^!3wiwhmoC-^ovk7@^AC=6C(o>k2&IgcEX9jnn9 z*SN&3QmPw&pw=%`gMN1q+ zX7owMReQ;kvraJCz`3CF#0dHEi80(d3vZVpeCdh2%^+MdRCRl*E0Th4sZ%bh2SsfM z*Ps_J&K3p>EV>50r2@w+8iL-~P%;a()NKriuWTBQd(qZn?J|xR!zRx6IEl%^FlO4h~S+^KIi$R`?f%g$ue9Ythx3!i)AvWEHFwaJ{v@SWO~Od)_t_ zeu$v)NuH1Mv2Yu@?W|qLy=|z@S|EGKpgD88ttg9VM?MQ{ES4ebpgpNA7Q%cB;GD=y zb~;Tt=jU!}V(G;MRci;)la$)csthUf1@)QpIPMDIDZ)`P&v;P3 zwMlnVJigLwvJ^;N4fCCcxlxJG{1`pRd0>=*#(Ew)CN7d#t|vq)%u3VeVZ7tq=Bpnl zG%*7|U$1u@fXM{SmoP5|4CYG?9DX?P->`|=e?E3{kTh{V))d#dSo(aud1dJ-?<4&p z3nf0PJ2{GN7`hV}@?U_72nLey1^Oa~fdjdhYLiA=Mu;UZfY4415mtPX4H_?R-uwW< zmc0Ny=ZUa-zYxSvl(tg{_g{#CDo$y+{ZSZRjC(;`aKiRqh=mM?sB?Ujgpvf^2bN(M z3Pi&fqW>7eCEf+|a=C9c5f6J{Gk85t=hiL03olRfu19BA=cHWlNg^i=vDA8?gw}CA zGR0hey`H~e0ZQk@Ud)M8l!7KG+_jJ>d=W}er?KcoNQLe!rcIrIZ~>?08R#tr0B6)i zC>&ot(**7tXMb9cakHO!E-uefZhBBwz>N#zF4mo*;h`-Exhf=s-+hPdvKJ$}`aY4H z?DR6@2XP%YCaY-~ET}NYa4@o7U_pu=E{RT&pGQYS;Pzy!EMa&+E9NBp4U>zj+dR%~ z!<#%lMt*!UyW@Q1;rO&mD1ATq@u~PAd3e1463*1nCE#&`i*<1q4=-~!#QM40#Rj?C z%Z9m&-4wb+YWbyTAFs)AM<@%Ikw1AUpLlSXTnUW#GM&RjE<>Z4(#sN;>CH<|3KKo} zWTl=l^C%!R(4-E%o?T&Ci_oy#$SnA(MxY{*S8=M^X!j@4X&5fy##6<}H;#@Q?MxkjU( zkl~YMa1G+27}Q~7M4TN`dyz_D-v|(J&it<~;a1U^kG-AqZjExk)!0i0SdH^lIyK=Q zA>DjC9rmC8fpiO1x@nktZ@})&$ochLiQ-O+aa~}!7CxzCQ*-1N}5s=W6v~- zgPN4^=Vu3Oa3lCKol7?2B;P=ya}(H&4%|a- zQ$HTX#U`h?Ck1eJ&x`xJ!G{?zzCNAL08*Qvq9~ahm7R-&u1!o9-OT(CTK#O+J+|dO zdY#B-w9XkFEU_7ao?z+CdYdDakq>{V{)(or>wxBtn-zL4~_|Jef&*6m07LW_r z}!2uR(2T#P1nJ+7hCSnxc>?3%5 zd8>(j9^N5>3&MvG&i-Sou()t-#e{003?@Lq!)3u;Tfy#`p0e;H4-c1x5ApEcvT*k{ zjF;)M;LtXd#KYNxxO_=sJiI~)5$^DGu)%GpZBK7c2b9npYkqlEV6ux@eB*32^AK0Wh<*ukllq zczEsdc@4i*b`LBbunLdtfHdP4b>!aIG@J9*o~K(gJBqW!?AF{t6CWs_DiTCzD%Jf% zY67VUn2AiT(pM=n3Y-w2LzN&QjLV~N#lK!%T4|$XiLuO}gO&j0hLho)7&=Z3v+T`i z&8JEd(NB4wfq8AdVg%`Eumd|G7IS>Oh&8H+T!GfuP|j453|R(uK{!*wYnP#enJe{4 zGYaZe04P#N583IdazL`V3k;rvONEHqIsGD9QtK|KR>b2ziT15?wzRWX#v3m8TrP}= zksaVu5=)h9TYD!#HP#v~qa{FT@#VWo^yH0(tOqP$DbhX<%?vrDUAbpwY7MIwa^lqGRy!7<0r(pU2dT;hMk=;qqXW!S$L zvEC~FsDQfZq0(|W4)9qifm{idM=Q>(YFPLWL19E_JsK(dmZXbQHAjSBjiyH#MN>P_ zU__UKZrdx;*`sZWrMuBHEeNs{vf*vJ&QM%^r%ynmJtP|qc?SbPy`7jEqdmR@IoZ&O zrBNOWorkoWp;TB{xS6ZJ6NAQr7~#X07t(BJ(XyN?B<$|lO|V>MiF2xJQN6a@EhOx* zYtYOVVF-mLaxx z$7l6Lvy}u@4Hx4x62hOCDBdwIRf3}MFOnUwN#}+ zM{dLf*c50{0)BKeKM?TkjRw_`Rw&ufji7O*U#<1rH-U=6Y5z@##(qfnCNQ9jAL_?u z2%icsM}gE#Pe}^sNfU+wda0cA^W_wTs%EbwQxb@Bi+Biu?`BlRnO^ealN~iEiJxLj zJTYgT>7(GBi6YawbAGovDK}2hBS$IE(=MB3E=@5mllHdhIxNZfWRmJQjB7(OPe1&{@czM1_ggaIZu=K6y z7*-AU+yI^?Z>W4;#;Kvl$rZMdfByaOk zxgYebQ$}RrdwF=WEIiG_%kenB20RzJ%i#SyyqHePw~L3z z%ixnde4s3Rh{7+H!Aj16$K6BWzB2ew4;tjfk+Sd@4^NbZ_w(@L`XV}qfZq|SVjAPx zVe?N|p{!#tV2rUSgZXcarG?|}<-SNSOiN>UvH=SAL%lGwjP-n-hXlT^w>m;T7XP~5 zQXQlG`DLbfOcCq2uj@fa$j`jrfNFYekVU_tU$pYl{$e86@=AiPk5@|0S{oEdR3lo; z!3*LO%=Jy2x%k<)^x9Lc%bfyRPJ7DyYk1Lt6;<<1eeV3rJBo9c>8(6maqewHY!K;o zTwcP$^Lf?etTiHkOZ7E2)yF8+8ZXZWbQR~fHo+oyW3Icliuvz{eoMwH{MMx@kxr&J z)q+H=UDv>dBUK3L3gTIXd_kDVPtmXVVE&W%Y?MjY zfH3Txb}zII5Sk=e`7Xa#-$U}7yjO3XeEx9^LGBO> zB_N3#-2{(Mmhc#O=!W3_1Wh^6`6E5y(e4xYgdgGbcFvyr^mPpzlLEIwzEQB-+K4T? z`+#KAP|vr4V>3ox?&7!$+@{UEmhv-Upcmhv3apfIws@xnlG1Ql z>G><@cr(d&VygMcPOYGuVbKTByp{4s<+D~2Yp0V!CFvrjP&!-bW2fs<^oizG(0qAw zQ`Lj!E&QP(_#JC_#g|W&uJ8#smCrg&r7I4;s zV*ffBU&?MN#&$MAN(Q+sh1={c#ut>uP;lL_Zr_{?ghtWCg@Us-$h8-?}w^_)DwLL5S{nR_+ zskrazK7K_xU97q1yZW8Dm89np{USpFN@iL+0<7Z^D8+UR5dwU&=TmS}*=Fr<;e`wI zF1Y6(Z~H!?x76&ASz=ESFHOO~_EEjXvBt@Qk7CwaAluPL^@|FDO~f~-c+~-@Hr@=a z@naZ@R6N>-|FKHxy+mt%0wSjhrk!5K!_ehGaq{p1uyGBJW^yuZFqSHT`$x$XO*oG) zaZta=u_KFD4~QLUL9QgPA>S47aP+%H@rA|jO8#^31RvKooTF-0)xM<5QuL@rR4`IR zml`lkJ09k+z&HDo<73e$itE9A0%9M8WzdtNeBmcCo&<3)zsT=np6?aLM_9k~YftHI zw#H9&3Hcch-RfIs+qPDS?|Vw$P}UmO#OVFjb4H#hNw$PUbuAbcZaI1Z7p!7kPwN{R z%Ge}YEuJbC*%35^*+wIy?OOWe+2JDH4K?}fSn_+cHu%2oS-LaHbFmw^91ZNAV`0A_ z;&|B+$jw{C<1GmsAj~5baOm}-{aDAA8X8HhI;G=k@|XMd#Wi+!|O=*!c-Q93Mzr@{mKp_T+X^l)?k&%{U-8=KaV*~KkFx_kKz3eItm+wwUBKF zSg>J2+cWf{jnhz6E53o6$d9o^xEYOtZs}5`DaZ+>nR+S?9*L~g*2S2t@K-ReaQ_6d zq2QD)$1%=a-SZPHC3X$7zMnvTZo!7lPhbuuYe;5g-D39q6ur;qhbd=#$I(BWed}O8 zggb5xvhYt~52mhuQAdPi`?YV!k$nl>JtEJ~q>$Y1ywoK+yLdKu=p`nyxi!R`KSTDn zazDakmErao|Ig5UsBE#dO;<41C_L0Ee}+bMTZr)Blj&Z*spo4%Kfdo~@;V*?3GhDU)H^!R~dqA(_bEMxxK=@BmIBX?Y2h9 zzlZnshzF9f}I~Ee^--KBUj6 z=2eq3PsK%*yD+M~atJ3iV*>0HD6J0b%jZcERFm3;GJ2t;Vxh#YCW;G(SoE+yZAC(0 zIW8&OPr0OjK>7p1T_F7ndS$pN-7aPx#(7kj0HpPG>bhK|gPAFzW+quQtvBzOM~P6k z^SsgxOE)gu`LYnooLpHGE}&?nTObSJjR?OtA;W{h^$kfk$+Q>IV3N%DBF@b(l7)h0 zOXNkpu6watfK8NzJ57=^Co96|NdMdp;h&on?gf6~oL#)ISR}M2hIxc_enPkx$P!&B!>f8lcw?7vrw&WMKxnNFNq<1N z@@$!Pk}3RS65KW4cME@A7v&F%>XRbiY#DJZj!YDUn8QON-Lc?Dj;H)9uzKVK|73Wn zf&auZpa_%NLwh4bF6)(6&srm^LT)Hnt%HJaxeB+|`Guby7}QzlCrSMDg26nsWM#o{{dHY0{=h) z$b6J?6E|BYaeo&3oTa;JR13Hd_8^wNXz3jybL+kVPK32zmPT2C-Iox=9Vbg$B}#97 z8~1Z$upRvE0L9~z8X=YWZ#_MAQ1mEGs7fw^+5QZXVrPwq+n`r`AjJ{Me>v+rN%{#l zCf)d5H=aBOO5UNnZaiyDE_1cX!mmMj^&L~j3(~Fc^s?U9psc!D)PwZ^MOOjd!v~ z54VfMSr3M#+X1q1AV3rk#qr*C;~6N%gSbrf4Q#MH*el^+%JT-Qd0bV`>!|ey`&f7g zwJfs9WzLn1e>fq)AL^5COuED!WTVKC*<`K*+TVj44-HDV0qH`zD7;VNeP~#Qr&;Rv zP)PRqg}=`yU1!gm(B}4aNpG0B--LdpuV4CmS?EoDkcTw)Iq4fFaC}mXBoiJE7cxOWkVt$tO26TTr0bV1Ze<}RC?*jTV3PipKHlgIN{}w; z2ATgYo4*uBU(R~eE!;6h_wyb?$7!_q$_-4sjy0ZQ0MUDBUrCg7ArSdRsGc;;+V#6LPH-IR0(K=Ejl zh~0Iob25u=aLyTRJ?3S-Z$s)Hm6<&XEq#I1J?7*LAH~y5nwYZ=5H7IgF-g>8S-}RG zx%DWdo22N=~QnoRvJx`u+qBd@{)f{selGxC#}n@i?yzfCy2w9(OZOmcsp%4qrYz zjBv-}T`ZObp2w4{kNdIz!2Q^ZB=-py)Ba4Zk9oNpVnOb9;c)=qeWF*ORZRoB`96xj zB*>z_rfYuw%r6rd{&UGKp?^W%Po#Rjik-Y43rVprm%-_-=wIkiFiZSJV8Z=1bxkvz zlvB=B;A&$>Z8YJ^zaL;TrS`A7bC#-%u@~;We*5liZcZb;B`i=V7sUGiiVXqfSK7;} z0S;%a!2bMSL4q&D;(tZ=QAz^#B;!+X(a1Z0#m%B&fg3o}@1lo1OYMsJ-o;gIF%dax zNVtk-6g7fq6gB>?Eb6=1eHj5&&wBukG534m#*ui_}0@MEDiXE@AI*+5`6K+7WsM*_zKvD_v0JS$riIJmT)&(thps&FyZAEU$lcaYhr2;po1t)(`l7Tj39i4u|u1 z=1vX^6!|P!{|9-Qwjd(e5A?d}{i2*5ZG07{S8(5uL>29 z9t3xhp1Vj-?!O^DcafgENdI@V)_;rid`Qu~%>5yGaRCnZo2-M}A62m!h2x#NBzFTn zAHjs$BcNjb(8jP0HmwoM8qn2Hf z(6X4z`*n+nI3d!bI9+x@Ygh>x#_t+Di%K3u%z@^&m}1kHrlSQ zg^b4e&!x$WPYRuiZjMnPIt9TUJDHLGS|5@oM>W(N#uB9H5HPA{XpP33XC`?`+pJKF_m6)8&tF|E^vIKlwajx**OrJO+56Fjb% z0F^FwoN+PeGmnE1w089zFR%sgg^}*zi*PUL?hx}G59VR4`Jq0Ct$jwTVYxfCv4yP{ zd$ORRiuE6lLV*@C&!;Xei&tyym!qZiuBkTVs1jj6x#<`pX4hirosWO#OtCFwFzU$) z9PM_WE`N&gfhEQojmGm__7Gt=JC+`6v^t*0u>_|<*Y1a%Xg^Bw?O~~laKU(ZK)9tQ zE?{laY1G-vjN>Id`no|Umr+mk|2bOXV!Rr4LdHqe#=34*$m4OXPy1ds(Ig5f+)qk% ze#GMl@HFrCeQx=)5TDu#S0i21v1$ueFfh{ObCYC^(b%onIVvp(JXZQqegUTl#D#tB z?KdMV%EPS}LgeC;wRjo#%B|Uqf_Gq~tJi zIFVlu*9&jcAs2z;lO1@4*_^Zh%bp0LP}5<0O(Vs;;|%%Wovqz7VPO~^hdd5p3O)`k zS#kjtmK-hbT8|xMQcuTdCKR3G=sI&$4j#{4I?dG8|%|R--{UBw$YKL7du!)<2IkT z^Pb(K8T1yqoKg>H#^P#@mFzxQ6c>8eN|301s(T!#FSU7*y z7g;BCgI~KBUTI97f_wM`;YyZO`Jcd6Sy2sU1BJ1yvC8!iTQY&HEk1d37GC-p^3(|HBV?F3&9#p z7!f(Ylr3uAq}WpuZ|SDEb_aLLilzgcql7M&Q;s5xkkl+kEp9}-caq^jQyIX$?haT$ zO8Z=xug*0}g%GPa&Bez(uM1om#8Z6+UAdmBgRhGvT!OLTE3`>dtQWb&V}gB^p3m*rqK7`o;4K`L=~( zWnD&H!%Ip=D^pB&NaBrfe(h!$C8$Jkd@_XoKXK8GuyQv42^0@DpnDjJG$r1L;&?cZ z*NlG(W@Y6p#`3))!6}3{{a2W(2%qfwcpF3GdO1#kG{x#U$*5cTzq-haPxfJIk}knV zz9cS5iTHI{5RJyAyFYBbMo zmT1+yTlv-azi`MVBRUmwi-p%z2yC;5nNy9$qk38TDyUUj8V%yK}3TVJd4;^qk1VL z!LODtyAMYd<)B~Yu6jAeVMyLIE(V$#6C|1_@pppU#^j?=5OEuer}q;^e2&xH+~xo5 z*)@(>Gi?b_9`rNQjn=EmFUxJuXjKW+%oeR1PcZShPjGs{lu)&HXr8;KqZVF?vUDFU zM7lA*M)CPYb>lcGbPp&|lQXkIeL=eUCba4yaXHeiVG#>f`5cw&D+vN5wI4%6YQU=6D_H@pK48B62dX%J|6z ze3ON;UWu{jjat2wPU|&ak@xi!_v(^wO8rA!?&6|e+{fdN${R`(H23;Xs)|(WJR7wI=n~;-NO#VbX zNyZ(RLO+%iei{;QA|*3!DaB~w$1UT9ag^n}gaG}dSyHH{q6FQ77!(Nqq1c&gub*#@m4qV6QQ^Ni9dDWr0!=SbrQ6 zaOhs*UW_y`*6&5Hltt%>(?zpYXDKDKV8|EAl*FR;T=S5;kNM}JhOnX?K-)%WWL`mE zsLUNy!4RK7eBl9x)I6hk>0cs*9iL?1U%JSX`y?|6_k7Im{~D9v9(2xUHA;4D@p7|0_*`~lz@OLag zRlM8FVhb>(c+XAwftCbwitTKfQA$NZY1KfK-;a4{Q1$_!G zyPq~))|p%vSnq2Byr2&IfyVKEoG(ykSf%)G=lr1KDI($RCi5<$a+ll_bTNjq z58^Dj7~|6Wz4YQG^!$qrZ;g!sTk<}zEh#Zd!+Yy}MK)ywSywIYeaI}}4aL@~VIB{@ zu<++Gy3G9{E`(H(P@5+KTw|9t%+l~XKImmbKFHGF(8^(~!Wx%gNa`1Nl`BFN!wU!v zEkT;UC+L~zdUod$jBOukEV%^2@FAxblt`h+JZ%WT#)rJ}?QrXFL6-WoQLjth%Z|?i zr|5oZ^$ol!h?de7j?6792^i$%@=k3aSm=QC#ap50P|O=K73LlfVn`PBmv zlCzf$_5d+5os`}_*8d4e6%%b)UIh;=O8nEPh9e#xQO53%{S;onR$1Lg1pD*VkY~4N z8Q72us0&2H%ZfQh=V6aVcF>AqaHb*15QpaY1mM5jE=q_Q+gpjbsp zJ@3#;qj~;^E`eFiVn6IF^4n)JWIS!|hZh-WHa-dG=dN`lIn;chFz;;NeXU&QWJVA0 z2vt68YT~IyV_J1wfS=RHvUElNp)(D7Ubh0FdP+b_0y3jvGk6wuG>+qhBTjZ_Gi;0! zJ|tW<6_JD+YKoA}ig-*tQo!dp9^D?4v_~19uuXh68mc`WZ~}5f5Pty!E2|LVn~v`y z#P})`W?>}5+pJTkWR8y#6po8276pVKl%~%{hncS_t<`9pJyxS=d{R=>I8|Y8faOsh zf2C1B-ilFq>;M~R#SrVnlJHUt6j(j`aVFb=$psGJ;#!GSP^ljDGj|q&P)dYXVLJF@ zNu=EVMd^toap|voUI&lo1XyYn#(!tLCtzGucr|i3VC*Jy#B=}!tnQ^}2C(?ZvlQ<^ z8+bYw6A15WzVZyO#(rY6tjhu+Oss}-(G+g7Fq-R<3%k0Kl|Oicg=It&kFeC9RF5q2!DYC zM>$+(+#vUr;U5qB*FbQ`^Kt{`H~~LCD_q&Bfe$iVWA3%+V#kj_@Aw!Cu0^$u$ATGf zYQkfeAMpvEK27-Wm6W#@;;|Mjy*9$ruPo(Xt#ixvjoapwm9Libw*tN>3$&qpwVZy$ z%kpVq{Klldw0yNu7H>oOYDcK=T4+gu?^3OU(u?nC^-(*#``W!5ckSJLn*@%Mo6Bf^ za`BavUyCr`I?$`B`jYg@31u0*fRC;Ny;{FOSB7thCD%b2tgHG0*wN_KhI)cPr+X`- z(>s_qh~n$2`XqTqfZ)s7sdwyY-!*6Fo^5-U7m1^u909+{`hcI_S*$2Nx{2HCL7%Xa z2aXc<86oCA5A+!+iC@w;!AJgb`i#&u``YKoDq5azjz&VJFU61hq|QTgoZy%7PI7aZ z37q}q&Cy72-yOMzp3Na^v^@R^E}6ar|AZiOolp2vMe&)5g8s7ZWI}MyHJ$kk?x>1V zI?&Twl-};HCV+n6pFPnp<9W}T%S=p>KWEAHfhE@u8Nd&nkM3{c2=q?G4J8*4KGj?# zzDfSd_y8Zd0QEO9LGk!X%0F?CB?#XnE>DOT<7j45ih#@M1ALb7O>$E_z7l+sAP*O! zJDM~g^7sg^;H@zl@jVtLrC!IX#mGBb&F+;n$q_w7hef|b*S(4#@yL;DIRNgPxT|TC%{M6qdw|JsNcFl*0&z=Qy(nB$LptD z{_6(!U9~+jXLoxi4I9gC`KkBF^dWY7=8zuA*HKM3d1yK}%tLXdBvhy`#7zb8Y!f$!1=KViZr`OzTcyNn-` z2dTf@*1o%a@Al0F{iQfIh4dx(8zA48fFBJhLXJxgb1nxv{KLc<<%L+(K=1n$n-73TM;Vb46t`!&hMCkk1b9tRi`1 ztgM*X5z+@YR3cko(btRTuCnXqcd10V(rJ-ZXEo?N`sOwtrd{yFXsMZ_fBFoZkr7GS``5OQo71A|K zi&joYH4S*11^J@&Yy?HqaqHnm2v!p;xw#81DDmRY8#i;+t!J~*Qf&&%r^6Hm_sFRy+cU^HifH7JEQeBNDX`S%sR>%!Vl<9wVh0x+ z^%a=bf!Io99*b$|Ek|XVtNs58(@Zd#Ua3vZfr6IaQ&V<;83cN^LTpZfZT#=Bq|Y=B z3yz$UW*rnU(`2!&=(s%Co`XBv6QFo}au(+CkSA{_RKr^oE-MrE334%Q+b3ice2q(_ zBfSZW(~WL19H6&Qlw znB}H;e3E`JK>H>%`?WvUj-Qe71Su+K9_Qw+?JuBKyMd_f7jT8tcA%S|m0)qW#%#qU zIkwG(YN!J`rrDfoq?NhPmihhEFYwW=W81M)IlGVi_!L}}JUO!fF1#J0Gn<#*hNIzt zo){);faG?rK}l~n>PC%YckVG}vhh2pw_@%ckcOM%EOjrv)vgSfJ_w5}fC6bIu^Vmb+zAQcDruP=<$im=>!+shLnW2|Ei5QW&ayj<*7>E@*g26f zqZpx-V&w=hs|SLHkq{sQ^D0<@&ElNPsbdaitK_gDDMw3>dOYU`co{3-3bfY;m&im(W^Up!Ms(hTYRU4XvRiEP-Y2 zKZ=r{k33l*tNGD@?RV{l{go-ad99rCv(RqHb_?w1HsEIeOiMsS&_>&COeDR2^5c`j z>J{-+=jLvq$A%fsWKKFNCP|>SRVwjB?wSW7qe48PNqj7c=LC&Kwmm7aj^eXy7{Lz1 z%STyx5;^$f zEO$YeMJap%uUdrXt1fx9v21=mJtabMTzlK0IalvgWfp`e9G_&y0xxs#MSEK?zzycadK(8Z$UU+80f+#hBG+#hAxz2NpjoI2S@E=JIOc>ern*BBZ*a5^9NVhE@- z7?Dj?wIt9wkuCov9>)UTvimsS_z}$Io!nR@(21;}r;c<&zuGSduBv6}e=iu*!J%X) zWb{)doETw_l=+mGWjmqZUlf)2B#%C6#g};KS zBVKl2)U;@T;_=D+)W(6DG=KwS!|+LM5A6J~!Qj0X6S>7vj@`yzT7KaFqz5*uV}yzu zC|w5`xCELKxWReCjbR|#04N|e`qMKE=a)=u;*f$Q{9b=c9p$=;vvSPNEawwf*gMb*^uGL ziB)5GLwh{r`e0DNkRS3ANEuJWOjB zc1$!;TY7p-(lH=hd%t}QPTX8YVf5uP<#3FqPP5CyMT)91o$Wh!%HKRa3*G<$__PZ{ zC7E8_0PDkKAgUsxQVWXVW zWS09_d?i`3+=SgNzm%8VA^wgoVABinP<$pIF7gz@j^9@ZKLDdQ87;1u@H#c&ZZ~B# z%O$mX%9=mR+Zt4qXg6d1KQk<#Mh|f}^JXmJBs2{; z`Rht@na!d^nZ1M?649EFZdAH4T=0O~Rn9iWEi0{fT=o`PPo-phoLqd>Ec-t=XUlKu zK-bcWtMWgOrOcTk)>c4WYX;X{aN(St+xK-ADS}qP(gW~IR|RAOIjLV4I&1ZcRTbbP z#c&+pip9TZ9H6&O{j@q* z3y#4x+FX=1K3UN;=+adaJ__UO12Q|dFT+>nvczx8wL;;g=USW!eY0Khx&lw{dHG=k<|xUZb|su8q?Pm;&-CUo|yXy(df{v}ZJa z^|*IGUknHLLnEfZQ0fT$#5BxvC$hWu8x6)mzsUPsCwFP0<9!;#`hgzJ$==y-c$Nl3 z6oXIXZeQMo)1EkTy~SP#1UXj<;GjXf6I2F=d1^a-w2O7!iOM<8%@R2O+#o41M+vTG z)&vMXN2V3ow=oXBdMC!g^Kd258(Isy^GR6GT^To=Y8Fvt3TV_7r~9I~p(~4tDxP!B zJW3AfI5)~mZ@~yQ{w^cvI4{k@cY${>@wp4jF0i!!E}TvVEeu>)7SWw-?w6re7-ar0 zBWZ{wU&Uz%bzVbG#4>AxbU>UP_%a6Q3tTMd#-MfN%f>96sqL|tUo2+4s_JR7F;>w8rzp|gle>u0LQ1YJP* zYp}MB6N((DWJt(5}h#gPe+*JQZT?xgJZ-b6~W!0sLo2zG}D~7ln?Q-&fJ} z|5Idy3|Z`JSmRwZ_=%GJSBIh#uY^KkE{>>VvJZ&#(CF7CN>NbA$U9o&Y`fMI0*mC8 z(q%y5CelHXn(g7OMPtYWt;5S8wko+okJb}Hysa=+jZPi$!C)R|sDg`!i|X`M%KvJXPcHH&Ko&V!S%+UPfuS?8~y-?{q_^_cFxAO`sved^}J9Llt8Xm{SD5>+Ha@!aa^gZKb!30L|jVAf=$!f+* zH=00e!+ISjG$*o??$&DT*PBVHjAd}4Kbrs#@+(C=C<@+e@-Q!4<0o;#oKqIn=yh56 zK0YPEo);Ek_Zib1o3bp4uoV#jD)r#FZb10urkA=uK;2%71M)oH8j}!k(6M03Kj~C? zGaLodm&pD6^$Y%&Io0#hkx=i1mLP?Q%<>gh#vnHsAKq?ne-V%0-pMkxGhzN6+V*NH-9 z+T)SE?U9Xp+ixQ{d{O$B%e2Rs_dDn-pe{vONAvXx%^0_uB7SR1y5bhR%vNy=p7%9e z@U#Q7#Rov+HUc5O;3~!kut44BVzCDxTHE~G6mv>uo0|hv(!i&_NAmQ5;dRUpGVg=N zOf^{;OJNC}olz>}R}q4;{{5$KdY&g)PXgFva7O z1yJ#$5)_y#xXJ(f!AFsaV;79*NXs(qNo}lcE39n!l|Jn$wAKRyV2aI~r3DGs9 z0;xS9j5>`1F-0QGaBJ{-FWtC z0OQg_QM=lA?b&-h{o={E)BtQy`jbq19Bp@>Q~FKje;ku&rH9z(<~LY6=$2UO4?5if zPK>1RJ4Ii&FMQXHK^A-h-CU<%f@rMk383zjtm(vSflnB%HJvFLA7#UccSL%bbt#^F zUGSta!FV`Ek@)gb9eT20a6|tWeF`nf$&ycE$i7AZD{vYHu$Ncqv9+G>8Pg_9o-G}q zWH~F^#a$D93yjt==l>ph)@!1qM#e7lHJlVav!j)#(>$8S~rE_6UE4k6?}8_OyY&3HY0cze)J3`~I@0>yM9p se~jOC^YrTP5w6_e=f3*=_(s>^QKM2UyxFxJBZ9ukIfeajv+Lvk4P*oLBme*a diff --git a/roms/openbios b/roms/openbios index a5af2b322e..f095c85813 160000 --- a/roms/openbios +++ b/roms/openbios @@ -1 +1 @@ -Subproject commit a5af2b322e54104f1b095c8c156ffd03bf6ca3e9 +Subproject commit f095c858136896d236931357b8d597f407286f71 From 571f65ec20fbcb991d7bce51787248ab9d325e3f Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Thu, 14 Feb 2013 08:58:49 -0600 Subject: [PATCH 0996/1634] Update VERSION of release Signed-off-by: Anthony Liguori --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index aa6058d68a..a24ba92401 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.91 +1.3.92 From 03e94e39ce5259efdbdeefa1f249ddb499d57321 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 15 Feb 2013 16:15:40 -0600 Subject: [PATCH 0997/1634] Update VERSION for release Signed-off-by: Anthony Liguori --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a24ba92401..88c5fb891d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.92 +1.4.0 From 2742f56d134ba0f5ed7e447afd0b6e2001ffc5c1 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 15 Feb 2013 17:40:56 -0600 Subject: [PATCH 0998/1634] Open up 1.5 development tree Signed-off-by: Anthony Liguori --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 88c5fb891d..8fe423b4ca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.0 +1.4.50 From 0b0d3320db74cde233ee7855ad32a9c121d20eb4 Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Fri, 1 Feb 2013 01:47:22 +0700 Subject: [PATCH 0999/1634] TCG: Final globals clean-up Signed-off-by: Evgeny Voevodin Signed-off-by: Blue Swirl --- tcg/tcg.c | 2 +- tcg/tcg.h | 14 +++++-- translate-all.c | 97 +++++++++++++++++++++++++------------------------ 3 files changed, 61 insertions(+), 52 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 9275e372ff..c8a843ed09 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -263,7 +263,7 @@ void tcg_context_init(TCGContext *s) void tcg_prologue_init(TCGContext *s) { /* init global prologue and epilogue */ - s->code_buf = code_gen_prologue; + s->code_buf = s->code_gen_prologue; s->code_ptr = s->code_buf; tcg_target_qemu_prologue(s); flush_icache_range((tcg_target_ulong)s->code_buf, diff --git a/tcg/tcg.h b/tcg/tcg.h index a4279725a6..4086e985e3 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -462,6 +462,15 @@ struct TCGContext { uint16_t gen_opc_icount[OPC_BUF_SIZE]; uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; + /* Code generation */ + int code_gen_max_blocks; + uint8_t *code_gen_prologue; + uint8_t *code_gen_buffer; + size_t code_gen_buffer_size; + /* threshold to flush the translated code buffer */ + size_t code_gen_buffer_max_size; + uint8_t *code_gen_ptr; + #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) /* labels info for qemu_ld/st IRs The labels help to generate TLB miss case codes at the end of TB */ @@ -658,12 +667,11 @@ TCGv_i64 tcg_const_i64(int64_t val); TCGv_i32 tcg_const_local_i32(int32_t val); TCGv_i64 tcg_const_local_i64(int64_t val); -extern uint8_t *code_gen_prologue; - /* TCG targets may use a different definition of tcg_qemu_tb_exec. */ #if !defined(tcg_qemu_tb_exec) # define tcg_qemu_tb_exec(env, tb_ptr) \ - ((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr) + ((tcg_target_ulong (*)(void *, void *))tcg_ctx.code_gen_prologue)(env, \ + tb_ptr) #endif void tcg_register_jit(void *buf, size_t buf_size); diff --git a/translate-all.c b/translate-all.c index d367fc4d11..d666562a44 100644 --- a/translate-all.c +++ b/translate-all.c @@ -72,21 +72,13 @@ #define SMC_BITMAP_USE_THRESHOLD 10 -/* Code generation and translation blocks */ +/* Translation blocks */ static TranslationBlock *tbs; -static int code_gen_max_blocks; TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; static int nb_tbs; /* any access to the tbs or the page table must use this lock */ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; -uint8_t *code_gen_prologue; -static uint8_t *code_gen_buffer; -static size_t code_gen_buffer_size; -/* threshold to flush the translated code buffer */ -static size_t code_gen_buffer_max_size; -static uint8_t *code_gen_ptr; - typedef struct PageDesc { /* list of TBs intersecting this ram page */ TranslationBlock *first_tb; @@ -514,7 +506,7 @@ static inline size_t size_code_gen_buffer(size_t tb_size) if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) { tb_size = MAX_CODE_GEN_BUFFER_SIZE; } - code_gen_buffer_size = tb_size; + tcg_ctx.code_gen_buffer_size = tb_size; return tb_size; } @@ -524,7 +516,7 @@ static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE] static inline void *alloc_code_gen_buffer(void) { - map_exec(static_code_gen_buffer, code_gen_buffer_size); + map_exec(static_code_gen_buffer, tcg_ctx.code_gen_buffer_size); return static_code_gen_buffer; } #elif defined(USE_MMAP) @@ -547,8 +539,8 @@ static inline void *alloc_code_gen_buffer(void) Leave the choice of exact location with the kernel. */ flags |= MAP_32BIT; /* Cannot expect to map more than 800MB in low memory. */ - if (code_gen_buffer_size > 800u * 1024 * 1024) { - code_gen_buffer_size = 800u * 1024 * 1024; + if (tcg_ctx.code_gen_buffer_size > 800u * 1024 * 1024) { + tcg_ctx.code_gen_buffer_size = 800u * 1024 * 1024; } # elif defined(__sparc__) start = 0x40000000ul; @@ -556,17 +548,17 @@ static inline void *alloc_code_gen_buffer(void) start = 0x90000000ul; # endif - buf = mmap((void *)start, code_gen_buffer_size, + buf = mmap((void *)start, tcg_ctx.code_gen_buffer_size, PROT_WRITE | PROT_READ | PROT_EXEC, flags, -1, 0); return buf == MAP_FAILED ? NULL : buf; } #else static inline void *alloc_code_gen_buffer(void) { - void *buf = g_malloc(code_gen_buffer_size); + void *buf = g_malloc(tcg_ctx.code_gen_buffer_size); if (buf) { - map_exec(buf, code_gen_buffer_size); + map_exec(buf, tcg_ctx.code_gen_buffer_size); } return buf; } @@ -574,27 +566,30 @@ static inline void *alloc_code_gen_buffer(void) static inline void code_gen_alloc(size_t tb_size) { - code_gen_buffer_size = size_code_gen_buffer(tb_size); - code_gen_buffer = alloc_code_gen_buffer(); - if (code_gen_buffer == NULL) { + tcg_ctx.code_gen_buffer_size = size_code_gen_buffer(tb_size); + tcg_ctx.code_gen_buffer = alloc_code_gen_buffer(); + if (tcg_ctx.code_gen_buffer == NULL) { fprintf(stderr, "Could not allocate dynamic translator buffer\n"); exit(1); } - qemu_madvise(code_gen_buffer, code_gen_buffer_size, QEMU_MADV_HUGEPAGE); + qemu_madvise(tcg_ctx.code_gen_buffer, tcg_ctx.code_gen_buffer_size, + QEMU_MADV_HUGEPAGE); /* Steal room for the prologue at the end of the buffer. This ensures (via the MAX_CODE_GEN_BUFFER_SIZE limits above) that direct branches from TB's to the prologue are going to be in range. It also means that we don't need to mark (additional) portions of the data segment as executable. */ - code_gen_prologue = code_gen_buffer + code_gen_buffer_size - 1024; - code_gen_buffer_size -= 1024; + tcg_ctx.code_gen_prologue = tcg_ctx.code_gen_buffer + + tcg_ctx.code_gen_buffer_size - 1024; + tcg_ctx.code_gen_buffer_size -= 1024; - code_gen_buffer_max_size = code_gen_buffer_size - + tcg_ctx.code_gen_buffer_max_size = tcg_ctx.code_gen_buffer_size - (TCG_MAX_OP_SIZE * OPC_BUF_SIZE); - code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; - tbs = g_malloc(code_gen_max_blocks * sizeof(TranslationBlock)); + tcg_ctx.code_gen_max_blocks = tcg_ctx.code_gen_buffer_size / + CODE_GEN_AVG_BLOCK_SIZE; + tbs = g_malloc(tcg_ctx.code_gen_max_blocks * sizeof(TranslationBlock)); } /* Must be called before using the QEMU cpus. 'tb_size' is the size @@ -604,8 +599,8 @@ void tcg_exec_init(unsigned long tb_size) { cpu_gen_init(); code_gen_alloc(tb_size); - code_gen_ptr = code_gen_buffer; - tcg_register_jit(code_gen_buffer, code_gen_buffer_size); + tcg_ctx.code_gen_ptr = tcg_ctx.code_gen_buffer; + tcg_register_jit(tcg_ctx.code_gen_buffer, tcg_ctx.code_gen_buffer_size); page_init(); #if !defined(CONFIG_USER_ONLY) || !defined(CONFIG_USE_GUEST_BASE) /* There's no guest base to take into account, so go ahead and @@ -616,7 +611,7 @@ void tcg_exec_init(unsigned long tb_size) bool tcg_enabled(void) { - return code_gen_buffer != NULL; + return tcg_ctx.code_gen_buffer != NULL; } /* Allocate a new translation block. Flush the translation buffer if @@ -625,8 +620,9 @@ static TranslationBlock *tb_alloc(target_ulong pc) { TranslationBlock *tb; - if (nb_tbs >= code_gen_max_blocks || - (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) { + if (nb_tbs >= tcg_ctx.code_gen_max_blocks || + (tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) >= + tcg_ctx.code_gen_buffer_max_size) { return NULL; } tb = &tbs[nb_tbs++]; @@ -641,7 +637,7 @@ void tb_free(TranslationBlock *tb) Ignore the hard cases and just back up if this TB happens to be the last one generated. */ if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { - code_gen_ptr = tb->tc_ptr; + tcg_ctx.code_gen_ptr = tb->tc_ptr; nb_tbs--; } } @@ -696,12 +692,13 @@ void tb_flush(CPUArchState *env1) #if defined(DEBUG_FLUSH) printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n", - (unsigned long)(code_gen_ptr - code_gen_buffer), + (unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer), nb_tbs, nb_tbs > 0 ? - ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); + ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer)) / + nb_tbs : 0); #endif - if ((unsigned long)(code_gen_ptr - code_gen_buffer) - > code_gen_buffer_size) { + if ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) + > tcg_ctx.code_gen_buffer_size) { cpu_abort(env1, "Internal error: code buffer overflow\n"); } nb_tbs = 0; @@ -713,7 +710,7 @@ void tb_flush(CPUArchState *env1) memset(tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof(void *)); page_flush_tb(); - code_gen_ptr = code_gen_buffer; + tcg_ctx.code_gen_ptr = tcg_ctx.code_gen_buffer; /* XXX: flush processor icache at this point if cache flush is expensive */ tb_flush_count++; @@ -960,14 +957,14 @@ TranslationBlock *tb_gen_code(CPUArchState *env, /* Don't forget to invalidate previous TB info. */ tb_invalidated_flag = 1; } - tc_ptr = code_gen_ptr; + tc_ptr = tcg_ctx.code_gen_ptr; tb->tc_ptr = tc_ptr; tb->cs_base = cs_base; tb->flags = flags; tb->cflags = cflags; cpu_gen_code(env, tb, &code_gen_size); - code_gen_ptr = (void *)(((uintptr_t)code_gen_ptr + code_gen_size + - CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); + tcg_ctx.code_gen_ptr = (void *)(((uintptr_t)tcg_ctx.code_gen_ptr + + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); /* check next page if needed */ virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; @@ -1312,8 +1309,9 @@ bool is_tcg_gen_code(uintptr_t tc_ptr) { /* This can be called during code generation, code_gen_buffer_max_size is used instead of code_gen_ptr for upper boundary checking */ - return (tc_ptr >= (uintptr_t)code_gen_buffer && - tc_ptr < (uintptr_t)(code_gen_buffer + code_gen_buffer_max_size)); + return (tc_ptr >= (uintptr_t)tcg_ctx.code_gen_buffer && + tc_ptr < (uintptr_t)(tcg_ctx.code_gen_buffer + + tcg_ctx.code_gen_buffer_max_size)); } #endif @@ -1328,8 +1326,8 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) if (nb_tbs <= 0) { return NULL; } - if (tc_ptr < (uintptr_t)code_gen_buffer || - tc_ptr >= (uintptr_t)code_gen_ptr) { + if (tc_ptr < (uintptr_t)tcg_ctx.code_gen_buffer || + tc_ptr >= (uintptr_t)tcg_ctx.code_gen_ptr) { return NULL; } /* binary search (cf Knuth) */ @@ -1587,16 +1585,19 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) /* XXX: avoid using doubles ? */ cpu_fprintf(f, "Translation buffer state:\n"); cpu_fprintf(f, "gen code size %td/%zd\n", - code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); + tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer, + tcg_ctx.code_gen_buffer_max_size); cpu_fprintf(f, "TB count %d/%d\n", - nb_tbs, code_gen_max_blocks); + nb_tbs, tcg_ctx.code_gen_max_blocks); cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", nb_tbs ? target_code_size / nb_tbs : 0, max_target_code_size); cpu_fprintf(f, "TB avg host size %td bytes (expansion ratio: %0.1f)\n", - nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, - target_code_size ? (double) (code_gen_ptr - code_gen_buffer) - / target_code_size : 0); + nb_tbs ? (tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) / + nb_tbs : 0, + target_code_size ? + (double) (tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) / + target_code_size : 0); cpu_fprintf(f, "cross page TB count %d (%d%%)\n", cross_page, nb_tbs ? (cross_page * 100) / nb_tbs : 0); From 5e5f07e08f7ed8c8eb9b02d9f9c3c79cf95d65ee Mon Sep 17 00:00:00 2001 From: Evgeny Voevodin Date: Fri, 1 Feb 2013 01:47:23 +0700 Subject: [PATCH 1000/1634] TCG: Move translation block variables to new context inside tcg_ctx: tb_ctx It's worth to clean-up translation blocks variables and move them into one context as was suggested by Swirl. Also if we use this context directly inside tcg_ctx, then it speeds up code generation a bit. Signed-off-by: Evgeny Voevodin Signed-off-by: Blue Swirl --- cpu-exec.c | 18 ++++---- include/exec/exec-all.h | 27 ++++++++---- linux-user/main.c | 6 +-- tcg/tcg.h | 2 + translate-all.c | 96 ++++++++++++++++++++--------------------- 5 files changed, 79 insertions(+), 70 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 19ebb4a924..ff9a884a96 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -23,8 +23,6 @@ #include "qemu/atomic.h" #include "sysemu/qtest.h" -int tb_invalidated_flag; - //#define CONFIG_DEBUG_EXEC bool qemu_cpu_has_work(CPUState *cpu) @@ -90,13 +88,13 @@ static TranslationBlock *tb_find_slow(CPUArchState *env, tb_page_addr_t phys_pc, phys_page1; target_ulong virt_page2; - tb_invalidated_flag = 0; + tcg_ctx.tb_ctx.tb_invalidated_flag = 0; /* find translated block using physical mappings */ phys_pc = get_page_addr_code(env, pc); phys_page1 = phys_pc & TARGET_PAGE_MASK; h = tb_phys_hash_func(phys_pc); - ptb1 = &tb_phys_hash[h]; + ptb1 = &tcg_ctx.tb_ctx.tb_phys_hash[h]; for(;;) { tb = *ptb1; if (!tb) @@ -128,8 +126,8 @@ static TranslationBlock *tb_find_slow(CPUArchState *env, /* Move the last found TB to the head of the list */ if (likely(*ptb1)) { *ptb1 = tb->phys_hash_next; - tb->phys_hash_next = tb_phys_hash[h]; - tb_phys_hash[h] = tb; + tb->phys_hash_next = tcg_ctx.tb_ctx.tb_phys_hash[h]; + tcg_ctx.tb_ctx.tb_phys_hash[h] = tb; } /* we add the TB in the virtual pc hash table */ env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb; @@ -563,16 +561,16 @@ int cpu_exec(CPUArchState *env) #endif } #endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */ - spin_lock(&tb_lock); + spin_lock(&tcg_ctx.tb_ctx.tb_lock); tb = tb_find_fast(env); /* Note: we do it here to avoid a gcc bug on Mac OS X when doing it in tb_find_slow */ - if (tb_invalidated_flag) { + if (tcg_ctx.tb_ctx.tb_invalidated_flag) { /* as some TB could have been invalidated because of memory exceptions while generating the code, we must recompute the hash index here */ next_tb = 0; - tb_invalidated_flag = 0; + tcg_ctx.tb_ctx.tb_invalidated_flag = 0; } #ifdef CONFIG_DEBUG_EXEC qemu_log_mask(CPU_LOG_EXEC, "Trace %p [" TARGET_FMT_lx "] %s\n", @@ -585,7 +583,7 @@ int cpu_exec(CPUArchState *env) if (next_tb != 0 && tb->page_addr[1] == -1) { tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); } - spin_unlock(&tb_lock); + spin_unlock(&tcg_ctx.tb_ctx.tb_lock); /* cpu_interrupt might be called while translating the TB, but before it is linked into a potentially diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index d235ef8b2e..f685c28573 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -168,6 +168,25 @@ struct TranslationBlock { uint32_t icount; }; +#include "exec/spinlock.h" + +typedef struct TBContext TBContext; + +struct TBContext { + + TranslationBlock *tbs; + TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; + int nb_tbs; + /* any access to the tbs or the page table must use this lock */ + spinlock_t tb_lock; + + /* statistics */ + int tb_flush_count; + int tb_phys_invalidate_count; + + int tb_invalidated_flag; +}; + static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) { target_ulong tmp; @@ -192,8 +211,6 @@ void tb_free(TranslationBlock *tb); void tb_flush(CPUArchState *env); void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); -extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; - #if defined(USE_DIRECT_JUMP) #if defined(CONFIG_TCG_INTERPRETER) @@ -275,12 +292,6 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, } } -#include "exec/spinlock.h" - -extern spinlock_t tb_lock; - -extern int tb_invalidated_flag; - /* The return address may point to the start of the next instruction. Subtracting one gets us the call instruction itself. */ #if defined(CONFIG_TCG_INTERPRETER) diff --git a/linux-user/main.c b/linux-user/main.c index 3df8aa2cc5..7902f3beb2 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -111,7 +111,7 @@ static int pending_cpus; /* Make sure everything is in a consistent state for calling fork(). */ void fork_start(void) { - pthread_mutex_lock(&tb_lock); + pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock); pthread_mutex_lock(&exclusive_lock); mmap_fork_start(); } @@ -129,11 +129,11 @@ void fork_end(int child) pthread_mutex_init(&cpu_list_mutex, NULL); pthread_cond_init(&exclusive_cond, NULL); pthread_cond_init(&exclusive_resume, NULL); - pthread_mutex_init(&tb_lock, NULL); + pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL); gdbserver_fork(thread_env); } else { pthread_mutex_unlock(&exclusive_lock); - pthread_mutex_unlock(&tb_lock); + pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock); } } diff --git a/tcg/tcg.h b/tcg/tcg.h index 4086e985e3..51c8176550 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -471,6 +471,8 @@ struct TCGContext { size_t code_gen_buffer_max_size; uint8_t *code_gen_ptr; + TBContext tb_ctx; + #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) /* labels info for qemu_ld/st IRs The labels help to generate TLB miss case codes at the end of TB */ diff --git a/translate-all.c b/translate-all.c index d666562a44..efeb247add 100644 --- a/translate-all.c +++ b/translate-all.c @@ -72,13 +72,6 @@ #define SMC_BITMAP_USE_THRESHOLD 10 -/* Translation blocks */ -static TranslationBlock *tbs; -TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; -static int nb_tbs; -/* any access to the tbs or the page table must use this lock */ -spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; - typedef struct PageDesc { /* list of TBs intersecting this ram page */ TranslationBlock *first_tb; @@ -125,10 +118,6 @@ uintptr_t qemu_host_page_mask; The bottom level has pointers to PageDesc. */ static void *l1_map[V_L1_SIZE]; -/* statistics */ -static int tb_flush_count; -static int tb_phys_invalidate_count; - /* code generation context */ TCGContext tcg_ctx; @@ -589,7 +578,8 @@ static inline void code_gen_alloc(size_t tb_size) (TCG_MAX_OP_SIZE * OPC_BUF_SIZE); tcg_ctx.code_gen_max_blocks = tcg_ctx.code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; - tbs = g_malloc(tcg_ctx.code_gen_max_blocks * sizeof(TranslationBlock)); + tcg_ctx.tb_ctx.tbs = + g_malloc(tcg_ctx.code_gen_max_blocks * sizeof(TranslationBlock)); } /* Must be called before using the QEMU cpus. 'tb_size' is the size @@ -620,12 +610,12 @@ static TranslationBlock *tb_alloc(target_ulong pc) { TranslationBlock *tb; - if (nb_tbs >= tcg_ctx.code_gen_max_blocks || + if (tcg_ctx.tb_ctx.nb_tbs >= tcg_ctx.code_gen_max_blocks || (tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) >= tcg_ctx.code_gen_buffer_max_size) { return NULL; } - tb = &tbs[nb_tbs++]; + tb = &tcg_ctx.tb_ctx.tbs[tcg_ctx.tb_ctx.nb_tbs++]; tb->pc = pc; tb->cflags = 0; return tb; @@ -636,9 +626,10 @@ void tb_free(TranslationBlock *tb) /* In practice this is mostly used for single use temporary TB Ignore the hard cases and just back up if this TB happens to be the last one generated. */ - if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { + if (tcg_ctx.tb_ctx.nb_tbs > 0 && + tb == &tcg_ctx.tb_ctx.tbs[tcg_ctx.tb_ctx.nb_tbs - 1]) { tcg_ctx.code_gen_ptr = tb->tc_ptr; - nb_tbs--; + tcg_ctx.tb_ctx.nb_tbs--; } } @@ -693,27 +684,28 @@ void tb_flush(CPUArchState *env1) #if defined(DEBUG_FLUSH) printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n", (unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer), - nb_tbs, nb_tbs > 0 ? + tcg_ctx.tb_ctx.nb_tbs, tcg_ctx.tb_ctx.nb_tbs > 0 ? ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer)) / - nb_tbs : 0); + tcg_ctx.tb_ctx.nb_tbs : 0); #endif if ((unsigned long)(tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) > tcg_ctx.code_gen_buffer_size) { cpu_abort(env1, "Internal error: code buffer overflow\n"); } - nb_tbs = 0; + tcg_ctx.tb_ctx.nb_tbs = 0; for (env = first_cpu; env != NULL; env = env->next_cpu) { memset(env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *)); } - memset(tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof(void *)); + memset(tcg_ctx.tb_ctx.tb_phys_hash, 0, + CODE_GEN_PHYS_HASH_SIZE * sizeof(void *)); page_flush_tb(); tcg_ctx.code_gen_ptr = tcg_ctx.code_gen_buffer; /* XXX: flush processor icache at this point if cache flush is expensive */ - tb_flush_count++; + tcg_ctx.tb_ctx.tb_flush_count++; } #ifdef DEBUG_TB_CHECK @@ -725,7 +717,7 @@ static void tb_invalidate_check(target_ulong address) address &= TARGET_PAGE_MASK; for (i = 0; i < CODE_GEN_PHYS_HASH_SIZE; i++) { - for (tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { + for (tb = tb_ctx.tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { if (!(address + TARGET_PAGE_SIZE <= tb->pc || address >= tb->pc + tb->size)) { printf("ERROR invalidate: address=" TARGET_FMT_lx @@ -743,7 +735,8 @@ static void tb_page_check(void) int i, flags1, flags2; for (i = 0; i < CODE_GEN_PHYS_HASH_SIZE; i++) { - for (tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) { + for (tb = tcg_ctx.tb_ctx.tb_phys_hash[i]; tb != NULL; + tb = tb->phys_hash_next) { flags1 = page_get_flags(tb->pc); flags2 = page_get_flags(tb->pc + tb->size - 1); if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { @@ -835,7 +828,7 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) /* remove the TB from the hash list */ phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); h = tb_phys_hash_func(phys_pc); - tb_hash_remove(&tb_phys_hash[h], tb); + tb_hash_remove(&tcg_ctx.tb_ctx.tb_phys_hash[h], tb); /* remove the TB from the page list */ if (tb->page_addr[0] != page_addr) { @@ -849,7 +842,7 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) invalidate_page_bitmap(p); } - tb_invalidated_flag = 1; + tcg_ctx.tb_ctx.tb_invalidated_flag = 1; /* remove the TB from the hash list */ h = tb_jmp_cache_hash_func(tb->pc); @@ -878,7 +871,7 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr) } tb->jmp_first = (TranslationBlock *)((uintptr_t)tb | 2); /* fail safe */ - tb_phys_invalidate_count++; + tcg_ctx.tb_ctx.tb_phys_invalidate_count++; } static inline void set_bits(uint8_t *tab, int start, int len) @@ -955,7 +948,7 @@ TranslationBlock *tb_gen_code(CPUArchState *env, /* cannot fail at this point */ tb = tb_alloc(pc); /* Don't forget to invalidate previous TB info. */ - tb_invalidated_flag = 1; + tcg_ctx.tb_ctx.tb_invalidated_flag = 1; } tc_ptr = tcg_ctx.code_gen_ptr; tb->tc_ptr = tc_ptr; @@ -1273,7 +1266,7 @@ static void tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc, mmap_lock(); /* add in the physical hash table */ h = tb_phys_hash_func(phys_pc); - ptb = &tb_phys_hash[h]; + ptb = &tcg_ctx.tb_ctx.tb_phys_hash[h]; tb->phys_hash_next = *ptb; *ptb = tb; @@ -1323,7 +1316,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) uintptr_t v; TranslationBlock *tb; - if (nb_tbs <= 0) { + if (tcg_ctx.tb_ctx.nb_tbs <= 0) { return NULL; } if (tc_ptr < (uintptr_t)tcg_ctx.code_gen_buffer || @@ -1332,10 +1325,10 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) } /* binary search (cf Knuth) */ m_min = 0; - m_max = nb_tbs - 1; + m_max = tcg_ctx.tb_ctx.nb_tbs - 1; while (m_min <= m_max) { m = (m_min + m_max) >> 1; - tb = &tbs[m]; + tb = &tcg_ctx.tb_ctx.tbs[m]; v = (uintptr_t)tb->tc_ptr; if (v == tc_ptr) { return tb; @@ -1345,7 +1338,7 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) m_min = m + 1; } } - return &tbs[m_max]; + return &tcg_ctx.tb_ctx.tbs[m_max]; } static void tb_reset_jump_recursive(TranslationBlock *tb); @@ -1566,8 +1559,8 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) cross_page = 0; direct_jmp_count = 0; direct_jmp2_count = 0; - for (i = 0; i < nb_tbs; i++) { - tb = &tbs[i]; + for (i = 0; i < tcg_ctx.tb_ctx.nb_tbs; i++) { + tb = &tcg_ctx.tb_ctx.tbs[i]; target_code_size += tb->size; if (tb->size > max_target_code_size) { max_target_code_size = tb->size; @@ -1588,27 +1581,32 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer, tcg_ctx.code_gen_buffer_max_size); cpu_fprintf(f, "TB count %d/%d\n", - nb_tbs, tcg_ctx.code_gen_max_blocks); + tcg_ctx.tb_ctx.nb_tbs, tcg_ctx.code_gen_max_blocks); cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", - nb_tbs ? target_code_size / nb_tbs : 0, - max_target_code_size); + tcg_ctx.tb_ctx.nb_tbs ? target_code_size / + tcg_ctx.tb_ctx.nb_tbs : 0, + max_target_code_size); cpu_fprintf(f, "TB avg host size %td bytes (expansion ratio: %0.1f)\n", - nb_tbs ? (tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) / - nb_tbs : 0, - target_code_size ? - (double) (tcg_ctx.code_gen_ptr - tcg_ctx.code_gen_buffer) / - target_code_size : 0); - cpu_fprintf(f, "cross page TB count %d (%d%%)\n", - cross_page, - nb_tbs ? (cross_page * 100) / nb_tbs : 0); + tcg_ctx.tb_ctx.nb_tbs ? (tcg_ctx.code_gen_ptr - + tcg_ctx.code_gen_buffer) / + tcg_ctx.tb_ctx.nb_tbs : 0, + target_code_size ? (double) (tcg_ctx.code_gen_ptr - + tcg_ctx.code_gen_buffer) / + target_code_size : 0); + cpu_fprintf(f, "cross page TB count %d (%d%%)\n", cross_page, + tcg_ctx.tb_ctx.nb_tbs ? (cross_page * 100) / + tcg_ctx.tb_ctx.nb_tbs : 0); cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n", direct_jmp_count, - nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, + tcg_ctx.tb_ctx.nb_tbs ? (direct_jmp_count * 100) / + tcg_ctx.tb_ctx.nb_tbs : 0, direct_jmp2_count, - nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); + tcg_ctx.tb_ctx.nb_tbs ? (direct_jmp2_count * 100) / + tcg_ctx.tb_ctx.nb_tbs : 0); cpu_fprintf(f, "\nStatistics:\n"); - cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); - cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); + cpu_fprintf(f, "TB flush count %d\n", tcg_ctx.tb_ctx.tb_flush_count); + cpu_fprintf(f, "TB invalidate count %d\n", + tcg_ctx.tb_ctx.tb_phys_invalidate_count); cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); tcg_dump_info(f, cpu_fprintf); } From 9a7e54242910d26d280589e1f5c7ec8814d02a6b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Feb 2013 16:41:20 +0000 Subject: [PATCH 1001/1634] qemu-log: Unify {cpu_set,set_cpu}_log_filename as qemu_set_log_filename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The qemu_log() functionality is no longer specific to TCG CPU debug logs. Rename cpu_set_log_filename() to qemu_set_log_filename() and drop the pointless wrapper set_cpu_log_filename(). Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Blue Swirl --- bsd-user/main.c | 2 +- cpus.c | 5 ----- include/qemu/log.h | 2 +- include/sysemu/cpus.h | 1 - linux-user/main.c | 4 ++-- monitor.c | 2 +- qemu-log.c | 2 +- vl.c | 2 +- 8 files changed, 7 insertions(+), 13 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index ae24723710..76ab35909c 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -861,7 +861,7 @@ int main(int argc, char **argv) } /* init debug */ - cpu_set_log_filename(log_file); + qemu_set_log_filename(log_file); if (log_mask) { int mask; const CPULogItem *item; diff --git a/cpus.c b/cpus.c index 41779eb02e..2155441b35 100644 --- a/cpus.c +++ b/cpus.c @@ -1191,11 +1191,6 @@ void set_cpu_log(const char *optarg) cpu_set_log(mask); } -void set_cpu_log_filename(const char *optarg) -{ - cpu_set_log_filename(optarg); -} - void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg) { /* XXX: implement xxx_cpu_list for targets that still miss it */ diff --git a/include/qemu/log.h b/include/qemu/log.h index 58f69cb494..4760e04c5e 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -154,7 +154,7 @@ static inline void cpu_set_log(int log_flags) #endif } -void cpu_set_log_filename(const char *filename); +void qemu_set_log_filename(const char *filename); int cpu_str_to_log_mask(const char *str); #endif diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index f7f6854259..60e44bb70c 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -25,7 +25,6 @@ extern int smp_threads; void set_numa_modes(void); void set_cpu_log(const char *optarg); -void set_cpu_log_filename(const char *optarg); void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg); #endif diff --git a/linux-user/main.c b/linux-user/main.c index 7902f3beb2..4beb5c9ae5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3113,7 +3113,7 @@ static void handle_arg_log(const char *arg) static void handle_arg_log_filename(const char *arg) { - cpu_set_log_filename(arg); + qemu_set_log_filename(arg); } static void handle_arg_set_env(const char *arg) @@ -3480,7 +3480,7 @@ int main(int argc, char **argv, char **envp) #endif /* init debug */ - cpu_set_log_filename(log_file); + qemu_set_log_filename(log_file); optind = parse_args(argc, argv); /* Zero out regs */ diff --git a/monitor.c b/monitor.c index 20bd19b05f..578a31803f 100644 --- a/monitor.c +++ b/monitor.c @@ -964,7 +964,7 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, static void do_logfile(Monitor *mon, const QDict *qdict) { - cpu_set_log_filename(qdict_get_str(qdict, "filename")); + qemu_set_log_filename(qdict_get_str(qdict, "filename")); } static void do_log(Monitor *mon, const QDict *qdict) diff --git a/qemu-log.c b/qemu-log.c index 30c9ab01bd..9a7e5675a1 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -86,7 +86,7 @@ void qemu_set_log(int log_flags, bool use_own_buffers) } } -void cpu_set_log_filename(const char *filename) +void qemu_set_log_filename(const char *filename) { g_free(logfilename); logfilename = g_strdup(filename); diff --git a/vl.c b/vl.c index 1355f6959e..f9f4dda2d7 100644 --- a/vl.c +++ b/vl.c @@ -3865,7 +3865,7 @@ int main(int argc, char **argv, char **envp) */ if (log_mask) { if (log_file) { - set_cpu_log_filename(log_file); + qemu_set_log_filename(log_file); } set_cpu_log(log_mask); } From 59a6fa6e67d2335d867c66c59d992847e5b62879 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Feb 2013 16:41:21 +0000 Subject: [PATCH 1002/1634] qemu-log: Abstract out "print usage message about valid log categories" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Abstract out the "print a human readable list of all the valid log categories" functionality which is currently duplicated in three separate places. (We leave the monitor.c help_cmd() implementation as-is since it wants to send the message to the monitor and add its own information.) Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Blue Swirl --- bsd-user/main.c | 6 +----- cpus.c | 6 +----- include/qemu/log.h | 5 +++++ linux-user/main.c | 6 +----- qemu-log.c | 9 +++++++++ 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 76ab35909c..26604b43cb 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -864,14 +864,10 @@ int main(int argc, char **argv) qemu_set_log_filename(log_file); if (log_mask) { int mask; - const CPULogItem *item; mask = cpu_str_to_log_mask(log_mask); if (!mask) { - printf("Log items (comma separated):\n"); - for (item = cpu_log_items; item->mask != 0; item++) { - printf("%-10s %s\n", item->name, item->help); - } + qemu_print_log_usage(stdout); exit(1); } cpu_set_log(mask); diff --git a/cpus.c b/cpus.c index 2155441b35..0fdc48ca88 100644 --- a/cpus.c +++ b/cpus.c @@ -1178,14 +1178,10 @@ void set_numa_modes(void) void set_cpu_log(const char *optarg) { int mask; - const CPULogItem *item; mask = cpu_str_to_log_mask(optarg); if (!mask) { - printf("Log items (comma separated):\n"); - for (item = cpu_log_items; item->mask != 0; item++) { - printf("%-10s %s\n", item->name, item->help); - } + qemu_print_log_usage(stdout); exit(1); } cpu_set_log(mask); diff --git a/include/qemu/log.h b/include/qemu/log.h index 4760e04c5e..59511a3748 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -157,4 +157,9 @@ static inline void cpu_set_log(int log_flags) void qemu_set_log_filename(const char *filename); int cpu_str_to_log_mask(const char *str); +/* Print a usage message listing all the valid logging categories + * to the specified FILE*. + */ +void qemu_print_log_usage(FILE *f); + #endif diff --git a/linux-user/main.c b/linux-user/main.c index 4beb5c9ae5..00b0125414 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3098,14 +3098,10 @@ static void handle_arg_help(const char *arg) static void handle_arg_log(const char *arg) { int mask; - const CPULogItem *item; mask = cpu_str_to_log_mask(arg); if (!mask) { - printf("Log items (comma separated):\n"); - for (item = cpu_log_items; item->mask != 0; item++) { - printf("%-10s %s\n", item->name, item->help); - } + qemu_print_log_usage(stdout); exit(1); } cpu_set_log(mask); diff --git a/qemu-log.c b/qemu-log.c index 9a7e5675a1..786d335893 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -170,3 +170,12 @@ int cpu_str_to_log_mask(const char *str) } return mask; } + +void qemu_print_log_usage(FILE *f) +{ + const CPULogItem *item; + fprintf(f, "Log items (comma separated):\n"); + for (item = cpu_log_items; item->mask != 0; item++) { + fprintf(f, "%-10s %s\n", item->name, item->help); + } +} From 4fde1eba0f98779d4fdb64818071f72bb1672438 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Feb 2013 16:41:22 +0000 Subject: [PATCH 1003/1634] qemu-log: Rename cpu_str_to_log_mask to qemu_str_to_log_mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename cpu_str_to_log_mask() to qemu_str_to_log_mask(), since the qemu_log functionality is no longer restricted to TCG CPU debug logging. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Blue Swirl --- bsd-user/main.c | 2 +- cpus.c | 2 +- include/qemu/log.h | 2 +- linux-user/main.c | 2 +- monitor.c | 2 +- qemu-log.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 26604b43cb..4b12e655b1 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -865,7 +865,7 @@ int main(int argc, char **argv) if (log_mask) { int mask; - mask = cpu_str_to_log_mask(log_mask); + mask = qemu_str_to_log_mask(log_mask); if (!mask) { qemu_print_log_usage(stdout); exit(1); diff --git a/cpus.c b/cpus.c index 0fdc48ca88..63cfb73613 100644 --- a/cpus.c +++ b/cpus.c @@ -1179,7 +1179,7 @@ void set_cpu_log(const char *optarg) { int mask; - mask = cpu_str_to_log_mask(optarg); + mask = qemu_str_to_log_mask(optarg); if (!mask) { qemu_print_log_usage(stdout); exit(1); diff --git a/include/qemu/log.h b/include/qemu/log.h index 59511a3748..10792ce0d1 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -155,7 +155,7 @@ static inline void cpu_set_log(int log_flags) } void qemu_set_log_filename(const char *filename); -int cpu_str_to_log_mask(const char *str); +int qemu_str_to_log_mask(const char *str); /* Print a usage message listing all the valid logging categories * to the specified FILE*. diff --git a/linux-user/main.c b/linux-user/main.c index 00b0125414..862619b438 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3099,7 +3099,7 @@ static void handle_arg_log(const char *arg) { int mask; - mask = cpu_str_to_log_mask(arg); + mask = qemu_str_to_log_mask(arg); if (!mask) { qemu_print_log_usage(stdout); exit(1); diff --git a/monitor.c b/monitor.c index 578a31803f..2a55d56686 100644 --- a/monitor.c +++ b/monitor.c @@ -975,7 +975,7 @@ static void do_log(Monitor *mon, const QDict *qdict) if (!strcmp(items, "none")) { mask = 0; } else { - mask = cpu_str_to_log_mask(items); + mask = qemu_str_to_log_mask(items); if (!mask) { help_cmd(mon, "log"); return; diff --git a/qemu-log.c b/qemu-log.c index 786d335893..10a8581f1f 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -136,7 +136,7 @@ static int cmp1(const char *s1, int n, const char *s2) } /* takes a comma separated list of log masks. Return 0 if error. */ -int cpu_str_to_log_mask(const char *str) +int qemu_str_to_log_mask(const char *str) { const CPULogItem *item; int mask; From 24537a01910f110fe3e343c13df13e48f7968a9e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Feb 2013 16:41:23 +0000 Subject: [PATCH 1004/1634] qemu-log: Rename the public-facing cpu_set_log function to qemu_set_log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the public-facing function cpu_set_log to qemu_set_log. This requires us to rename the internal-only qemu_set_log() to do_qemu_set_log(). Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Blue Swirl --- bsd-user/main.c | 2 +- cpus.c | 2 +- hw/ppc.c | 2 +- include/qemu/log.h | 12 ++++++++---- linux-user/main.c | 2 +- monitor.c | 2 +- qemu-log.c | 4 ++-- target-i386/translate.c | 2 +- tcg/tci/tcg-target.c | 2 +- 9 files changed, 17 insertions(+), 13 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 4b12e655b1..097fbfe432 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -870,7 +870,7 @@ int main(int argc, char **argv) qemu_print_log_usage(stdout); exit(1); } - cpu_set_log(mask); + qemu_set_log(mask); } if (optind >= argc) { diff --git a/cpus.c b/cpus.c index 63cfb73613..24e6affbf7 100644 --- a/cpus.c +++ b/cpus.c @@ -1184,7 +1184,7 @@ void set_cpu_log(const char *optarg) qemu_print_log_usage(stdout); exit(1); } - cpu_set_log(mask); + qemu_set_log(mask); } void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg) diff --git a/hw/ppc.c b/hw/ppc.c index c52e22f708..6053bd5652 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -1189,7 +1189,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) break; case 2: printf("Set loglevel to %04" PRIx32 "\n", val); - cpu_set_log(val | 0x100); + qemu_set_log(val | 0x100); break; } } diff --git a/include/qemu/log.h b/include/qemu/log.h index 10792ce0d1..5dcbe11d47 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -143,14 +143,18 @@ typedef struct CPULogItem { extern const CPULogItem cpu_log_items[]; -void qemu_set_log(int log_flags, bool use_own_buffers); +/* This is the function that actually does the work of + * changing the log level; it should only be accessed via + * the qemu_set_log() wrapper. + */ +void do_qemu_set_log(int log_flags, bool use_own_buffers); -static inline void cpu_set_log(int log_flags) +static inline void qemu_set_log(int log_flags) { #ifdef CONFIG_USER_ONLY - qemu_set_log(log_flags, true); + do_qemu_set_log(log_flags, true); #else - qemu_set_log(log_flags, false); + do_qemu_set_log(log_flags, false); #endif } diff --git a/linux-user/main.c b/linux-user/main.c index 862619b438..146a4683a5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3104,7 +3104,7 @@ static void handle_arg_log(const char *arg) qemu_print_log_usage(stdout); exit(1); } - cpu_set_log(mask); + qemu_set_log(mask); } static void handle_arg_log_filename(const char *arg) diff --git a/monitor.c b/monitor.c index 2a55d56686..6aac4c20bd 100644 --- a/monitor.c +++ b/monitor.c @@ -981,7 +981,7 @@ static void do_log(Monitor *mon, const QDict *qdict) return; } } - cpu_set_log(mask); + qemu_set_log(mask); } static void do_singlestep(Monitor *mon, const QDict *qdict) diff --git a/qemu-log.c b/qemu-log.c index 10a8581f1f..a96db882b3 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -54,7 +54,7 @@ void qemu_log_mask(int mask, const char *fmt, ...) } /* enable or disable low levels log */ -void qemu_set_log(int log_flags, bool use_own_buffers) +void do_qemu_set_log(int log_flags, bool use_own_buffers) { const char *fname = logfilename ?: DEFAULT_LOGFILENAME; @@ -94,7 +94,7 @@ void qemu_set_log_filename(const char *filename) fclose(qemu_logfile); qemu_logfile = NULL; } - cpu_set_log(qemu_loglevel); + qemu_set_log(qemu_loglevel); } const CPULogItem cpu_log_items[] = { diff --git a/target-i386/translate.c b/target-i386/translate.c index 32d21f52d0..112c3102a0 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6854,7 +6854,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, #else /* start debug */ tb_flush(env); - cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM); + qemu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM); #endif break; #endif diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index 1707169ea8..2d561b32e1 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -888,7 +888,7 @@ static void tcg_target_init(TCGContext *s) #if defined(CONFIG_DEBUG_TCG_INTERPRETER) const char *envval = getenv("DEBUG_TCG"); if (envval) { - cpu_set_log(strtol(envval, NULL, 0)); + qemu_set_log(strtol(envval, NULL, 0)); } #endif From b946bffab5e0d359accfcc78faead20fd69f26e8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Feb 2013 16:41:24 +0000 Subject: [PATCH 1005/1634] cpus.c: Drop unnecessary set_cpu_log() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The set_cpu_log() function in cpus.c is a fairly simple wrapper which is only called from one location. Just inline the code into vl.c, since there is no need to indirect it via cpus.c and the handling of the error case is more appropriate to vl.c. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Blue Swirl --- cpus.c | 12 ------------ include/sysemu/cpus.h | 1 - vl.c | 9 ++++++++- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/cpus.c b/cpus.c index 24e6affbf7..c4b021dd2e 100644 --- a/cpus.c +++ b/cpus.c @@ -1175,18 +1175,6 @@ void set_numa_modes(void) } } -void set_cpu_log(const char *optarg) -{ - int mask; - - mask = qemu_str_to_log_mask(optarg); - if (!mask) { - qemu_print_log_usage(stdout); - exit(1); - } - qemu_set_log(mask); -} - void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg) { /* XXX: implement xxx_cpu_list for targets that still miss it */ diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 60e44bb70c..6502488a05 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -24,7 +24,6 @@ extern int smp_threads; #endif void set_numa_modes(void); -void set_cpu_log(const char *optarg); void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg); #endif diff --git a/vl.c b/vl.c index f9f4dda2d7..c5b0eea29b 100644 --- a/vl.c +++ b/vl.c @@ -3864,10 +3864,17 @@ int main(int argc, char **argv, char **envp) * location or level of logging. */ if (log_mask) { + int mask; if (log_file) { qemu_set_log_filename(log_file); } - set_cpu_log(log_mask); + + mask = qemu_str_to_log_mask(log_mask); + if (!mask) { + qemu_print_log_usage(stdout); + exit(1); + } + qemu_set_log(mask); } if (!trace_backend_init(trace_events, trace_file)) { From 38dad9e574746981dfbac52b3bbbd6d894f31d26 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Feb 2013 16:41:25 +0000 Subject: [PATCH 1006/1634] qemu-log: Rename CPULogItem, cpu_log_items to QEMULogItem, qemu_log_items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the typedef CPULogItem and the public array cpu_log_items to names that better reflect the fact that the qemu_log functionality isn't restricted to TCG CPU debug logs any more. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Blue Swirl --- include/qemu/log.h | 6 +++--- monitor.c | 4 ++-- qemu-log.c | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/qemu/log.h b/include/qemu/log.h index 5dcbe11d47..5a46555112 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -135,13 +135,13 @@ static inline void qemu_log_try_set_file(FILE *f) } /* define log items */ -typedef struct CPULogItem { +typedef struct QEMULogItem { int mask; const char *name; const char *help; -} CPULogItem; +} QEMULogItem; -extern const CPULogItem cpu_log_items[]; +extern const QEMULogItem qemu_log_items[]; /* This is the function that actually does the work of * changing the log level; it should only be accessed via diff --git a/monitor.c b/monitor.c index 6aac4c20bd..6a0f2573f5 100644 --- a/monitor.c +++ b/monitor.c @@ -721,10 +721,10 @@ static void help_cmd(Monitor *mon, const char *name) } else { help_cmd_dump(mon, mon_cmds, "", name); if (name && !strcmp(name, "log")) { - const CPULogItem *item; + const QEMULogItem *item; monitor_printf(mon, "Log items (comma separated):\n"); monitor_printf(mon, "%-10s %s\n", "none", "remove all logs"); - for(item = cpu_log_items; item->mask != 0; item++) { + for (item = qemu_log_items; item->mask != 0; item++) { monitor_printf(mon, "%-10s %s\n", item->name, item->help); } } diff --git a/qemu-log.c b/qemu-log.c index a96db882b3..2f47aafd24 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -97,7 +97,7 @@ void qemu_set_log_filename(const char *filename) qemu_set_log(qemu_loglevel); } -const CPULogItem cpu_log_items[] = { +const QEMULogItem qemu_log_items[] = { { CPU_LOG_TB_OUT_ASM, "out_asm", "show generated host assembly code for each compiled TB" }, { CPU_LOG_TB_IN_ASM, "in_asm", @@ -138,7 +138,7 @@ static int cmp1(const char *s1, int n, const char *s2) /* takes a comma separated list of log masks. Return 0 if error. */ int qemu_str_to_log_mask(const char *str) { - const CPULogItem *item; + const QEMULogItem *item; int mask; const char *p, *p1; @@ -150,11 +150,11 @@ int qemu_str_to_log_mask(const char *str) p1 = p + strlen(p); } if (cmp1(p,p1-p,"all")) { - for (item = cpu_log_items; item->mask != 0; item++) { + for (item = qemu_log_items; item->mask != 0; item++) { mask |= item->mask; } } else { - for (item = cpu_log_items; item->mask != 0; item++) { + for (item = qemu_log_items; item->mask != 0; item++) { if (cmp1(p, p1 - p, item->name)) { goto found; } @@ -173,9 +173,9 @@ int qemu_str_to_log_mask(const char *str) void qemu_print_log_usage(FILE *f) { - const CPULogItem *item; + const QEMULogItem *item; fprintf(f, "Log items (comma separated):\n"); - for (item = cpu_log_items; item->mask != 0; item++) { + for (item = qemu_log_items; item->mask != 0; item++) { fprintf(f, "%-10s %s\n", item->name, item->help); } } From 0165437302448d210742cc3def362d1de0413621 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:34 -0800 Subject: [PATCH 1007/1634] host-utils: Add host long specific aliases for clz, ctz, ctpop We will standardize on these names, rather than the similar routines currently residing in qemu/bitops.h. Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- include/qemu/host-utils.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index 81c9a754ae..d72b72d88f 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -26,6 +26,7 @@ #define HOST_UTILS_H 1 #include "qemu/compiler.h" /* QEMU_GNUC_PREREQ */ +#include #if defined(__x86_64__) #define __HAVE_FAST_MULU64__ @@ -237,4 +238,22 @@ static inline int ctpop64(uint64_t val) #endif } +/* Host type specific sizes of these routines. */ + +#if ULONG_MAX == UINT32_MAX +# define clzl clz32 +# define ctzl ctz32 +# define clol clo32 +# define ctol cto32 +# define ctpopl ctpop32 +#elif ULONG_MAX == UINT64_MAX +# define clzl clz64 +# define ctzl ctz64 +# define clol clo64 +# define ctol cto64 +# define ctpopl ctpop64 +#else +# error Unknown sizeof long +#endif + #endif From 72d81155d0b88ba757c5a972d3fff83027e7a6e7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:35 -0800 Subject: [PATCH 1008/1634] host-utils: Fix coding style and add comments Add function comments to the routines, documenting the corner cases upon which we are standardizing. Fix the few instances of non-standard coding style. Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- include/qemu/host-utils.h | 100 +++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 18 deletions(-) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index d72b72d88f..f0dd850e1f 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -50,16 +50,19 @@ void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b); void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b); #endif -/* Binary search for leading zeros. */ - +/** + * clz32 - count leading zeros in a 32-bit value. + * @val: The value to search + * + * Returns 32 if the value is zero. Note that the GCC builtin is + * undefined if the value is zero. + */ static inline int clz32(uint32_t val) { #if QEMU_GNUC_PREREQ(3, 4) - if (val) - return __builtin_clz(val); - else - return 32; + return val ? __builtin_clz(val) : 32; #else + /* Binary search for the leading one bit. */ int cnt = 0; if (!(val & 0xFFFF0000U)) { @@ -89,18 +92,28 @@ static inline int clz32(uint32_t val) #endif } +/** + * clo32 - count leading ones in a 32-bit value. + * @val: The value to search + * + * Returns 32 if the value is -1. + */ static inline int clo32(uint32_t val) { return clz32(~val); } +/** + * clz64 - count leading zeros in a 64-bit value. + * @val: The value to search + * + * Returns 64 if the value is zero. Note that the GCC builtin is + * undefined if the value is zero. + */ static inline int clz64(uint64_t val) { #if QEMU_GNUC_PREREQ(3, 4) - if (val) - return __builtin_clzll(val); - else - return 64; + return val ? __builtin_clzll(val) : 64; #else int cnt = 0; @@ -114,19 +127,30 @@ static inline int clz64(uint64_t val) #endif } +/** + * clo64 - count leading ones in a 64-bit value. + * @val: The value to search + * + * Returns 64 if the value is -1. + */ static inline int clo64(uint64_t val) { return clz64(~val); } +/** + * ctz32 - count trailing zeros in a 32-bit value. + * @val: The value to search + * + * Returns 32 if the value is zero. Note that the GCC builtin is + * undefined if the value is zero. + */ static inline int ctz32(uint32_t val) { #if QEMU_GNUC_PREREQ(3, 4) - if (val) - return __builtin_ctz(val); - else - return 32; + return val ? __builtin_ctz(val) : 32; #else + /* Binary search for the trailing one bit. */ int cnt; cnt = 0; @@ -158,18 +182,28 @@ static inline int ctz32(uint32_t val) #endif } +/** + * cto32 - count trailing ones in a 32-bit value. + * @val: The value to search + * + * Returns 32 if the value is -1. + */ static inline int cto32(uint32_t val) { return ctz32(~val); } +/** + * ctz64 - count trailing zeros in a 64-bit value. + * @val: The value to search + * + * Returns 64 if the value is zero. Note that the GCC builtin is + * undefined if the value is zero. + */ static inline int ctz64(uint64_t val) { #if QEMU_GNUC_PREREQ(3, 4) - if (val) - return __builtin_ctzll(val); - else - return 64; + return val ? __builtin_ctzll(val) : 64; #else int cnt; @@ -183,30 +217,56 @@ static inline int ctz64(uint64_t val) #endif } +/** + * ctz64 - count trailing ones in a 64-bit value. + * @val: The value to search + * + * Returns 64 if the value is -1. + */ static inline int cto64(uint64_t val) { return ctz64(~val); } +/** + * ctpop8 - count the population of one bits in an 8-bit value. + * @val: The value to search + */ static inline int ctpop8(uint8_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcount(val); +#else val = (val & 0x55) + ((val >> 1) & 0x55); val = (val & 0x33) + ((val >> 2) & 0x33); val = (val & 0x0f) + ((val >> 4) & 0x0f); return val; +#endif } +/** + * ctpop16 - count the population of one bits in a 16-bit value. + * @val: The value to search + */ static inline int ctpop16(uint16_t val) { +#if QEMU_GNUC_PREREQ(3, 4) + return __builtin_popcount(val); +#else val = (val & 0x5555) + ((val >> 1) & 0x5555); val = (val & 0x3333) + ((val >> 2) & 0x3333); val = (val & 0x0f0f) + ((val >> 4) & 0x0f0f); val = (val & 0x00ff) + ((val >> 8) & 0x00ff); return val; +#endif } +/** + * ctpop32 - count the population of one bits in a 32-bit value. + * @val: The value to search + */ static inline int ctpop32(uint32_t val) { #if QEMU_GNUC_PREREQ(3, 4) @@ -222,6 +282,10 @@ static inline int ctpop32(uint32_t val) #endif } +/** + * ctpop64 - count the population of one bits in a 64-bit value. + * @val: The value to search + */ static inline int ctpop64(uint64_t val) { #if QEMU_GNUC_PREREQ(3, 4) From 18331e7c189507513008a2936f5fe79c3d8b8a08 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:36 -0800 Subject: [PATCH 1009/1634] hbitmap: Use non-bitops ctzl Both uses of ctz have already eliminated zero, and thus the difference in edge conditions between the two routines is irrelevant. Signed-off-by: Richard Henderson Acked-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- include/qemu/hbitmap.h | 3 ++- util/hbitmap.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 250de03b03..550d7ce2c3 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -16,6 +16,7 @@ #include #include #include "bitops.h" +#include "host-utils.h" typedef struct HBitmap HBitmap; typedef struct HBitmapIter HBitmapIter; @@ -170,7 +171,7 @@ static inline int64_t hbitmap_iter_next(HBitmapIter *hbi) /* The next call will resume work from the next bit. */ hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1); - item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + bitops_ctzl(cur); + item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur); return item << hbi->granularity; } diff --git a/util/hbitmap.c b/util/hbitmap.c index a0df5d3591..d93683128b 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -126,7 +126,8 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi) * The index of this word's least significant set bit provides * the low-order bits. */ - pos = (pos << BITS_PER_LEVEL) + bitops_ctzl(cur); + assert(cur); + pos = (pos << BITS_PER_LEVEL) + ctzl(cur); hbi->cur[i] = cur & (cur - 1); /* Set up next level for iteration. */ From 265ce4a5ca39fb7f74a803dd61bbd9108ca6cdee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:37 -0800 Subject: [PATCH 1010/1634] bitops: Use non-bitops ctzl The use of ctz has already eliminated zero, and thus the difference in edge conditions between the two routines is irrelevant. Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- util/bitops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/bitops.c b/util/bitops.c index 7b853cf944..9cd1c3a24c 100644 --- a/util/bitops.c +++ b/util/bitops.c @@ -60,7 +60,7 @@ found_first: return result + size; /* Nope. */ } found_middle: - return result + bitops_ctzl(tmp); + return result + ctzl(tmp); } /* From 5bbf90be97203c472f47da070c0040b464c0460f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:38 -0800 Subject: [PATCH 1011/1634] memory: Use non-bitops ctzl A memory size of zero is invalid, and so that edge condition does not occur. Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/memory.c b/memory.c index cd7d5e0cf5..92a2196b7e 100644 --- a/memory.c +++ b/memory.c @@ -855,7 +855,7 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr, } if (!mr->ops->read) { - return mr->ops->old_mmio.read[bitops_ctzl(size)](mr->opaque, addr); + return mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr); } /* FIXME: support unaligned access */ @@ -908,7 +908,7 @@ static void memory_region_dispatch_write(MemoryRegion *mr, adjust_endianness(mr, &data, size); if (!mr->ops->write) { - mr->ops->old_mmio.write[bitops_ctzl(size)](mr->opaque, addr, data); + mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, data); return; } From 0cfa6adc7fd1eba4694515bde6bbfb9ecd892f2f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:39 -0800 Subject: [PATCH 1012/1634] bitops: Write bitops_flsl in terms of clzl Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- include/qemu/bitops.h | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 8b88791862..b50629bb58 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -57,34 +57,7 @@ static unsigned long bitops_ctzl(unsigned long word) */ static inline unsigned long bitops_flsl(unsigned long word) { - int num = BITS_PER_LONG - 1; - -#if LONG_MAX > 0x7FFFFFFF - if (!(word & (~0ul << 32))) { - num -= 32; - word <<= 32; - } -#endif - if (!(word & (~0ul << (BITS_PER_LONG-16)))) { - num -= 16; - word <<= 16; - } - if (!(word & (~0ul << (BITS_PER_LONG-8)))) { - num -= 8; - word <<= 8; - } - if (!(word & (~0ul << (BITS_PER_LONG-4)))) { - num -= 4; - word <<= 4; - } - if (!(word & (~0ul << (BITS_PER_LONG-2)))) { - num -= 2; - - word <<= 2; - } - if (!(word & (~0ul << (BITS_PER_LONG-1)))) - num -= 1; - return num; + return BITS_PER_LONG - 1 - clzl(word); } /** From 14e534265aad0796690a5aea429f5bd2877ccff0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:40 -0800 Subject: [PATCH 1013/1634] target-i386: Inline bitops_flsl Use clz32 directly. Which makes slightly more sense given that the input is type "int" and not type "long". Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- target-i386/topology.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target-i386/topology.h b/target-i386/topology.h index 24ed525453..07a6c5fb55 100644 --- a/target-i386/topology.h +++ b/target-i386/topology.h @@ -52,10 +52,8 @@ typedef uint32_t apic_id_t; static unsigned apicid_bitwidth_for_count(unsigned count) { g_assert(count >= 1); - if (count == 1) { - return 0; - } - return bitops_flsl(count - 1) + 1; + count -= 1; + return count ? 32 - clz32(count) : 0; } /* Bit width of the SMT_ID (thread ID) field on the APIC ID From 4932398fac273b8ebe5688bc4b79407a7f41edbd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:41 -0800 Subject: [PATCH 1014/1634] bitops: Inline bitops_flsl This is the only remaining user. Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- util/bitops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/bitops.c b/util/bitops.c index 9cd1c3a24c..50b4a811a6 100644 --- a/util/bitops.c +++ b/util/bitops.c @@ -133,7 +133,7 @@ unsigned long find_last_bit(const unsigned long *addr, unsigned long size) tmp = addr[--words]; if (tmp) { found: - return words * BITS_PER_LONG + bitops_flsl(tmp); + return words * BITS_PER_LONG + BITS_PER_LONG - 1 - clzl(tmp); } } From 0f9d8bd386c9b7b17fc68fef36caa81750c39494 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:42 -0800 Subject: [PATCH 1015/1634] bitops: Replace bitops_ctol with ctzl The is the only remaining user. Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- util/bitops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/bitops.c b/util/bitops.c index 50b4a811a6..e72237ab2b 100644 --- a/util/bitops.c +++ b/util/bitops.c @@ -109,7 +109,7 @@ found_first: return result + size; /* Nope. */ } found_middle: - return result + bitops_ctol(tmp); + return result + ctzl(~tmp); } unsigned long find_last_bit(const unsigned long *addr, unsigned long size) From 453776e5746be23c66df65fadf12e115b7d2dadd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Feb 2013 17:47:43 -0800 Subject: [PATCH 1016/1634] bitops: Remove routines redundant with host-utils Signed-off-by: Richard Henderson Reviewed-by: Eric Blake Signed-off-by: Blue Swirl --- include/qemu/bitops.h | 48 ------------------------------------------- 1 file changed, 48 deletions(-) diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index b50629bb58..affcc969dc 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -23,54 +23,6 @@ #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) -/** - * bitops_ctzl - count trailing zeroes in word. - * @word: The word to search - * - * Returns -1 if no bit exists. Note that compared to the C library - * routine ffsl, this one returns one less. - */ -static unsigned long bitops_ctzl(unsigned long word) -{ -#if QEMU_GNUC_PREREQ(3, 4) - return __builtin_ffsl(word) - 1; -#else - if (!word) { - return -1; - } - - if (sizeof(long) == 4) { - return ctz32(word); - } else if (sizeof(long) == 8) { - return ctz64(word); - } else { - abort(); - } -#endif -} - -/** - * bitops_fls - find last (most-significant) set bit in a long word - * @word: the word to search - * - * Undefined if no set bit exists, so code should check against 0 first. - */ -static inline unsigned long bitops_flsl(unsigned long word) -{ - return BITS_PER_LONG - 1 - clzl(word); -} - -/** - * cto - count trailing ones in word. - * @word: The word to search - * - * Returns -1 if all bit are set. - */ -static inline unsigned long bitops_ctol(unsigned long word) -{ - return bitops_ctzl(~word); -} - /** * set_bit - Set a bit in memory * @nr: the bit to set From 4f65809994274989bdf51c8605bb974565cb1c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 19 Jan 2013 06:17:06 +0100 Subject: [PATCH 1017/1634] cpu: Prepare QOM realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Overwrite the default implementation with a no-op, no longer attempting to call DeviceClass::init. Signed-off-by: Andreas Färber --- qom/cpu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/qom/cpu.c b/qom/cpu.c index 8fb538bf3b..870e9baad9 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -46,6 +46,10 @@ static ObjectClass *cpu_common_class_by_name(const char *cpu_model) return NULL; } +static void cpu_common_realizefn(DeviceState *dev, Error **errp) +{ +} + static void cpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -53,6 +57,7 @@ static void cpu_class_init(ObjectClass *klass, void *data) k->class_by_name = cpu_common_class_by_name; k->reset = cpu_common_reset; + dc->realize = cpu_common_realizefn; dc->no_user = 1; } From bd1b282836a7885a13c13f9cc63123fa8e32f02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 14:01:30 +0100 Subject: [PATCH 1018/1634] target-alpha: Update AlphaCPU to QOM realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the alpha_cpu_realize() signature and hook up to DeviceClass::realize. Set realized = true in cpu_alpha_init(). qapi/error.h is included through qdev now and no longer needed. Acked-by: Richard Henderson [AF: Invoke parent's realizefn] Signed-off-by: Andreas Färber --- target-alpha/cpu-qom.h | 2 ++ target-alpha/cpu.c | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h index 16367d2ea4..c0f6c6d165 100644 --- a/target-alpha/cpu-qom.h +++ b/target-alpha/cpu-qom.h @@ -34,6 +34,7 @@ /** * AlphaCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * An Alpha CPU model. @@ -43,6 +44,7 @@ typedef struct AlphaCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } AlphaCPUClass; diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 0ad69f0859..0cdae6986f 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -21,14 +21,16 @@ #include "cpu.h" #include "qemu-common.h" -#include "qapi/error.h" -static void alpha_cpu_realize(Object *obj, Error **errp) +static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) { - AlphaCPU *cpu = ALPHA_CPU(obj); + AlphaCPU *cpu = ALPHA_CPU(dev); + AlphaCPUClass *acc = ALPHA_CPU_GET_CLASS(dev); qemu_init_vcpu(&cpu->env); + + acc->parent_realize(dev, errp); } /* Sort alphabetically by type name. */ @@ -134,7 +136,8 @@ AlphaCPU *cpu_alpha_init(const char *cpu_model) env->cpu_model_str = cpu_model; - alpha_cpu_realize(OBJECT(cpu), NULL); + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return cpu; } @@ -250,7 +253,12 @@ static void alpha_cpu_initfn(Object *obj) static void alpha_cpu_class_init(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); + AlphaCPUClass *acc = ALPHA_CPU_CLASS(oc); + + acc->parent_realize = dc->realize; + dc->realize = alpha_cpu_realizefn; cc->class_by_name = alpha_cpu_class_by_name; } From 149692667f8a46430127ca0555b38965f52177f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 10:18:18 +0100 Subject: [PATCH 1019/1634] target-arm: Update ARMCPU to QOM realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turn arm_cpu_realize() into a QOM realize function, no longer called via cpu.h prototype. To maintain the semantics of cpu_init(), set realized = true explicitly in cpu_arm_init(). Move GDB coprocessor registration, CPU reset and vCPU initialization into the realizefn. Signed-off-by: Andreas Färber --- target-arm/cpu-qom.h | 3 ++- target-arm/cpu.c | 21 ++++++++++++++------- target-arm/cpu.h | 1 + target-arm/helper.c | 14 ++++++++++---- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 0f455c40ff..aff7bf302e 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -33,6 +33,7 @@ /** * ARMCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * An ARM CPU model. @@ -42,6 +43,7 @@ typedef struct ARMCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } ARMCPUClass; @@ -107,7 +109,6 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) #define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e)) -void arm_cpu_realize(ARMCPU *cpu); void register_cp_regs_for_features(ARMCPU *cpu); #endif diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 1c6a628df4..9915172a1d 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -147,15 +147,12 @@ static void arm_cpu_finalizefn(Object *obj) g_hash_table_destroy(cpu->cp_regs); } -void arm_cpu_realize(ARMCPU *cpu) +static void arm_cpu_realizefn(DeviceState *dev, Error **errp) { - /* This function is called by cpu_arm_init() because it - * needs to do common actions based on feature bits, etc - * that have been set by the subclass init functions. - * When we have QOM realize support it should become - * a true realize function instead. - */ + ARMCPU *cpu = ARM_CPU(dev); + ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev); CPUARMState *env = &cpu->env; + /* Some features automatically imply others: */ if (arm_feature(env, ARM_FEATURE_V7)) { set_feature(env, ARM_FEATURE_VAPA); @@ -197,6 +194,12 @@ void arm_cpu_realize(ARMCPU *cpu) } register_cp_regs_for_features(cpu); + arm_cpu_register_gdb_regs_for_features(cpu); + + cpu_reset(CPU(cpu)); + qemu_init_vcpu(env); + + acc->parent_realize(dev, errp); } /* CPU models */ @@ -782,6 +785,10 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(acc); + DeviceClass *dc = DEVICE_CLASS(oc); + + acc->parent_realize = dc->realize; + dc->realize = arm_cpu_realizefn; acc->parent_reset = cc->reset; cc->reset = arm_cpu_reset; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index ffddfcbc0d..2902ba575b 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -234,6 +234,7 @@ typedef struct CPUARMState { ARMCPU *cpu_arm_init(const char *cpu_model); void arm_translate_init(void); +void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu); int cpu_arm_exec(CPUARMState *s); void do_interrupt(CPUARMState *); void switch_mode(CPUARMState *, int); diff --git a/target-arm/helper.c b/target-arm/helper.c index eb7b2910c3..4538a09445 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1272,14 +1272,22 @@ ARMCPU *cpu_arm_init(const char *cpu_model) cpu = ARM_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; env->cpu_model_str = cpu_model; - arm_cpu_realize(cpu); + + /* TODO this should be set centrally, once possible */ + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); if (tcg_enabled() && !inited) { inited = 1; arm_translate_init(); } - cpu_reset(CPU(cpu)); + return cpu; +} + +void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) +{ + CPUARMState *env = &cpu->env; + if (arm_feature(env, ARM_FEATURE_NEON)) { gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, 51, "arm-neon.xml", 0); @@ -1290,8 +1298,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model) gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg, 19, "arm-vfp.xml", 0); } - qemu_init_vcpu(env); - return cpu; } /* Sort alphabetically by type name, except for "any". */ From 2b6f294cacd9f4e133a7813d22e1b4e87ac6b2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 03:41:47 +0100 Subject: [PATCH 1020/1634] target-i386: Update X86CPU to QOM realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt the signature of x86_cpu_realize(), hook up to DeviceClass::realize and set realized = true in cpu_x86_init(). The QOM realizefn cannot depend on errp being non-NULL as in cpu_x86_init(), so use a local Error to preserve error handling behavior on APIC initialization errors. Reviewed-by: Igor Mammedov Reviewed-by: Eduardo Habkost [AF: Invoke parent's realizefn] Signed-off-by: Andreas Färber --- target-i386/cpu-qom.h | 5 ++--- target-i386/cpu.c | 19 +++++++++++++++---- target-i386/helper.c | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 332916a185..48e6b54b1f 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -39,6 +39,7 @@ /** * X86CPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * An x86 CPU model or family. @@ -48,6 +49,7 @@ typedef struct X86CPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } X86CPUClass; @@ -72,8 +74,5 @@ static inline X86CPU *x86_env_get_cpu(CPUX86State *env) #define ENV_GET_CPU(e) CPU(x86_env_get_cpu(e)) -/* TODO Drop once ObjectClass::realize is available */ -void x86_cpu_realize(Object *obj, Error **errp); - #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index aab35c74d9..e2fd6268ef 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2060,10 +2060,14 @@ static void x86_cpu_apic_init(X86CPU *cpu, Error **errp) } #endif -void x86_cpu_realize(Object *obj, Error **errp) +static void x86_cpu_realizefn(DeviceState *dev, Error **errp) { - X86CPU *cpu = X86_CPU(obj); + X86CPU *cpu = X86_CPU(dev); + X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); CPUX86State *env = &cpu->env; +#ifndef CONFIG_USER_ONLY + Error *local_err = NULL; +#endif if (env->cpuid_7_0_ebx_features && env->cpuid_level < 7) { env->cpuid_level = 7; @@ -2105,8 +2109,9 @@ void x86_cpu_realize(Object *obj, Error **errp) qemu_register_reset(x86_cpu_machine_reset_cb, cpu); if (cpu->env.cpuid_features & CPUID_APIC || smp_cpus > 1) { - x86_cpu_apic_init(cpu, errp); - if (error_is_set(errp)) { + x86_cpu_apic_init(cpu, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); return; } } @@ -2115,6 +2120,8 @@ void x86_cpu_realize(Object *obj, Error **errp) mce_init(cpu); qemu_init_vcpu(&cpu->env); cpu_reset(CPU(cpu)); + + xcc->parent_realize(dev, errp); } /* Enables contiguous-apic-ID mode, for compatibility */ @@ -2200,6 +2207,10 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + xcc->parent_realize = dc->realize; + dc->realize = x86_cpu_realizefn; xcc->parent_reset = cc->reset; cc->reset = x86_cpu_reset; diff --git a/target-i386/helper.c b/target-i386/helper.c index d1cb4e2445..1a872fa3d8 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1282,7 +1282,7 @@ X86CPU *cpu_x86_init(const char *cpu_model) return NULL; } - x86_cpu_realize(OBJECT(cpu), &error); + object_property_set_bool(OBJECT(cpu), true, "realized", &error); if (error) { error_free(error); object_unref(OBJECT(cpu)); From c296262bc94651a7a43639857d8343470f4129f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 14:11:07 +0100 Subject: [PATCH 1021/1634] target-openrisc: Update OpenRISCCPU to QOM realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the openrisc_cpu_realize() signature, hook it up to DeviceClass::realize and set realized = true in cpu_openrisc_init(). qapi/error.h is now included through qdev and no longer needed. Signed-off-by: Andreas Färber Cc: Jia Liu --- target-openrisc/cpu.c | 13 ++++++++++--- target-openrisc/cpu.h | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index a7a8de8a37..d8cc533efe 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -62,12 +62,15 @@ static inline void set_feature(OpenRISCCPU *cpu, int feature) cpu->env.cpucfgr = cpu->feature; } -void openrisc_cpu_realize(Object *obj, Error **errp) +static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) { - OpenRISCCPU *cpu = OPENRISC_CPU(obj); + OpenRISCCPU *cpu = OPENRISC_CPU(dev); + OpenRISCCPUClass *occ = OPENRISC_CPU_GET_CLASS(dev); qemu_init_vcpu(&cpu->env); cpu_reset(CPU(cpu)); + + occ->parent_realize(dev, errp); } static void openrisc_cpu_initfn(Object *obj) @@ -134,6 +137,10 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) { OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(occ); + DeviceClass *dc = DEVICE_CLASS(oc); + + occ->parent_realize = dc->realize; + dc->realize = openrisc_cpu_realizefn; occ->parent_reset = cc->reset; cc->reset = openrisc_cpu_reset; @@ -187,7 +194,7 @@ OpenRISCCPU *cpu_openrisc_init(const char *cpu_model) cpu = OPENRISC_CPU(object_new(object_class_get_name(oc))); cpu->env.cpu_model_str = cpu_model; - openrisc_cpu_realize(OBJECT(cpu), NULL); + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); return cpu; } diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index 3beab45c3c..419f007991 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -33,7 +33,6 @@ struct OpenRISCCPU; #include "exec/cpu-defs.h" #include "fpu/softfloat.h" #include "qom/cpu.h" -#include "qapi/error.h" #define TYPE_OPENRISC_CPU "or32-cpu" @@ -46,6 +45,7 @@ struct OpenRISCCPU; /** * OpenRISCCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A OpenRISC CPU model. @@ -55,6 +55,7 @@ typedef struct OpenRISCCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } OpenRISCCPUClass; @@ -340,7 +341,6 @@ static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env) #define ENV_GET_CPU(e) CPU(openrisc_env_get_cpu(e)) OpenRISCCPU *cpu_openrisc_init(const char *cpu_model); -void openrisc_cpu_realize(Object *obj, Error **errp); void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf); int cpu_openrisc_exec(CPUOpenRISCState *s); From 4776ce600338e17f75d200d1ad17d4ce9effa57f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 03:55:14 +0100 Subject: [PATCH 1022/1634] target-ppc: Update PowerPCCPU to QOM realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt ppc_cpu_realize() signature, hook it up to DeviceClass and set realized = true in cpu_ppc_init(). Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-ppc/cpu-qom.h | 2 ++ target-ppc/translate_init.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index b338f8fb56..2b82cdbe40 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -40,6 +40,7 @@ /** * PowerPCCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A PowerPC CPU model. @@ -49,6 +50,7 @@ typedef struct PowerPCCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); /* TODO inline fields here */ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6cebaa1982..49eaeac7c5 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10030,9 +10030,9 @@ static int ppc_fixup_cpu(PowerPCCPU *cpu) return 0; } -static void ppc_cpu_realize(Object *obj, Error **errp) +static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) { - PowerPCCPU *cpu = POWERPC_CPU(obj); + PowerPCCPU *cpu = POWERPC_CPU(dev); CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); ppc_def_t *def = pcc->info; @@ -10083,6 +10083,8 @@ static void ppc_cpu_realize(Object *obj, Error **errp) qemu_init_vcpu(env); + pcc->parent_realize(dev, errp); + #if defined(PPC_DUMP_CPU) { const char *mmu_model, *excp_model, *bus_model; @@ -10354,7 +10356,7 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model) env->cpu_model_str = cpu_model; - ppc_cpu_realize(OBJECT(cpu), &err); + object_property_set_bool(OBJECT(cpu), true, "realized", &err); if (err != NULL) { fprintf(stderr, "%s\n", error_get_pretty(err)); error_free(err); @@ -10575,6 +10577,10 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) { PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + pcc->parent_realize = dc->realize; + dc->realize = ppc_cpu_realizefn; pcc->parent_reset = cc->reset; cc->reset = ppc_cpu_reset; From ca45f8b0440358ccca63446cf0df05772791b2a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 15:41:21 +0100 Subject: [PATCH 1023/1634] target-cris: Introduce QOM realizefn for CRISCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce realizefn and set realized = true from cpu_cris_init(). Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-cris/cpu-qom.h | 2 ++ target-cris/cpu.c | 15 +++++++++++++++ target-cris/translate.c | 3 +-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h index 41ab9b2fa5..7ad8398760 100644 --- a/target-cris/cpu-qom.h +++ b/target-cris/cpu-qom.h @@ -33,6 +33,7 @@ /** * CRISCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A CRIS CPU model. @@ -42,6 +43,7 @@ typedef struct CRISCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } CRISCPUClass; diff --git a/target-cris/cpu.c b/target-cris/cpu.c index 3f64a5747e..34c4f75a44 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -55,6 +55,17 @@ static void cris_cpu_reset(CPUState *s) #endif } +static void cris_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CRISCPU *cpu = CRIS_CPU(dev); + CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(dev); + + cpu_reset(CPU(cpu)); + qemu_init_vcpu(&cpu->env); + + ccc->parent_realize(dev, errp); +} + static void cris_cpu_initfn(Object *obj) { CRISCPU *cpu = CRIS_CPU(obj); @@ -65,9 +76,13 @@ static void cris_cpu_initfn(Object *obj) static void cris_cpu_class_init(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + ccc->parent_realize = dc->realize; + dc->realize = cris_cpu_realizefn; + ccc->parent_reset = cc->reset; cc->reset = cris_cpu_reset; } diff --git a/target-cris/translate.c b/target-cris/translate.c index 09e6011ea4..25ff490399 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3558,8 +3558,7 @@ CRISCPU *cpu_cris_init(const char *cpu_model) env->pregs[PR_VR] = vr_by_name(cpu_model); - cpu_reset(CPU(cpu)); - qemu_init_vcpu(env); + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); if (tcg_initialized) { return cpu; From 9c23169e8cd54b490d55221b6498d42966f964f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 03:31:27 +0100 Subject: [PATCH 1024/1634] target-lm32: Introduce QOM realizefn for LM32CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a realizefn and set realized = true in cpu_lm32_init(). Also move cpu_reset() call from initfn to realizefn. Signed-off-by: Andreas Färber --- target-lm32/cpu-qom.h | 2 ++ target-lm32/cpu.c | 18 ++++++++++++++++-- target-lm32/helper.c | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h index 400cdbd554..d7525b300c 100644 --- a/target-lm32/cpu-qom.h +++ b/target-lm32/cpu-qom.h @@ -34,6 +34,7 @@ /** * LM32CPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A LatticeMico32 CPU model. @@ -43,6 +44,7 @@ typedef struct LM32CPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } LM32CPUClass; diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index eca2dca427..6a84f51bf9 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -42,6 +42,18 @@ static void lm32_cpu_reset(CPUState *s) memset(env, 0, offsetof(CPULM32State, breakpoints)); } +static void lm32_cpu_realizefn(DeviceState *dev, Error **errp) +{ + LM32CPU *cpu = LM32_CPU(dev); + LM32CPUClass *lcc = LM32_CPU_GET_CLASS(dev); + + cpu_reset(CPU(cpu)); + + qemu_init_vcpu(&cpu->env); + + lcc->parent_realize(dev, errp); +} + static void lm32_cpu_initfn(Object *obj) { LM32CPU *cpu = LM32_CPU(obj); @@ -50,14 +62,16 @@ static void lm32_cpu_initfn(Object *obj) cpu_exec_init(env); env->flags = 0; - - cpu_reset(CPU(cpu)); } static void lm32_cpu_class_init(ObjectClass *oc, void *data) { LM32CPUClass *lcc = LM32_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + lcc->parent_realize = dc->realize; + dc->realize = lm32_cpu_realizefn; lcc->parent_reset = cc->reset; cc->reset = lm32_cpu_reset; diff --git a/target-lm32/helper.c b/target-lm32/helper.c index d76ea3fe09..a6691addba 100644 --- a/target-lm32/helper.c +++ b/target-lm32/helper.c @@ -212,13 +212,13 @@ LM32CPU *cpu_lm32_init(const char *cpu_model) env->num_wps = def->num_watchpoints; env->cfg = cfg_by_def(def); - qemu_init_vcpu(env); - if (tcg_enabled() && !tcg_initialized) { tcg_initialized = 1; lm32_translate_init(); } + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return cpu; } From 6d1bbc6273d45520c5ce6475186bfa30d8afb47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 15:15:30 +0100 Subject: [PATCH 1025/1634] target-m68k: Introduce QOM realizefn for M68kCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce realizefn and set realized = true in cpu_m68k_init(). Split off GDB registration to a new m68k_cpu_init_gdb() so that it can be called from the realizefn. Signed-off-by: Andreas Färber --- target-m68k/cpu-qom.h | 2 ++ target-m68k/cpu.c | 16 ++++++++++++++++ target-m68k/cpu.h | 1 + target-m68k/helper.c | 14 ++++++++++---- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h index 170daa7c96..20e5684552 100644 --- a/target-m68k/cpu-qom.h +++ b/target-m68k/cpu-qom.h @@ -33,6 +33,7 @@ /** * M68kCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A Motorola 68k CPU model. @@ -42,6 +43,7 @@ typedef struct M68kCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } M68kCPUClass; diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index c71f715174..e3eaffc9ed 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -139,6 +139,19 @@ static const M68kCPUInfo m68k_cpus[] = { { .name = "any", .instance_init = any_cpu_initfn }, }; +static void m68k_cpu_realizefn(DeviceState *dev, Error **errp) +{ + M68kCPU *cpu = M68K_CPU(dev); + M68kCPUClass *mcc = M68K_CPU_GET_CLASS(dev); + + m68k_cpu_init_gdb(cpu); + + cpu_reset(CPU(cpu)); + qemu_init_vcpu(&cpu->env); + + mcc->parent_realize(dev, errp); +} + static void m68k_cpu_initfn(Object *obj) { M68kCPU *cpu = M68K_CPU(obj); @@ -158,6 +171,9 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); + mcc->parent_realize = dc->realize; + dc->realize = m68k_cpu_realizefn; + mcc->parent_reset = cc->reset; cc->reset = m68k_cpu_reset; diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index adaf56c471..94937c4fd7 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -116,6 +116,7 @@ typedef struct CPUM68KState { #include "cpu-qom.h" void m68k_tcg_init(void); +void m68k_cpu_init_gdb(M68kCPU *cpu); CPUM68KState *cpu_m68k_init(const char *cpu_model); int cpu_m68k_exec(CPUM68KState *s); void do_interrupt(CPUM68KState *env1); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 5ddcd707fd..3ae6fa0492 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -120,15 +120,21 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model) env->cpu_model_str = cpu_model; register_m68k_insns(env); + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + + return env; +} + +void m68k_cpu_init_gdb(M68kCPU *cpu) +{ + CPUM68KState *env = &cpu->env; + if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg, 11, "cf-fp.xml", 18); } /* TODO: Add [E]MAC registers. */ - - cpu_reset(ENV_GET_CPU(env)); - qemu_init_vcpu(env); - return env; } void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) From 746b03b27cac48be5a376d8635ffaf568339ebd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 15:27:31 +0100 Subject: [PATCH 1026/1634] target-microblaze: Introduce QOM realizefn for MicroBlazeCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce realizefn and set realized = true from cpu_mb_init(). Signed-off-by: Andreas Färber --- target-microblaze/cpu-qom.h | 2 ++ target-microblaze/cpu.c | 14 ++++++++++++++ target-microblaze/translate.c | 3 +-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h index f75549dc22..5ea911c8e4 100644 --- a/target-microblaze/cpu-qom.h +++ b/target-microblaze/cpu-qom.h @@ -33,6 +33,7 @@ /** * MicroBlazeCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A MicroBlaze CPU model. @@ -42,6 +43,7 @@ typedef struct MicroBlazeCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } MicroBlazeCPUClass; diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 39230fddcc..baae47b2c6 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -85,6 +85,17 @@ static void mb_cpu_reset(CPUState *s) #endif } +static void mb_cpu_realizefn(DeviceState *dev, Error **errp) +{ + MicroBlazeCPU *cpu = MICROBLAZE_CPU(dev); + MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(dev); + + cpu_reset(CPU(cpu)); + qemu_init_vcpu(&cpu->env); + + mcc->parent_realize(dev, errp); +} + static void mb_cpu_initfn(Object *obj) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); @@ -106,6 +117,9 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_CLASS(oc); + mcc->parent_realize = dc->realize; + dc->realize = mb_cpu_realizefn; + mcc->parent_reset = cc->reset; cc->reset = mb_cpu_reset; diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 58ce71267d..a84856ba43 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1970,8 +1970,7 @@ MicroBlazeCPU *cpu_mb_init(const char *cpu_model) cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); - cpu_reset(CPU(cpu)); - qemu_init_vcpu(&cpu->env); + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); if (tcg_initialized) { return cpu; From c1caf1d961288e41c25de6631c6751ae7baa20f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 03:48:37 +0100 Subject: [PATCH 1027/1634] target-mips: Introduce QOM realizefn for MIPSCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a realizefn and set realized = true from cpu_mips_init(). Signed-off-by: Andreas Färber --- target-mips/cpu-qom.h | 2 ++ target-mips/cpu.c | 15 +++++++++++++++ target-mips/translate.c | 5 +++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h index 2a4b812402..55aa692a85 100644 --- a/target-mips/cpu-qom.h +++ b/target-mips/cpu-qom.h @@ -37,6 +37,7 @@ /** * MIPSCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A MIPS CPU model. @@ -46,6 +47,7 @@ typedef struct MIPSCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } MIPSCPUClass; diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 10ff46d6a7..18895da80e 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -42,6 +42,17 @@ static void mips_cpu_reset(CPUState *s) cpu_state_reset(env); } +static void mips_cpu_realizefn(DeviceState *dev, Error **errp) +{ + MIPSCPU *cpu = MIPS_CPU(dev); + MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev); + + cpu_reset(CPU(cpu)); + qemu_init_vcpu(&cpu->env); + + mcc->parent_realize(dev, errp); +} + static void mips_cpu_initfn(Object *obj) { MIPSCPU *cpu = MIPS_CPU(obj); @@ -54,6 +65,10 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) { MIPSCPUClass *mcc = MIPS_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); + DeviceClass *dc = DEVICE_CLASS(c); + + mcc->parent_realize = dc->realize; + dc->realize = mips_cpu_realizefn; mcc->parent_reset = cc->reset; cc->reset = mips_cpu_reset; diff --git a/target-mips/translate.c b/target-mips/translate.c index 3b77b53b93..d7f650e0bf 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15916,8 +15916,9 @@ MIPSCPU *cpu_mips_init(const char *cpu_model) fpu_init(env, def); mvp_init(env, def); mips_tcg_init(); - cpu_reset(CPU(cpu)); - qemu_init_vcpu(env); + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return cpu; } From 1f1366322b21678c33003a373366697a4542d2d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 04:00:41 +0100 Subject: [PATCH 1028/1634] target-s390x: Introduce QOM realizefn for S390CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce realizefn and set realized = true in cpu_s390x_init(). Defer CPU reset from initfn to realizefn. Acked-by: Richard Henderson [AF: Invoke parent's realizefn] Signed-off-by: Andreas Färber --- target-s390x/cpu-qom.h | 2 ++ target-s390x/cpu.c | 16 ++++++++++++++-- target-s390x/helper.c | 4 +++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index d54e4a2ee2..237184f55a 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -34,6 +34,7 @@ /** * S390CPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * An S/390 CPU model. @@ -43,6 +44,7 @@ typedef struct S390CPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } S390CPUClass; diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index d765e7b984..ee15783b94 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -97,6 +97,17 @@ static void s390_cpu_machine_reset_cb(void *opaque) } #endif +static void s390_cpu_realizefn(DeviceState *dev, Error **errp) +{ + S390CPU *cpu = S390_CPU(dev); + S390CPUClass *scc = S390_CPU_GET_CLASS(dev); + + qemu_init_vcpu(&cpu->env); + cpu_reset(CPU(cpu)); + + scc->parent_realize(dev, errp); +} + static void s390_cpu_initfn(Object *obj) { S390CPU *cpu = S390_CPU(obj); @@ -122,8 +133,6 @@ static void s390_cpu_initfn(Object *obj) #endif env->cpu_num = cpu_num++; env->ext_index = -1; - - cpu_reset(CPU(cpu)); } static void s390_cpu_finalize(Object *obj) @@ -146,6 +155,9 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(scc); DeviceClass *dc = DEVICE_CLASS(oc); + scc->parent_realize = dc->realize; + dc->realize = s390_cpu_realizefn; + scc->parent_reset = cc->reset; cc->reset = s390_cpu_reset; diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 76268317a3..d3bb4561f1 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -85,7 +85,9 @@ S390CPU *cpu_s390x_init(const char *cpu_model) } env->cpu_model_str = cpu_model; - qemu_init_vcpu(env); + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return cpu; } From 55acb588dd184a1e33be0ff1fe23f8c19f88fd6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 23 Apr 2012 18:16:02 +0200 Subject: [PATCH 1029/1634] target-sh4: Introduce QOM realizefn for SuperHCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a realizefn and set realized = true in cpu_sh4_init(). Signed-off-by: Andreas Färber --- target-sh4/cpu-qom.h | 2 ++ target-sh4/cpu.c | 14 ++++++++++++++ target-sh4/translate.c | 5 +++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h index 09573c9c34..d368db1b0a 100644 --- a/target-sh4/cpu-qom.h +++ b/target-sh4/cpu-qom.h @@ -33,6 +33,7 @@ /** * SuperHCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A SuperH CPU model. @@ -42,6 +43,7 @@ typedef struct SuperHCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } SuperHCPUClass; diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index d2831226b9..c66442f445 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -54,6 +54,17 @@ static void superh_cpu_reset(CPUState *s) set_default_nan_mode(1, &env->fp_status); } +static void superh_cpu_realizefn(DeviceState *dev, Error **errp) +{ + SuperHCPU *cpu = SUPERH_CPU(dev); + SuperHCPUClass *scc = SUPERH_CPU_GET_CLASS(dev); + + cpu_reset(CPU(cpu)); + qemu_init_vcpu(&cpu->env); + + scc->parent_realize(dev, errp); +} + static void superh_cpu_initfn(Object *obj) { SuperHCPU *cpu = SUPERH_CPU(obj); @@ -75,6 +86,9 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); + scc->parent_realize = dc->realize; + dc->realize = superh_cpu_realizefn; + scc->parent_reset = cc->reset; cc->reset = superh_cpu_reset; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 260aaab559..2409a103b2 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -253,9 +253,10 @@ SuperHCPU *cpu_sh4_init(const char *cpu_model) env->features = def->features; sh4_translate_init(); env->cpu_model_str = cpu_model; - cpu_reset(CPU(cpu)); cpu_register(env, def); - qemu_init_vcpu(env); + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return cpu; } From b6e91ebfe06f1d90331d162259553a5330514143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 04:13:19 +0100 Subject: [PATCH 1030/1634] target-sparc: Introduce QOM realizefn for SPARCCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce realizefn and set realized = true in cpu_sparc_init(). Signed-off-by: Andreas Färber --- target-sparc/cpu-qom.h | 2 ++ target-sparc/cpu.c | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h index 2a738ae360..89cd1cf2d3 100644 --- a/target-sparc/cpu-qom.h +++ b/target-sparc/cpu-qom.h @@ -38,6 +38,7 @@ /** * SPARCCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * A SPARC CPU model. @@ -47,6 +48,7 @@ typedef struct SPARCCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } SPARCCPUClass; diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 4bc1afc755..1690cf5b15 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -122,7 +122,8 @@ SPARCCPU *cpu_sparc_init(const char *cpu_model) object_unref(OBJECT(cpu)); return NULL; } - qemu_init_vcpu(env); + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); return cpu; } @@ -851,6 +852,16 @@ void cpu_dump_state(CPUSPARCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n"); } +static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) +{ + SPARCCPU *cpu = SPARC_CPU(dev); + SPARCCPUClass *scc = SPARC_CPU_GET_CLASS(dev); + + qemu_init_vcpu(&cpu->env); + + scc->parent_realize(dev, errp); +} + static void sparc_cpu_initfn(Object *obj) { SPARCCPU *cpu = SPARC_CPU(obj); @@ -871,6 +882,10 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) { SPARCCPUClass *scc = SPARC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + scc->parent_realize = dc->realize; + dc->realize = sparc_cpu_realizefn; scc->parent_reset = cc->reset; cc->reset = sparc_cpu_reset; From 088383e3220776917f538d0e43933e842e16b804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 5 Jan 2013 14:38:30 +0100 Subject: [PATCH 1031/1634] target-unicore32: Introduce QOM realizefn for UniCore32CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a realizefn and set realized = true in uc32_cpu_init(). Acked-by: Guan Xuetao [AF: Invoke the parent's realizefn] Signed-off-by: Andreas Färber --- target-unicore32/cpu-qom.h | 3 +++ target-unicore32/cpu.c | 14 ++++++++++++++ target-unicore32/helper.c | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/target-unicore32/cpu-qom.h b/target-unicore32/cpu-qom.h index fe40b2d6a8..625c6143db 100644 --- a/target-unicore32/cpu-qom.h +++ b/target-unicore32/cpu-qom.h @@ -25,6 +25,7 @@ /** * UniCore32CPUClass: + * @parent_realize: The parent class' realize handler. * * A UniCore32 CPU model. */ @@ -32,6 +33,8 @@ typedef struct UniCore32CPUClass { /*< private >*/ CPUClass parent_class; /*< public >*/ + + DeviceRealize parent_realize; } UniCore32CPUClass; /** diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 4e4177fc57..8de17a49d6 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -81,6 +81,16 @@ static const UniCore32CPUInfo uc32_cpus[] = { { .name = "any", .instance_init = uc32_any_cpu_initfn }, }; +static void uc32_cpu_realizefn(DeviceState *dev, Error **errp) +{ + UniCore32CPU *cpu = UNICORE32_CPU(dev); + UniCore32CPUClass *ucc = UNICORE32_CPU_GET_CLASS(dev); + + qemu_init_vcpu(&cpu->env); + + ucc->parent_realize(dev, errp); +} + static void uc32_cpu_initfn(Object *obj) { UniCore32CPU *cpu = UNICORE32_CPU(obj); @@ -108,6 +118,10 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); + UniCore32CPUClass *ucc = UNICORE32_CPU_CLASS(oc); + + ucc->parent_realize = dc->realize; + dc->realize = uc32_cpu_realizefn; cc->class_by_name = uc32_cpu_class_by_name; dc->vmsd = &vmstate_uc32_cpu; diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index 3a92232de5..2442133319 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -45,7 +45,8 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model) uc32_translate_init(); } - qemu_init_vcpu(env); + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return env; } From 5f6c964389ea5320e81e2fb8c2bc3aa40c5a8013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 04:19:35 +0100 Subject: [PATCH 1032/1634] target-xtensa: Introduce QOM realizefn for XtensaCPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce realizefn and set realized = true in cpu_xtensa_init(). Signed-off-by: Andreas Färber --- target-xtensa/cpu-qom.h | 2 ++ target-xtensa/cpu.c | 13 +++++++++++++ target-xtensa/helper.c | 4 +++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h index e344a9aa79..270de16583 100644 --- a/target-xtensa/cpu-qom.h +++ b/target-xtensa/cpu-qom.h @@ -43,6 +43,7 @@ /** * XtensaCPUClass: + * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * * An Xtensa CPU model. @@ -52,6 +53,7 @@ typedef struct XtensaCPUClass { CPUClass parent_class; /*< public >*/ + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } XtensaCPUClass; diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index ebc7e9979b..d3706a30ac 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -57,6 +57,16 @@ static void xtensa_cpu_reset(CPUState *s) reset_mmu(env); } +static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) +{ + XtensaCPU *cpu = XTENSA_CPU(dev); + XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev); + + qemu_init_vcpu(&cpu->env); + + xcc->parent_realize(dev, errp); +} + static void xtensa_cpu_initfn(Object *obj) { XtensaCPU *cpu = XTENSA_CPU(obj); @@ -76,6 +86,9 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) CPUClass *cc = CPU_CLASS(oc); XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc); + xcc->parent_realize = dc->realize; + dc->realize = xtensa_cpu_realizefn; + xcc->parent_reset = cc->reset; cc->reset = xtensa_cpu_reset; diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index 94c03a1d3c..14bcc7ef23 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -104,7 +104,9 @@ XtensaCPU *cpu_xtensa_init(const char *cpu_model) } xtensa_irq_init(env); - qemu_init_vcpu(env); + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + return cpu; } From 79614b781df5096ffecf531992314781dbab54af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 19 Jan 2013 07:37:45 +0100 Subject: [PATCH 1033/1634] target-arm: Move TCG initialization to ARMCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensures that a QOM-created ARMCPU is usable. Signed-off-by: Andreas Färber --- target-arm/cpu.c | 6 ++++++ target-arm/helper.c | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 9915172a1d..f54d20057d 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -135,10 +135,16 @@ static inline void set_feature(CPUARMState *env, int feature) static void arm_cpu_initfn(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); + static bool inited; cpu_exec_init(&cpu->env); cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); + + if (tcg_enabled() && !inited) { + inited = true; + arm_translate_init(); + } } static void arm_cpu_finalizefn(Object *obj) diff --git a/target-arm/helper.c b/target-arm/helper.c index 4538a09445..e63da57a51 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1263,7 +1263,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model) ARMCPU *cpu; CPUARMState *env; ObjectClass *oc; - static int inited = 0; oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model); if (!oc) { @@ -1276,11 +1275,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model) /* TODO this should be set centrally, once possible */ object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - if (tcg_enabled() && !inited) { - inited = 1; - arm_translate_init(); - } - return cpu; } From d1a94fec3d8d70009fd5ac27ade5539fe58cd702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 19 Jan 2013 23:55:42 +0100 Subject: [PATCH 1034/1634] target-cris: Move TCG initialization to CRISCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out TCG initialization from cpu_cris_init(). Avoid CPUCRISState dependency for v10-specific initialization and for non-v10 by inlining the decision into the initfn as well. Signed-off-by: Andreas Färber --- target-cris/cpu.c | 10 ++++++++++ target-cris/cpu.h | 3 +++ target-cris/translate.c | 19 +++++-------------- target-cris/translate_v10.c | 5 +---- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/target-cris/cpu.c b/target-cris/cpu.c index 34c4f75a44..fedf64191d 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -70,8 +70,18 @@ static void cris_cpu_initfn(Object *obj) { CRISCPU *cpu = CRIS_CPU(obj); CPUCRISState *env = &cpu->env; + static bool tcg_initialized; cpu_exec_init(env); + + if (tcg_enabled() && !tcg_initialized) { + tcg_initialized = true; + if (env->pregs[PR_VR] < 32) { + cris_initialize_crisv10_tcg(); + } else { + cris_initialize_tcg(); + } + } } static void cris_cpu_class_init(ObjectClass *oc, void *data) diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 257cb52be2..ebf2d4027f 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -182,6 +182,9 @@ void do_interrupt(CPUCRISState *env); int cpu_cris_signal_handler(int host_signum, void *pinfo, void *puc); +void cris_initialize_tcg(void); +void cris_initialize_crisv10_tcg(void); + enum { CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, diff --git a/target-cris/translate.c b/target-cris/translate.c index 25ff490399..25a43faf35 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3550,8 +3550,6 @@ CRISCPU *cpu_cris_init(const char *cpu_model) { CRISCPU *cpu; CPUCRISState *env; - static int tcg_initialized = 0; - int i; cpu = CRIS_CPU(object_new(TYPE_CRIS_CPU)); env = &cpu->env; @@ -3560,21 +3558,16 @@ CRISCPU *cpu_cris_init(const char *cpu_model) object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - if (tcg_initialized) { - return cpu; - } + return cpu; +} - tcg_initialized = 1; +void cris_initialize_tcg(void) +{ + int i; #define GEN_HELPER 2 #include "helper.h" - if (env->pregs[PR_VR] < 32) { - cpu_crisv10_init(env); - return cpu; - } - - cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); cc_x = tcg_global_mem_new(TCG_AREG0, offsetof(CPUCRISState, cc_x), "cc_x"); @@ -3614,8 +3607,6 @@ CRISCPU *cpu_cris_init(const char *cpu_model) offsetof(CPUCRISState, pregs[i]), pregnames[i]); } - - return cpu; } void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, int pc_pos) diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c index d2cca892e0..d6ef084483 100644 --- a/target-cris/translate_v10.c +++ b/target-cris/translate_v10.c @@ -1257,7 +1257,7 @@ static unsigned int crisv10_decoder(CPUCRISState *env, DisasContext *dc) return insn_len; } -static CPUCRISState *cpu_crisv10_init (CPUCRISState *env) +void cris_initialize_crisv10_tcg(void) { int i; @@ -1300,7 +1300,4 @@ static CPUCRISState *cpu_crisv10_init (CPUCRISState *env) offsetof(CPUCRISState, pregs[i]), pregnames_v10[i]); } - - return env; } - From 868e2824276cbe6ef2e202c05c4eb3a3a19d3ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 00:05:12 +0100 Subject: [PATCH 1035/1634] target-lm32: Move TCG initialization to LM32CPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber --- target-lm32/cpu.c | 6 ++++++ target-lm32/helper.c | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index 6a84f51bf9..5f167340e4 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -58,10 +58,16 @@ static void lm32_cpu_initfn(Object *obj) { LM32CPU *cpu = LM32_CPU(obj); CPULM32State *env = &cpu->env; + static bool tcg_initialized; cpu_exec_init(env); env->flags = 0; + + if (tcg_enabled() && !tcg_initialized) { + tcg_initialized = true; + lm32_translate_init(); + } } static void lm32_cpu_class_init(ObjectClass *oc, void *data) diff --git a/target-lm32/helper.c b/target-lm32/helper.c index a6691addba..47ae7e775a 100644 --- a/target-lm32/helper.c +++ b/target-lm32/helper.c @@ -197,7 +197,6 @@ LM32CPU *cpu_lm32_init(const char *cpu_model) LM32CPU *cpu; CPULM32State *env; const LM32Def *def; - static int tcg_initialized; def = cpu_lm32_find_by_name(cpu_model); if (!def) { @@ -212,11 +211,6 @@ LM32CPU *cpu_lm32_init(const char *cpu_model) env->num_wps = def->num_watchpoints; env->cfg = cfg_by_def(def); - if (tcg_enabled() && !tcg_initialized) { - tcg_initialized = 1; - lm32_translate_init(); - } - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); return cpu; From 1cc896195bae54d7a5f48f9032037d8f6f65abd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 00:48:29 +0100 Subject: [PATCH 1036/1634] target-m68k: Move TCG initialization to M68kCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a tcg_enabled() check to suppress it for qtest. Signed-off-by: Andreas Färber --- target-m68k/cpu.c | 6 ++++++ target-m68k/helper.c | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index e3eaffc9ed..42735dbe40 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -156,8 +156,14 @@ static void m68k_cpu_initfn(Object *obj) { M68kCPU *cpu = M68K_CPU(obj); CPUM68KState *env = &cpu->env; + static bool inited; cpu_exec_init(env); + + if (tcg_enabled() && !inited) { + inited = true; + m68k_tcg_init(); + } } static const VMStateDescription vmstate_m68k_cpu = { diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 3ae6fa0492..6030807753 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -103,7 +103,6 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model) M68kCPU *cpu; CPUM68KState *env; ObjectClass *oc; - static int inited; oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model); if (oc == NULL) { @@ -111,12 +110,6 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model) } cpu = M68K_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; - - if (!inited) { - inited = 1; - m68k_tcg_init(); - } - env->cpu_model_str = cpu_model; register_m68k_insns(env); From cd0c24f9095b1f825210bb9d9f99532c78668074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 01:10:52 +0100 Subject: [PATCH 1037/1634] target-microblaze: Move TCG initialization to MicroBlazeCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split off TCG initialization from cpu_mb_init() into mb_tcg_init() to call it from the initfn. Ensures that a QOM-created MicroBlazeCPU is usable. Signed-off-by: Andreas Färber --- target-microblaze/cpu.c | 6 ++++++ target-microblaze/cpu.h | 1 + target-microblaze/translate.c | 13 +++++-------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index baae47b2c6..28b5a88789 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -100,10 +100,16 @@ static void mb_cpu_initfn(Object *obj) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); CPUMBState *env = &cpu->env; + static bool tcg_initialized; cpu_exec_init(env); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + + if (tcg_enabled() && !tcg_initialized) { + tcg_initialized = true; + mb_tcg_init(); + } } static const VMStateDescription vmstate_mb_cpu = { diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 41480e71e1..c3dd7f6219 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -272,6 +272,7 @@ struct CPUMBState { #include "cpu-qom.h" +void mb_tcg_init(void); MicroBlazeCPU *cpu_mb_init(const char *cpu_model); int cpu_mb_exec(CPUMBState *s); void do_interrupt(CPUMBState *env); diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index a84856ba43..12ea820522 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1965,18 +1965,17 @@ void cpu_dump_state (CPUMBState *env, FILE *f, fprintf_function cpu_fprintf, MicroBlazeCPU *cpu_mb_init(const char *cpu_model) { MicroBlazeCPU *cpu; - static int tcg_initialized = 0; - int i; cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - if (tcg_initialized) { - return cpu; - } + return cpu; +} - tcg_initialized = 1; +void mb_tcg_init(void) +{ + int i; cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); @@ -2007,8 +2006,6 @@ MicroBlazeCPU *cpu_mb_init(const char *cpu_model) } #define GEN_HELPER 2 #include "helper.h" - - return cpu; } void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos) From 78ce64f492498050083e46cdd7e6cbae6435843c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 01:22:25 +0100 Subject: [PATCH 1038/1634] target-mips: Move TCG initialization to MIPSCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make mips_tcg_init() non-static and add tcg_enabled() check to suppress it for qtest. Signed-off-by: Andreas Färber --- target-mips/cpu.c | 4 ++++ target-mips/cpu.h | 1 + target-mips/translate.c | 3 +-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 18895da80e..09d61723c5 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -59,6 +59,10 @@ static void mips_cpu_initfn(Object *obj) CPUMIPSState *env = &cpu->env; cpu_exec_init(env); + + if (tcg_enabled()) { + mips_tcg_init(); + } } static void mips_cpu_class_init(ObjectClass *c, void *data) diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 5963d62973..0e198b12db 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -629,6 +629,7 @@ enum { #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 int cpu_mips_exec(CPUMIPSState *s); +void mips_tcg_init(void); MIPSCPU *cpu_mips_init(const char *cpu_model); int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc); diff --git a/target-mips/translate.c b/target-mips/translate.c index d7f650e0bf..4ee9615fda 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15836,7 +15836,7 @@ void cpu_dump_state (CPUMIPSState *env, FILE *f, fprintf_function cpu_fprintf, #endif } -static void mips_tcg_init(void) +void mips_tcg_init(void) { int i; static int inited; @@ -15915,7 +15915,6 @@ MIPSCPU *cpu_mips_init(const char *cpu_model) #endif fpu_init(env, def); mvp_init(env, def); - mips_tcg_init(); object_property_set_bool(OBJECT(cpu), true, "realized", NULL); From 60925d2644953ce1ca7813411853d8c04e637050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 01:26:37 +0100 Subject: [PATCH 1039/1634] target-ppc: Move TCG initialization to PowerPCCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensures that a QOM-created PowerPCCPU is usable. Signed-off-by: Andreas Färber --- target-ppc/translate_init.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 49eaeac7c5..5a2acaafe8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10349,11 +10349,6 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model) cpu = POWERPC_CPU(object_new(object_class_get_name(oc))); env = &cpu->env; - - if (tcg_enabled()) { - ppc_translate_init(); - } - env->cpu_model_str = cpu_model; object_property_set_bool(OBJECT(cpu), true, "realized", &err); @@ -10571,6 +10566,10 @@ static void ppc_cpu_initfn(Object *obj) env->sps = defsps; } #endif /* defined(TARGET_PPC64) */ + + if (tcg_enabled()) { + ppc_translate_init(); + } } static void ppc_cpu_class_init(ObjectClass *oc, void *data) From 2b7ac76729c8253d799a8d3bb9bae76cccb0714e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 19 Jan 2013 22:43:32 +0100 Subject: [PATCH 1040/1634] target-s390x: Move TCG initialization to S390CPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensures that a QOM-created S390CPU is usable. Acked-by: Richard Henderson Signed-off-by: Andreas Färber --- target-s390x/cpu.c | 6 ++++++ target-s390x/helper.c | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index ee15783b94..787c937579 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -112,6 +112,7 @@ static void s390_cpu_initfn(Object *obj) { S390CPU *cpu = S390_CPU(obj); CPUS390XState *env = &cpu->env; + static bool inited; static int cpu_num = 0; #if !defined(CONFIG_USER_ONLY) struct tm tm; @@ -133,6 +134,11 @@ static void s390_cpu_initfn(Object *obj) #endif env->cpu_num = cpu_num++; env->ext_index = -1; + + if (tcg_enabled() && !inited) { + inited = true; + s390x_translate_init(); + } } static void s390_cpu_finalize(Object *obj) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index d3bb4561f1..1183b45ca1 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -74,16 +74,9 @@ S390CPU *cpu_s390x_init(const char *cpu_model) { S390CPU *cpu; CPUS390XState *env; - static int inited; cpu = S390_CPU(object_new(TYPE_S390_CPU)); env = &cpu->env; - - if (tcg_enabled() && !inited) { - inited = 1; - s390x_translate_init(); - } - env->cpu_model_str = cpu_model; object_property_set_bool(OBJECT(cpu), true, "realized", NULL); From aa7408ec18c3517b2476a3671cd0b7f171241e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 01:30:32 +0100 Subject: [PATCH 1041/1634] target-sh4: Move TCG initialization to SuperHCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a tcg_enabled() check to suppress it for qtest. Signed-off-by: Andreas Färber --- target-sh4/cpu.c | 4 ++++ target-sh4/cpu.h | 1 + target-sh4/translate.c | 3 +-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index c66442f445..dc5d7568ea 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -73,6 +73,10 @@ static void superh_cpu_initfn(Object *obj) cpu_exec_init(env); env->movcal_backup_tail = &(env->movcal_backup); + + if (tcg_enabled()) { + sh4_translate_init(); + } } static const VMStateDescription vmstate_sh_cpu = { diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 34e9b0acf7..49dcd9e7f3 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -191,6 +191,7 @@ typedef struct CPUSH4State { #include "cpu-qom.h" +void sh4_translate_init(void); SuperHCPU *cpu_sh4_init(const char *cpu_model); int cpu_sh4_exec(CPUSH4State * s); int cpu_sh4_signal_handler(int host_signum, void *pinfo, diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 2409a103b2..c58d79a5cd 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -71,7 +71,7 @@ static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; #include "exec/gen-icount.h" -static void sh4_translate_init(void) +void sh4_translate_init(void) { int i; static int done_init = 0; @@ -251,7 +251,6 @@ SuperHCPU *cpu_sh4_init(const char *cpu_model) cpu = SUPERH_CPU(object_new(TYPE_SUPERH_CPU)); env = &cpu->env; env->features = def->features; - sh4_translate_init(); env->cpu_model_str = cpu_model; cpu_register(env, def); From 5266d20a12f2ef01841aad5f1692d73551a39dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 01:34:18 +0100 Subject: [PATCH 1042/1634] target-sparc: Move TCG initialization to SPARCCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber --- target-sparc/cpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 1690cf5b15..759be532a3 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -114,10 +114,6 @@ SPARCCPU *cpu_sparc_init(const char *cpu_model) cpu = SPARC_CPU(object_new(TYPE_SPARC_CPU)); env = &cpu->env; - if (tcg_enabled()) { - gen_intermediate_code_init(env); - } - if (cpu_sparc_register(env, cpu_model) < 0) { object_unref(OBJECT(cpu)); return NULL; @@ -868,6 +864,10 @@ static void sparc_cpu_initfn(Object *obj) CPUSPARCState *env = &cpu->env; cpu_exec_init(env); + + if (tcg_enabled()) { + gen_intermediate_code_init(env); + } } static void sparc_cpu_uninitfn(Object *obj) From d9c27f00b174df070470d48d6577042d2186d969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 01:36:47 +0100 Subject: [PATCH 1043/1634] target-unicore32: Move TCG initialization to UniCore32CPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normalize the "inited" logic and add a tcg_enabled() check to suppress it for qtest. Ensures that a QOM-created UniCore32CPU is usable. Acked-by: Guan Xuetao Signed-off-by: Andreas Färber --- target-unicore32/cpu.c | 6 ++++++ target-unicore32/helper.c | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 8de17a49d6..7bcf3b3658 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -95,6 +95,7 @@ static void uc32_cpu_initfn(Object *obj) { UniCore32CPU *cpu = UNICORE32_CPU(obj); CPUUniCore32State *env = &cpu->env; + static bool inited; cpu_exec_init(env); @@ -107,6 +108,11 @@ static void uc32_cpu_initfn(Object *obj) #endif tlb_flush(env, 1); + + if (tcg_enabled() && !inited) { + inited = true; + uc32_translate_init(); + } } static const VMStateDescription vmstate_uc32_cpu = { diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index 2442133319..7eeb9bc633 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -30,7 +30,6 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model) UniCore32CPU *cpu; CPUUniCore32State *env; ObjectClass *oc; - static int inited = 1; oc = cpu_class_by_name(TYPE_UNICORE32_CPU, cpu_model); if (oc == NULL) { @@ -40,11 +39,6 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model) env = &cpu->env; env->cpu_model_str = cpu_model; - if (inited) { - inited = 0; - uc32_translate_init(); - } - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); return env; From 25733eada6c1d4928262e77e2ee1e9ed12de18fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 01:46:45 +0100 Subject: [PATCH 1044/1634] target-xtensa: Move TCG initialization to XtensaCPU initfn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Combine this with breakpoint handler registration, guarding both with tcg_enabled() to suppress also TCG init for qtest. Rename the handler to xtensa_breakpoint_handler() since it needs to become global. Signed-off-by: Andreas Färber --- target-xtensa/cpu.c | 7 +++++++ target-xtensa/cpu.h | 1 + target-xtensa/helper.c | 14 +------------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index d3706a30ac..309bb169ec 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -71,8 +71,15 @@ static void xtensa_cpu_initfn(Object *obj) { XtensaCPU *cpu = XTENSA_CPU(obj); CPUXtensaState *env = &cpu->env; + static bool tcg_inited; cpu_exec_init(env); + + if (tcg_enabled() && !tcg_inited) { + tcg_inited = true; + xtensa_translate_init(); + cpu_set_debug_excp_handler(xtensa_breakpoint_handler); + } } static const VMStateDescription vmstate_xtensa_cpu = { diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 5acf78c692..dece224478 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -385,6 +385,7 @@ static inline CPUXtensaState *cpu_init(const char *cpu_model) } void xtensa_translate_init(void); +void xtensa_breakpoint_handler(CPUXtensaState *env); int cpu_xtensa_exec(CPUXtensaState *s); void xtensa_register_core(XtensaConfigList *node); void do_interrupt(CPUXtensaState *s); diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index 14bcc7ef23..a8a64932da 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -54,7 +54,7 @@ static uint32_t check_hw_breakpoints(CPUXtensaState *env) return 0; } -static void breakpoint_handler(CPUXtensaState *env) +void xtensa_breakpoint_handler(CPUXtensaState *env) { if (env->watchpoint_hit) { if (env->watchpoint_hit->flags & BP_CPU) { @@ -72,8 +72,6 @@ static void breakpoint_handler(CPUXtensaState *env) XtensaCPU *cpu_xtensa_init(const char *cpu_model) { - static int tcg_inited; - static int debug_handler_inited; XtensaCPU *cpu; CPUXtensaState *env; const XtensaConfig *config = NULL; @@ -93,16 +91,6 @@ XtensaCPU *cpu_xtensa_init(const char *cpu_model) env = &cpu->env; env->config = config; - if (!tcg_inited) { - tcg_inited = 1; - xtensa_translate_init(); - } - - if (!debug_handler_inited && tcg_enabled()) { - debug_handler_inited = 1; - cpu_set_debug_excp_handler(breakpoint_handler); - } - xtensa_irq_init(env); object_property_set_bool(OBJECT(cpu), true, "realized", NULL); From f3273ba643f2d0221492381b24bbc35fb6089a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 15:57:51 +0100 Subject: [PATCH 1045/1634] ppc405_uc: Pass PowerPCCPU to ppc40x_{core,chip,system}_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares for changing cpu_interrupt() argument to CPUState. Signed-off-by: Andreas Färber Acked-by: Alexander Graf --- hw/ppc.c | 12 ++++++------ hw/ppc.h | 6 +++--- hw/ppc405_uc.c | 16 ++++++++++------ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/hw/ppc.c b/hw/ppc.c index 6053bd5652..8cfb84fa13 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -300,20 +300,20 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) if (level) { LOG_IRQ("%s: reset the PowerPC system\n", __func__); - ppc40x_system_reset(env); + ppc40x_system_reset(cpu); } break; case PPC40x_INPUT_RESET_CHIP: if (level) { LOG_IRQ("%s: reset the PowerPC chip\n", __func__); - ppc40x_chip_reset(env); + ppc40x_chip_reset(cpu); } break; case PPC40x_INPUT_RESET_CORE: /* XXX: TODO: update DBSR[MRR] */ if (level) { LOG_IRQ("%s: reset the PowerPC core\n", __func__); - ppc40x_core_reset(env); + ppc40x_core_reset(cpu); } break; case PPC40x_INPUT_CINT: @@ -1011,13 +1011,13 @@ static void cpu_4xx_wdt_cb (void *opaque) /* No reset */ break; case 0x1: /* Core reset */ - ppc40x_core_reset(env); + ppc40x_core_reset(cpu); break; case 0x2: /* Chip reset */ - ppc40x_chip_reset(env); + ppc40x_chip_reset(cpu); break; case 0x3: /* System reset */ - ppc40x_system_reset(env); + ppc40x_system_reset(cpu); break; } } diff --git a/hw/ppc.h b/hw/ppc.h index ee0cd16ee5..acaf0d6580 100644 --- a/hw/ppc.h +++ b/hw/ppc.h @@ -58,9 +58,9 @@ clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq, unsigned int decr_excp); /* Embedded PowerPC reset */ -void ppc40x_core_reset (CPUPPCState *env); -void ppc40x_chip_reset (CPUPPCState *env); -void ppc40x_system_reset (CPUPPCState *env); +void ppc40x_core_reset(PowerPCCPU *cpu); +void ppc40x_chip_reset(PowerPCCPU *cpu); +void ppc40x_system_reset(PowerPCCPU *cpu); void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); extern CPUWriteMemoryFunc * const PPC_io_write[]; diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index c96d103d1c..d8cbe875bd 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -1770,8 +1770,9 @@ static void ppc405_mal_init(CPUPPCState *env, qemu_irq irqs[4]) /*****************************************************************************/ /* SPR */ -void ppc40x_core_reset (CPUPPCState *env) +void ppc40x_core_reset(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; target_ulong dbsr; printf("Reset PowerPC core\n"); @@ -1782,8 +1783,9 @@ void ppc40x_core_reset (CPUPPCState *env) env->spr[SPR_40x_DBSR] = dbsr; } -void ppc40x_chip_reset (CPUPPCState *env) +void ppc40x_chip_reset(PowerPCCPU *cpu) { + CPUPPCState *env = &cpu->env; target_ulong dbsr; printf("Reset PowerPC chip\n"); @@ -1795,7 +1797,7 @@ void ppc40x_chip_reset (CPUPPCState *env) env->spr[SPR_40x_DBSR] = dbsr; } -void ppc40x_system_reset (CPUPPCState *env) +void ppc40x_system_reset(PowerPCCPU *cpu) { printf("Reset PowerPC system\n"); qemu_system_reset_request(); @@ -1803,21 +1805,23 @@ void ppc40x_system_reset (CPUPPCState *env) void store_40x_dbcr0 (CPUPPCState *env, uint32_t val) { + PowerPCCPU *cpu = ppc_env_get_cpu(env); + switch ((val >> 28) & 0x3) { case 0x0: /* No action */ break; case 0x1: /* Core reset */ - ppc40x_core_reset(env); + ppc40x_core_reset(cpu); break; case 0x2: /* Chip reset */ - ppc40x_chip_reset(env); + ppc40x_chip_reset(cpu); break; case 0x3: /* System reset */ - ppc40x_system_reset(env); + ppc40x_system_reset(cpu); break; } } From c7937d9f9a99d8cc2848e85f608d89c6f326daf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 14:03:58 +0100 Subject: [PATCH 1046/1634] target-m68k: Return M68kCPU from cpu_m68k_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turn cpu_init() into a static inline function for backwards compatibility. Signed-off-by: Andreas Färber --- target-m68k/cpu.h | 12 ++++++++++-- target-m68k/helper.c | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 94937c4fd7..ed9be802d4 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -117,7 +117,7 @@ typedef struct CPUM68KState { void m68k_tcg_init(void); void m68k_cpu_init_gdb(M68kCPU *cpu); -CPUM68KState *cpu_m68k_init(const char *cpu_model); +M68kCPU *cpu_m68k_init(const char *cpu_model); int cpu_m68k_exec(CPUM68KState *s); void do_interrupt(CPUM68KState *env1); void do_interrupt_m68k_hardirq(CPUM68KState *env1); @@ -215,7 +215,15 @@ void register_m68k_insns (CPUM68KState *env); #define TARGET_PHYS_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define cpu_init cpu_m68k_init +static inline CPUM68KState *cpu_init(const char *cpu_model) +{ + M68kCPU *cpu = cpu_m68k_init(cpu_model); + if (cpu == NULL) { + return NULL; + } + return &cpu->env; +} + #define cpu_exec cpu_m68k_exec #define cpu_gen_code cpu_m68k_gen_code #define cpu_signal_handler cpu_m68k_signal_handler diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 6030807753..7d3fd944be 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -98,7 +98,7 @@ static int fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) return 0; } -CPUM68KState *cpu_m68k_init(const char *cpu_model) +M68kCPU *cpu_m68k_init(const char *cpu_model) { M68kCPU *cpu; CPUM68KState *env; @@ -116,7 +116,7 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model) object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - return env; + return cpu; } void m68k_cpu_init_gdb(M68kCPU *cpu) From 4025cfd5d7175203008343a375f9287c77cd383c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 14:10:34 +0100 Subject: [PATCH 1047/1634] mcf5206: Pass M68kCPU to mcf5206_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store it in m5206_mbar_state. Prepares for passing M68kCPU to m68k_set_irq_level(). Signed-off-by: Andreas Färber --- hw/an5206.c | 11 +++++++---- hw/mcf.h | 2 +- hw/mcf5206.c | 8 ++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/hw/an5206.c b/hw/an5206.c index 750115a3aa..924be81d57 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -24,6 +24,7 @@ static void an5206_init(QEMUMachineInitArgs *args) ram_addr_t ram_size = args->ram_size; const char *cpu_model = args->cpu_model; const char *kernel_filename = args->kernel_filename; + M68kCPU *cpu; CPUM68KState *env; int kernel_size; uint64_t elf_entry; @@ -32,12 +33,14 @@ static void an5206_init(QEMUMachineInitArgs *args) MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); - if (!cpu_model) + if (!cpu_model) { cpu_model = "m5206"; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_m68k_init(cpu_model); + if (!cpu) { hw_error("Unable to find m68k CPU definition\n"); } + env = &cpu->env; /* Initialize CPU registers. */ env->vbr = 0; @@ -55,7 +58,7 @@ static void an5206_init(QEMUMachineInitArgs *args) vmstate_register_ram_global(sram); memory_region_add_subregion(address_space_mem, AN5206_RAMBAR_ADDR, sram); - mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, env); + mcf5206_init(address_space_mem, AN5206_MBAR_ADDR, cpu); /* Load kernel. */ if (!kernel_filename) { diff --git a/hw/mcf.h b/hw/mcf.h index f929910f02..dc21028cd2 100644 --- a/hw/mcf.h +++ b/hw/mcf.h @@ -25,6 +25,6 @@ void mcf_fec_init(struct MemoryRegion *sysmem, NICInfo *nd, /* mcf5206.c */ qemu_irq *mcf5206_init(struct MemoryRegion *sysmem, - uint32_t base, CPUM68KState *env); + uint32_t base, M68kCPU *cpu); #endif diff --git a/hw/mcf5206.c b/hw/mcf5206.c index d8c0059ed6..9bb393e3d4 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -145,7 +145,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq) /* System Integration Module. */ typedef struct { - CPUM68KState *env; + M68kCPU *cpu; MemoryRegion iomem; m5206_timer_state *timer[2]; void *uart[2]; @@ -226,7 +226,7 @@ static void m5206_mbar_update(m5206_mbar_state *s) level = 0; vector = 0; } - m68k_set_irq_level(s->env, level, vector); + m68k_set_irq_level(&s->cpu->env, level, vector); } static void m5206_mbar_set_irq(void *opaque, int irq, int level) @@ -525,7 +525,7 @@ static const MemoryRegionOps m5206_mbar_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, CPUM68KState *env) +qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, M68kCPU *cpu) { m5206_mbar_state *s; qemu_irq *pic; @@ -541,7 +541,7 @@ qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, CPUM68KState *env) s->timer[1] = m5206_timer_init(pic[10]); s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); - s->env = env; + s->cpu = cpu; m5206_mbar_reset(s); return pic; From 9a6ee9fd35483446fe14e083fa335358c86ba595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 14:15:09 +0100 Subject: [PATCH 1048/1634] mcf_intc: Pass M68kCPU to mcf_intc_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store it in mcf_intc_state. Prepares for passing it to m68k_set_irq_level(). Signed-off-by: Andreas Färber --- hw/mcf.h | 2 +- hw/mcf5208.c | 11 +++++++---- hw/mcf_intc.c | 8 ++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/hw/mcf.h b/hw/mcf.h index dc21028cd2..fbc8dc26df 100644 --- a/hw/mcf.h +++ b/hw/mcf.h @@ -17,7 +17,7 @@ void mcf_uart_mm_init(struct MemoryRegion *sysmem, /* mcf_intc.c */ qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem, hwaddr base, - CPUM68KState *env); + M68kCPU *cpu); /* mcf_fec.c */ void mcf_fec_init(struct MemoryRegion *sysmem, NICInfo *nd, diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 2c9a5dc98a..86402d30d5 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -192,6 +192,7 @@ static void mcf5208evb_init(QEMUMachineInitArgs *args) ram_addr_t ram_size = args->ram_size; const char *cpu_model = args->cpu_model; const char *kernel_filename = args->kernel_filename; + M68kCPU *cpu; CPUM68KState *env; int kernel_size; uint64_t elf_entry; @@ -201,13 +202,15 @@ static void mcf5208evb_init(QEMUMachineInitArgs *args) MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); - if (!cpu_model) + if (!cpu_model) { cpu_model = "m5208"; - env = cpu_init(cpu_model); - if (!env) { + } + cpu = cpu_m68k_init(cpu_model); + if (!cpu) { fprintf(stderr, "Unable to find m68k CPU definition\n"); exit(1); } + env = &cpu->env; /* Initialize CPU registers. */ env->vbr = 0; @@ -224,7 +227,7 @@ static void mcf5208evb_init(QEMUMachineInitArgs *args) memory_region_add_subregion(address_space_mem, 0x80000000, sram); /* Internal peripherals. */ - pic = mcf_intc_init(address_space_mem, 0xfc048000, env); + pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu); mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]); mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]); diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index 3bed3a2e4c..450f622e9d 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -16,7 +16,7 @@ typedef struct { uint64_t ifr; uint64_t enabled; uint8_t icr[64]; - CPUM68KState *env; + M68kCPU *cpu; int active_vector; } mcf_intc_state; @@ -40,7 +40,7 @@ static void mcf_intc_update(mcf_intc_state *s) } } s->active_vector = ((best == 64) ? 24 : (best + 64)); - m68k_set_irq_level(s->env, best_level, s->active_vector); + m68k_set_irq_level(&s->cpu->env, best_level, s->active_vector); } static uint64_t mcf_intc_read(void *opaque, hwaddr addr, @@ -139,12 +139,12 @@ static const MemoryRegionOps mcf_intc_ops = { qemu_irq *mcf_intc_init(MemoryRegion *sysmem, hwaddr base, - CPUM68KState *env) + M68kCPU *cpu) { mcf_intc_state *s; s = g_malloc0(sizeof(mcf_intc_state)); - s->env = env; + s->cpu = cpu; mcf_intc_reset(s); memory_region_init_io(&s->iomem, &mcf_intc_ops, s, "mcf", 0x100); From cb3fb38e91caacfcb0f86e8c587ed74ffa34fe8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 14:20:52 +0100 Subject: [PATCH 1049/1634] target-m68k: Pass M68kCPU to m68k_set_irq_level() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplifies use of cpu_reset_interrupt() et al. Signed-off-by: Andreas Färber --- hw/mcf5206.c | 2 +- hw/mcf_intc.c | 2 +- target-m68k/cpu.h | 2 +- target-m68k/helper.c | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/mcf5206.c b/hw/mcf5206.c index 9bb393e3d4..ea2db2325a 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -226,7 +226,7 @@ static void m5206_mbar_update(m5206_mbar_state *s) level = 0; vector = 0; } - m68k_set_irq_level(&s->cpu->env, level, vector); + m68k_set_irq_level(s->cpu, level, vector); } static void m5206_mbar_set_irq(void *opaque, int irq, int level) diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index 450f622e9d..b213656300 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -40,7 +40,7 @@ static void mcf_intc_update(mcf_intc_state *s) } } s->active_vector = ((best == 64) ? 24 : (best + 64)); - m68k_set_irq_level(&s->cpu->env, best_level, s->active_vector); + m68k_set_irq_level(s->cpu, best_level, s->active_vector); } static uint64_t mcf_intc_read(void *opaque, hwaddr addr, diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index ed9be802d4..2672eae7c8 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -169,7 +169,7 @@ enum { #define MACSR_V 0x002 #define MACSR_EV 0x001 -void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector); +void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector); void m68k_set_macsr(CPUM68KState *env, uint32_t val); void m68k_switch_sp(CPUM68KState *env); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 7d3fd944be..1bae3ab326 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -310,8 +310,10 @@ int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw, be handled by the interrupt controller. Real hardware only requests the vector when the interrupt is acknowledged by the CPU. For simplicitly we calculate it when the interrupt is signalled. */ -void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector) +void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) { + CPUM68KState *env = &cpu->env; + env->pending_level = level; env->pending_vector = vector; if (level) From 6ae064fc671f1c475b1371c067fa3100ec6daf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 6 Feb 2013 17:18:12 +0100 Subject: [PATCH 1050/1634] target-cris: Introduce CRISCPU subclasses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use class_init functions to initialize the VR in preparation for overriding v32+ behavior there. Move cpu_cris_init() to cpu.c and hook up a class_by_name callback. This change leads to unknown -cpu model names no longer falling back to a CPU with VR 32 but instead returning NULL. Acked-by: Edgar E. Iglesias Signed-off-by: Andreas Färber --- target-cris/cpu-qom.h | 3 + target-cris/cpu.c | 153 +++++++++++++++++++++++++++++++++++++++- target-cris/translate.c | 48 ------------- 3 files changed, 155 insertions(+), 49 deletions(-) diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h index 7ad8398760..2bac71fd81 100644 --- a/target-cris/cpu-qom.h +++ b/target-cris/cpu-qom.h @@ -35,6 +35,7 @@ * CRISCPUClass: * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. + * @vr: Version Register value. * * A CRIS CPU model. */ @@ -45,6 +46,8 @@ typedef struct CRISCPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); + + uint32_t vr; } CRISCPUClass; /** diff --git a/target-cris/cpu.c b/target-cris/cpu.c index fedf64191d..80089884e9 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -55,6 +55,84 @@ static void cris_cpu_reset(CPUState *s) #endif } +static ObjectClass *cris_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + char *typename; + + if (cpu_model == NULL) { + return NULL; + } + + typename = g_strdup_printf("%s-" TYPE_CRIS_CPU, cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_CRIS_CPU) || + object_class_is_abstract(oc))) { + oc = NULL; + } + return oc; +} + +CRISCPU *cpu_cris_init(const char *cpu_model) +{ + CRISCPU *cpu; + ObjectClass *oc; + + oc = cris_cpu_class_by_name(cpu_model); + if (oc == NULL) { + return NULL; + } + cpu = CRIS_CPU(object_new(object_class_get_name(oc))); + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + + return cpu; +} + +/* Sort alphabetically by VR. */ +static gint cris_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + CRISCPUClass *ccc_a = CRIS_CPU_CLASS(a); + CRISCPUClass *ccc_b = CRIS_CPU_CLASS(b); + + /* */ + if (ccc_a->vr > ccc_b->vr) { + return 1; + } else if (ccc_a->vr < ccc_b->vr) { + return -1; + } else { + return 0; + } +} + +static void cris_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CPUListState *s = user_data; + const char *typename = object_class_get_name(oc); + char *name; + + name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_CRIS_CPU)); + (*s->cpu_fprintf)(s->file, " %s\n", name); + g_free(name); +} + +void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_CRIS_CPU, false); + list = g_slist_sort(list, cris_cpu_list_compare); + (*cpu_fprintf)(f, "Available CPUs:\n"); + g_slist_foreach(list, cris_cpu_list_entry, &s); + g_slist_free(list); +} + static void cris_cpu_realizefn(DeviceState *dev, Error **errp) { CRISCPU *cpu = CRIS_CPU(dev); @@ -69,11 +147,14 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp) static void cris_cpu_initfn(Object *obj) { CRISCPU *cpu = CRIS_CPU(obj); + CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj); CPUCRISState *env = &cpu->env; static bool tcg_initialized; cpu_exec_init(env); + env->pregs[PR_VR] = ccc->vr; + if (tcg_enabled() && !tcg_initialized) { tcg_initialized = true; if (env->pregs[PR_VR] < 32) { @@ -84,6 +165,69 @@ static void cris_cpu_initfn(Object *obj) } } +static void crisv8_cpu_class_init(ObjectClass *oc, void *data) +{ + CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + + ccc->vr = 8; +} + +static void crisv9_cpu_class_init(ObjectClass *oc, void *data) +{ + CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + + ccc->vr = 9; +} + +static void crisv10_cpu_class_init(ObjectClass *oc, void *data) +{ + CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + + ccc->vr = 10; +} + +static void crisv11_cpu_class_init(ObjectClass *oc, void *data) +{ + CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + + ccc->vr = 11; +} + +static void crisv32_cpu_class_init(ObjectClass *oc, void *data) +{ + CRISCPUClass *ccc = CRIS_CPU_CLASS(oc); + + ccc->vr = 32; +} + +#define TYPE(model) model "-" TYPE_CRIS_CPU + +static const TypeInfo cris_cpu_model_type_infos[] = { + { + .name = TYPE("crisv8"), + .parent = TYPE_CRIS_CPU, + .class_init = crisv8_cpu_class_init, + }, { + .name = TYPE("crisv9"), + .parent = TYPE_CRIS_CPU, + .class_init = crisv9_cpu_class_init, + }, { + .name = TYPE("crisv10"), + .parent = TYPE_CRIS_CPU, + .class_init = crisv10_cpu_class_init, + }, { + .name = TYPE("crisv11"), + .parent = TYPE_CRIS_CPU, + .class_init = crisv11_cpu_class_init, + }, { + .name = TYPE("crisv32"), + .parent = TYPE_CRIS_CPU, + .class_init = crisv32_cpu_class_init, + } +}; + +#undef TYPE + static void cris_cpu_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -95,6 +239,8 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) ccc->parent_reset = cc->reset; cc->reset = cris_cpu_reset; + + cc->class_by_name = cris_cpu_class_by_name; } static const TypeInfo cris_cpu_type_info = { @@ -102,14 +248,19 @@ static const TypeInfo cris_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(CRISCPU), .instance_init = cris_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(CRISCPUClass), .class_init = cris_cpu_class_init, }; static void cris_cpu_register_types(void) { + int i; + type_register_static(&cris_cpu_type_info); + for (i = 0; i < ARRAY_SIZE(cris_cpu_model_type_infos); i++) { + type_register_static(&cris_cpu_model_type_infos[i]); + } } type_init(cris_cpu_register_types) diff --git a/target-cris/translate.c b/target-cris/translate.c index 25a43faf35..04a5379775 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3513,54 +3513,6 @@ void cpu_dump_state (CPUCRISState *env, FILE *f, fprintf_function cpu_fprintf, } -struct -{ - uint32_t vr; - const char *name; -} cris_cores[] = { - {8, "crisv8"}, - {9, "crisv9"}, - {10, "crisv10"}, - {11, "crisv11"}, - {32, "crisv32"}, -}; - -void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf) -{ - unsigned int i; - - (*cpu_fprintf)(f, "Available CPUs:\n"); - for (i = 0; i < ARRAY_SIZE(cris_cores); i++) { - (*cpu_fprintf)(f, " %s\n", cris_cores[i].name); - } -} - -static uint32_t vr_by_name(const char *name) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(cris_cores); i++) { - if (strcmp(name, cris_cores[i].name) == 0) { - return cris_cores[i].vr; - } - } - return 32; -} - -CRISCPU *cpu_cris_init(const char *cpu_model) -{ - CRISCPU *cpu; - CPUCRISState *env; - - cpu = CRIS_CPU(object_new(TYPE_CRIS_CPU)); - env = &cpu->env; - - env->pregs[PR_VR] = vr_by_name(cpu_model); - - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - - return cpu; -} - void cris_initialize_tcg(void) { int i; From 0d34282fdde1d8f337d2a9e10f5ac793b12ef2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 07:12:13 +0100 Subject: [PATCH 1051/1634] cpu: Move host_tid field to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change gdbstub's cpu_index() argument to CPUState now that CPUArchState is no longer used. Signed-off-by: Andreas Färber --- dump.c | 8 ++++++-- gdbstub.c | 14 +++++++++----- include/exec/cpu-defs.h | 1 - include/exec/gdbstub.h | 5 ++--- include/qom/cpu.h | 2 ++ linux-user/syscall.c | 4 +++- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/dump.c b/dump.c index 4ed1fa8622..a25f5096eb 100644 --- a/dump.c +++ b/dump.c @@ -271,11 +271,13 @@ static int write_elf64_note(DumpState *s) static int write_elf64_notes(DumpState *s) { CPUArchState *env; + CPUState *cpu; int ret; int id; for (env = first_cpu; env != NULL; env = env->next_cpu) { - id = cpu_index(env); + cpu = ENV_GET_CPU(env); + id = cpu_index(cpu); ret = cpu_write_elf64_note(fd_write_vmcore, env, id, s); if (ret < 0) { dump_error(s, "dump: failed to write elf notes.\n"); @@ -321,11 +323,13 @@ static int write_elf32_note(DumpState *s) static int write_elf32_notes(DumpState *s) { CPUArchState *env; + CPUState *cpu; int ret; int id; for (env = first_cpu; env != NULL; env = env->next_cpu) { - id = cpu_index(env); + cpu = ENV_GET_CPU(env); + id = cpu_index(cpu); ret = cpu_write_elf32_note(fd_write_vmcore, env, id, s); if (ret < 0) { dump_error(s, "dump: failed to write elf notes.\n"); diff --git a/gdbstub.c b/gdbstub.c index 6cd26f1619..32dfea9ed0 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2066,9 +2066,11 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) static CPUArchState *find_cpu(uint32_t thread_id) { CPUArchState *env; + CPUState *cpu; for (env = first_cpu; env != NULL; env = env->next_cpu) { - if (cpu_index(env) == thread_id) { + cpu = ENV_GET_CPU(env); + if (cpu_index(cpu) == thread_id) { return env; } } @@ -2096,7 +2098,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) case '?': /* TODO: Make this return the correct value for user-mode. */ snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP, - cpu_index(s->c_cpu)); + cpu_index(ENV_GET_CPU(s->c_cpu))); put_packet(s, buf); /* Remove all the breakpoints when this query is issued, * because gdb is doing and initial connect and the state @@ -2391,7 +2393,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) } else if (strcmp(p,"sThreadInfo") == 0) { report_cpuinfo: if (s->query_cpu) { - snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu)); + snprintf(buf, sizeof(buf), "m%x", + cpu_index(ENV_GET_CPU(s->query_cpu))); put_packet(s, buf); s->query_cpu = s->query_cpu->next_cpu; } else @@ -2512,6 +2515,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) { GDBState *s = gdbserver_state; CPUArchState *env = s->c_cpu; + CPUState *cpu = ENV_GET_CPU(env); char buf[256]; const char *type; int ret; @@ -2540,7 +2544,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) } snprintf(buf, sizeof(buf), "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", - GDB_SIGNAL_TRAP, cpu_index(env), type, + GDB_SIGNAL_TRAP, cpu_index(cpu), type, env->watchpoint_hit->vaddr); env->watchpoint_hit = NULL; goto send_packet; @@ -2573,7 +2577,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) ret = GDB_SIGNAL_UNKNOWN; break; } - snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(env)); + snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(cpu)); send_packet: put_packet(s, buf); diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 2911b9fc90..ae832a9f83 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -191,7 +191,6 @@ typedef struct CPUWatchpoint { int exception_index; \ \ CPUArchState *next_cpu; /* next CPU sharing TB cache */ \ - uint32_t host_tid; /* host thread ID */ \ int running; /* Nonzero if cpu is currently running(usermode). */ \ /* user data */ \ void *opaque; \ diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 49231feb29..ba20afa091 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -30,12 +30,11 @@ void gdb_register_coprocessor(CPUArchState *env, gdb_reg_cb get_reg, gdb_reg_cb set_reg, int num_regs, const char *xml, int g_pos); -static inline int cpu_index(CPUArchState *env) +static inline int cpu_index(CPUState *cpu) { #if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL) - return env->host_tid; + return cpu->host_tid; #else - CPUState *cpu = ENV_GET_CPU(env); return cpu->cpu_index + 1; #endif } diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 46f2247274..e371655d15 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -65,6 +65,7 @@ struct kvm_run; * @nr_cores: Number of cores within this CPU package. * @nr_threads: Number of threads within this CPU. * @numa_node: NUMA node this CPU is belonging to. + * @host_tid: Host thread ID. * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. @@ -86,6 +87,7 @@ struct CPUState { HANDLE hThread; #endif int thread_id; + uint32_t host_tid; struct QemuCond *halt_cond; struct qemu_work_item *queued_work_first, *queued_work_last; bool thread_kicked; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9e31ea7200..19630eaf20 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4312,13 +4312,15 @@ static void *clone_func(void *arg) { new_thread_info *info = arg; CPUArchState *env; + CPUState *cpu; TaskState *ts; env = info->env; + cpu = ENV_GET_CPU(env); thread_env = env; ts = (TaskState *)thread_env->opaque; info->tid = gettid(); - env->host_tid = info->tid; + cpu->host_tid = info->tid; task_settid(ts); if (info->child_tidptr) put_user_u32(info->tid, info->child_tidptr); From 0315c31cda054775585b31f8cb3c9228cc6fc28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 07:34:52 +0100 Subject: [PATCH 1052/1634] cpu: Move running field to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass CPUState to cpu_exec_{start,end}() functions. Signed-off-by: Andreas Färber --- include/exec/cpu-defs.h | 1 - include/qom/cpu.h | 2 ++ linux-user/main.c | 37 ++++++++++++++++++++++--------------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ae832a9f83..ba814ff10d 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -191,7 +191,6 @@ typedef struct CPUWatchpoint { int exception_index; \ \ CPUArchState *next_cpu; /* next CPU sharing TB cache */ \ - int running; /* Nonzero if cpu is currently running(usermode). */ \ /* user data */ \ void *opaque; \ \ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index e371655d15..c465d88260 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -66,6 +66,7 @@ struct kvm_run; * @nr_threads: Number of threads within this CPU. * @numa_node: NUMA node this CPU is belonging to. * @host_tid: Host thread ID. + * @running: #true if CPU is currently running (usermode). * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. @@ -88,6 +89,7 @@ struct CPUState { #endif int thread_id; uint32_t host_tid; + bool running; struct QemuCond *halt_cond; struct qemu_work_item *queued_work_first, *queued_work_last; bool thread_kicked; diff --git a/linux-user/main.c b/linux-user/main.c index 146a4683a5..e51568430f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -151,13 +151,16 @@ static inline void exclusive_idle(void) static inline void start_exclusive(void) { CPUArchState *other; + CPUState *other_cpu; + pthread_mutex_lock(&exclusive_lock); exclusive_idle(); pending_cpus = 1; /* Make all other cpus stop executing. */ for (other = first_cpu; other; other = other->next_cpu) { - if (other->running) { + other_cpu = ENV_GET_CPU(other); + if (other_cpu->running) { pending_cpus++; cpu_exit(other); } @@ -176,19 +179,19 @@ static inline void end_exclusive(void) } /* Wait for exclusive ops to finish, and begin cpu execution. */ -static inline void cpu_exec_start(CPUArchState *env) +static inline void cpu_exec_start(CPUState *cpu) { pthread_mutex_lock(&exclusive_lock); exclusive_idle(); - env->running = 1; + cpu->running = true; pthread_mutex_unlock(&exclusive_lock); } /* Mark cpu as not executing, and release pending exclusive ops. */ -static inline void cpu_exec_end(CPUArchState *env) +static inline void cpu_exec_end(CPUState *cpu) { pthread_mutex_lock(&exclusive_lock); - env->running = 0; + cpu->running = false; if (pending_cpus > 1) { pending_cpus--; if (pending_cpus == 1) { @@ -210,11 +213,11 @@ void cpu_list_unlock(void) } #else /* if !CONFIG_USE_NPTL */ /* These are no-ops because we are not threadsafe. */ -static inline void cpu_exec_start(CPUArchState *env) +static inline void cpu_exec_start(CPUState *cpu) { } -static inline void cpu_exec_end(CPUArchState *env) +static inline void cpu_exec_end(CPUState *cpu) { } @@ -697,15 +700,16 @@ done: void cpu_loop(CPUARMState *env) { + CPUState *cs = CPU(arm_env_get_cpu(env)); int trapnr; unsigned int n, insn; target_siginfo_t info; uint32_t addr; for(;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = cpu_arm_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch(trapnr) { case EXCP_UDEF: { @@ -912,14 +916,15 @@ void cpu_loop(CPUARMState *env) void cpu_loop(CPUUniCore32State *env) { + CPUState *cs = CPU(uc32_env_get_cpu(env)); int trapnr; unsigned int n, insn; target_siginfo_t info; for (;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = uc32_cpu_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch (trapnr) { case UC32_EXCP_PRIV: { @@ -1367,14 +1372,15 @@ static int do_store_exclusive(CPUPPCState *env) void cpu_loop(CPUPPCState *env) { + CPUState *cs = CPU(ppc_env_get_cpu(env)); target_siginfo_t info; int trapnr; target_ulong ret; for(;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = cpu_ppc_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch(trapnr) { case POWERPC_EXCP_NONE: /* Just go on */ @@ -2184,14 +2190,15 @@ static int do_store_exclusive(CPUMIPSState *env) void cpu_loop(CPUMIPSState *env) { + CPUState *cs = CPU(mips_env_get_cpu(env)); target_siginfo_t info; int trapnr, ret; unsigned int syscall_num; for(;;) { - cpu_exec_start(env); + cpu_exec_start(cs); trapnr = cpu_mips_exec(env); - cpu_exec_end(env); + cpu_exec_end(cs); switch(trapnr) { case EXCP_SYSCALL: syscall_num = env->active_tc.gpr[2] - 4000; From fcd7d0034b7eddba505a548f456f452bf5a7d56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 17 Dec 2012 08:02:44 +0100 Subject: [PATCH 1053/1634] cpu: Move exit_request field to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it was located before breakpoints field, it needs to be reset. Signed-off-by: Andreas Färber --- cpu-exec.c | 8 ++++---- exec.c | 4 +++- hw/spapr_hcall.c | 5 +++-- include/exec/cpu-defs.h | 2 -- include/qom/cpu.h | 2 ++ kvm-all.c | 6 +++--- qom/cpu.c | 1 + target-i386/kvm.c | 4 ++-- 8 files changed, 18 insertions(+), 14 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index ff9a884a96..cf103f227b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -196,7 +196,7 @@ int cpu_exec(CPUArchState *env) cpu_single_env = env; if (unlikely(exit_request)) { - env->exit_request = 1; + cpu->exit_request = 1; } #if defined(TARGET_I386) @@ -537,8 +537,8 @@ int cpu_exec(CPUArchState *env) next_tb = 0; } } - if (unlikely(env->exit_request)) { - env->exit_request = 0; + if (unlikely(cpu->exit_request)) { + cpu->exit_request = 0; env->exception_index = EXCP_INTERRUPT; cpu_loop_exit(env); } @@ -591,7 +591,7 @@ int cpu_exec(CPUArchState *env) starting execution if there is a pending interrupt. */ env->current_tb = tb; barrier(); - if (likely(!env->exit_request)) { + if (likely(!cpu->exit_request)) { tc_ptr = tb->tc_ptr; /* execute the generated code */ next_tb = tcg_qemu_tb_exec(env, tc_ptr); diff --git a/exec.c b/exec.c index b85508ba30..dbb893a08e 100644 --- a/exec.c +++ b/exec.c @@ -492,7 +492,9 @@ void cpu_reset_interrupt(CPUArchState *env, int mask) void cpu_exit(CPUArchState *env) { - env->exit_request = 1; + CPUState *cpu = ENV_GET_CPU(env); + + cpu->exit_request = 1; cpu_unlink_tb(env); } diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 2889742788..af1db6ea08 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -513,13 +513,14 @@ static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { CPUPPCState *env = &cpu->env; + CPUState *cs = CPU(cpu); env->msr |= (1ULL << MSR_EE); hreg_compute_hflags(env); - if (!cpu_has_work(CPU(cpu))) { + if (!cpu_has_work(cs)) { env->halted = 1; env->exception_index = EXCP_HLT; - env->exit_request = 1; + cs->exit_request = 1; } return H_SUCCESS; } diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ba814ff10d..ca39f05567 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -26,7 +26,6 @@ #include "config.h" #include #include -#include #include "qemu/osdep.h" #include "qemu/queue.h" #include "exec/hwaddr.h" @@ -160,7 +159,6 @@ typedef struct CPUWatchpoint { memory was accessed */ \ uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ uint32_t interrupt_request; \ - volatile sig_atomic_t exit_request; \ CPU_COMMON_TLB \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ /* buffer for temporaries in the code generator */ \ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index c465d88260..42f3f34bbd 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -20,6 +20,7 @@ #ifndef QEMU_CPU_H #define QEMU_CPU_H +#include #include "hw/qdev-core.h" #include "qemu/thread.h" @@ -96,6 +97,7 @@ struct CPUState { bool created; bool stop; bool stopped; + volatile sig_atomic_t exit_request; int kvm_fd; bool kvm_vcpu_dirty; diff --git a/kvm-all.c b/kvm-all.c index 04ec2d541a..4decfdccd3 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1537,7 +1537,7 @@ int kvm_cpu_exec(CPUArchState *env) DPRINTF("kvm_cpu_exec()\n"); if (kvm_arch_process_async_events(cpu)) { - env->exit_request = 0; + cpu->exit_request = 0; return EXCP_HLT; } @@ -1548,7 +1548,7 @@ int kvm_cpu_exec(CPUArchState *env) } kvm_arch_pre_run(cpu, run); - if (env->exit_request) { + if (cpu->exit_request) { DPRINTF("interrupt exit requested\n"); /* * KVM requires us to reenter the kernel after IO exits to complete @@ -1622,7 +1622,7 @@ int kvm_cpu_exec(CPUArchState *env) vm_stop(RUN_STATE_INTERNAL_ERROR); } - env->exit_request = 0; + cpu->exit_request = 0; return ret; } diff --git a/qom/cpu.c b/qom/cpu.c index 870e9baad9..7d8c675dd0 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -32,6 +32,7 @@ void cpu_reset(CPUState *cpu) static void cpu_common_reset(CPUState *cpu) { + cpu->exit_request = 0; } ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 9ebf1816d9..0cf413dbfd 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1777,7 +1777,7 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) * or pending TPR access reports. */ if (env->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { - env->exit_request = 1; + cpu->exit_request = 1; } /* Try to inject an interrupt if the guest can accept it */ @@ -1847,7 +1847,7 @@ int kvm_arch_process_async_events(CPUState *cs) if (env->exception_injected == EXCP08_DBLE) { /* this means triple fault */ qemu_system_reset_request(); - env->exit_request = 1; + cs->exit_request = 1; return 0; } env->exception_injected = EXCP12_MCHK; From d77953b94ff20868b21796ee22ca57baa1cfc941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 16 Jan 2013 19:29:31 +0100 Subject: [PATCH 1054/1634] cpu: Move current_tb field to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explictly NULL it on CPU reset since it was located before breakpoints. Change vapic_report_tpr_access() argument to CPUState. This also resolves the use of void* for cpu.h independence. Change vAPIC patch_instruction() argument to X86CPU. Signed-off-by: Andreas Färber --- cpu-exec.c | 13 ++++++++----- cputlb.c | 6 ++++-- hw/apic_common.c | 2 +- hw/apic_internal.h | 2 +- hw/kvmvapic.c | 13 ++++++++----- include/exec/cpu-defs.h | 1 - include/exec/exec-all.h | 4 +++- include/qom/cpu.h | 3 +++ qom/cpu.c | 1 + translate-all.c | 29 +++++++++++++++++++---------- 10 files changed, 48 insertions(+), 26 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index cf103f227b..9fcfe9e0db 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -32,7 +32,9 @@ bool qemu_cpu_has_work(CPUState *cpu) void cpu_loop_exit(CPUArchState *env) { - env->current_tb = NULL; + CPUState *cpu = ENV_GET_CPU(env); + + cpu->current_tb = NULL; longjmp(env->jmp_env, 1); } @@ -54,6 +56,7 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc) static void cpu_exec_nocache(CPUArchState *env, int max_cycles, TranslationBlock *orig_tb) { + CPUState *cpu = ENV_GET_CPU(env); tcg_target_ulong next_tb; TranslationBlock *tb; @@ -64,10 +67,10 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles, tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags, max_cycles); - env->current_tb = tb; + cpu->current_tb = tb; /* execute the generated code */ next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr); - env->current_tb = NULL; + cpu->current_tb = NULL; if ((next_tb & 3) == 2) { /* Restore PC. This may happen if async event occurs before @@ -589,7 +592,7 @@ int cpu_exec(CPUArchState *env) TB, but before it is linked into a potentially infinite loop and becomes env->current_tb. Avoid starting execution if there is a pending interrupt. */ - env->current_tb = tb; + cpu->current_tb = tb; barrier(); if (likely(!cpu->exit_request)) { tc_ptr = tb->tc_ptr; @@ -623,7 +626,7 @@ int cpu_exec(CPUArchState *env) } } } - env->current_tb = NULL; + cpu->current_tb = NULL; /* reset soft MMU for next block (it can currently only be set by a memory fault) */ } /* for(;;) */ diff --git a/cputlb.c b/cputlb.c index 88239c494a..aba7e44e1e 100644 --- a/cputlb.c +++ b/cputlb.c @@ -54,6 +54,7 @@ static const CPUTLBEntry s_cputlb_empty_entry = { */ void tlb_flush(CPUArchState *env, int flush_global) { + CPUState *cpu = ENV_GET_CPU(env); int i; #if defined(DEBUG_TLB) @@ -61,7 +62,7 @@ void tlb_flush(CPUArchState *env, int flush_global) #endif /* must reset current TB so that interrupts cannot modify the links while we are modifying them */ - env->current_tb = NULL; + cpu->current_tb = NULL; for (i = 0; i < CPU_TLB_SIZE; i++) { int mmu_idx; @@ -92,6 +93,7 @@ static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) void tlb_flush_page(CPUArchState *env, target_ulong addr) { + CPUState *cpu = ENV_GET_CPU(env); int i; int mmu_idx; @@ -110,7 +112,7 @@ void tlb_flush_page(CPUArchState *env, target_ulong addr) } /* must reset current TB so that interrupts cannot modify the links while we are modifying them */ - env->current_tb = NULL; + cpu->current_tb = NULL; addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); diff --git a/hw/apic_common.c b/hw/apic_common.c index 6e1b1e0320..d8c9810509 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -103,7 +103,7 @@ void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip, { APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); - vapic_report_tpr_access(s->vapic, &s->cpu->env, ip, access); + vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access); } void apic_report_irq_delivered(int delivered) diff --git a/hw/apic_internal.h b/hw/apic_internal.h index dcbbfd41cb..9265e52cd6 100644 --- a/hw/apic_internal.h +++ b/hw/apic_internal.h @@ -143,7 +143,7 @@ bool apic_next_timer(APICCommonState *s, int64_t current_time); void apic_enable_tpr_access_reporting(DeviceState *d, bool enable); void apic_enable_vapic(DeviceState *d, hwaddr paddr); -void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip, +void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip, TPRAccess access); #endif /* !QEMU_APIC_INTERNAL_H */ diff --git a/hw/kvmvapic.c b/hw/kvmvapic.c index 1b5f416a78..9265baf568 100644 --- a/hw/kvmvapic.c +++ b/hw/kvmvapic.c @@ -382,8 +382,10 @@ static void patch_call(VAPICROMState *s, CPUX86State *env, target_ulong ip, cpu_memory_rw_debug(env, ip + 1, (void *)&offset, sizeof(offset), 1); } -static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong ip) +static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) { + CPUState *cs = CPU(cpu); + CPUX86State *env = &cpu->env; VAPICHandlers *handlers; uint8_t opcode[2]; uint32_t imm32; @@ -439,17 +441,18 @@ static void patch_instruction(VAPICROMState *s, CPUX86State *env, target_ulong i resume_all_vcpus(); if (!kvm_enabled()) { - env->current_tb = NULL; + cs->current_tb = NULL; tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); cpu_resume_from_signal(env, NULL); } } -void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip, +void vapic_report_tpr_access(DeviceState *dev, CPUState *cs, target_ulong ip, TPRAccess access) { VAPICROMState *s = DO_UPCAST(VAPICROMState, busdev.qdev, dev); - CPUX86State *env = cpu; + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; cpu_synchronize_state(env); @@ -465,7 +468,7 @@ void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip, if (vapic_enable(s, env) < 0) { return; } - patch_instruction(s, env, ip); + patch_instruction(s, cpu, ip); } typedef struct VAPICEnableTPRReporting { diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ca39f05567..ae64590cdf 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -148,7 +148,6 @@ typedef struct CPUWatchpoint { #define CPU_TEMP_BUF_NLONGS 128 #define CPU_COMMON \ - struct TranslationBlock *current_tb; /* currently executing TB */ \ /* soft mmu support */ \ /* in order to avoid passing too many arguments to the MMIO \ helpers, we store some rarely used information in the CPU \ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index f685c28573..e856191e40 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -404,11 +404,13 @@ extern volatile sig_atomic_t exit_request; instruction of a TB so that interrupts take effect immediately. */ static inline int can_do_io(CPUArchState *env) { + CPUState *cpu = ENV_GET_CPU(env); + if (!use_icount) { return 1; } /* If not executing code then assume we are ok. */ - if (!env->current_tb) { + if (cpu->current_tb == NULL) { return 1; } return env->can_do_io != 0; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 42f3f34bbd..c25a997808 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -71,6 +71,7 @@ struct kvm_run; * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. + * @current_tb: Currently executing TB. * @kvm_fd: vCPU file descriptor for KVM. * * State of one CPU core or thread. @@ -99,6 +100,8 @@ struct CPUState { bool stopped; volatile sig_atomic_t exit_request; + struct TranslationBlock *current_tb; + int kvm_fd; bool kvm_vcpu_dirty; struct KVMState *kvm_state; diff --git a/qom/cpu.c b/qom/cpu.c index 7d8c675dd0..0a2194d413 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -33,6 +33,7 @@ void cpu_reset(CPUState *cpu) static void cpu_common_reset(CPUState *cpu) { cpu->exit_request = 0; + cpu->current_tb = NULL; } ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) diff --git a/translate-all.c b/translate-all.c index efeb247add..52128aa0c4 100644 --- a/translate-all.c +++ b/translate-all.c @@ -998,6 +998,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, { TranslationBlock *tb, *tb_next, *saved_tb; CPUArchState *env = cpu_single_env; + CPUState *cpu = NULL; tb_page_addr_t tb_start, tb_end; PageDesc *p; int n; @@ -1020,6 +1021,9 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, /* build code bitmap */ build_page_bitmap(p); } + if (env != NULL) { + cpu = ENV_GET_CPU(env); + } /* we remove all the TBs in the range [start, end[ */ /* XXX: see if in some cases it could be faster to invalidate all @@ -1066,14 +1070,14 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, /* we need to do that to handle the case where a signal occurs while doing tb_phys_invalidate() */ saved_tb = NULL; - if (env) { - saved_tb = env->current_tb; - env->current_tb = NULL; + if (cpu != NULL) { + saved_tb = cpu->current_tb; + cpu->current_tb = NULL; } tb_phys_invalidate(tb, -1); - if (env) { - env->current_tb = saved_tb; - if (env->interrupt_request && env->current_tb) { + if (cpu != NULL) { + cpu->current_tb = saved_tb; + if (env && env->interrupt_request && cpu->current_tb) { cpu_interrupt(env, env->interrupt_request); } } @@ -1094,7 +1098,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, /* we generate a block containing just the instruction modifying the memory. It will ensure that it cannot modify itself */ - env->current_tb = NULL; + cpu->current_tb = NULL; tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); cpu_resume_from_signal(env, NULL); } @@ -1142,6 +1146,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, #ifdef TARGET_HAS_PRECISE_SMC TranslationBlock *current_tb = NULL; CPUArchState *env = cpu_single_env; + CPUState *cpu = NULL; int current_tb_modified = 0; target_ulong current_pc = 0; target_ulong current_cs_base = 0; @@ -1158,6 +1163,9 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, if (tb && pc != 0) { current_tb = tb_find_pc(pc); } + if (env != NULL) { + cpu = ENV_GET_CPU(env); + } #endif while (tb != NULL) { n = (uintptr_t)tb & 3; @@ -1186,7 +1194,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, /* we generate a block containing just the instruction modifying the memory. It will ensure that it cannot modify itself */ - env->current_tb = NULL; + cpu->current_tb = NULL; tb_gen_code(env, current_pc, current_cs_base, current_flags, 1); cpu_resume_from_signal(env, puc); } @@ -1414,15 +1422,16 @@ void cpu_unlink_tb(CPUArchState *env) problem and hope the cpu will stop of its own accord. For userspace emulation this often isn't actually as bad as it sounds. Often signals are used primarily to interrupt blocking syscalls. */ + CPUState *cpu = ENV_GET_CPU(env); TranslationBlock *tb; static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; spin_lock(&interrupt_lock); - tb = env->current_tb; + tb = cpu->current_tb; /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ if (tb) { - env->current_tb = NULL; + cpu->current_tb = NULL; tb_reset_jump_recursive(tb); } spin_unlock(&interrupt_lock); From 907a5e32f293a0af8875973d4cce12b96bea5bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Jan 2013 09:16:15 +0100 Subject: [PATCH 1055/1634] cputlb: Pass CPUState to cpu_unlink_tb() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPUArchState is no longer needed. Signed-off-by: Andreas Färber --- exec.c | 2 +- translate-all.c | 9 +++++---- translate-all.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/exec.c b/exec.c index dbb893a08e..a41bcb8694 100644 --- a/exec.c +++ b/exec.c @@ -495,7 +495,7 @@ void cpu_exit(CPUArchState *env) CPUState *cpu = ENV_GET_CPU(env); cpu->exit_request = 1; - cpu_unlink_tb(env); + cpu_unlink_tb(cpu); } void cpu_abort(CPUArchState *env, const char *fmt, ...) diff --git a/translate-all.c b/translate-all.c index 52128aa0c4..b50fb89528 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1416,13 +1416,12 @@ void tb_invalidate_phys_addr(hwaddr addr) } #endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */ -void cpu_unlink_tb(CPUArchState *env) +void cpu_unlink_tb(CPUState *cpu) { /* FIXME: TB unchaining isn't SMP safe. For now just ignore the problem and hope the cpu will stop of its own accord. For userspace emulation this often isn't actually as bad as it sounds. Often signals are used primarily to interrupt blocking syscalls. */ - CPUState *cpu = ENV_GET_CPU(env); TranslationBlock *tb; static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; @@ -1476,7 +1475,7 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask) cpu_abort(env, "Raised interrupt while not in I/O function"); } } else { - cpu_unlink_tb(env); + cpu_unlink_tb(cpu); } } @@ -1624,8 +1623,10 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) void cpu_interrupt(CPUArchState *env, int mask) { + CPUState *cpu = ENV_GET_CPU(env); + env->interrupt_request |= mask; - cpu_unlink_tb(env); + cpu_unlink_tb(cpu); } /* diff --git a/translate-all.h b/translate-all.h index b181fb48ad..5c38819eb8 100644 --- a/translate-all.h +++ b/translate-all.h @@ -28,7 +28,7 @@ /* translate-all.c */ void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len); -void cpu_unlink_tb(CPUArchState *env); +void cpu_unlink_tb(CPUState *cpu); void tb_check_watchpoint(CPUArchState *env); #endif /* TRANSLATE_ALL_H */ From c05efcb18ee30cdf2b00b3512aa0f5233b52911f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Jan 2013 12:13:41 +0100 Subject: [PATCH 1056/1634] cpu: Add CPUArchState pointer to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The target-specific ENV_GET_CPU() macros have allowed us to navigate from CPUArchState to CPUState. The reverse direction was not supported. Avoid introducing CPU_GET_ENV() macros by initializing an untyped pointer that is initialized in derived instance_init functions. The field may not be called "env" due to it being poisoned. Acked-by: Richard Henderson Signed-off-by: Andreas Färber --- include/qom/cpu.h | 2 ++ target-alpha/cpu.c | 2 ++ target-arm/cpu.c | 2 ++ target-cris/cpu.c | 2 ++ target-i386/cpu.c | 1 + target-lm32/cpu.c | 2 ++ target-m68k/cpu.c | 2 ++ target-microblaze/cpu.c | 2 ++ target-mips/cpu.c | 2 ++ target-openrisc/cpu.c | 2 ++ target-ppc/translate_init.c | 2 ++ target-s390x/cpu.c | 2 ++ target-sh4/cpu.c | 2 ++ target-sparc/cpu.c | 2 ++ target-unicore32/cpu.c | 2 ++ target-xtensa/cpu.c | 2 ++ 16 files changed, 31 insertions(+) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index c25a997808..ee1a7c878a 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -71,6 +71,7 @@ struct kvm_run; * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. + * @env_ptr: Pointer to subclass-specific CPUArchState field. * @current_tb: Currently executing TB. * @kvm_fd: vCPU file descriptor for KVM. * @@ -100,6 +101,7 @@ struct CPUState { bool stopped; volatile sig_atomic_t exit_request; + void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; int kvm_fd; diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 0cdae6986f..cec9989925 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -233,9 +233,11 @@ static const TypeInfo ev68_cpu_type_info = { static void alpha_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); AlphaCPU *cpu = ALPHA_CPU(obj); CPUAlphaState *env = &cpu->env; + cs->env_ptr = env; cpu_exec_init(env); tlb_flush(env, 1); diff --git a/target-arm/cpu.c b/target-arm/cpu.c index f54d20057d..5dfcb740d9 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -134,9 +134,11 @@ static inline void set_feature(CPUARMState *env, int feature) static void arm_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); ARMCPU *cpu = ARM_CPU(obj); static bool inited; + cs->env_ptr = &cpu->env; cpu_exec_init(&cpu->env); cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); diff --git a/target-cris/cpu.c b/target-cris/cpu.c index 80089884e9..7974be33f2 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -146,11 +146,13 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp) static void cris_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); CRISCPU *cpu = CRIS_CPU(obj); CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj); CPUCRISState *env = &cpu->env; static bool tcg_initialized; + cs->env_ptr = env; cpu_exec_init(env); env->pregs[PR_VR] = ccc->vr; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index e2fd6268ef..635f33407e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2164,6 +2164,7 @@ static void x86_cpu_initfn(Object *obj) CPUX86State *env = &cpu->env; static int inited; + cs->env_ptr = env; cpu_exec_init(env); object_property_add(obj, "family", "int", diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index 5f167340e4..a2badb5701 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -56,10 +56,12 @@ static void lm32_cpu_realizefn(DeviceState *dev, Error **errp) static void lm32_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); LM32CPU *cpu = LM32_CPU(obj); CPULM32State *env = &cpu->env; static bool tcg_initialized; + cs->env_ptr = env; cpu_exec_init(env); env->flags = 0; diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 42735dbe40..f5a109854b 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -154,10 +154,12 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp) static void m68k_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); M68kCPU *cpu = M68K_CPU(obj); CPUM68KState *env = &cpu->env; static bool inited; + cs->env_ptr = env; cpu_exec_init(env); if (tcg_enabled() && !inited) { diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 28b5a88789..81359db168 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -98,10 +98,12 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) static void mb_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); CPUMBState *env = &cpu->env; static bool tcg_initialized; + cs->env_ptr = env; cpu_exec_init(env); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 09d61723c5..4d62031c36 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -55,9 +55,11 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) static void mips_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); MIPSCPU *cpu = MIPS_CPU(obj); CPUMIPSState *env = &cpu->env; + cs->env_ptr = env; cpu_exec_init(env); if (tcg_enabled()) { diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index d8cc533efe..72d5e8d2a5 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -75,9 +75,11 @@ static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp) static void openrisc_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); OpenRISCCPU *cpu = OPENRISC_CPU(obj); static int inited; + cs->env_ptr = &cpu->env; cpu_exec_init(&cpu->env); #ifndef CONFIG_USER_ONLY diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5a2acaafe8..5df205757b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10529,11 +10529,13 @@ static void ppc_cpu_reset(CPUState *s) static void ppc_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); PowerPCCPU *cpu = POWERPC_CPU(obj); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; ppc_def_t *def = pcc->info; + cs->env_ptr = env; cpu_exec_init(env); env->msr_mask = def->msr_mask; diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 787c937579..b74654724d 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -110,6 +110,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) static void s390_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); S390CPU *cpu = S390_CPU(obj); CPUS390XState *env = &cpu->env; static bool inited; @@ -118,6 +119,7 @@ static void s390_cpu_initfn(Object *obj) struct tm tm; #endif + cs->env_ptr = env; cpu_exec_init(env); #if !defined(CONFIG_USER_ONLY) qemu_register_reset(s390_cpu_machine_reset_cb, cpu); diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index dc5d7568ea..ef0e62195d 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -67,9 +67,11 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp) static void superh_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); SuperHCPU *cpu = SUPERH_CPU(obj); CPUSH4State *env = &cpu->env; + cs->env_ptr = env; cpu_exec_init(env); env->movcal_backup_tail = &(env->movcal_backup); diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 759be532a3..ef52df6d74 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -860,9 +860,11 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp) static void sparc_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); SPARCCPU *cpu = SPARC_CPU(obj); CPUSPARCState *env = &cpu->env; + cs->env_ptr = env; cpu_exec_init(env); if (tcg_enabled()) { diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 7bcf3b3658..b7024c85bb 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -93,10 +93,12 @@ static void uc32_cpu_realizefn(DeviceState *dev, Error **errp) static void uc32_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); UniCore32CPU *cpu = UNICORE32_CPU(obj); CPUUniCore32State *env = &cpu->env; static bool inited; + cs->env_ptr = env; cpu_exec_init(env); #ifdef CONFIG_USER_ONLY diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 309bb169ec..785e56d367 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -69,10 +69,12 @@ static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) static void xtensa_cpu_initfn(Object *obj) { + CPUState *cs = CPU(obj); XtensaCPU *cpu = XTENSA_CPU(obj); CPUXtensaState *env = &cpu->env; static bool tcg_inited; + cs->env_ptr = env; cpu_exec_init(env); if (tcg_enabled() && !tcg_inited) { From 440c8152bd410b0f928d4de6f187f1e2280e1324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 15 Feb 2013 15:21:13 +0100 Subject: [PATCH 1057/1634] e500: Replace open-coded loop with qemu_get_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we still need env for ppc-specific fields, obtain it via the new env_ptr fields to avoid "cpu" name conflicts between CPUState and PowerPCCPU for now. This fixes a potential issue with env being NULL at the end of the loop but cpu still being a valid pointer corresponding to a previous env. Acked-by: Alexander Graf Signed-off-by: Andreas Färber --- hw/ppc/e500.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index b7474c05f9..451682cb83 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -240,20 +240,15 @@ static int ppce500_load_device_tree(CPUPPCState *env, /* We need to generate the cpu nodes in reverse order, so Linux can pick the first node as boot node and be happy */ for (i = smp_cpus - 1; i >= 0; i--) { - CPUState *cpu = NULL; + CPUState *cpu; char cpu_name[128]; uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); - if (cpu->cpu_index == i) { - break; - } - } - + cpu = qemu_get_cpu(i); if (cpu == NULL) { continue; } + env = cpu->env_ptr; snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", cpu->cpu_index); From 912ebe10eff6cf7e05f908a44283033c1c0270a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 15 Feb 2013 15:56:27 +0100 Subject: [PATCH 1058/1634] ppce500_spin: Replace open-coded CPU loop with qemu_get_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Potentially env could be NULL whereas cpu would still be valid and correspond to a previous env. Wrapping this in qemu_get_cpu(), env is no longer needed, so simplify code that existed before 55e5c2850293547203874098f7cec148ffd12dfa. Acked-by: Alexander Graf Signed-off-by: Andreas Färber --- hw/ppce500_spin.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 7e90fb9824..5bdce52e24 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -123,18 +123,11 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value, { SpinState *s = opaque; int env_idx = addr / sizeof(SpinInfo); - CPUPPCState *env; - CPUState *cpu = NULL; + CPUState *cpu; SpinInfo *curspin = &s->spin[env_idx]; uint8_t *curspin_p = (uint8_t*)curspin; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = CPU(ppc_env_get_cpu(env)); - if (cpu->cpu_index == env_idx) { - break; - } - } - + cpu = qemu_get_cpu(env_idx); if (cpu == NULL) { /* Unknown CPU */ return; @@ -161,11 +154,11 @@ static void spin_write(void *opaque, hwaddr addr, uint64_t value, if (!(ldq_p(&curspin->addr) & 1)) { /* run CPU */ SpinKick kick = { - .cpu = ppc_env_get_cpu(env), + .cpu = POWERPC_CPU(cpu), .spin = curspin, }; - run_on_cpu(CPU(kick.cpu), spin_kick, &kick); + run_on_cpu(cpu, spin_kick, &kick); } } From 5353d03dd7917875b46ff03e0d9e2935770f5e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 15 Feb 2013 16:43:08 +0100 Subject: [PATCH 1059/1634] spapr_hcall: Replace open-coded CPU loop with qemu_get_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper functions all access ppc-specific fields only so don't bother to change arguments to PowerPCCPU and use env_ptr instead. No functional change. Acked-by: Alexander Graf Signed-off-by: Andreas Färber --- hw/spapr_hcall.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index af1db6ea08..7b8959488e 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -469,16 +469,11 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr, CPUPPCState *tenv; CPUState *tcpu; - for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) { - tcpu = CPU(ppc_env_get_cpu(tenv)); - if (tcpu->cpu_index == procno) { - break; - } - } - - if (!tenv) { + tcpu = qemu_get_cpu(procno); + if (!tcpu) { return H_PARAMETER; } + tenv = tcpu->env_ptr; switch (flags) { case FLAGS_REGISTER_VPA: From 0dac84597a66eb8f416972faef451ce786b3cdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 2 Feb 2013 12:10:37 +0100 Subject: [PATCH 1060/1634] target-s390x: Drop unused cpu_s390x_close() prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was never implemented. Signed-off-by: Andreas Färber --- target-s390x/cpu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index fa8dfe0737..e450db74a2 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -315,7 +315,6 @@ static inline int get_ilen(uint8_t opc) S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); int cpu_s390x_exec(CPUS390XState *s); -void cpu_s390x_close(CPUS390XState *s); void do_interrupt (CPUS390XState *env); /* you can call this signal handler from your SIGBUS and SIGSEGV From 0203f86f5205e09a56df41021d872c6353754250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 2 Feb 2013 12:13:15 +0100 Subject: [PATCH 1061/1634] target-lm32: Drop unused cpu_lm32_close() prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was never implemented. Signed-off-by: Andreas Färber --- target-lm32/cpu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 4e202db32c..6948d0e248 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -189,7 +189,6 @@ struct CPULM32State { LM32CPU *cpu_lm32_init(const char *cpu_model); void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf); int cpu_lm32_exec(CPULM32State *s); -void cpu_lm32_close(CPULM32State *s); void do_interrupt(CPULM32State *env); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero From 5c3c6a682dedb3ef6becf112867cf92abf203816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 1 Feb 2013 15:12:13 +0100 Subject: [PATCH 1062/1634] target-i386: Move cpu_x86_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate CPU functions in cpu.c. Allows to make cpu_x86_register() static. No functional changes. Reviewed-by: Eduardo Habkost Reviewed-by: Igor Mammedov Signed-off-by: Andreas Färber --- target-i386/cpu.c | 26 +++++++++++++++++++++++++- target-i386/cpu.h | 1 - target-i386/helper.c | 24 ------------------------ 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 635f33407e..462d6c9c2d 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1516,7 +1516,7 @@ static void filter_features_for_kvm(X86CPU *cpu) } #endif -int cpu_x86_register(X86CPU *cpu, const char *cpu_model) +static int cpu_x86_register(X86CPU *cpu, const char *cpu_model) { CPUX86State *env = &cpu->env; x86_def_t def1, *def = &def1; @@ -1576,6 +1576,30 @@ out: return 0; } +X86CPU *cpu_x86_init(const char *cpu_model) +{ + X86CPU *cpu; + CPUX86State *env; + Error *error = NULL; + + cpu = X86_CPU(object_new(TYPE_X86_CPU)); + env = &cpu->env; + env->cpu_model_str = cpu_model; + + if (cpu_x86_register(cpu, cpu_model) < 0) { + object_unref(OBJECT(cpu)); + return NULL; + } + + object_property_set_bool(OBJECT(cpu), true, "realized", &error); + if (error) { + error_free(error); + object_unref(OBJECT(cpu)); + return NULL; + } + return cpu; +} + #if !defined(CONFIG_USER_ONLY) void cpu_clear_apic_feature(CPUX86State *env) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 9e6e1a652f..7577e4f8bb 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1002,7 +1002,6 @@ int cpu_x86_signal_handler(int host_signum, void *pinfo, void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); -int cpu_x86_register(X86CPU *cpu, const char *cpu_model); void cpu_clear_apic_feature(CPUX86State *env); void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); diff --git a/target-i386/helper.c b/target-i386/helper.c index 1a872fa3d8..4bf9db7f7d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1267,30 +1267,6 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, return 1; } -X86CPU *cpu_x86_init(const char *cpu_model) -{ - X86CPU *cpu; - CPUX86State *env; - Error *error = NULL; - - cpu = X86_CPU(object_new(TYPE_X86_CPU)); - env = &cpu->env; - env->cpu_model_str = cpu_model; - - if (cpu_x86_register(cpu, cpu_model) < 0) { - object_unref(OBJECT(cpu)); - return NULL; - } - - object_property_set_bool(OBJECT(cpu), true, "realized", &error); - if (error) { - error_free(error); - object_unref(OBJECT(cpu)); - return NULL; - } - return cpu; -} - #if !defined(CONFIG_USER_ONLY) void do_cpu_init(X86CPU *cpu) { From 2d64255bd7c0d3933ff5ab2cabff11bcb09117a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 15 Feb 2013 14:06:56 +0100 Subject: [PATCH 1063/1634] target-i386: Split command line parsing out of cpu_x86_register() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to instantiate a CPU subtype we will need to know which type, so move the cpu_model splitting into cpu_x86_init(). Parameters need to be set on the X86CPU instance, so move cpu_x86_parse_featurestr() into cpu_x86_init() as well. This leaves cpu_x86_register() operating on the model name only. Signed-off-by: Andreas Färber Signed-off-by: Igor Mammedov Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/pc.c | 1 - target-i386/cpu.c | 110 +++++++++++++++++++++++----------------------- 2 files changed, 55 insertions(+), 56 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 53cc173eb2..07caba78ba 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -876,7 +876,6 @@ void pc_cpus_init(const char *cpu_model) for (i = 0; i < smp_cpus; i++) { if (!cpu_x86_init(cpu_model)) { - fprintf(stderr, "Unable to find x86 CPU definition\n"); exit(1); } } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 462d6c9c2d..dfcf86e862 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1516,16 +1516,50 @@ static void filter_features_for_kvm(X86CPU *cpu) } #endif -static int cpu_x86_register(X86CPU *cpu, const char *cpu_model) +static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp) { CPUX86State *env = &cpu->env; x86_def_t def1, *def = &def1; - Error *error = NULL; - char *name, *features; - gchar **model_pieces; memset(def, 0, sizeof(*def)); + if (cpu_x86_find_by_name(def, name) < 0) { + error_setg(errp, "Unable to find CPU definition: %s", name); + return; + } + + if (kvm_enabled()) { + def->kvm_features |= kvm_default_features; + } + def->ext_features |= CPUID_EXT_HYPERVISOR; + + object_property_set_str(OBJECT(cpu), def->vendor, "vendor", errp); + object_property_set_int(OBJECT(cpu), def->level, "level", errp); + object_property_set_int(OBJECT(cpu), def->family, "family", errp); + object_property_set_int(OBJECT(cpu), def->model, "model", errp); + object_property_set_int(OBJECT(cpu), def->stepping, "stepping", errp); + env->cpuid_features = def->features; + env->cpuid_ext_features = def->ext_features; + env->cpuid_ext2_features = def->ext2_features; + env->cpuid_ext3_features = def->ext3_features; + object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", errp); + env->cpuid_kvm_features = def->kvm_features; + env->cpuid_svm_features = def->svm_features; + env->cpuid_ext4_features = def->ext4_features; + env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features; + env->cpuid_xlevel2 = def->xlevel2; + + object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp); +} + +X86CPU *cpu_x86_init(const char *cpu_model) +{ + X86CPU *cpu = NULL; + CPUX86State *env; + gchar **model_pieces; + char *name, *features; + Error *error = NULL; + model_pieces = g_strsplit(cpu_model, ",", 2); if (!model_pieces[0]) { error_setg(&error, "Invalid/empty CPU model name"); @@ -1534,68 +1568,34 @@ static int cpu_x86_register(X86CPU *cpu, const char *cpu_model) name = model_pieces[0]; features = model_pieces[1]; - if (cpu_x86_find_by_name(def, name) < 0) { - error_setg(&error, "Unable to find CPU definition: %s", name); - goto out; - } + cpu = X86_CPU(object_new(TYPE_X86_CPU)); + env = &cpu->env; + env->cpu_model_str = cpu_model; - if (kvm_enabled()) { - def->kvm_features |= kvm_default_features; - } - def->ext_features |= CPUID_EXT_HYPERVISOR; - - object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error); - object_property_set_int(OBJECT(cpu), def->level, "level", &error); - object_property_set_int(OBJECT(cpu), def->family, "family", &error); - object_property_set_int(OBJECT(cpu), def->model, "model", &error); - object_property_set_int(OBJECT(cpu), def->stepping, "stepping", &error); - env->cpuid_features = def->features; - env->cpuid_ext_features = def->ext_features; - env->cpuid_ext2_features = def->ext2_features; - env->cpuid_ext3_features = def->ext3_features; - object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", &error); - env->cpuid_kvm_features = def->kvm_features; - env->cpuid_svm_features = def->svm_features; - env->cpuid_ext4_features = def->ext4_features; - env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features; - env->cpuid_xlevel2 = def->xlevel2; - - object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); + cpu_x86_register(cpu, name, &error); if (error) { goto out; } cpu_x86_parse_featurestr(cpu, features, &error); + if (error) { + goto out; + } + + object_property_set_bool(OBJECT(cpu), true, "realized", &error); + if (error) { + goto out; + } + out: g_strfreev(model_pieces); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); error_free(error); - return -1; - } - return 0; -} - -X86CPU *cpu_x86_init(const char *cpu_model) -{ - X86CPU *cpu; - CPUX86State *env; - Error *error = NULL; - - cpu = X86_CPU(object_new(TYPE_X86_CPU)); - env = &cpu->env; - env->cpu_model_str = cpu_model; - - if (cpu_x86_register(cpu, cpu_model) < 0) { - object_unref(OBJECT(cpu)); - return NULL; - } - - object_property_set_bool(OBJECT(cpu), true, "realized", &error); - if (error) { - error_free(error); - object_unref(OBJECT(cpu)); - return NULL; + if (cpu != NULL) { + object_unref(OBJECT(cpu)); + cpu = NULL; + } } return cpu; } From 05499f4b9fd431631299dc1b70156dbc1fb43318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 27 Jan 2013 14:32:05 +0100 Subject: [PATCH 1064/1634] target-sparc: Fix debug output for DEBUG_MMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Färber Acked-by: Edgar E. Iglesias Signed-off-by: Blue Swirl --- target-sparc/ldst_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index cf1bddf2db..7decd66d0b 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -1850,7 +1850,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); #ifdef DEBUG_MMU - dump_mmu(stdout, fprintf, env1); + dump_mmu(stdout, fprintf, env); #endif tlb_flush(env, 1); } From be96bd3fbffde908a392c830c856063e122791c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 16 Feb 2013 23:21:24 +0100 Subject: [PATCH 1065/1634] tcg/ppc: Fix build of tcg_qemu_tb_exec() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0b0d3320db74cde233ee7855ad32a9c121d20eb4 (TCG: Final globals clean-up) moved code_gen_prologue but forgot to update ppc code. This broke the build on 32-bit ppc. ppc64 is unaffected. Cc: Evgeny Voevodin Cc: Blue Swirl Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- tcg/ppc/tcg-target.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index ea26769581..0fdad04ee4 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -99,6 +99,6 @@ typedef enum { #define tcg_qemu_tb_exec(env, tb_ptr) \ ((long __attribute__ ((longcall)) \ - (*)(void *, void *))code_gen_prologue)(env, tb_ptr) + (*)(void *, void *))tcg_ctx.code_gen_prologue)(env, tb_ptr) #endif From f540166b7dfdf4ec2057ac322d8cbfd0691e1d65 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 16 Feb 2013 12:46:59 -0800 Subject: [PATCH 1066/1634] host-utils: Use __int128_t for mul[us]64 Replace some x86_64 specific inline assembly with something that all 64-bit hosts ought to optimize well. At worst this becomes a call to the gcc __multi3 routine, which is no worse than our implementation in util/host-utils.c. With gcc 4.7, we get identical code generation for x86_64. We now get native multiplication on ia64 and s390x hosts. With minor improvements to gcc we can get it for ppc64 as well. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- configure | 20 ++++++++++++++++++++ include/qemu/host-utils.h | 17 ++++++++--------- util/host-utils.c | 4 ++-- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/configure b/configure index 8789324a9b..bf5970f74b 100755 --- a/configure +++ b/configure @@ -3150,6 +3150,22 @@ if compile_prog "" "" ; then cpuid_h=yes fi +######################################## +# check if __[u]int128_t is usable. + +int128=no +cat > $TMPC << EOF +__int128_t a; +__uint128_t b; +int main (void) { + a = a + b; + b = a * b; + return 0; +} +EOF +if compile_prog "" "" ; then + int128=yes +fi ########################################## # End of CC checks @@ -3692,6 +3708,10 @@ if test "$cpuid_h" = "yes" ; then echo "CONFIG_CPUID_H=y" >> $config_host_mak fi +if test "$int128" = "yes" ; then + echo "CONFIG_INT128=y" >> $config_host_mak +fi + if test "$glusterfs" = "yes" ; then echo "CONFIG_GLUSTERFS=y" >> $config_host_mak fi diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index f0dd850e1f..0f688c1c00 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -28,22 +28,21 @@ #include "qemu/compiler.h" /* QEMU_GNUC_PREREQ */ #include -#if defined(__x86_64__) -#define __HAVE_FAST_MULU64__ +#ifdef CONFIG_INT128 static inline void mulu64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { - __asm__ ("mul %0\n\t" - : "=d" (*phigh), "=a" (*plow) - : "a" (a), "0" (b)); + __uint128_t r = (__uint128_t)a * b; + *plow = r; + *phigh = r >> 64; } -#define __HAVE_FAST_MULS64__ + static inline void muls64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) { - __asm__ ("imul %0\n\t" - : "=d" (*phigh), "=a" (*plow) - : "a" (a), "0" (b)); + __int128_t r = (__int128_t)a * b; + *plow = r; + *phigh = r >> 64; } #else void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b); diff --git a/util/host-utils.c b/util/host-utils.c index 5e3915abba..2d06a2cb78 100644 --- a/util/host-utils.c +++ b/util/host-utils.c @@ -30,7 +30,7 @@ //#define DEBUG_MULDIV /* Long integer helpers */ -#if !defined(__x86_64__) +#ifndef CONFIG_INT128 static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { *plow += a; @@ -102,4 +102,4 @@ void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) a, b, *phigh, *plow); #endif } -#endif /* !defined(__x86_64__) */ +#endif /* !CONFIG_INT128 */ From ff7a1eb0a1262f7d451cc1e70c65dd23771ce2a2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 16 Feb 2013 12:47:00 -0800 Subject: [PATCH 1067/1634] host-utils: Improve mulu64 and muls64 The new formulation makes better use of add-with-carry type insns that the host may have. Use gcc's sign adjustment trick to avoid having to perform a 128-bit negation. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- util/host-utils.c | 92 ++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/util/host-utils.c b/util/host-utils.c index 2d06a2cb78..f0784d6335 100644 --- a/util/host-utils.c +++ b/util/host-utils.c @@ -27,79 +27,63 @@ #include #include "qemu/host-utils.h" -//#define DEBUG_MULDIV - /* Long integer helpers */ #ifndef CONFIG_INT128 -static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +static inline void mul64(uint64_t *plow, uint64_t *phigh, + uint64_t a, uint64_t b) { - *plow += a; - /* carry test */ - if (*plow < a) - (*phigh)++; - *phigh += b; -} + typedef union { + uint64_t ll; + struct { +#ifdef HOST_WORDS_BIGENDIAN + uint32_t high, low; +#else + uint32_t low, high; +#endif + } l; + } LL; + LL rl, rm, rn, rh, a0, b0; + uint64_t c; -static void neg128 (uint64_t *plow, uint64_t *phigh) -{ - *plow = ~*plow; - *phigh = ~*phigh; - add128(plow, phigh, 1, 0); -} + a0.ll = a; + b0.ll = b; -static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) -{ - uint32_t a0, a1, b0, b1; - uint64_t v; + rl.ll = (uint64_t)a0.l.low * b0.l.low; + rm.ll = (uint64_t)a0.l.low * b0.l.high; + rn.ll = (uint64_t)a0.l.high * b0.l.low; + rh.ll = (uint64_t)a0.l.high * b0.l.high; - a0 = a; - a1 = a >> 32; + c = (uint64_t)rl.l.high + rm.l.low + rn.l.low; + rl.l.high = c; + c >>= 32; + c = c + rm.l.high + rn.l.high + rh.l.low; + rh.l.low = c; + rh.l.high += (uint32_t)(c >> 32); - b0 = b; - b1 = b >> 32; - - v = (uint64_t)a0 * (uint64_t)b0; - *plow = v; - *phigh = 0; - - v = (uint64_t)a0 * (uint64_t)b1; - add128(plow, phigh, v << 32, v >> 32); - - v = (uint64_t)a1 * (uint64_t)b0; - add128(plow, phigh, v << 32, v >> 32); - - v = (uint64_t)a1 * (uint64_t)b1; - *phigh += v; + *plow = rl.ll; + *phigh = rh.ll; } /* Unsigned 64x64 -> 128 multiplication */ void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) { mul64(plow, phigh, a, b); -#if defined(DEBUG_MULDIV) - printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", - a, b, *phigh, *plow); -#endif } /* Signed 64x64 -> 128 multiplication */ void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b) { - int sa, sb; + uint64_t rh; - sa = (a < 0); - if (sa) - a = -a; - sb = (b < 0); - if (sb) - b = -b; - mul64(plow, phigh, a, b); - if (sa ^ sb) { - neg128(plow, phigh); + mul64(plow, &rh, a, b); + + /* Adjust for signs. */ + if (b < 0) { + rh -= a; } -#if defined(DEBUG_MULDIV) - printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n", - a, b, *phigh, *plow); -#endif + if (a < 0) { + rh -= b; + } + *phigh = rh; } #endif /* !CONFIG_INT128 */ From f4c0f986c061f34fd5b020c30e2aa8c37e17193b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 16 Feb 2013 12:47:01 -0800 Subject: [PATCH 1068/1634] tests: Add unit tests for mulu64 and muls64 Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tests/Makefile | 6 +++- tests/test-mul64.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 tests/test-mul64.c diff --git a/tests/Makefile b/tests/Makefile index a2d62b8596..567e36e777 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -54,6 +54,8 @@ check-unit-y += tests/test-xbzrle$(EXESUF) gcov-files-test-xbzrle-y = xbzrle.c check-unit-y += tests/test-cutils$(EXESUF) gcov-files-test-cutils-y += util/cutils.c +check-unit-y += tests/test-mul64$(EXESUF) +gcov-files-test-mul64-y = util/host-utils.c check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -82,7 +84,7 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \ tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \ tests/test-qmp-commands.o tests/test-visitor-serialization.o \ - tests/test-x86-cpuid.o + tests/test-x86-cpuid.o tests/test-mul64.o test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o @@ -124,6 +126,8 @@ tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi- tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) qapi-types.o qapi-visit.o libqemuutil.a libqemustub.a tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a +tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a + tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/fdc-test$(EXESUF): tests/fdc-test.o diff --git a/tests/test-mul64.c b/tests/test-mul64.c new file mode 100644 index 0000000000..a0a17f7775 --- /dev/null +++ b/tests/test-mul64.c @@ -0,0 +1,70 @@ +/* + * Test 64x64 -> 128 multiply subroutines + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include +#include +#include "qemu/host-utils.h" +#include "qemu/osdep.h" + + +typedef struct { + uint64_t a, b; + uint64_t rh, rl; +} Test; + +static const Test test_u_data[] = { + { 1, 1, 0, 1 }, + { 10000, 10000, 0, 100000000 }, + { 0xffffffffffffffffULL, 2, 1, 0xfffffffffffffffeULL }, + { 0xffffffffffffffffULL, 0xffffffffffffffffULL, + 0xfffffffffffffffeULL, 0x0000000000000001ULL }, + { 0x1122334455667788ull, 0x8877665544332211ull, + 0x092228fb777ae38full, 0x0a3e963337c60008ull }, +}; + +static const Test test_s_data[] = { + { 1, 1, 0, 1 }, + { 1, -1, -1, -1 }, + { -10, -10, 0, 100 }, + { 10000, 10000, 0, 100000000 }, + { -1, 2, -1, -2 }, + { 0x1122334455667788ULL, 0x1122334455667788ULL, + 0x01258f60bbc2975cULL, 0x1eace4a3c82fb840ULL }, +}; + +static void test_u(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(test_u_data); ++i) { + uint64_t rl, rh; + mulu64(&rl, &rh, test_u_data[i].a, test_u_data[i].b); + g_assert_cmpuint(rl, ==, test_u_data[i].rl); + g_assert_cmpuint(rh, ==, test_u_data[i].rh); + } +} + +static void test_s(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(test_s_data); ++i) { + uint64_t rl, rh; + muls64(&rl, &rh, test_s_data[i].a, test_s_data[i].b); + g_assert_cmpuint(rl, ==, test_s_data[i].rl); + g_assert_cmpint(rh, ==, test_s_data[i].rh); + } +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/host-utils/mulu64", test_u); + g_test_add_func("/host-utils/muls64", test_s); + return g_test_run(); +} From 6acf801de5a6e299c02ab3efe3e0dcd75ae678e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 16 Feb 2013 22:44:01 +0100 Subject: [PATCH 1069/1634] libqtest: Convert macros to functions and clean up documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libqtest.h provides a number of shortcut macros to avoid tests feeding it the QTestState they operate on. Most of these can easily be turned into static inline functions, so let's do that for clarity. This avoids getting off-by-one error messages when passing wrong args. Some macros had a val argument but documented @value argument. Fix this. While touching things, enforce gtk-doc markup for return values and for referencing types. Signed-off-by: Andreas Färber Signed-off-by: Andreas Färber Message-id: 1361051043-27944-2-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- tests/libqtest.h | 160 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 50 deletions(-) diff --git a/tests/libqtest.h b/tests/libqtest.h index 110e2ecdaf..a111c9cddb 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -26,12 +26,14 @@ extern QTestState *global_qtest; /** * qtest_init: * @extra_args: other arguments to pass to QEMU. + * + * Returns: #QTestState instance. */ QTestState *qtest_init(const char *extra_args); /** * qtest_quit: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * * Shut down the QEMU process associated to @s. */ @@ -39,7 +41,7 @@ void qtest_quit(QTestState *s); /** * qtest_qmp: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @fmt...: QMP message to send to qemu * * Sends a QMP message to QEMU @@ -48,16 +50,16 @@ void qtest_qmp(QTestState *s, const char *fmt, ...); /** * qtest_get_irq: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @num: Interrupt to observe. * - * Return the level of the @num interrupt. + * Returns: The level of the @num interrupt. */ bool qtest_get_irq(QTestState *s, int num); /** * qtest_irq_intercept_in: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @string: QOM path of a device. * * Associate qtest irqs with the GPIO-in pins of the device @@ -67,7 +69,7 @@ void qtest_irq_intercept_in(QTestState *s, const char *string); /** * qtest_irq_intercept_out: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @string: QOM path of a device. * * Associate qtest irqs with the GPIO-out pins of the device @@ -77,7 +79,7 @@ void qtest_irq_intercept_out(QTestState *s, const char *string); /** * qtest_outb: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: I/O port to write to. * @value: Value being written. * @@ -87,7 +89,7 @@ void qtest_outb(QTestState *s, uint16_t addr, uint8_t value); /** * qtest_outw: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: I/O port to write to. * @value: Value being written. * @@ -97,7 +99,7 @@ void qtest_outw(QTestState *s, uint16_t addr, uint16_t value); /** * qtest_outl: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: I/O port to write to. * @value: Value being written. * @@ -107,7 +109,7 @@ void qtest_outl(QTestState *s, uint16_t addr, uint32_t value); /** * qtest_inb: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: I/O port to read from. * * Returns an 8-bit value from an I/O port. @@ -116,7 +118,7 @@ uint8_t qtest_inb(QTestState *s, uint16_t addr); /** * qtest_inw: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: I/O port to read from. * * Returns a 16-bit value from an I/O port. @@ -125,7 +127,7 @@ uint16_t qtest_inw(QTestState *s, uint16_t addr); /** * qtest_inl: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: I/O port to read from. * * Returns a 32-bit value from an I/O port. @@ -134,7 +136,7 @@ uint32_t qtest_inl(QTestState *s, uint16_t addr); /** * qtest_memread: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: Guest address to read from. * @data: Pointer to where memory contents will be stored. * @size: Number of bytes to read. @@ -145,7 +147,7 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size); /** * qtest_memwrite: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * @addr: Guest address to write to. * @data: Pointer to the bytes that will be written to guest memory. * @size: Number of bytes to write. @@ -156,10 +158,11 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size) /** * qtest_clock_step_next: - * @s: QTestState instance to operate on. + * @s: #QTestState instance to operate on. * - * Advance the vm_clock to the next deadline. Return the current - * value of the vm_clock in nanoseconds. + * Advance the vm_clock to the next deadline. + * + * Returns: The current value of the vm_clock in nanoseconds. */ int64_t qtest_clock_step_next(QTestState *s); @@ -168,8 +171,9 @@ int64_t qtest_clock_step_next(QTestState *s); * @s: QTestState instance to operate on. * @step: Number of nanoseconds to advance the clock by. * - * Advance the vm_clock by @step nanoseconds. Return the current - * value of the vm_clock in nanoseconds. + * Advance the vm_clock by @step nanoseconds. + * + * Returns: The current value of the vm_clock in nanoseconds. */ int64_t qtest_clock_step(QTestState *s, int64_t step); @@ -179,14 +183,15 @@ int64_t qtest_clock_step(QTestState *s, int64_t step); * @val: Nanoseconds value to advance the clock to. * * Advance the vm_clock to @val nanoseconds since the VM was launched. - * Return the current value of the vm_clock in nanoseconds. + * + * Returns: The current value of the vm_clock in nanoseconds. */ int64_t qtest_clock_set(QTestState *s, int64_t val); /** * qtest_get_arch: * - * Returns the architecture for the QEMU executable under test. + * Returns: The architecture for the QEMU executable under test. */ const char *qtest_get_arch(void); @@ -197,7 +202,7 @@ const char *qtest_get_arch(void); * * Add a GTester testcase with the given name and function. * The path is prefixed with the architecture under test, as - * returned by qtest_get_arch. + * returned by qtest_get_arch(). */ void qtest_add_func(const char *str, void (*fn)); @@ -205,12 +210,16 @@ void qtest_add_func(const char *str, void (*fn)); * qtest_start: * @args: other arguments to pass to QEMU * - * Start QEMU and assign the resulting QTestState to a global variable. - * The global variable is used by "shortcut" macros documented below. + * Start QEMU and assign the resulting #QTestState to a global variable. + * The global variable is used by "shortcut" functions documented below. + * + * Returns: #QTestState instance. */ -#define qtest_start(args) ( \ - global_qtest = qtest_init((args)) \ - ) +static inline QTestState *qtest_start(const char *args) +{ + global_qtest = qtest_init(args); + return global_qtest; +} /** * qmp: @@ -224,9 +233,12 @@ void qtest_add_func(const char *str, void (*fn)); * get_irq: * @num: Interrupt to observe. * - * Return the level of the @num interrupt. + * Returns: The level of the @num interrupt. */ -#define get_irq(num) qtest_get_irq(global_qtest, num) +static inline bool get_irq(int num) +{ + return qtest_get_irq(global_qtest, num); +} /** * irq_intercept_in: @@ -235,7 +247,10 @@ void qtest_add_func(const char *str, void (*fn)); * Associate qtest irqs with the GPIO-in pins of the device * whose path is specified by @string. */ -#define irq_intercept_in(string) qtest_irq_intercept_in(global_qtest, string) +static inline void irq_intercept_in(const char *string) +{ + qtest_irq_intercept_in(global_qtest, string); +} /** * qtest_irq_intercept_out: @@ -244,7 +259,10 @@ void qtest_add_func(const char *str, void (*fn)); * Associate qtest irqs with the GPIO-out pins of the device * whose path is specified by @string. */ -#define irq_intercept_out(string) qtest_irq_intercept_out(global_qtest, string) +static inline void irq_intercept_out(const char *string) +{ + qtest_irq_intercept_out(global_qtest, string); +} /** * outb: @@ -253,7 +271,10 @@ void qtest_add_func(const char *str, void (*fn)); * * Write an 8-bit value to an I/O port. */ -#define outb(addr, val) qtest_outb(global_qtest, addr, val) +static inline void outb(uint16_t addr, uint8_t value) +{ + qtest_outb(global_qtest, addr, value); +} /** * outw: @@ -262,7 +283,10 @@ void qtest_add_func(const char *str, void (*fn)); * * Write a 16-bit value to an I/O port. */ -#define outw(addr, val) qtest_outw(global_qtest, addr, val) +static inline void outw(uint16_t addr, uint16_t value) +{ + qtest_outw(global_qtest, addr, value); +} /** * outl: @@ -271,31 +295,49 @@ void qtest_add_func(const char *str, void (*fn)); * * Write a 32-bit value to an I/O port. */ -#define outl(addr, val) qtest_outl(global_qtest, addr, val) +static inline void outl(uint16_t addr, uint32_t value) +{ + qtest_outl(global_qtest, addr, value); +} /** * inb: * @addr: I/O port to read from. * - * Returns an 8-bit value from an I/O port. + * Reads an 8-bit value from an I/O port. + * + * Returns: Value read. */ -#define inb(addr) qtest_inb(global_qtest, addr) +static inline uint8_t inb(uint16_t addr) +{ + return qtest_inb(global_qtest, addr); +} /** * inw: * @addr: I/O port to read from. * - * Returns a 16-bit value from an I/O port. + * Reads a 16-bit value from an I/O port. + * + * Returns: Value read. */ -#define inw(addr) qtest_inw(global_qtest, addr) +static inline uint16_t inw(uint16_t addr) +{ + return qtest_inw(global_qtest, addr); +} /** * inl: * @addr: I/O port to read from. * - * Returns a 32-bit value from an I/O port. + * Reads a 32-bit value from an I/O port. + * + * Returns: Value read. */ -#define inl(addr) qtest_inl(global_qtest, addr) +static inline uint32_t inl(uint16_t addr) +{ + return qtest_inl(global_qtest, addr); +} /** * memread: @@ -305,7 +347,10 @@ void qtest_add_func(const char *str, void (*fn)); * * Read guest memory into a buffer. */ -#define memread(addr, data, size) qtest_memread(global_qtest, addr, data, size) +static inline void memread(uint64_t addr, void *data, size_t size) +{ + qtest_memread(global_qtest, addr, data, size); +} /** * memwrite: @@ -315,32 +360,47 @@ void qtest_add_func(const char *str, void (*fn)); * * Write a buffer to guest memory. */ -#define memwrite(addr, data, size) qtest_memwrite(global_qtest, addr, data, size) +static inline void memwrite(uint64_t addr, const void *data, size_t size) +{ + qtest_memwrite(global_qtest, addr, data, size); +} /** * clock_step_next: * - * Advance the vm_clock to the next deadline. Return the current - * value of the vm_clock in nanoseconds. + * Advance the vm_clock to the next deadline. + * + * Returns: The current value of the vm_clock in nanoseconds. */ -#define clock_step_next() qtest_clock_step_next(global_qtest) +static inline int64_t clock_step_next(void) +{ + return qtest_clock_step_next(global_qtest); +} /** * clock_step: * @step: Number of nanoseconds to advance the clock by. * - * Advance the vm_clock by @step nanoseconds. Return the current - * value of the vm_clock in nanoseconds. + * Advance the vm_clock by @step nanoseconds. + * + * Returns: The current value of the vm_clock in nanoseconds. */ -#define clock_step(step) qtest_clock_step(global_qtest, step) +static inline int64_t clock_step(int64_t step) +{ + return qtest_clock_step(global_qtest, step); +} /** * clock_set: * @val: Nanoseconds value to advance the clock to. * * Advance the vm_clock to @val nanoseconds since the VM was launched. - * Return the current value of the vm_clock in nanoseconds. + * + * Returns: The current value of the vm_clock in nanoseconds. */ -#define clock_set(val) qtest_clock_set(global_qtest, val) +static inline int64_t clock_set(int64_t val) +{ + return qtest_clock_set(global_qtest, val); +} #endif From b73cf9e93f1c7fd6e949f71172c49848b4d70aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 16 Feb 2013 22:44:02 +0100 Subject: [PATCH 1070/1634] libqtest: Introduce qtest_qmpv() and convert remaining macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to convert qmp() macro to an inline function, expose a qtest_qmpv() function, reused by qtest_qmp(). We can't apply GCC_FMT_ATTR() since fdc-test is using zero-length format strings, which would result in warnings treated as errors. Signed-off-by: Andreas Färber Signed-off-by: Andreas Färber Message-id: 1361051043-27944-3-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- tests/libqtest.c | 14 ++++++++++---- tests/libqtest.h | 20 +++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/tests/libqtest.c b/tests/libqtest.c index 762dec4ac0..da58ff5034 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -288,16 +288,13 @@ redo: return words; } -void qtest_qmp(QTestState *s, const char *fmt, ...) +void qtest_qmpv(QTestState *s, const char *fmt, va_list ap) { - va_list ap; bool has_reply = false; int nesting = 0; /* Send QMP request */ - va_start(ap, fmt); socket_sendf(s->qmp_fd, fmt, ap); - va_end(ap); /* Receive reply */ while (!has_reply || nesting > 0) { @@ -326,6 +323,15 @@ void qtest_qmp(QTestState *s, const char *fmt, ...) } } +void qtest_qmp(QTestState *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qtest_qmpv(s, fmt, ap); + va_end(ap); +} + const char *qtest_get_arch(void) { const char *qemu = getenv("QTEST_QEMU_BINARY"); diff --git a/tests/libqtest.h b/tests/libqtest.h index a111c9cddb..f5c6e21d45 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -17,6 +17,7 @@ #include #include +#include #include typedef struct QTestState QTestState; @@ -48,6 +49,16 @@ void qtest_quit(QTestState *s); */ void qtest_qmp(QTestState *s, const char *fmt, ...); +/** + * qtest_qmpv: + * @s: #QTestState instance to operate on. + * @fmt: QMP message to send to QEMU + * @ap: QMP message arguments + * + * Sends a QMP message to QEMU. + */ +void qtest_qmpv(QTestState *s, const char *fmt, va_list ap); + /** * qtest_get_irq: * @s: #QTestState instance to operate on. @@ -227,7 +238,14 @@ static inline QTestState *qtest_start(const char *args) * * Sends a QMP message to QEMU */ -#define qmp(fmt, ...) qtest_qmp(global_qtest, fmt, ## __VA_ARGS__) +static inline void qmp(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qtest_qmpv(global_qtest, fmt, ap); + va_end(ap); +} /** * get_irq: From 872536bf5dfdf207d275cd627caec2aefb68aab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 16 Feb 2013 22:44:03 +0100 Subject: [PATCH 1071/1634] qtest: Add MMIO support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce [qtest_]{read,write}[bwlq]() libqtest functions and corresponding QTest protocol commands to replace local versions in libi2c-omap.c. Also convert m48t59-test's cmos_{read,write}_mmio() to {read,write}b(). Signed-off-by: Andreas Färber Signed-off-by: Andreas Färber Message-id: 1361051043-27944-4-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- Makefile.objs | 1 - Makefile.target | 1 + qtest.c | 81 +++++++++++++++++++ tests/libi2c-omap.c | 23 ------ tests/libqtest.c | 62 +++++++++++++++ tests/libqtest.h | 186 ++++++++++++++++++++++++++++++++++++++++++++ tests/m48t59-test.c | 7 +- 7 files changed, 332 insertions(+), 29 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index 21e9c911f5..a68cdac7ce 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -72,7 +72,6 @@ common-obj-y += ui/ common-obj-y += bt-host.o bt-vhci.o common-obj-y += dma-helpers.o -common-obj-y += qtest.o common-obj-y += vl.o common-obj-$(CONFIG_SLIRP) += slirp/ diff --git a/Makefile.target b/Makefile.target index 760da1edf6..ca657b325a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -109,6 +109,7 @@ CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING) CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y) obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o +obj-y += qtest.o obj-y += hw/ obj-$(CONFIG_KVM) += kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o diff --git a/qtest.c b/qtest.c index 4663a38e11..5e0e9ec791 100644 --- a/qtest.c +++ b/qtest.c @@ -87,6 +87,30 @@ static bool qtest_opened; * > inl ADDR * < OK VALUE * + * > writeb ADDR VALUE + * < OK + * + * > writew ADDR VALUE + * < OK + * + * > writel ADDR VALUE + * < OK + * + * > writeq ADDR VALUE + * < OK + * + * > readb ADDR + * < OK VALUE + * + * > readw ADDR + * < OK VALUE + * + * > readl ADDR + * < OK VALUE + * + * > readq ADDR + * < OK VALUE + * * > read ADDR SIZE * < OK DATA * @@ -277,6 +301,63 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) } qtest_send_prefix(chr); qtest_send(chr, "OK 0x%04x\n", value); + } else if (strcmp(words[0], "writeb") == 0 || + strcmp(words[0], "writew") == 0 || + strcmp(words[0], "writel") == 0 || + strcmp(words[0], "writeq") == 0) { + uint64_t addr; + uint64_t value; + + g_assert(words[1] && words[2]); + addr = strtoull(words[1], NULL, 0); + value = strtoull(words[2], NULL, 0); + + if (words[0][5] == 'b') { + uint8_t data = value; + cpu_physical_memory_write(addr, &data, 1); + } else if (words[0][5] == 'w') { + uint16_t data = value; + tswap16s(&data); + cpu_physical_memory_write(addr, &data, 2); + } else if (words[0][5] == 'l') { + uint32_t data = value; + tswap32s(&data); + cpu_physical_memory_write(addr, &data, 4); + } else if (words[0][5] == 'q') { + uint64_t data = value; + tswap64s(&data); + cpu_physical_memory_write(addr, &data, 8); + } + qtest_send_prefix(chr); + qtest_send(chr, "OK\n"); + } else if (strcmp(words[0], "readb") == 0 || + strcmp(words[0], "readw") == 0 || + strcmp(words[0], "readl") == 0 || + strcmp(words[0], "readq") == 0) { + uint64_t addr; + uint64_t value = UINT64_C(-1); + + g_assert(words[1]); + addr = strtoull(words[1], NULL, 0); + + if (words[0][4] == 'b') { + uint8_t data; + cpu_physical_memory_read(addr, &data, 1); + value = data; + } else if (words[0][4] == 'w') { + uint16_t data; + cpu_physical_memory_read(addr, &data, 2); + value = tswap16(data); + } else if (words[0][4] == 'l') { + uint32_t data; + cpu_physical_memory_read(addr, &data, 4); + value = tswap32(data); + } else if (words[0][4] == 'q') { + cpu_physical_memory_read(addr, &value, 8); + tswap64s(&value); + } + qtest_send_prefix(chr); + qtest_send(chr, "OK 0x%016" PRIx64 "\n", value); } else if (strcmp(words[0], "read") == 0) { uint64_t addr, len, i; uint8_t *data; diff --git a/tests/libi2c-omap.c b/tests/libi2c-omap.c index b7b10b5cbd..c52458cbd6 100644 --- a/tests/libi2c-omap.c +++ b/tests/libi2c-omap.c @@ -49,29 +49,6 @@ typedef struct OMAPI2C { } OMAPI2C; -/* FIXME Use TBD readw qtest API */ -static inline uint16_t readw(uint64_t addr) -{ - uint16_t data; - - memread(addr, &data, 2); - return le16_to_cpu(data); -} - -/* FIXME Use TBD writew qtest API */ -static inline void writew(uint64_t addr, uint16_t data) -{ - data = cpu_to_le16(data); - memwrite(addr, &data, 2); -} - -#ifdef __GNUC__ -#undef memread -#undef memwrite -#pragma GCC poison memread -#pragma GCC poison memwrite -#endif - static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr) { uint16_t data = addr; diff --git a/tests/libqtest.c b/tests/libqtest.c index da58ff5034..389596a055 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -3,10 +3,12 @@ * * Copyright IBM, Corp. 2012 * Copyright Red Hat, Inc. 2012 + * Copyright SUSE LINUX Products GmbH 2013 * * Authors: * Anthony Liguori * Paolo Bonzini + * Andreas Färber * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -437,6 +439,66 @@ uint32_t qtest_inl(QTestState *s, uint16_t addr) return qtest_in(s, "inl", addr); } +static void qtest_write(QTestState *s, const char *cmd, uint64_t addr, + uint64_t value) +{ + qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64 "\n", cmd, addr, value); + qtest_rsp(s, 0); +} + +void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value) +{ + qtest_write(s, "writeb", addr, value); +} + +void qtest_writew(QTestState *s, uint64_t addr, uint16_t value) +{ + qtest_write(s, "writew", addr, value); +} + +void qtest_writel(QTestState *s, uint64_t addr, uint32_t value) +{ + qtest_write(s, "writel", addr, value); +} + +void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value) +{ + qtest_write(s, "writeq", addr, value); +} + +static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr) +{ + gchar **args; + uint64_t value; + + qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr); + args = qtest_rsp(s, 2); + value = strtoull(args[1], NULL, 0); + g_strfreev(args); + + return value; +} + +uint8_t qtest_readb(QTestState *s, uint64_t addr) +{ + return qtest_read(s, "readb", addr); +} + +uint16_t qtest_readw(QTestState *s, uint64_t addr) +{ + return qtest_read(s, "readw", addr); +} + +uint32_t qtest_readl(QTestState *s, uint64_t addr) +{ + return qtest_read(s, "readl", addr); +} + +uint64_t qtest_readq(QTestState *s, uint64_t addr) +{ + return qtest_read(s, "readq", addr); +} + static int hex2nib(char ch) { if (ch >= '0' && ch <= '9') { diff --git a/tests/libqtest.h b/tests/libqtest.h index f5c6e21d45..437bda39f3 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -3,10 +3,12 @@ * * Copyright IBM, Corp. 2012 * Copyright Red Hat, Inc. 2012 + * Copyright SUSE LINUX Products GmbH 2013 * * Authors: * Anthony Liguori * Paolo Bonzini + * Andreas Färber * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -145,6 +147,90 @@ uint16_t qtest_inw(QTestState *s, uint16_t addr); */ uint32_t qtest_inl(QTestState *s, uint16_t addr); +/** + * qtest_writeb: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes an 8-bit value to memory. + */ +void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value); + +/** + * qtest_writew: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 16-bit value to memory. + */ +void qtest_writew(QTestState *s, uint64_t addr, uint16_t value); + +/** + * qtest_writel: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 32-bit value to memory. + */ +void qtest_writel(QTestState *s, uint64_t addr, uint32_t value); + +/** + * qtest_writeq: + * @s: #QTestState instance to operate on. + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 64-bit value to memory. + */ +void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value); + +/** + * qtest_readb: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads an 8-bit value from memory. + * + * Returns: Value read. + */ +uint8_t qtest_readb(QTestState *s, uint64_t addr); + +/** + * qtest_readw: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 16-bit value from memory. + * + * Returns: Value read. + */ +uint16_t qtest_readw(QTestState *s, uint64_t addr); + +/** + * qtest_readl: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 32-bit value from memory. + * + * Returns: Value read. + */ +uint32_t qtest_readl(QTestState *s, uint64_t addr); + +/** + * qtest_readq: + * @s: #QTestState instance to operate on. + * @addr: Guest address to read from. + * + * Reads a 64-bit value from memory. + * + * Returns: Value read. + */ +uint64_t qtest_readq(QTestState *s, uint64_t addr); + /** * qtest_memread: * @s: #QTestState instance to operate on. @@ -357,6 +443,106 @@ static inline uint32_t inl(uint16_t addr) return qtest_inl(global_qtest, addr); } +/** + * writeb: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes an 8-bit value to guest memory. + */ +static inline void writeb(uint64_t addr, uint8_t value) +{ + qtest_writeb(global_qtest, addr, value); +} + +/** + * writew: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 16-bit value to guest memory. + */ +static inline void writew(uint64_t addr, uint16_t value) +{ + qtest_writew(global_qtest, addr, value); +} + +/** + * writel: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 32-bit value to guest memory. + */ +static inline void writel(uint64_t addr, uint32_t value) +{ + qtest_writel(global_qtest, addr, value); +} + +/** + * writeq: + * @addr: Guest address to write to. + * @value: Value being written. + * + * Writes a 64-bit value to guest memory. + */ +static inline void writeq(uint64_t addr, uint64_t value) +{ + qtest_writeq(global_qtest, addr, value); +} + +/** + * readb: + * @addr: Guest address to read from. + * + * Reads an 8-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint8_t readb(uint64_t addr) +{ + return qtest_readb(global_qtest, addr); +} + +/** + * readw: + * @addr: Guest address to read from. + * + * Reads a 16-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint16_t readw(uint64_t addr) +{ + return qtest_readw(global_qtest, addr); +} + +/** + * readl: + * @addr: Guest address to read from. + * + * Reads a 32-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint32_t readl(uint64_t addr) +{ + return qtest_readl(global_qtest, addr); +} + +/** + * readq: + * @addr: Guest address to read from. + * + * Reads a 64-bit value from guest memory. + * + * Returns: Value read. + */ +static inline uint64_t readq(uint64_t addr) +{ + return qtest_readq(global_qtest, addr); +} + /** * memread: * @addr: Guest address to read from. diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c index 77d69b330d..4081a5fdb2 100644 --- a/tests/m48t59-test.c +++ b/tests/m48t59-test.c @@ -35,17 +35,14 @@ static bool use_mmio; static uint8_t cmos_read_mmio(uint8_t reg) { - uint8_t data; - - memread(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1); - return data; + return readb(base + (uint32_t)reg_base + (uint32_t)reg); } static void cmos_write_mmio(uint8_t reg, uint8_t val) { uint8_t data = val; - memwrite(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1); + writeb(base + (uint32_t)reg_base + (uint32_t)reg, data); } static uint8_t cmos_read_ioio(uint8_t reg) From c538ca66ffec97432057d3fe1aa5a4bb417ae9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 16 Feb 2013 11:27:26 +0100 Subject: [PATCH 1072/1634] isa: Split off instance_init for ISADevice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepares for assigning IRQs before QOM realize. Signed-off-by: Andreas Färber Signed-off-by: Andreas Färber Message-id: 1361010446-1427-1-git-send-email-afaerber@suse.de Signed-off-by: Anthony Liguori --- hw/isa-bus.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/isa-bus.c b/hw/isa-bus.c index fce311bc2a..6dc34f09f3 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -124,9 +124,6 @@ static int isa_qdev_init(DeviceState *qdev) ISADevice *dev = ISA_DEVICE(qdev); ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev); - dev->isairq[0] = -1; - dev->isairq[1] = -1; - if (klass->init) { return klass->init(dev); } @@ -134,6 +131,14 @@ static int isa_qdev_init(DeviceState *qdev) return 0; } +static void isa_device_init(Object *obj) +{ + ISADevice *dev = ISA_DEVICE(obj); + + dev->isairq[0] = -1; + dev->isairq[1] = -1; +} + ISADevice *isa_create(ISABus *bus, const char *name) { DeviceState *dev; @@ -233,6 +238,7 @@ static const TypeInfo isa_device_type_info = { .name = TYPE_ISA_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(ISADevice), + .instance_init = isa_device_init, .abstract = true, .class_size = sizeof(ISADeviceClass), .class_init = isa_device_class_init, From 31e70d6c12d8f0170d7eeb56fa8275a9cc77c4a4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 19:49:37 +0100 Subject: [PATCH 1073/1634] help: Drop bogus help on -qtest and -qtest-log Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-id: 1360781383-28635-2-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 9d7131aa0f..7fc4af9be9 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2928,13 +2928,9 @@ the @var{simple} tracing backend. @end table ETEXI -DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, - "-qtest CHR specify tracing options\n", - QEMU_ARCH_ALL) - -DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, - "-qtest-log LOG specify tracing options\n", - QEMU_ARCH_ALL) +HXCOMM Internal use +DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL) +DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL) #ifdef __linux__ DEF("enable-fips", 0, QEMU_OPTION_enablefips, From b8f490eb271cf07f491f05e11e3a3a4e7fde9f70 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 19:49:38 +0100 Subject: [PATCH 1074/1634] doc: Fix some option entries in qemu-doc's function index Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-id: 1360781383-28635-3-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 7fc4af9be9..f7d8482310 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -446,6 +446,7 @@ DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath, "-mem-path FILE provide backing storage for guest RAM\n", QEMU_ARCH_ALL) STEXI @item -mem-path @var{path} +@findex -mem-path Allocate guest RAM from a temporarily created file in @var{path}. ETEXI @@ -455,6 +456,7 @@ DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc, QEMU_ARCH_ALL) STEXI @item -mem-prealloc +@findex -mem-prealloc Preallocate memory when using -mem-path. ETEXI #endif @@ -827,7 +829,7 @@ DEF("curses", 0, QEMU_OPTION_curses, QEMU_ARCH_ALL) STEXI @item -curses -@findex curses +@findex -curses Normally, QEMU uses SDL to display the VGA output. With this option, QEMU can display the VGA output when in text mode using a curses/ncurses interface. Nothing is displayed in graphical mode. @@ -1294,7 +1296,6 @@ STEXI Load SMBIOS entry from binary file. @item -smbios type=0[,vendor=@var{str}][,version=@var{str}][,date=@var{str}][,release=@var{%d.%d}] -@findex -smbios Specify SMBIOS type 0 fields @item -smbios type=1[,manufacturer=@var{str}][,product=@var{str}] [,version=@var{str}][,serial=@var{str}][,uuid=@var{uuid}][,sku=@var{str}] [,family=@var{str}] @@ -1409,6 +1410,7 @@ Not all devices are supported on all targets. Use @code{-net nic,model=help} for a list of available devices for your target. @item -netdev user,id=@var{id}[,@var{option}][,@var{option}][,...] +@findex -netdev @item -net user[,@var{option}][,@var{option}][,...] Use the user mode network stack which requires no administrator privilege to run. Valid options are: @@ -2709,6 +2711,7 @@ DEF("watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action, \ QEMU_ARCH_ALL) STEXI @item -watchdog-action @var{action} +@findex -watchdog-action The @var{action} controls what QEMU will do when the watchdog timer expires. From 6265c43b0c872015e4331d3a93ff99946f3edb01 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 19:49:39 +0100 Subject: [PATCH 1075/1634] doc: Fill some option doc gaps in manual page and qemu-doc Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-id: 1360781383-28635-4-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index f7d8482310..e33cdc9f5e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -326,9 +326,9 @@ DEF("set", HAS_ARG, QEMU_OPTION_set, " set parameter for item of type \n" " i.e. -set drive.$id.file=/path/to/image\n", QEMU_ARCH_ALL) STEXI -@item -set +@item -set @var{group}.@var{id}.@var{arg}=@var{value} @findex -set -TODO +Set parameter @var{arg} for item @var{id} of type @var{group}\n" ETEXI DEF("global", HAS_ARG, QEMU_OPTION_global, @@ -1000,7 +1000,7 @@ DEF("rotate", HAS_ARG, QEMU_OPTION_rotate, "-rotate rotate graphical output some deg left (only PXA LCD)\n", QEMU_ARCH_ALL) STEXI -@item -rotate +@item -rotate @var{deg} @findex -rotate Rotate graphical output some deg left (only PXA LCD). ETEXI @@ -2858,7 +2858,7 @@ DEF("sandbox", HAS_ARG, QEMU_OPTION_sandbox, \ "-sandbox Enable seccomp mode 2 system call filter (default 'off').\n", QEMU_ARCH_ALL) STEXI -@item -sandbox +@item -sandbox @var{arg} @findex -sandbox Enable Seccomp mode 2 system call filter. 'on' will enable syscall filtering and 'off' will disable it. The default is 'off'. @@ -2969,6 +2969,14 @@ DEF("object", HAS_ARG, QEMU_OPTION_object, " property must be set. These objects are placed in the\n" " '/objects' path.\n", QEMU_ARCH_ALL) +STEXI +@item -object @var{typename}[,@var{prop1}=@var{value1},...] +@findex -object +Create an new object of type @var{typename} setting properties +in the order they are specified. Note that the 'id' +property must be set. These objects are placed in the +'/objects' path. +ETEXI HXCOMM This is the last statement. Insert new options before this line! STEXI From c70a01e449536c616c85ab820c6fbad7d7e9cf39 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 19:49:40 +0100 Subject: [PATCH 1076/1634] doc: Fix texinfo @table markup in qemu-options.hx End tables before headings, start new ones afterwards. Fixes incorrect indentation of headings "File system options" and "Virtual File system pass-through options" in manual page and qemu-doc. Normalize markup some to increase chances it survives future edits. Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-id: 1360781383-28635-5-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 60 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index e33cdc9f5e..8c435cd35d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -539,13 +539,15 @@ STEXI @end table ETEXI +STEXI +USB options: +@table @option +ETEXI + DEF("usb", 0, QEMU_OPTION_usb, "-usb enable the USB driver (will be the default soon)\n", QEMU_ARCH_ALL) STEXI -USB options: -@table @option - @item -usb @findex -usb Enable the USB driver (will be the default soon) @@ -612,9 +614,15 @@ possible drivers and properties, use @code{-device help} and @code{-device @var{driver},help}. ETEXI +STEXI +@end table +ETEXI DEFHEADING() DEFHEADING(File system options:) +STEXI +@table @option +ETEXI DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev, "-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n" @@ -678,9 +686,15 @@ Specifies the tag name to be used by the guest to mount this export point ETEXI +STEXI +@end table +ETEXI DEFHEADING() DEFHEADING(Virtual File system pass-through options:) +STEXI +@table @option +ETEXI DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs, "-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n" @@ -771,11 +785,9 @@ ETEXI STEXI @end table ETEXI - DEFHEADING() DEFHEADING(Display options:) - STEXI @table @option ETEXI @@ -1217,7 +1229,6 @@ ETEXI STEXI @end table ETEXI - ARCHHEADING(, QEMU_ARCH_I386) ARCHHEADING(i386 target only:, QEMU_ARCH_I386) @@ -1302,10 +1313,10 @@ Specify SMBIOS type 0 fields Specify SMBIOS type 1 fields ETEXI -DEFHEADING() STEXI @end table ETEXI +DEFHEADING() DEFHEADING(Network options:) STEXI @@ -1720,13 +1731,19 @@ libpcap, so it can be analyzed with tools such as tcpdump or Wireshark. Indicate that no network devices should be configured. It is used to override the default configuration (@option{-net nic -net user}) which is activated if no @option{-net} options are provided. - -@end table ETEXI +STEXI +@end table +ETEXI DEFHEADING() DEFHEADING(Character device options:) +STEXI + +The general form of a character device option is: +@table @option +ETEXI DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev null,id=id[,mux=on|off]\n" @@ -1768,10 +1785,6 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, ) STEXI - -The general form of a character device option is: -@table @option - @item -chardev @var{backend} ,id=@var{id} [,mux=on|off] [,@var{options}] @findex -chardev Backend is one of: @@ -1992,14 +2005,15 @@ Connect to a spice virtual machine channel, such as vdiport. Connect to a spice port, allowing a Spice client to handle the traffic identified by a name (preferably a fqdn). - -@end table ETEXI +STEXI +@end table +ETEXI DEFHEADING() -STEXI DEFHEADING(Device URL Syntax:) +STEXI In addition to using normal file images for the emulated storage devices, QEMU can also use networked resources such as iSCSI devices. These are @@ -2115,10 +2129,16 @@ qemu-system-x86_84 --drive file=gluster://192.0.2.1/testvol/a.img @end example See also @url{http://www.gluster.org}. +ETEXI + +STEXI @end table ETEXI DEFHEADING(Bluetooth(R) options:) +STEXI +@table @option +ETEXI DEF("bt", HAS_ARG, QEMU_OPTION_bt, \ "-bt hci,null dumb bluetooth HCI - doesn't respond to commands\n" \ @@ -2132,8 +2152,6 @@ DEF("bt", HAS_ARG, QEMU_OPTION_bt, \ " emulate a bluetooth device 'dev' in scatternet 'n'\n", QEMU_ARCH_ALL) STEXI -@table @option - @item -bt hci[...] @findex -bt Defines the function of the corresponding Bluetooth HCI. -bt options @@ -2185,9 +2203,11 @@ currently: @item keyboard Virtual wireless keyboard implementing the HIDP bluetooth profile. @end table -@end table ETEXI +STEXI +@end table +ETEXI DEFHEADING() DEFHEADING(Linux/Multiboot boot specific:) @@ -2244,11 +2264,9 @@ ETEXI STEXI @end table ETEXI - DEFHEADING() DEFHEADING(Debug/Expert options:) - STEXI @table @option ETEXI From f037809907bcc51295a471ad66b14e90f22d8caa Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 19:49:41 +0100 Subject: [PATCH 1077/1634] help: Fix markup of heading "USB options" so it appears in -help Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-id: 1360781383-28635-6-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index 8c435cd35d..ce9602fec7 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -538,9 +538,10 @@ ETEXI STEXI @end table ETEXI +DEFHEADING() +DEFHEADING(USB options:) STEXI -USB options: @table @option ETEXI From 84644c451ce7cf8e3cf027501f0f44041f8c6972 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 19:49:42 +0100 Subject: [PATCH 1078/1634] doc help: A few options are under inappropriate headings, fix --device is under heading "USB options". --name and --uuid are under "Virtual File system pass-through options". Move all three to "Standard options". Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-id: 1360781383-28635-7-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 80 ++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index ce9602fec7..27c9e612a3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -535,6 +535,45 @@ Enable virtio balloon device (default), optionally with PCI address @var{addr}. ETEXI +DEF("device", HAS_ARG, QEMU_OPTION_device, + "-device driver[,prop[=value][,...]]\n" + " add device (based on driver)\n" + " prop=value,... sets driver properties\n" + " use '-device help' to print all possible drivers\n" + " use '-device driver,help' to print all possible properties\n", + QEMU_ARCH_ALL) +STEXI +@item -device @var{driver}[,@var{prop}[=@var{value}][,...]] +@findex -device +Add device @var{driver}. @var{prop}=@var{value} sets driver +properties. Valid properties depend on the driver. To get help on +possible drivers and properties, use @code{-device help} and +@code{-device @var{driver},help}. +ETEXI + +DEF("name", HAS_ARG, QEMU_OPTION_name, + "-name string1[,process=string2]\n" + " set the name of the guest\n" + " string1 sets the window title and string2 the process name (on Linux)\n", + QEMU_ARCH_ALL) +STEXI +@item -name @var{name} +@findex -name +Sets the @var{name} of the guest. +This name will be displayed in the SDL window caption. +The @var{name} will also be used for the VNC server. +Also optionally set the top visible process name in Linux. +ETEXI + +DEF("uuid", HAS_ARG, QEMU_OPTION_uuid, + "-uuid %08x-%04x-%04x-%04x-%012x\n" + " specify machine UUID\n", QEMU_ARCH_ALL) +STEXI +@item -uuid @var{uuid} +@findex -uuid +Set system UUID. +ETEXI + STEXI @end table ETEXI @@ -599,22 +638,6 @@ Network adapter that supports CDC ethernet and RNDIS protocols. @end table ETEXI -DEF("device", HAS_ARG, QEMU_OPTION_device, - "-device driver[,prop[=value][,...]]\n" - " add device (based on driver)\n" - " prop=value,... sets driver properties\n" - " use '-device help' to print all possible drivers\n" - " use '-device driver,help' to print all possible properties\n", - QEMU_ARCH_ALL) -STEXI -@item -device @var{driver}[,@var{prop}[=@var{value}][,...]] -@findex -device -Add device @var{driver}. @var{prop}=@var{value} sets driver -properties. Valid properties depend on the driver. To get help on -possible drivers and properties, use @code{-device help} and -@code{-device @var{driver},help}. -ETEXI - STEXI @end table ETEXI @@ -758,31 +781,6 @@ STEXI Create synthetic file system image ETEXI -DEFHEADING() - -DEF("name", HAS_ARG, QEMU_OPTION_name, - "-name string1[,process=string2]\n" - " set the name of the guest\n" - " string1 sets the window title and string2 the process name (on Linux)\n", - QEMU_ARCH_ALL) -STEXI -@item -name @var{name} -@findex -name -Sets the @var{name} of the guest. -This name will be displayed in the SDL window caption. -The @var{name} will also be used for the VNC server. -Also optionally set the top visible process name in Linux. -ETEXI - -DEF("uuid", HAS_ARG, QEMU_OPTION_uuid, - "-uuid %08x-%04x-%04x-%04x-%012x\n" - " specify machine UUID\n", QEMU_ARCH_ALL) -STEXI -@item -uuid @var{uuid} -@findex -uuid -Set system UUID. -ETEXI - STEXI @end table ETEXI From 10adb8be87c315573a5bf9f5bda885f25da28ce6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 13 Feb 2013 19:49:43 +0100 Subject: [PATCH 1079/1634] doc help: Collect block device stuff under its own heading Collect them from "Standard options", "File system options", "Virtual File system pass-through options", "Debug/Expert options". Signed-off-by: Markus Armbruster Reviewed-by: Stefan Hajnoczi Message-id: 1360781383-28635-8-git-send-email-armbru@redhat.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 670 ++++++++++++++++++++++++------------------------ 1 file changed, 330 insertions(+), 340 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 27c9e612a3..4bc9c85d9e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -103,6 +103,261 @@ Simulate a multi node NUMA system. If mem and cpus are omitted, resources are split equally. ETEXI +DEF("add-fd", HAS_ARG, QEMU_OPTION_add_fd, + "-add-fd fd=fd,set=set[,opaque=opaque]\n" + " Add 'fd' to fd 'set'\n", QEMU_ARCH_ALL) +STEXI +@item -add-fd fd=@var{fd},set=@var{set}[,opaque=@var{opaque}] +@findex -add-fd + +Add a file descriptor to an fd set. Valid options are: + +@table @option +@item fd=@var{fd} +This option defines the file descriptor of which a duplicate is added to fd set. +The file descriptor cannot be stdin, stdout, or stderr. +@item set=@var{set} +This option defines the ID of the fd set to add the file descriptor to. +@item opaque=@var{opaque} +This option defines a free-form string that can be used to describe @var{fd}. +@end table + +You can open an image using pre-opened file descriptors from an fd set: +@example +qemu-system-i386 +-add-fd fd=3,set=2,opaque="rdwr:/path/to/file" +-add-fd fd=4,set=2,opaque="rdonly:/path/to/file" +-drive file=/dev/fdset/2,index=0,media=disk +@end example +ETEXI + +DEF("set", HAS_ARG, QEMU_OPTION_set, + "-set group.id.arg=value\n" + " set parameter for item of type \n" + " i.e. -set drive.$id.file=/path/to/image\n", QEMU_ARCH_ALL) +STEXI +@item -set @var{group}.@var{id}.@var{arg}=@var{value} +@findex -set +Set parameter @var{arg} for item @var{id} of type @var{group}\n" +ETEXI + +DEF("global", HAS_ARG, QEMU_OPTION_global, + "-global driver.prop=value\n" + " set a global default for a driver property\n", + QEMU_ARCH_ALL) +STEXI +@item -global @var{driver}.@var{prop}=@var{value} +@findex -global +Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.: + +@example +qemu-system-i386 -global ide-drive.physical_block_size=4096 -drive file=file,if=ide,index=0,media=disk +@end example + +In particular, you can use this to set driver properties for devices which are +created automatically by the machine model. To create a device which is not +created automatically and set properties on it, use -@option{device}. +ETEXI + +DEF("boot", HAS_ARG, QEMU_OPTION_boot, + "-boot [order=drives][,once=drives][,menu=on|off]\n" + " [,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_time]\n" + " 'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n" + " 'sp_name': the file's name that would be passed to bios as logo picture, if menu=on\n" + " 'sp_time': the period that splash picture last if menu=on, unit is ms\n" + " 'rb_timeout': the timeout before guest reboot when boot failed, unit is ms\n", + QEMU_ARCH_ALL) +STEXI +@item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off][,splash=@var{sp_name}][,splash-time=@var{sp_time}][,reboot-timeout=@var{rb_timeout}] +@findex -boot +Specify boot order @var{drives} as a string of drive letters. Valid +drive letters depend on the target achitecture. The x86 PC uses: a, b +(floppy 1 and 2), c (first hard disk), d (first CD-ROM), n-p (Etherboot +from network adapter 1-4), hard disk boot is the default. To apply a +particular boot order only on the first startup, specify it via +@option{once}. + +Interactive boot menus/prompts can be enabled via @option{menu=on} as far +as firmware/BIOS supports them. The default is non-interactive boot. + +A splash picture could be passed to bios, enabling user to show it as logo, +when option splash=@var{sp_name} is given and menu=on, If firmware/BIOS +supports them. Currently Seabios for X86 system support it. +limitation: The splash file could be a jpeg file or a BMP file in 24 BPP +format(true color). The resolution should be supported by the SVGA mode, so +the recommended is 320x240, 640x480, 800x640. + +A timeout could be passed to bios, guest will pause for @var{rb_timeout} ms +when boot failed, then reboot. If @var{rb_timeout} is '-1', guest will not +reboot, qemu passes '-1' to bios by default. Currently Seabios for X86 +system support it. + +@example +# try to boot from network first, then from hard disk +qemu-system-i386 -boot order=nc +# boot from CD-ROM first, switch back to default order after reboot +qemu-system-i386 -boot once=d +# boot with a splash picture for 5 seconds. +qemu-system-i386 -boot menu=on,splash=/root/boot.bmp,splash-time=5000 +@end example + +Note: The legacy format '-boot @var{drives}' is still supported but its +use is discouraged as it may be removed from future versions. +ETEXI + +DEF("m", HAS_ARG, QEMU_OPTION_m, + "-m megs set virtual RAM size to megs MB [default=" + stringify(DEFAULT_RAM_SIZE) "]\n", QEMU_ARCH_ALL) +STEXI +@item -m @var{megs} +@findex -m +Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. Optionally, +a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or +gigabytes respectively. +ETEXI + +DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath, + "-mem-path FILE provide backing storage for guest RAM\n", QEMU_ARCH_ALL) +STEXI +@item -mem-path @var{path} +@findex -mem-path +Allocate guest RAM from a temporarily created file in @var{path}. +ETEXI + +#ifdef MAP_POPULATE +DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc, + "-mem-prealloc preallocate guest memory (use with -mem-path)\n", + QEMU_ARCH_ALL) +STEXI +@item -mem-prealloc +@findex -mem-prealloc +Preallocate memory when using -mem-path. +ETEXI +#endif + +DEF("k", HAS_ARG, QEMU_OPTION_k, + "-k language use keyboard layout (for example 'fr' for French)\n", + QEMU_ARCH_ALL) +STEXI +@item -k @var{language} +@findex -k +Use keyboard layout @var{language} (for example @code{fr} for +French). This option is only needed where it is not easy to get raw PC +keycodes (e.g. on Macs, with some X11 servers or with a VNC +display). You don't normally need to use it on PC/Linux or PC/Windows +hosts. + +The available layouts are: +@example +ar de-ch es fo fr-ca hu ja mk no pt-br sv +da en-gb et fr fr-ch is lt nl pl ru th +de en-us fi fr-be hr it lv nl-be pt sl tr +@end example + +The default is @code{en-us}. +ETEXI + + +DEF("audio-help", 0, QEMU_OPTION_audio_help, + "-audio-help print list of audio drivers and their options\n", + QEMU_ARCH_ALL) +STEXI +@item -audio-help +@findex -audio-help +Will show the audio subsystem help: list of drivers, tunable +parameters. +ETEXI + +DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw, + "-soundhw c1,... enable audio support\n" + " and only specified sound cards (comma separated list)\n" + " use '-soundhw help' to get the list of supported cards\n" + " use '-soundhw all' to enable all of them\n", QEMU_ARCH_ALL) +STEXI +@item -soundhw @var{card1}[,@var{card2},...] or -soundhw all +@findex -soundhw +Enable audio and selected sound hardware. Use 'help' to print all +available sound hardware. + +@example +qemu-system-i386 -soundhw sb16,adlib disk.img +qemu-system-i386 -soundhw es1370 disk.img +qemu-system-i386 -soundhw ac97 disk.img +qemu-system-i386 -soundhw hda disk.img +qemu-system-i386 -soundhw all disk.img +qemu-system-i386 -soundhw help +@end example + +Note that Linux's i810_audio OSS kernel (for AC97) module might +require manually specifying clocking. + +@example +modprobe i810_audio clocking=48000 +@end example +ETEXI + +DEF("balloon", HAS_ARG, QEMU_OPTION_balloon, + "-balloon none disable balloon device\n" + "-balloon virtio[,addr=str]\n" + " enable virtio balloon device (default)\n", QEMU_ARCH_ALL) +STEXI +@item -balloon none +@findex -balloon +Disable balloon device. +@item -balloon virtio[,addr=@var{addr}] +Enable virtio balloon device (default), optionally with PCI address +@var{addr}. +ETEXI + +DEF("device", HAS_ARG, QEMU_OPTION_device, + "-device driver[,prop[=value][,...]]\n" + " add device (based on driver)\n" + " prop=value,... sets driver properties\n" + " use '-device help' to print all possible drivers\n" + " use '-device driver,help' to print all possible properties\n", + QEMU_ARCH_ALL) +STEXI +@item -device @var{driver}[,@var{prop}[=@var{value}][,...]] +@findex -device +Add device @var{driver}. @var{prop}=@var{value} sets driver +properties. Valid properties depend on the driver. To get help on +possible drivers and properties, use @code{-device help} and +@code{-device @var{driver},help}. +ETEXI + +DEF("name", HAS_ARG, QEMU_OPTION_name, + "-name string1[,process=string2]\n" + " set the name of the guest\n" + " string1 sets the window title and string2 the process name (on Linux)\n", + QEMU_ARCH_ALL) +STEXI +@item -name @var{name} +@findex -name +Sets the @var{name} of the guest. +This name will be displayed in the SDL window caption. +The @var{name} will also be used for the VNC server. +Also optionally set the top visible process name in Linux. +ETEXI + +DEF("uuid", HAS_ARG, QEMU_OPTION_uuid, + "-uuid %08x-%04x-%04x-%04x-%012x\n" + " specify machine UUID\n", QEMU_ARCH_ALL) +STEXI +@item -uuid @var{uuid} +@findex -uuid +Set system UUID. +ETEXI + +STEXI +@end table +ETEXI +DEFHEADING() + +DEFHEADING(Block device options:) +STEXI +@table @option +ETEXI + DEF("fda", HAS_ARG, QEMU_OPTION_fda, "-fda/-fdb file use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL) DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL) @@ -293,62 +548,6 @@ qemu-system-i386 -hda a -hdb b @end example ETEXI -DEF("add-fd", HAS_ARG, QEMU_OPTION_add_fd, - "-add-fd fd=fd,set=set[,opaque=opaque]\n" - " Add 'fd' to fd 'set'\n", QEMU_ARCH_ALL) -STEXI -@item -add-fd fd=@var{fd},set=@var{set}[,opaque=@var{opaque}] -@findex -add-fd - -Add a file descriptor to an fd set. Valid options are: - -@table @option -@item fd=@var{fd} -This option defines the file descriptor of which a duplicate is added to fd set. -The file descriptor cannot be stdin, stdout, or stderr. -@item set=@var{set} -This option defines the ID of the fd set to add the file descriptor to. -@item opaque=@var{opaque} -This option defines a free-form string that can be used to describe @var{fd}. -@end table - -You can open an image using pre-opened file descriptors from an fd set: -@example -qemu-system-i386 --add-fd fd=3,set=2,opaque="rdwr:/path/to/file" --add-fd fd=4,set=2,opaque="rdonly:/path/to/file" --drive file=/dev/fdset/2,index=0,media=disk -@end example -ETEXI - -DEF("set", HAS_ARG, QEMU_OPTION_set, - "-set group.id.arg=value\n" - " set parameter for item of type \n" - " i.e. -set drive.$id.file=/path/to/image\n", QEMU_ARCH_ALL) -STEXI -@item -set @var{group}.@var{id}.@var{arg}=@var{value} -@findex -set -Set parameter @var{arg} for item @var{id} of type @var{group}\n" -ETEXI - -DEF("global", HAS_ARG, QEMU_OPTION_global, - "-global driver.prop=value\n" - " set a global default for a driver property\n", - QEMU_ARCH_ALL) -STEXI -@item -global @var{driver}.@var{prop}=@var{value} -@findex -global -Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.: - -@example -qemu-system-i386 -global ide-drive.physical_block_size=4096 -drive file=file,if=ide,index=0,media=disk -@end example - -In particular, you can use this to set driver properties for devices which are -created automatically by the machine model. To create a device which is not -created automatically and set properties on it, use -@option{device}. -ETEXI - DEF("mtdblock", HAS_ARG, QEMU_OPTION_mtdblock, "-mtdblock file use 'file' as on-board Flash memory image\n", QEMU_ARCH_ALL) @@ -374,52 +573,6 @@ STEXI Use @var{file} as a parallel flash image. ETEXI -DEF("boot", HAS_ARG, QEMU_OPTION_boot, - "-boot [order=drives][,once=drives][,menu=on|off]\n" - " [,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_time]\n" - " 'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n" - " 'sp_name': the file's name that would be passed to bios as logo picture, if menu=on\n" - " 'sp_time': the period that splash picture last if menu=on, unit is ms\n" - " 'rb_timeout': the timeout before guest reboot when boot failed, unit is ms\n", - QEMU_ARCH_ALL) -STEXI -@item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off][,splash=@var{sp_name}][,splash-time=@var{sp_time}][,reboot-timeout=@var{rb_timeout}] -@findex -boot -Specify boot order @var{drives} as a string of drive letters. Valid -drive letters depend on the target achitecture. The x86 PC uses: a, b -(floppy 1 and 2), c (first hard disk), d (first CD-ROM), n-p (Etherboot -from network adapter 1-4), hard disk boot is the default. To apply a -particular boot order only on the first startup, specify it via -@option{once}. - -Interactive boot menus/prompts can be enabled via @option{menu=on} as far -as firmware/BIOS supports them. The default is non-interactive boot. - -A splash picture could be passed to bios, enabling user to show it as logo, -when option splash=@var{sp_name} is given and menu=on, If firmware/BIOS -supports them. Currently Seabios for X86 system support it. -limitation: The splash file could be a jpeg file or a BMP file in 24 BPP -format(true color). The resolution should be supported by the SVGA mode, so -the recommended is 320x240, 640x480, 800x640. - -A timeout could be passed to bios, guest will pause for @var{rb_timeout} ms -when boot failed, then reboot. If @var{rb_timeout} is '-1', guest will not -reboot, qemu passes '-1' to bios by default. Currently Seabios for X86 -system support it. - -@example -# try to boot from network first, then from hard disk -qemu-system-i386 -boot order=nc -# boot from CD-ROM first, switch back to default order after reboot -qemu-system-i386 -boot once=d -# boot with a splash picture for 5 seconds. -qemu-system-i386 -boot menu=on,splash=/root/boot.bmp,splash-time=5000 -@end example - -Note: The legacy format '-boot @var{drives}' is still supported but its -use is discouraged as it may be removed from future versions. -ETEXI - DEF("snapshot", 0, QEMU_OPTION_snapshot, "-snapshot write to temporary files instead of disk image files\n", QEMU_ARCH_ALL) @@ -431,221 +584,19 @@ the raw disk image you use is not written back. You can however force the write back by pressing @key{C-a s} (@pxref{disk_images}). ETEXI -DEF("m", HAS_ARG, QEMU_OPTION_m, - "-m megs set virtual RAM size to megs MB [default=" - stringify(DEFAULT_RAM_SIZE) "]\n", QEMU_ARCH_ALL) -STEXI -@item -m @var{megs} -@findex -m -Set virtual RAM size to @var{megs} megabytes. Default is 128 MiB. Optionally, -a suffix of ``M'' or ``G'' can be used to signify a value in megabytes or -gigabytes respectively. -ETEXI - -DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath, - "-mem-path FILE provide backing storage for guest RAM\n", QEMU_ARCH_ALL) -STEXI -@item -mem-path @var{path} -@findex -mem-path -Allocate guest RAM from a temporarily created file in @var{path}. -ETEXI - -#ifdef MAP_POPULATE -DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc, - "-mem-prealloc preallocate guest memory (use with -mem-path)\n", +DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \ + "-hdachs c,h,s[,t]\n" \ + " force hard disk 0 physical geometry and the optional BIOS\n" \ + " translation (t=none or lba) (usually QEMU can guess them)\n", QEMU_ARCH_ALL) STEXI -@item -mem-prealloc -@findex -mem-prealloc -Preallocate memory when using -mem-path. -ETEXI -#endif - -DEF("k", HAS_ARG, QEMU_OPTION_k, - "-k language use keyboard layout (for example 'fr' for French)\n", - QEMU_ARCH_ALL) -STEXI -@item -k @var{language} -@findex -k -Use keyboard layout @var{language} (for example @code{fr} for -French). This option is only needed where it is not easy to get raw PC -keycodes (e.g. on Macs, with some X11 servers or with a VNC -display). You don't normally need to use it on PC/Linux or PC/Windows -hosts. - -The available layouts are: -@example -ar de-ch es fo fr-ca hu ja mk no pt-br sv -da en-gb et fr fr-ch is lt nl pl ru th -de en-us fi fr-be hr it lv nl-be pt sl tr -@end example - -The default is @code{en-us}. -ETEXI - - -DEF("audio-help", 0, QEMU_OPTION_audio_help, - "-audio-help print list of audio drivers and their options\n", - QEMU_ARCH_ALL) -STEXI -@item -audio-help -@findex -audio-help -Will show the audio subsystem help: list of drivers, tunable -parameters. -ETEXI - -DEF("soundhw", HAS_ARG, QEMU_OPTION_soundhw, - "-soundhw c1,... enable audio support\n" - " and only specified sound cards (comma separated list)\n" - " use '-soundhw help' to get the list of supported cards\n" - " use '-soundhw all' to enable all of them\n", QEMU_ARCH_ALL) -STEXI -@item -soundhw @var{card1}[,@var{card2},...] or -soundhw all -@findex -soundhw -Enable audio and selected sound hardware. Use 'help' to print all -available sound hardware. - -@example -qemu-system-i386 -soundhw sb16,adlib disk.img -qemu-system-i386 -soundhw es1370 disk.img -qemu-system-i386 -soundhw ac97 disk.img -qemu-system-i386 -soundhw hda disk.img -qemu-system-i386 -soundhw all disk.img -qemu-system-i386 -soundhw help -@end example - -Note that Linux's i810_audio OSS kernel (for AC97) module might -require manually specifying clocking. - -@example -modprobe i810_audio clocking=48000 -@end example -ETEXI - -DEF("balloon", HAS_ARG, QEMU_OPTION_balloon, - "-balloon none disable balloon device\n" - "-balloon virtio[,addr=str]\n" - " enable virtio balloon device (default)\n", QEMU_ARCH_ALL) -STEXI -@item -balloon none -@findex -balloon -Disable balloon device. -@item -balloon virtio[,addr=@var{addr}] -Enable virtio balloon device (default), optionally with PCI address -@var{addr}. -ETEXI - -DEF("device", HAS_ARG, QEMU_OPTION_device, - "-device driver[,prop[=value][,...]]\n" - " add device (based on driver)\n" - " prop=value,... sets driver properties\n" - " use '-device help' to print all possible drivers\n" - " use '-device driver,help' to print all possible properties\n", - QEMU_ARCH_ALL) -STEXI -@item -device @var{driver}[,@var{prop}[=@var{value}][,...]] -@findex -device -Add device @var{driver}. @var{prop}=@var{value} sets driver -properties. Valid properties depend on the driver. To get help on -possible drivers and properties, use @code{-device help} and -@code{-device @var{driver},help}. -ETEXI - -DEF("name", HAS_ARG, QEMU_OPTION_name, - "-name string1[,process=string2]\n" - " set the name of the guest\n" - " string1 sets the window title and string2 the process name (on Linux)\n", - QEMU_ARCH_ALL) -STEXI -@item -name @var{name} -@findex -name -Sets the @var{name} of the guest. -This name will be displayed in the SDL window caption. -The @var{name} will also be used for the VNC server. -Also optionally set the top visible process name in Linux. -ETEXI - -DEF("uuid", HAS_ARG, QEMU_OPTION_uuid, - "-uuid %08x-%04x-%04x-%04x-%012x\n" - " specify machine UUID\n", QEMU_ARCH_ALL) -STEXI -@item -uuid @var{uuid} -@findex -uuid -Set system UUID. -ETEXI - -STEXI -@end table -ETEXI -DEFHEADING() - -DEFHEADING(USB options:) -STEXI -@table @option -ETEXI - -DEF("usb", 0, QEMU_OPTION_usb, - "-usb enable the USB driver (will be the default soon)\n", - QEMU_ARCH_ALL) -STEXI -@item -usb -@findex -usb -Enable the USB driver (will be the default soon) -ETEXI - -DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice, - "-usbdevice name add the host or guest USB device 'name'\n", - QEMU_ARCH_ALL) -STEXI - -@item -usbdevice @var{devname} -@findex -usbdevice -Add the USB device @var{devname}. @xref{usb_devices}. - -@table @option - -@item mouse -Virtual Mouse. This will override the PS/2 mouse emulation when activated. - -@item tablet -Pointer device that uses absolute coordinates (like a touchscreen). This -means QEMU is able to report the mouse position without having to grab the -mouse. Also overrides the PS/2 mouse emulation when activated. - -@item disk:[format=@var{format}]:@var{file} -Mass storage device based on file. The optional @var{format} argument -will be used rather than detecting the format. Can be used to specifiy -@code{format=raw} to avoid interpreting an untrusted format header. - -@item host:@var{bus}.@var{addr} -Pass through the host device identified by @var{bus}.@var{addr} (Linux only). - -@item host:@var{vendor_id}:@var{product_id} -Pass through the host device identified by @var{vendor_id}:@var{product_id} -(Linux only). - -@item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev} -Serial converter to host character device @var{dev}, see @code{-serial} for the -available devices. - -@item braille -Braille device. This will use BrlAPI to display the braille output on a real -or fake device. - -@item net:@var{options} -Network adapter that supports CDC ethernet and RNDIS protocols. - -@end table -ETEXI - -STEXI -@end table -ETEXI -DEFHEADING() - -DEFHEADING(File system options:) -STEXI -@table @option +@item -hdachs @var{c},@var{h},@var{s},[,@var{t}] +@findex -hdachs +Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= +@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS +translation mode (@var{t}=none, lba or auto). Usually QEMU can guess +all those parameters. This option is useful for old MS-DOS disk +images. ETEXI DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev, @@ -710,16 +661,6 @@ Specifies the tag name to be used by the guest to mount this export point ETEXI -STEXI -@end table -ETEXI -DEFHEADING() - -DEFHEADING(Virtual File system pass-through options:) -STEXI -@table @option -ETEXI - DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs, "-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n" " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n", @@ -786,6 +727,70 @@ STEXI ETEXI DEFHEADING() +DEFHEADING(USB options:) +STEXI +@table @option +ETEXI + +DEF("usb", 0, QEMU_OPTION_usb, + "-usb enable the USB driver (will be the default soon)\n", + QEMU_ARCH_ALL) +STEXI +@item -usb +@findex -usb +Enable the USB driver (will be the default soon) +ETEXI + +DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice, + "-usbdevice name add the host or guest USB device 'name'\n", + QEMU_ARCH_ALL) +STEXI + +@item -usbdevice @var{devname} +@findex -usbdevice +Add the USB device @var{devname}. @xref{usb_devices}. + +@table @option + +@item mouse +Virtual Mouse. This will override the PS/2 mouse emulation when activated. + +@item tablet +Pointer device that uses absolute coordinates (like a touchscreen). This +means QEMU is able to report the mouse position without having to grab the +mouse. Also overrides the PS/2 mouse emulation when activated. + +@item disk:[format=@var{format}]:@var{file} +Mass storage device based on file. The optional @var{format} argument +will be used rather than detecting the format. Can be used to specifiy +@code{format=raw} to avoid interpreting an untrusted format header. + +@item host:@var{bus}.@var{addr} +Pass through the host device identified by @var{bus}.@var{addr} (Linux only). + +@item host:@var{vendor_id}:@var{product_id} +Pass through the host device identified by @var{vendor_id}:@var{product_id} +(Linux only). + +@item serial:[vendorid=@var{vendor_id}][,productid=@var{product_id}]:@var{dev} +Serial converter to host character device @var{dev}, see @code{-serial} for the +available devices. + +@item braille +Braille device. This will use BrlAPI to display the braille output on a real +or fake device. + +@item net:@var{options} +Network adapter that supports CDC ethernet and RNDIS protocols. + +@end table +ETEXI + +STEXI +@end table +ETEXI +DEFHEADING() + DEFHEADING(Display options:) STEXI @table @option @@ -2525,21 +2530,6 @@ STEXI Output log in @var{logfile} instead of /tmp/qemu.log ETEXI -DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \ - "-hdachs c,h,s[,t]\n" \ - " force hard disk 0 physical geometry and the optional BIOS\n" \ - " translation (t=none or lba) (usually QEMU can guess them)\n", - QEMU_ARCH_ALL) -STEXI -@item -hdachs @var{c},@var{h},@var{s},[,@var{t}] -@findex -hdachs -Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= -@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS -translation mode (@var{t}=none, lba or auto). Usually QEMU can guess -all those parameters. This option is useful for old MS-DOS disk -images. -ETEXI - DEF("L", HAS_ARG, QEMU_OPTION_L, \ "-L path set the directory for the BIOS, VGA BIOS and keymaps\n", QEMU_ARCH_ALL) From 7d2a929feba319c18603e324b1750830d6c8b7a1 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Thu, 18 Oct 2012 11:16:58 +0200 Subject: [PATCH 1080/1634] vnc-tls: Fix compilation with newer versions of GNU-TLS In my installation of GNU-TLS (v3.0.23) the type gnutls_anon_server_credentials is marked deprecated, so -Werror breaks compilation. Simply replacing it with the newer ..._t version fixed the compilation on my machine (Slackware 14.0). I cannot tell how far back this "new" type goes, at least the header file in RHEL 5.0 (v1.4.1) seems to have it already. If someone finds a broken distribution, tell me and I insert some compat code. Signed-off-by: Andre Przywara Message-id: 1350551818-14717-1-git-send-email-andre.przywara@amd.com Signed-off-by: Anthony Liguori --- ui/vnc-tls.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/vnc-tls.c b/ui/vnc-tls.c index 56292636d7..8d4cc8e47c 100644 --- a/ui/vnc-tls.c +++ b/ui/vnc-tls.c @@ -99,9 +99,9 @@ static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport, } -static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void) +static gnutls_anon_server_credentials_t vnc_tls_initialize_anon_cred(void) { - gnutls_anon_server_credentials anon_cred; + gnutls_anon_server_credentials_t anon_cred; int ret; if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) { @@ -382,7 +382,7 @@ int vnc_tls_client_setup(struct VncState *vs, } } else { - gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred(); + gnutls_anon_server_credentials_t anon_cred = vnc_tls_initialize_anon_cred(); if (!anon_cred) { gnutls_deinit(vs->tls.session); vs->tls.session = NULL; From f9b3ed401c5cf3df9689f74c15a7b4d91566a3ac Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Jan 2013 17:46:56 +0100 Subject: [PATCH 1081/1634] rtc-test: always set register B in its entirety Eliminate dependencies between one test and the others. Signed-off-by: Paolo Bonzini Message-id: 1357922817-17584-2-git-send-email-pbonzini@redhat.com Signed-off-by: Anthony Liguori --- tests/rtc-test.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/tests/rtc-test.c b/tests/rtc-test.c index 203c0fc363..c55215cd54 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -26,11 +26,6 @@ static int bcd2dec(int value) return (((value >> 4) & 0x0F) * 10) + (value & 0x0F); } -static int dec2bcd(int value) -{ - return ((value / 10) << 4) | (value % 10); -} - static uint8_t cmos_read(uint8_t reg) { outb(base + 0, reg); @@ -184,7 +179,7 @@ static int wiggle = 2; static void set_year_20xx(void) { /* Set BCD mode */ - cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM); + cmos_write(RTC_REG_B, REG_B_24H); cmos_write(RTC_REG_A, 0x76); cmos_write(RTC_YEAR, 0x11); cmos_write(RTC_CENTURY, 0x20); @@ -236,7 +231,7 @@ static void set_year_20xx(void) static void set_year_1980(void) { /* Set BCD mode */ - cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM); + cmos_write(RTC_REG_B, REG_B_24H); cmos_write(RTC_REG_A, 0x76); cmos_write(RTC_YEAR, 0x80); cmos_write(RTC_CENTURY, 0x19); @@ -259,32 +254,17 @@ static void set_year_1980(void) static void bcd_check_time(void) { /* Set BCD mode */ - cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM); + cmos_write(RTC_REG_B, REG_B_24H); check_time(wiggle); } static void dec_check_time(void) { /* Set DEC mode */ - cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM); + cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM); check_time(wiggle); } -static void set_alarm_time(struct tm *tm) -{ - int sec; - - sec = tm->tm_sec; - - if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) { - sec = dec2bcd(sec); - } - - cmos_write(RTC_SECONDS_ALARM, sec); - cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); - cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); -} - static void alarm_time(void) { struct tm now; @@ -295,13 +275,15 @@ static void alarm_time(void) gmtime_r(&ts, &now); /* set DEC mode */ - cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM); + cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM); g_assert(!get_irq(RTC_ISA_IRQ)); cmos_read(RTC_REG_C); now.tm_sec = (now.tm_sec + 2) % 60; - set_alarm_time(&now); + cmos_write(RTC_SECONDS_ALARM, now.tm_sec); + cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); + cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE); for (i = 0; i < 2 + wiggle; i++) { @@ -336,7 +318,7 @@ static void fuzz_registers(void) static void register_b_set_flag(void) { /* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/ - cmos_write(RTC_REG_B, (cmos_read(RTC_REG_B) & ~REG_B_DM) | REG_B_SET); + cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET); cmos_write(RTC_REG_A, 0x76); cmos_write(RTC_YEAR, 0x11); From cc2832a51c8ce43349967ab1b6c7aafd510e55b2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 11 Jan 2013 17:46:57 +0100 Subject: [PATCH 1082/1634] rtc-test: add testcases for alarms in 12hour mode Trying (unsuccessfully) to break the device model as mentioned in https://bugs.launchpad.net/qemu/+bug/1090558. At least if someone tries to fix that, it won't break what works... Signed-off-by: Paolo Bonzini Message-id: 1357922817-17584-3-git-send-email-pbonzini@redhat.com Signed-off-by: Anthony Liguori --- tests/rtc-test.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 199 insertions(+), 3 deletions(-) diff --git a/tests/rtc-test.c b/tests/rtc-test.c index c55215cd54..c5fd042610 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -299,6 +299,197 @@ static void alarm_time(void) g_assert(cmos_read(RTC_REG_C) == 0); } +static void set_time(int mode, int h, int m, int s) +{ + /* set BCD 12 hour mode */ + cmos_write(RTC_REG_B, mode); + + cmos_write(RTC_REG_A, 0x76); + cmos_write(RTC_HOURS, h); + cmos_write(RTC_MINUTES, m); + cmos_write(RTC_SECONDS, s); + cmos_write(RTC_REG_A, 0x26); +} + +#define assert_time(h, m, s) \ + do { \ + g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \ + g_assert_cmpint(cmos_read(RTC_MINUTES), ==, m); \ + g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \ + } while(0) + +static void basic_12h_bcd(void) +{ + /* set BCD 12 hour mode */ + set_time(0, 0x81, 0x59, 0x00); + clock_step(1000000000LL); + assert_time(0x81, 0x59, 0x01); + clock_step(59000000000LL); + assert_time(0x82, 0x00, 0x00); + + /* test BCD wraparound */ + set_time(0, 0x09, 0x59, 0x59); + clock_step(60000000000LL); + assert_time(0x10, 0x00, 0x59); + + /* 12 AM -> 1 AM */ + set_time(0, 0x12, 0x59, 0x59); + clock_step(1000000000LL); + assert_time(0x01, 0x00, 0x00); + + /* 12 PM -> 1 PM */ + set_time(0, 0x92, 0x59, 0x59); + clock_step(1000000000LL); + assert_time(0x81, 0x00, 0x00); + + /* 11 AM -> 12 PM */ + set_time(0, 0x11, 0x59, 0x59); + clock_step(1000000000LL); + assert_time(0x92, 0x00, 0x00); + /* TODO: test day wraparound */ + + /* 11 PM -> 12 AM */ + set_time(0, 0x91, 0x59, 0x59); + clock_step(1000000000LL); + assert_time(0x12, 0x00, 0x00); + /* TODO: test day wraparound */ +} + +static void basic_12h_dec(void) +{ + /* set decimal 12 hour mode */ + set_time(REG_B_DM, 0x81, 59, 0); + clock_step(1000000000LL); + assert_time(0x81, 59, 1); + clock_step(59000000000LL); + assert_time(0x82, 0, 0); + + /* 12 PM -> 1 PM */ + set_time(REG_B_DM, 0x8c, 59, 59); + clock_step(1000000000LL); + assert_time(0x81, 0, 0); + + /* 12 AM -> 1 AM */ + set_time(REG_B_DM, 0x0c, 59, 59); + clock_step(1000000000LL); + assert_time(0x01, 0, 0); + + /* 11 AM -> 12 PM */ + set_time(REG_B_DM, 0x0b, 59, 59); + clock_step(1000000000LL); + assert_time(0x8c, 0, 0); + + /* 11 PM -> 12 AM */ + set_time(REG_B_DM, 0x8b, 59, 59); + clock_step(1000000000LL); + assert_time(0x0c, 0, 0); + /* TODO: test day wraparound */ +} + +static void basic_24h_bcd(void) +{ + /* set BCD 24 hour mode */ + set_time(REG_B_24H, 0x09, 0x59, 0x00); + clock_step(1000000000LL); + assert_time(0x09, 0x59, 0x01); + clock_step(59000000000LL); + assert_time(0x10, 0x00, 0x00); + + /* test BCD wraparound */ + set_time(REG_B_24H, 0x09, 0x59, 0x00); + clock_step(60000000000LL); + assert_time(0x10, 0x00, 0x00); + + /* TODO: test day wraparound */ + set_time(REG_B_24H, 0x23, 0x59, 0x00); + clock_step(60000000000LL); + assert_time(0x00, 0x00, 0x00); +} + +static void basic_24h_dec(void) +{ + /* set decimal 24 hour mode */ + set_time(REG_B_24H | REG_B_DM, 9, 59, 0); + clock_step(1000000000LL); + assert_time(9, 59, 1); + clock_step(59000000000LL); + assert_time(10, 0, 0); + + /* test BCD wraparound */ + set_time(REG_B_24H | REG_B_DM, 9, 59, 0); + clock_step(60000000000LL); + assert_time(10, 0, 0); + + /* TODO: test day wraparound */ + set_time(REG_B_24H | REG_B_DM, 23, 59, 0); + clock_step(60000000000LL); + assert_time(0, 0, 0); +} + +static void am_pm_alarm(void) +{ + cmos_write(RTC_MINUTES_ALARM, 0xC0); + cmos_write(RTC_SECONDS_ALARM, 0xC0); + + /* set BCD 12 hour mode */ + cmos_write(RTC_REG_B, 0); + + /* Set time and alarm hour. */ + cmos_write(RTC_REG_A, 0x76); + cmos_write(RTC_HOURS_ALARM, 0x82); + cmos_write(RTC_HOURS, 0x81); + cmos_write(RTC_MINUTES, 0x59); + cmos_write(RTC_SECONDS, 0x00); + cmos_read(RTC_REG_C); + cmos_write(RTC_REG_A, 0x26); + + /* Check that alarm triggers when AM/PM is set. */ + clock_step(60000000000LL); + g_assert(cmos_read(RTC_HOURS) == 0x82); + g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0); + + /* + * Each of the following two tests takes over 60 seconds due to the time + * needed to report the PIT interrupts. Unfortunately, our PIT device + * model keeps counting even when GATE=0, so we cannot simply disable + * it in main(). + */ + if (g_test_quick()) { + return; + } + + /* set DEC 12 hour mode */ + cmos_write(RTC_REG_B, REG_B_DM); + + /* Set time and alarm hour. */ + cmos_write(RTC_REG_A, 0x76); + cmos_write(RTC_HOURS_ALARM, 0x82); + cmos_write(RTC_HOURS, 3); + cmos_write(RTC_MINUTES, 0); + cmos_write(RTC_SECONDS, 0); + cmos_read(RTC_REG_C); + cmos_write(RTC_REG_A, 0x26); + + /* Check that alarm triggers. */ + clock_step(3600 * 11 * 1000000000LL); + g_assert(cmos_read(RTC_HOURS) == 0x82); + g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0); + + /* Same as above, with inverted HOURS and HOURS_ALARM. */ + cmos_write(RTC_REG_A, 0x76); + cmos_write(RTC_HOURS_ALARM, 2); + cmos_write(RTC_HOURS, 3); + cmos_write(RTC_MINUTES, 0); + cmos_write(RTC_SECONDS, 0); + cmos_read(RTC_REG_C); + cmos_write(RTC_REG_A, 0x26); + + /* Check that alarm does not trigger if hours differ only by AM/PM. */ + clock_step(3600 * 11 * 1000000000LL); + g_assert(cmos_read(RTC_HOURS) == 0x82); + g_assert((cmos_read(RTC_REG_C) & REG_C_AF) == 0); +} + /* success if no crash or abort */ static void fuzz_registers(void) { @@ -364,9 +555,14 @@ int main(int argc, char **argv) s = qtest_start("-display none -rtc clock=vm"); qtest_irq_intercept_in(s, "ioapic"); - qtest_add_func("/rtc/bcd/check-time", bcd_check_time); - qtest_add_func("/rtc/dec/check-time", dec_check_time); - qtest_add_func("/rtc/alarm-time", alarm_time); + qtest_add_func("/rtc/check-time/bcd", bcd_check_time); + qtest_add_func("/rtc/check-time/dec", dec_check_time); + qtest_add_func("/rtc/alarm/interrupt", alarm_time); + qtest_add_func("/rtc/alarm/am-pm", am_pm_alarm); + qtest_add_func("/rtc/basic/dec-24h", basic_24h_dec); + qtest_add_func("/rtc/basic/bcd-24h", basic_24h_bcd); + qtest_add_func("/rtc/basic/dec-12h", basic_12h_dec); + qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd); qtest_add_func("/rtc/set-year/20xx", set_year_20xx); qtest_add_func("/rtc/set-year/1980", set_year_1980); qtest_add_func("/rtc/register_b_set_flag", register_b_set_flag); From 40475087a5ee80f5251dac6087142458d8dc7d99 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 12 Oct 2012 16:40:41 +0200 Subject: [PATCH 1083/1634] test-i386: QEMU_PACKED is not defined here Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- tests/tcg/test-i386.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tcg/test-i386.c b/tests/tcg/test-i386.c index 6dc730d882..b18fe20c76 100644 --- a/tests/tcg/test-i386.c +++ b/tests/tcg/test-i386.c @@ -925,7 +925,7 @@ void test_fbcd(double a) void test_fenv(void) { - struct QEMU_PACKED { + struct __attribute__((__packed__)) { uint16_t fpuc; uint16_t dummy1; uint16_t fpus; @@ -935,7 +935,7 @@ void test_fenv(void) uint32_t ignored[4]; long double fpregs[8]; } float_env32; - struct QEMU_PACKED { + struct __attribute__((__packed__)) { uint16_t fpuc; uint16_t fpus; uint16_t fptag; @@ -1280,7 +1280,7 @@ void test_segs(void) struct { uint32_t offset; uint16_t seg; - } QEMU_PACKED segoff; + } __attribute__((__packed__)) segoff; ldt.entry_number = 1; ldt.base_addr = (unsigned long)&seg_data1; From 1b99f83e3946c447eefb3417ec1ea4c2f3b44582 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 12 Oct 2012 16:40:21 +0200 Subject: [PATCH 1084/1634] test-i386: make it compile with a recent gcc Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- tests/tcg/test-i386.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tcg/test-i386.c b/tests/tcg/test-i386.c index b18fe20c76..b05572b734 100644 --- a/tests/tcg/test-i386.c +++ b/tests/tcg/test-i386.c @@ -209,7 +209,7 @@ static inline long i2l(long v) #define TEST_LEA16(STR)\ {\ asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\ - : "=wq" (res)\ + : "=r" (res)\ : "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\ printf("lea %s = %08lx\n", STR, res);\ } @@ -1828,7 +1828,7 @@ void test_exceptions(void) printf("lock nop exception:\n"); if (setjmp(jmp_env) == 0) { /* now execute an invalid instruction */ - asm volatile(".byte 0xf0, 0x90"); /* lock nop */ + asm volatile(".byte 0xf0, 0x90"); } printf("INT exception:\n"); From 93ab25d7d129fbe47a99fd8c91292ea99bff747e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 6 Oct 2012 01:56:03 +0200 Subject: [PATCH 1085/1634] target-i386: use OT_* consistently Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 88 +++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 112c3102a0..94e14342d3 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -323,17 +323,17 @@ static inline void gen_op_mov_reg_T1(int ot, int reg) static inline void gen_op_mov_reg_A0(int size, int reg) { switch(size) { - case 0: + case OT_BYTE: tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_A0, 0, 16); break; default: /* XXX this shouldn't be reached; abort? */ - case 1: + case OT_WORD: /* For x86_64, this sets the higher half of register to zero. For i386, this is equivalent to a mov. */ tcg_gen_ext32u_tl(cpu_regs[reg], cpu_A0); break; #ifdef TARGET_X86_64 - case 2: + case OT_LONG: tcg_gen_mov_tl(cpu_regs[reg], cpu_A0); break; #endif @@ -398,11 +398,11 @@ static inline void gen_op_jmp_T0(void) static inline void gen_op_add_reg_im(int size, int reg, int32_t val) { switch(size) { - case 0: + case OT_BYTE: tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val); tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16); break; - case 1: + case OT_WORD: tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val); /* For x86_64, this sets the higher half of register to zero. For i386, this is equivalent to a nop. */ @@ -410,7 +410,7 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val) tcg_gen_mov_tl(cpu_regs[reg], cpu_tmp0); break; #ifdef TARGET_X86_64 - case 2: + case OT_LONG: tcg_gen_addi_tl(cpu_regs[reg], cpu_regs[reg], val); break; #endif @@ -420,11 +420,11 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val) static inline void gen_op_add_reg_T0(int size, int reg) { switch(size) { - case 0: + case OT_BYTE: tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]); tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0, 0, 16); break; - case 1: + case OT_WORD: tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]); /* For x86_64, this sets the higher half of register to zero. For i386, this is equivalent to a nop. */ @@ -432,7 +432,7 @@ static inline void gen_op_add_reg_T0(int size, int reg) tcg_gen_mov_tl(cpu_regs[reg], cpu_tmp0); break; #ifdef TARGET_X86_64 - case 2: + case OT_LONG: tcg_gen_add_tl(cpu_regs[reg], cpu_regs[reg], cpu_T[0]); break; #endif @@ -506,14 +506,14 @@ static inline void gen_op_lds_T0_A0(int idx) { int mem_index = (idx >> 2) - 1; switch(idx & 3) { - case 0: + case OT_BYTE: tcg_gen_qemu_ld8s(cpu_T[0], cpu_A0, mem_index); break; - case 1: + case OT_WORD: tcg_gen_qemu_ld16s(cpu_T[0], cpu_A0, mem_index); break; default: - case 2: + case OT_LONG: tcg_gen_qemu_ld32s(cpu_T[0], cpu_A0, mem_index); break; } @@ -523,17 +523,17 @@ static inline void gen_op_ld_v(int idx, TCGv t0, TCGv a0) { int mem_index = (idx >> 2) - 1; switch(idx & 3) { - case 0: + case OT_BYTE: tcg_gen_qemu_ld8u(t0, a0, mem_index); break; - case 1: + case OT_WORD: tcg_gen_qemu_ld16u(t0, a0, mem_index); break; - case 2: + case OT_LONG: tcg_gen_qemu_ld32u(t0, a0, mem_index); break; default: - case 3: + case OT_QUAD: /* Should never happen on 32-bit targets. */ #ifdef TARGET_X86_64 tcg_gen_qemu_ld64(t0, a0, mem_index); @@ -562,17 +562,17 @@ static inline void gen_op_st_v(int idx, TCGv t0, TCGv a0) { int mem_index = (idx >> 2) - 1; switch(idx & 3) { - case 0: + case OT_BYTE: tcg_gen_qemu_st8(t0, a0, mem_index); break; - case 1: + case OT_WORD: tcg_gen_qemu_st16(t0, a0, mem_index); break; - case 2: + case OT_LONG: tcg_gen_qemu_st32(t0, a0, mem_index); break; default: - case 3: + case OT_QUAD: /* Should never happen on 32-bit targets. */ #ifdef TARGET_X86_64 tcg_gen_qemu_st64(t0, a0, mem_index); @@ -710,21 +710,31 @@ static inline void gen_op_jz_ecx(int size, int label1) static void gen_helper_in_func(int ot, TCGv v, TCGv_i32 n) { switch (ot) { - case 0: gen_helper_inb(v, n); break; - case 1: gen_helper_inw(v, n); break; - case 2: gen_helper_inl(v, n); break; + case OT_BYTE: + gen_helper_inb(v, n); + break; + case OT_WORD: + gen_helper_inw(v, n); + break; + case OT_LONG: + gen_helper_inl(v, n); + break; } - } static void gen_helper_out_func(int ot, TCGv_i32 v, TCGv_i32 n) { switch (ot) { - case 0: gen_helper_outb(v, n); break; - case 1: gen_helper_outw(v, n); break; - case 2: gen_helper_outl(v, n); break; + case OT_BYTE: + gen_helper_outb(v, n); + break; + case OT_WORD: + gen_helper_outw(v, n); + break; + case OT_LONG: + gen_helper_outl(v, n); + break; } - } static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip, @@ -741,13 +751,13 @@ static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip, state_saved = 1; tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); switch (ot) { - case 0: + case OT_BYTE: gen_helper_check_iob(cpu_env, cpu_tmp2_i32); break; - case 1: + case OT_WORD: gen_helper_check_iow(cpu_env, cpu_tmp2_i32); break; - case 2: + case OT_LONG: gen_helper_check_iol(cpu_env, cpu_tmp2_i32); break; } @@ -1781,34 +1791,34 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, if (is_right) { switch (ot) { - case 0: + case OT_BYTE: gen_helper_rcrb(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; - case 1: + case OT_WORD: gen_helper_rcrw(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; - case 2: + case OT_LONG: gen_helper_rcrl(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; #ifdef TARGET_X86_64 - case 3: + case OT_QUAD: gen_helper_rcrq(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; #endif } } else { switch (ot) { - case 0: + case OT_BYTE: gen_helper_rclb(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; - case 1: + case OT_WORD: gen_helper_rclw(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; - case 2: + case OT_LONG: gen_helper_rcll(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; #ifdef TARGET_X86_64 - case 3: + case OT_QUAD: gen_helper_rclq(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); break; #endif From d824df34e8cdd2fbe55258f26731d7ef3ac7ced2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 5 Oct 2012 18:02:41 +0200 Subject: [PATCH 1086/1634] target-i386: introduce gen_ext_tl Introduce a function that abstracts extracting an 8, 16, 32 or 64-bit value with or without sign, generalizing gen_extu and gen_exts. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 154 +++++++++++----------------------------- 1 file changed, 41 insertions(+), 113 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 94e14342d3..ccb06e27f5 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -659,38 +659,45 @@ static inline void gen_op_movl_T0_Dshift(int ot) tcg_gen_shli_tl(cpu_T[0], cpu_T[0], ot); }; +static TCGv gen_ext_tl(TCGv dst, TCGv src, int size, bool sign) +{ + switch (size) { + case OT_BYTE: + if (sign) { + tcg_gen_ext8s_tl(dst, src); + } else { + tcg_gen_ext8u_tl(dst, src); + } + return dst; + case OT_WORD: + if (sign) { + tcg_gen_ext16s_tl(dst, src); + } else { + tcg_gen_ext16u_tl(dst, src); + } + return dst; +#ifdef TARGET_X86_64 + case OT_LONG: + if (sign) { + tcg_gen_ext32s_tl(dst, src); + } else { + tcg_gen_ext32u_tl(dst, src); + } + return dst; +#endif + default: + return src; + } +} + static void gen_extu(int ot, TCGv reg) { - switch(ot) { - case OT_BYTE: - tcg_gen_ext8u_tl(reg, reg); - break; - case OT_WORD: - tcg_gen_ext16u_tl(reg, reg); - break; - case OT_LONG: - tcg_gen_ext32u_tl(reg, reg); - break; - default: - break; - } + gen_ext_tl(reg, reg, ot, false); } static void gen_exts(int ot, TCGv reg) { - switch(ot) { - case OT_BYTE: - tcg_gen_ext8s_tl(reg, reg); - break; - case OT_WORD: - tcg_gen_ext16s_tl(reg, reg); - break; - case OT_LONG: - tcg_gen_ext32s_tl(reg, reg); - break; - default: - break; - } + gen_ext_tl(reg, reg, ot, true); } static inline void gen_op_jnz_ecx(int size, int label1) @@ -966,54 +973,15 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1) switch(jcc_op) { case JCC_Z: fast_jcc_z: - switch(size) { - case 0: - tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xff); - t0 = cpu_tmp0; - break; - case 1: - tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffff); - t0 = cpu_tmp0; - break; -#ifdef TARGET_X86_64 - case 2: - tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffffffff); - t0 = cpu_tmp0; - break; -#endif - default: - t0 = cpu_cc_dst; - break; - } + t0 = gen_ext_tl(cpu_tmp0, cpu_cc_dst, size, false); tcg_gen_brcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, t0, 0, l1); break; case JCC_S: fast_jcc_s: - switch(size) { - case 0: - tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80); - tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, - 0, l1); - break; - case 1: - tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x8000); - tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, - 0, l1); - break; -#ifdef TARGET_X86_64 - case 2: - tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80000000); - tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0, - 0, l1); - break; -#endif - default: - tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, cpu_cc_dst, - 0, l1); - break; - } + t0 = gen_ext_tl(cpu_tmp0, cpu_cc_dst, size, true); + tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, t0, 0, l1); break; - + case JCC_B: cond = inv ? TCG_COND_GEU : TCG_COND_LTU; goto fast_jcc_b; @@ -1021,28 +989,8 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1) cond = inv ? TCG_COND_GTU : TCG_COND_LEU; fast_jcc_b: tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); - switch(size) { - case 0: - t0 = cpu_tmp0; - tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xff); - tcg_gen_andi_tl(t0, cpu_cc_src, 0xff); - break; - case 1: - t0 = cpu_tmp0; - tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffff); - tcg_gen_andi_tl(t0, cpu_cc_src, 0xffff); - break; -#ifdef TARGET_X86_64 - case 2: - t0 = cpu_tmp0; - tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffffffff); - tcg_gen_andi_tl(t0, cpu_cc_src, 0xffffffff); - break; -#endif - default: - t0 = cpu_cc_src; - break; - } + gen_extu(size, cpu_tmp4); + t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1); break; @@ -1053,28 +1001,8 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1) cond = inv ? TCG_COND_GT : TCG_COND_LE; fast_jcc_l: tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); - switch(size) { - case 0: - t0 = cpu_tmp0; - tcg_gen_ext8s_tl(cpu_tmp4, cpu_tmp4); - tcg_gen_ext8s_tl(t0, cpu_cc_src); - break; - case 1: - t0 = cpu_tmp0; - tcg_gen_ext16s_tl(cpu_tmp4, cpu_tmp4); - tcg_gen_ext16s_tl(t0, cpu_cc_src); - break; -#ifdef TARGET_X86_64 - case 2: - t0 = cpu_tmp0; - tcg_gen_ext32s_tl(cpu_tmp4, cpu_tmp4); - tcg_gen_ext32s_tl(t0, cpu_cc_src); - break; -#endif - default: - t0 = cpu_cc_src; - break; - } + gen_exts(size, cpu_tmp4); + t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, true); tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1); break; From 91642ff80607ad90c66ba044fe91e4a53b09bdbb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 6 Oct 2012 01:22:09 +0200 Subject: [PATCH 1087/1634] target-i386: factor setting of s->cc_op handling for string functions Set it to the appropriate CC_OP_SUBx constant in gen_scas/gen_cmps. In the repz case it can be overridden to CC_OP_DYNAMIC after generating the code. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index ccb06e27f5..9ac66b984f 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1112,6 +1112,7 @@ static inline void gen_scas(DisasContext *s, int ot) gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_EDI); + s->cc_op = CC_OP_SUBB + ot; } static inline void gen_cmps(DisasContext *s, int ot) @@ -1124,6 +1125,7 @@ static inline void gen_cmps(DisasContext *s, int ot) gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_ESI); gen_op_add_reg_T0(s->aflag, R_EDI); + s->cc_op = CC_OP_SUBB + ot; } static inline void gen_ins(DisasContext *s, int ot) @@ -1194,11 +1196,12 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ l2 = gen_jz_ecx_string(s, next_eip); \ gen_ ## op(s, ot); \ gen_op_add_reg_im(s->aflag, R_ECX, -1); \ - gen_op_set_cc_op(CC_OP_SUBB + ot); \ - gen_jcc1(s, CC_OP_SUBB + ot, (JCC_Z << 1) | (nz ^ 1), l2); \ + gen_op_set_cc_op(s->cc_op); \ + gen_jcc1(s, s->cc_op, (JCC_Z << 1) | (nz ^ 1), l2); \ if (!s->jmp_opt) \ gen_op_jz_ecx(s->aflag, l2); \ gen_jmp(s, cur_eip); \ + s->cc_op = CC_OP_DYNAMIC; \ } GEN_REPZ(movs) @@ -6088,7 +6091,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); } else { gen_scas(s, ot); - s->cc_op = CC_OP_SUBB + ot; } break; @@ -6104,7 +6106,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); } else { gen_cmps(s, ot); - s->cc_op = CC_OP_SUBB + ot; } break; case 0x6c: /* insS */ From b27fc131fe8dc18924904e4dd0b82dfd77dc51c7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 6 Oct 2012 01:36:45 +0200 Subject: [PATCH 1088/1634] target-i386: drop cc_op argument of gen_jcc1 As in the gen_repz_scas/gen_repz_cmps case, delay setting CC_OP_DYNAMIC in gen_jcc until after code generation. All of gen_jcc1/is_fast_jcc/gen_setcc_slow_T0 now work on s->cc_op, which makes things a bit easier to follow and to patch. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 9ac66b984f..48a3255a40 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -954,7 +954,7 @@ static int is_fast_jcc_case(DisasContext *s, int b) /* generate a conditional jump to label 'l1' according to jump opcode value 'b'. In the fast case, T0 is guaranted not to be used. */ -static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1) +static inline void gen_jcc1(DisasContext *s, int b, int l1) { int inv, jcc_op, size, cond; TCGv t0; @@ -962,14 +962,14 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1) inv = b & 1; jcc_op = (b >> 1) & 7; - switch(cc_op) { + switch (s->cc_op) { /* we optimize the cmp/jcc case */ case CC_OP_SUBB: case CC_OP_SUBW: case CC_OP_SUBL: case CC_OP_SUBQ: - size = cc_op - CC_OP_SUBB; + size = s->cc_op - CC_OP_SUBB; switch(jcc_op) { case JCC_Z: fast_jcc_z: @@ -1053,10 +1053,10 @@ static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1) case CC_OP_SARQ: switch(jcc_op) { case JCC_Z: - size = (cc_op - CC_OP_ADDB) & 3; + size = (s->cc_op - CC_OP_ADDB) & 3; goto fast_jcc_z; case JCC_S: - size = (cc_op - CC_OP_ADDB) & 3; + size = (s->cc_op - CC_OP_ADDB) & 3; goto fast_jcc_s; default: goto slow_jcc; @@ -1197,7 +1197,7 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ gen_ ## op(s, ot); \ gen_op_add_reg_im(s->aflag, R_ECX, -1); \ gen_op_set_cc_op(s->cc_op); \ - gen_jcc1(s, s->cc_op, (JCC_Z << 1) | (nz ^ 1), l2); \ + gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2); \ if (!s->jmp_opt) \ gen_op_jz_ecx(s->aflag, l2); \ gen_jmp(s, cur_eip); \ @@ -2303,13 +2303,15 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) static inline void gen_jcc(DisasContext *s, int b, target_ulong val, target_ulong next_eip) { - int l1, l2, cc_op; + int l1, l2; - cc_op = s->cc_op; - gen_update_cc_op(s); + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + } if (s->jmp_opt) { l1 = gen_new_label(); - gen_jcc1(s, cc_op, b, l1); + gen_jcc1(s, b, l1); + s->cc_op = CC_OP_DYNAMIC; gen_goto_tb(s, 0, next_eip); @@ -2320,7 +2322,8 @@ static inline void gen_jcc(DisasContext *s, int b, l1 = gen_new_label(); l2 = gen_new_label(); - gen_jcc1(s, cc_op, b, l1); + gen_jcc1(s, b, l1); + s->cc_op = CC_OP_DYNAMIC; gen_jmp_im(next_eip); tcg_gen_br(l2); @@ -2343,7 +2346,7 @@ static void gen_setcc(DisasContext *s, int b) t0 = tcg_temp_local_new(); tcg_gen_movi_tl(t0, 0); l1 = gen_new_label(); - gen_jcc1(s, s->cc_op, b ^ 1, l1); + gen_jcc1(s, b ^ 1, l1); tcg_gen_movi_tl(t0, 1); gen_set_label(l1); tcg_gen_mov_tl(cpu_T[0], t0); @@ -6027,7 +6030,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, }; op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1); l1 = gen_new_label(); - gen_jcc1(s, s->cc_op, op1, l1); + gen_jcc1(s, op1, l1); gen_helper_fmov_ST0_STN(cpu_env, tcg_const_i32(opreg)); gen_set_label(l1); } @@ -6418,7 +6421,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (ot == OT_LONG) { /* XXX: specific Intel behaviour ? */ l1 = gen_new_label(); - gen_jcc1(s, s->cc_op, b ^ 1, l1); + gen_jcc1(s, b ^ 1, l1); tcg_gen_mov_tl(cpu_regs[reg], t0); gen_set_label(l1); tcg_gen_ext32u_tl(cpu_regs[reg], cpu_regs[reg]); @@ -6426,7 +6429,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, #endif { l1 = gen_new_label(); - gen_jcc1(s, s->cc_op, b ^ 1, l1); + gen_jcc1(s, b ^ 1, l1); gen_op_mov_reg_v(ot, reg, t0); gen_set_label(l1); } From 52320e15dbb0c2531501a924972e63cdb59742a7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 6 Oct 2012 00:18:55 +0200 Subject: [PATCH 1089/1634] target-i386: move carry computation for inc/dec closer to gen_op_set_cc_op This ensures the invariant that cpu_cc_op matches s->cc_op when calling the helpers. The next patches need this because gen_compute_eflags and gen_compute_eflags_c will take care of setting cpu_cc_op. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 48a3255a40..ed373c3ad6 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1373,6 +1373,7 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_op_ld_T0_A0(ot + s1->mem_index); if (s1->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s1->cc_op); + gen_compute_eflags_c(cpu_cc_src); if (c > 0) { tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1); s1->cc_op = CC_OP_INCB + ot; @@ -1384,7 +1385,6 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_op_mov_reg_T0(ot, d); else gen_op_st_T0_A0(ot + s1->mem_index); - gen_compute_eflags_c(cpu_cc_src); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); } From 0ff6addd92979b9759efa1c0945526e6ac78ce5b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 6 Oct 2012 00:18:55 +0200 Subject: [PATCH 1090/1634] target-i386: move eflags computation closer to gen_op_set_cc_op This ensures the invariant that cpu_cc_op matches s->cc_op when calling the helpers. The next patches need this because gen_compute_eflags and gen_compute_eflags_c will take care of setting cpu_cc_op. Always compute EFLAGS first since it is needed whenever the shift is non-zero, i.e. most of the time. This makes it possible to remove some writes of CC_OP_EFLAGS to cpu_cc_op and more importantly removes cases where s->cc_op becomes CC_OP_DYNAMIC. These are slow and we want to avoid them: CC_OP_EFLAGS is quite efficient once we paid the initial cost of computing the flags. Finally, always follow gen_compute_eflags(cpu_cc_src) by setting s->cc_op and discarding cpu_cc_dst. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index ed373c3ad6..0970954217 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1597,14 +1597,16 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, gen_op_mov_reg_v(ot, op1, t0); } - /* update eflags */ + /* update eflags. It is needed anyway most of the time, do it always. */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); + gen_compute_eflags(cpu_cc_src); + tcg_gen_discard_tl(cpu_cc_dst); + s->cc_op = CC_OP_EFLAGS; label2 = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label2); - gen_compute_eflags(cpu_cc_src); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); tcg_gen_xor_tl(cpu_tmp0, t2, t0); tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1)); @@ -1615,12 +1617,8 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, } tcg_gen_andi_tl(t0, t0, CC_C); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); - - tcg_gen_discard_tl(cpu_cc_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS); - + gen_set_label(label2); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ tcg_temp_free(t0); tcg_temp_free(t1); @@ -1684,6 +1682,9 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_cc_src); + tcg_gen_discard_tl(cpu_cc_dst); + s->cc_op = CC_OP_EFLAGS; + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); tcg_gen_xor_tl(cpu_tmp0, t1, t0); tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1)); @@ -1694,10 +1695,6 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, } tcg_gen_andi_tl(t0, t0, CC_C); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); - - tcg_gen_discard_tl(cpu_cc_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS); - s->cc_op = CC_OP_EFLAGS; } tcg_temp_free(t0); From f5847c912d62d60a9917ed1e88cd6d4548fd40f3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 6 Oct 2012 00:18:55 +0200 Subject: [PATCH 1091/1634] target-i386: compute eflags outside rcl/rcr helper Always compute EFLAGS first since it is needed whenever the shift is non-zero, i.e. most of the time. This makes it possible to remove some writes of CC_OP_EFLAGS to cpu_cc_op and more importantly removes cases where s->cc_op becomes CC_OP_DYNAMIC. Also, we can remove cc_tmp and just modify cc_src from within the helper. Finally, always follow gen_compute_eflags(cpu_cc_src) by setting s->cc_op and discarding cpu_cc_dst. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/cpu.h | 1 - target-i386/shift_helper_template.h | 12 ++++-------- target-i386/translate.c | 20 ++++---------------- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 7577e4f8bb..cd35cd52c0 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -764,7 +764,6 @@ typedef struct CPUX86State { XMMReg xmm_regs[CPU_NB_REGS]; XMMReg xmm_t0; MMXReg mmx_t0; - target_ulong cc_tmp; /* temporary for rcr/rcl */ /* sysenter registers */ uint32_t sysenter_cs; diff --git a/target-i386/shift_helper_template.h b/target-i386/shift_helper_template.h index dda0da30cf..cf91a2d284 100644 --- a/target-i386/shift_helper_template.h +++ b/target-i386/shift_helper_template.h @@ -55,7 +55,7 @@ target_ulong glue(helper_rcl, SUFFIX)(CPUX86State *env, target_ulong t0, count = rclb_table[count]; #endif if (count) { - eflags = helper_cc_compute_all(env, CC_OP); + eflags = env->cc_src; t0 &= DATA_MASK; src = t0; res = (t0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1)); @@ -63,11 +63,9 @@ target_ulong glue(helper_rcl, SUFFIX)(CPUX86State *env, target_ulong t0, res |= t0 >> (DATA_BITS + 1 - count); } t0 = res; - env->cc_tmp = (eflags & ~(CC_C | CC_O)) | + env->cc_src = (eflags & ~(CC_C | CC_O)) | (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) | ((src >> (DATA_BITS - count)) & CC_C); - } else { - env->cc_tmp = -1; } return t0; } @@ -86,7 +84,7 @@ target_ulong glue(helper_rcr, SUFFIX)(CPUX86State *env, target_ulong t0, count = rclb_table[count]; #endif if (count) { - eflags = helper_cc_compute_all(env, CC_OP); + eflags = env->cc_src; t0 &= DATA_MASK; src = t0; res = (t0 >> count) | @@ -95,11 +93,9 @@ target_ulong glue(helper_rcr, SUFFIX)(CPUX86State *env, target_ulong t0, res |= t0 << (DATA_BITS + 1 - count); } t0 = res; - env->cc_tmp = (eflags & ~(CC_C | CC_O)) | + env->cc_src = (eflags & ~(CC_C | CC_O)) | (lshift(src ^ t0, 11 - (DATA_BITS - 1)) & CC_O) | ((src >> (count - 1)) & CC_C); - } else { - env->cc_tmp = -1; } return t0; } diff --git a/target-i386/translate.c b/target-i386/translate.c index 0970954217..80483c0ffd 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -51,7 +51,7 @@ /* global register indexes */ static TCGv_ptr cpu_env; -static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst, cpu_cc_tmp; +static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst; static TCGv_i32 cpu_cc_op; static TCGv cpu_regs[CPU_NB_REGS]; /* local temps */ @@ -1706,10 +1706,11 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, int is_right) { - int label1; - if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); + gen_compute_eflags(cpu_cc_src); + tcg_gen_discard_tl(cpu_cc_dst); + s->cc_op = CC_OP_EFLAGS; /* load */ if (op1 == OR_TMP0) @@ -1757,17 +1758,6 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, gen_op_st_T0_A0(ot + s->mem_index); else gen_op_mov_reg_T0(ot, op1); - - /* update eflags */ - label1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cc_tmp, -1, label1); - - tcg_gen_mov_tl(cpu_cc_src, cpu_cc_tmp); - tcg_gen_discard_tl(cpu_cc_dst); - tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS); - - gen_set_label(label1); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } /* XXX: add faster immediate case */ @@ -7763,8 +7753,6 @@ void optimize_flags_init(void) "cc_src"); cpu_cc_dst = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_dst), "cc_dst"); - cpu_cc_tmp = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_tmp), - "cc_tmp"); #ifdef TARGET_X86_64 cpu_regs[R_EAX] = tcg_global_mem_new_i64(TCG_AREG0, From 6fa38ed219587723fcab9b878f42269489d51705 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sat, 6 Oct 2012 00:18:55 +0200 Subject: [PATCH 1092/1634] target-i386: clean up sahf Discard CC_DST and set s->cc_op immediately after computing EFLAGS. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 80483c0ffd..64564e0712 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6502,10 +6502,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_compute_eflags(cpu_cc_src); + tcg_gen_discard_tl(cpu_cc_dst); + s->cc_op = CC_OP_EFLAGS; + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]); - s->cc_op = CC_OP_EFLAGS; break; case 0x9f: /* lahf */ if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) From 5bdb91b0dd66b7e0fdfc801601c433ad4752aeb0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 12 Oct 2012 13:35:40 +0200 Subject: [PATCH 1093/1634] target-i386: use gen_jcc1 to compile loopz Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 64564e0712..6fcd0f6e20 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -6896,13 +6896,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_set_cc_op(s->cc_op); gen_op_add_reg_im(s->aflag, R_ECX, -1); gen_op_jz_ecx(s->aflag, l3); - gen_compute_eflags(cpu_tmp0); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_Z); - if (b == 0) { - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1); - } else { - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, l1); - } + gen_jcc1(s, (JCC_Z << 1) | (b ^ 1), l1); break; case 2: /* loop */ gen_op_add_reg_im(s->aflag, R_ECX, -1); From c7b3c87397a3458d3d26499c483e0badaf79849c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 5 Oct 2012 18:29:21 +0200 Subject: [PATCH 1094/1634] target-i386: factor gen_op_set_cc_op/tcg_gen_discard_tl around computing flags Before computing flags we need to store the cc_op to memory. Move this to gen_compute_eflags_c and gen_compute_eflags rather than doing it all over the place. Alo, after computing the flags in cpu_cc_src we are in EFLAGS mode. Set s->cc_op and discard cpu_cc_dst in gen_compute_eflags, rather than doing it all over the place. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 103 +++++++++++++++------------------------- 1 file changed, 37 insertions(+), 66 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 6fcd0f6e20..89f290822b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -834,55 +834,63 @@ static void gen_op_update_neg_cc(void) } /* compute eflags.C to reg */ -static void gen_compute_eflags_c(TCGv reg) +static void gen_compute_eflags_c(DisasContext *s, TCGv reg) { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + } gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op); tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); } -/* compute all eflags to cc_src */ -static void gen_compute_eflags(TCGv reg) +/* compute all eflags to reg */ +static void gen_compute_eflags(DisasContext *s, TCGv reg) { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + } gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op); + if (TCGV_EQUAL(reg, cpu_cc_src)) { + tcg_gen_discard_tl(cpu_cc_dst); + s->cc_op = CC_OP_EFLAGS; + } tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); } static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); switch(jcc_op) { case JCC_O: - gen_compute_eflags(cpu_T[0]); + gen_compute_eflags(s, cpu_T[0]); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 11); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_B: - gen_compute_eflags_c(cpu_T[0]); + gen_compute_eflags_c(s, cpu_T[0]); break; case JCC_Z: - gen_compute_eflags(cpu_T[0]); + gen_compute_eflags(s, cpu_T[0]); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 6); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_BE: - gen_compute_eflags(cpu_tmp0); + gen_compute_eflags(s, cpu_tmp0); tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 6); tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_S: - gen_compute_eflags(cpu_T[0]); + gen_compute_eflags(s, cpu_T[0]); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 7); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_P: - gen_compute_eflags(cpu_T[0]); + gen_compute_eflags(s, cpu_T[0]); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 2); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_L: - gen_compute_eflags(cpu_tmp0); + gen_compute_eflags(s, cpu_tmp0); tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */ tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 7); /* CC_S */ tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); @@ -890,7 +898,7 @@ static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) break; default: case JCC_LE: - gen_compute_eflags(cpu_tmp0); + gen_compute_eflags(s, cpu_tmp0); tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */ tcg_gen_shri_tl(cpu_tmp4, cpu_tmp0, 7); /* CC_S */ tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 6); /* CC_Z */ @@ -1278,9 +1286,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) } switch(op) { case OP_ADCL: - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - gen_compute_eflags_c(cpu_tmp4); + gen_compute_eflags_c(s1, cpu_tmp4); tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4); if (d != OR_TMP0) @@ -1295,9 +1301,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) s1->cc_op = CC_OP_DYNAMIC; break; case OP_SBBL: - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - gen_compute_eflags_c(cpu_tmp4); + gen_compute_eflags_c(s1, cpu_tmp4); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4); if (d != OR_TMP0) @@ -1371,9 +1375,7 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_op_mov_TN_reg(ot, 0, d); else gen_op_ld_T0_A0(ot + s1->mem_index); - if (s1->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s1->cc_op); - gen_compute_eflags_c(cpu_cc_src); + gen_compute_eflags_c(s1, cpu_cc_src); if (c > 0) { tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1); s1->cc_op = CC_OP_INCB + ot; @@ -1598,11 +1600,8 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, } /* update eflags. It is needed anyway most of the time, do it always. */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_cc_src); - tcg_gen_discard_tl(cpu_cc_dst); - s->cc_op = CC_OP_EFLAGS; + gen_compute_eflags(s, cpu_cc_src); + assert(s->cc_op == CC_OP_EFLAGS); label2 = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label2); @@ -1678,12 +1677,8 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, if (op2 != 0) { /* update eflags */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - - gen_compute_eflags(cpu_cc_src); - tcg_gen_discard_tl(cpu_cc_dst); - s->cc_op = CC_OP_EFLAGS; + gen_compute_eflags(s, cpu_cc_src); + assert(s->cc_op == CC_OP_EFLAGS); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); tcg_gen_xor_tl(cpu_tmp0, t1, t0); @@ -1708,9 +1703,8 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_cc_src); - tcg_gen_discard_tl(cpu_cc_dst); - s->cc_op = CC_OP_EFLAGS; + gen_compute_eflags(s, cpu_cc_src); + assert(s->cc_op == CC_OP_EFLAGS); /* load */ if (op1 == OR_TMP0) @@ -6499,12 +6493,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; gen_op_mov_TN_reg(OT_BYTE, 0, R_AH); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_cc_src); - tcg_gen_discard_tl(cpu_cc_dst); - s->cc_op = CC_OP_EFLAGS; - + gen_compute_eflags(s, cpu_cc_src); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]); @@ -6512,33 +6501,22 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0x9f: /* lahf */ if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_T[0]); + gen_compute_eflags(s, cpu_T[0]); /* Note: gen_compute_eflags() only gives the condition codes */ tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 0x02); gen_op_mov_reg_T0(OT_BYTE, R_AH); break; case 0xf5: /* cmc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_cc_src); + gen_compute_eflags(s, cpu_cc_src); tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C); - s->cc_op = CC_OP_EFLAGS; break; case 0xf8: /* clc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_cc_src); + gen_compute_eflags(s, cpu_cc_src); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C); - s->cc_op = CC_OP_EFLAGS; break; case 0xf9: /* stc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_cc_src); + gen_compute_eflags(s, cpu_cc_src); tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C); - s->cc_op = CC_OP_EFLAGS; break; case 0xfc: /* cld */ tcg_gen_movi_i32(cpu_tmp2_i32, 1); @@ -6866,9 +6844,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0xd6: /* salc */ if (CODE64(s)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags_c(cpu_T[0]); + gen_compute_eflags_c(s, cpu_T[0]); tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; @@ -6892,8 +6868,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, switch(b) { case 0: /* loopnz */ case 1: /* loopz */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); gen_op_add_reg_im(s->aflag, R_ECX, -1); gen_op_jz_ecx(s->aflag, l3); gen_jcc1(s, (JCC_Z << 1) | (b ^ 1), l1); @@ -7432,12 +7406,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } else { gen_op_mov_reg_v(ot, rm, t0); } - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_compute_eflags(cpu_cc_src); + gen_compute_eflags(s, cpu_cc_src); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2); - s->cc_op = CC_OP_EFLAGS; tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); From fee71888a29ab9f31b23386383812a4f5c953829 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 16 Jan 2013 16:23:46 -0800 Subject: [PATCH 1095/1634] target-i386: Name the cc_op enumeration Signed-off-by: Richard Henderson --- target-i386/cpu.h | 4 ++-- target-i386/translate.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index cd35cd52c0..8c4c605299 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -582,7 +582,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPU_INTERRUPT_TPR CPU_INTERRUPT_TGT_INT_3 -enum { +typedef enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitly computed, CC_SRC = flags */ @@ -637,7 +637,7 @@ enum { CC_OP_SARQ, CC_OP_NB, -}; +} CCOp; typedef struct SegmentCache { uint32_t selector; diff --git a/target-i386/translate.c b/target-i386/translate.c index 89f290822b..cf71878e8b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -89,7 +89,7 @@ typedef struct DisasContext { int rex_x, rex_b; #endif int ss32; /* 32 bit stack segment */ - int cc_op; /* current CC operation */ + CCOp cc_op; /* current CC operation */ int addseg; /* non zero if either DS/ES/SS have a non zero base */ int f_st; /* currently unused */ int vm86; /* vm86 mode */ From 3ca51d07dae5b2d2301431c55b08d4faaad95d91 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 12:30:52 -0800 Subject: [PATCH 1096/1634] target-i386: Introduce set_cc_op This will provide a good hook into which we can consolidate all of the cc variable discards. Signed-off-by: Richard Henderson --- target-i386/translate.c | 134 +++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index cf71878e8b..6df76d6a38 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -173,6 +173,11 @@ enum { OR_A0, /* temporary register used when doing address evaluation */ }; +static inline void set_cc_op(DisasContext *s, CCOp op) +{ + s->cc_op = op; +} + static inline void gen_op_movl_T0_0(void) { tcg_gen_movi_tl(cpu_T[0], 0); @@ -799,7 +804,7 @@ static inline void gen_update_cc_op(DisasContext *s) { if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; + set_cc_op(s, CC_OP_DYNAMIC); } } @@ -852,7 +857,7 @@ static void gen_compute_eflags(DisasContext *s, TCGv reg) gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op); if (TCGV_EQUAL(reg, cpu_cc_src)) { tcg_gen_discard_tl(cpu_cc_dst); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); } tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); } @@ -1120,7 +1125,7 @@ static inline void gen_scas(DisasContext *s, int ot) gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_EDI); - s->cc_op = CC_OP_SUBB + ot; + set_cc_op(s, CC_OP_SUBB + ot); } static inline void gen_cmps(DisasContext *s, int ot) @@ -1133,7 +1138,7 @@ static inline void gen_cmps(DisasContext *s, int ot) gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_ESI); gen_op_add_reg_T0(s->aflag, R_EDI); - s->cc_op = CC_OP_SUBB + ot; + set_cc_op(s, CC_OP_SUBB + ot); } static inline void gen_ins(DisasContext *s, int ot) @@ -1209,7 +1214,7 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ if (!s->jmp_opt) \ gen_op_jz_ecx(s->aflag, l2); \ gen_jmp(s, cur_eip); \ - s->cc_op = CC_OP_DYNAMIC; \ + set_cc_op(s, CC_OP_DYNAMIC); \ } GEN_REPZ(movs) @@ -1298,7 +1303,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_ADDB + ot); - s1->cc_op = CC_OP_DYNAMIC; + set_cc_op(s1, CC_OP_DYNAMIC); break; case OP_SBBL: gen_compute_eflags_c(s1, cpu_tmp4); @@ -1313,7 +1318,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_SUBB + ot); - s1->cc_op = CC_OP_DYNAMIC; + set_cc_op(s1, CC_OP_DYNAMIC); break; case OP_ADDL: gen_op_addl_T0_T1(); @@ -1322,7 +1327,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) else gen_op_st_T0_A0(ot + s1->mem_index); gen_op_update2_cc(); - s1->cc_op = CC_OP_ADDB + ot; + set_cc_op(s1, CC_OP_ADDB + ot); break; case OP_SUBL: tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); @@ -1331,7 +1336,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) else gen_op_st_T0_A0(ot + s1->mem_index); gen_op_update2_cc(); - s1->cc_op = CC_OP_SUBB + ot; + set_cc_op(s1, CC_OP_SUBB + ot); break; default: case OP_ANDL: @@ -1341,7 +1346,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) else gen_op_st_T0_A0(ot + s1->mem_index); gen_op_update1_cc(); - s1->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s1, CC_OP_LOGICB + ot); break; case OP_ORL: tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]); @@ -1350,7 +1355,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) else gen_op_st_T0_A0(ot + s1->mem_index); gen_op_update1_cc(); - s1->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s1, CC_OP_LOGICB + ot); break; case OP_XORL: tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_T[1]); @@ -1359,11 +1364,11 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) else gen_op_st_T0_A0(ot + s1->mem_index); gen_op_update1_cc(); - s1->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s1, CC_OP_LOGICB + ot); break; case OP_CMPL: gen_op_cmpl_T0_T1_cc(); - s1->cc_op = CC_OP_SUBB + ot; + set_cc_op(s1, CC_OP_SUBB + ot); break; } } @@ -1378,10 +1383,10 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_compute_eflags_c(s1, cpu_cc_src); if (c > 0) { tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1); - s1->cc_op = CC_OP_INCB + ot; + set_cc_op(s1, CC_OP_INCB + ot); } else { tcg_gen_addi_tl(cpu_T[0], cpu_T[0], -1); - s1->cc_op = CC_OP_DECB + ot; + set_cc_op(s1, CC_OP_DECB + ot); } if (d != OR_TMP0) gen_op_mov_reg_T0(ot, d); @@ -1468,7 +1473,7 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, } gen_set_label(shift_label); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + set_cc_op(s, CC_OP_DYNAMIC); /* cannot predict flags after */ tcg_temp_free(t0); tcg_temp_free(t1); @@ -1519,10 +1524,7 @@ static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2, if (op2 != 0) { tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - if (is_right) - s->cc_op = CC_OP_SARB + ot; - else - s->cc_op = CC_OP_SHLB + ot; + set_cc_op(s, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot); } } @@ -1875,7 +1877,7 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1, tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot); } gen_set_label(label2); - s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + set_cc_op(s, CC_OP_DYNAMIC); /* cannot predict flags after */ tcg_temp_free(t0); tcg_temp_free(t1); @@ -2292,7 +2294,7 @@ static inline void gen_jcc(DisasContext *s, int b, if (s->jmp_opt) { l1 = gen_new_label(); gen_jcc1(s, b, l1); - s->cc_op = CC_OP_DYNAMIC; + set_cc_op(s, CC_OP_DYNAMIC); gen_goto_tb(s, 0, next_eip); @@ -2304,7 +2306,7 @@ static inline void gen_jcc(DisasContext *s, int b, l1 = gen_new_label(); l2 = gen_new_label(); gen_jcc1(s, b, l1); - s->cc_op = CC_OP_DYNAMIC; + set_cc_op(s, CC_OP_DYNAMIC); gen_jmp_im(next_eip); tcg_gen_br(l2); @@ -3792,8 +3794,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); sse_fn_epp(cpu_env, cpu_ptr0, cpu_ptr1); - if (b == 0x17) - s->cc_op = CC_OP_EFLAGS; + if (b == 0x17) { + set_cc_op(s, CC_OP_EFLAGS); + } break; case 0x338: /* crc32 */ crc32: @@ -3995,7 +3998,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, val = cpu_ldub_code(env, s->pc++); if ((b & 0xfc) == 0x60) { /* pcmpXstrX */ - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); if (s->dflag == 2) /* The helper must use entire 64-bit gp registers */ @@ -4116,7 +4119,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, break; } if (b == 0x2e || b == 0x2f) { - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); } } } @@ -4300,7 +4303,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, xor_zero: /* xor reg, reg optimisation */ gen_op_movl_T0_0(); - s->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s, CC_OP_LOGICB + ot); gen_op_mov_reg_T0(ot, reg); gen_op_update1_cc(); break; @@ -4415,7 +4418,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, val = insn_get(env, s, ot); gen_op_movl_T1_im(val); gen_op_testl_T0_T1_cc(); - s->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s, CC_OP_LOGICB + ot); break; case 2: /* not */ tcg_gen_not_tl(cpu_T[0], cpu_T[0]); @@ -4433,7 +4436,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_mov_reg_T0(ot, rm); } gen_op_update_neg_cc(); - s->cc_op = CC_OP_SUBB + ot; + set_cc_op(s, CC_OP_SUBB + ot); break; case 4: /* mul */ switch(ot) { @@ -4446,7 +4449,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_mov_reg_T0(OT_WORD, R_EAX); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_andi_tl(cpu_cc_src, cpu_T[0], 0xff00); - s->cc_op = CC_OP_MULB; + set_cc_op(s, CC_OP_MULB); break; case OT_WORD: gen_op_mov_TN_reg(OT_WORD, 1, R_EAX); @@ -4459,7 +4462,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16); gen_op_mov_reg_T0(OT_WORD, R_EDX); tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); - s->cc_op = CC_OP_MULW; + set_cc_op(s, CC_OP_MULW); break; default: case OT_LONG: @@ -4491,12 +4494,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); } #endif - s->cc_op = CC_OP_MULL; + set_cc_op(s, CC_OP_MULL); break; #ifdef TARGET_X86_64 case OT_QUAD: gen_helper_mulq_EAX_T0(cpu_env, cpu_T[0]); - s->cc_op = CC_OP_MULQ; + set_cc_op(s, CC_OP_MULQ); break; #endif } @@ -4513,7 +4516,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_ext8s_tl(cpu_tmp0, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); - s->cc_op = CC_OP_MULB; + set_cc_op(s, CC_OP_MULB); break; case OT_WORD: gen_op_mov_TN_reg(OT_WORD, 1, R_EAX); @@ -4527,7 +4530,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16); gen_op_mov_reg_T0(OT_WORD, R_EDX); - s->cc_op = CC_OP_MULW; + set_cc_op(s, CC_OP_MULW); break; default: case OT_LONG: @@ -4561,12 +4564,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); } #endif - s->cc_op = CC_OP_MULL; + set_cc_op(s, CC_OP_MULL); break; #ifdef TARGET_X86_64 case OT_QUAD: gen_helper_imulq_EAX_T0(cpu_env, cpu_T[0]); - s->cc_op = CC_OP_MULQ; + set_cc_op(s, CC_OP_MULQ); break; #endif } @@ -4747,7 +4750,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); gen_op_mov_TN_reg(ot, 1, reg); gen_op_testl_T0_T1_cc(); - s->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s, CC_OP_LOGICB + ot); break; case 0xa8: /* test eAX, Iv */ @@ -4761,7 +4764,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_mov_TN_reg(ot, 0, OR_EAX); gen_op_movl_T1_im(val); gen_op_testl_T0_T1_cc(); - s->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s, CC_OP_LOGICB + ot); break; case 0x98: /* CWDE/CBW */ @@ -4862,7 +4865,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); } gen_op_mov_reg_T0(ot, reg); - s->cc_op = CC_OP_MULB + ot; + set_cc_op(s, CC_OP_MULB + ot); break; case 0x1c0: case 0x1c1: /* xadd Ev, Gv */ @@ -4889,7 +4892,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_mov_reg_T1(ot, reg); } gen_op_update2_cc(); - s->cc_op = CC_OP_ADDB + ot; + set_cc_op(s, CC_OP_ADDB + ot); break; case 0x1b0: case 0x1b1: /* cmpxchg Ev, Gv */ @@ -4941,7 +4944,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_set_label(label2); tcg_gen_mov_tl(cpu_cc_src, t0); tcg_gen_mov_tl(cpu_cc_dst, t2); - s->cc_op = CC_OP_SUBB + ot; + set_cc_op(s, CC_OP_SUBB + ot); tcg_temp_free(t0); tcg_temp_free(t1); tcg_temp_free(t2); @@ -4973,7 +4976,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); gen_helper_cmpxchg8b(cpu_env, cpu_A0); } - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; /**************************/ @@ -5925,14 +5928,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_set_cc_op(s->cc_op); gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fucomi_ST0_FT0(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x1e: /* fcomi */ if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fcomi_ST0_FT0(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x28: /* ffree sti */ gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg)); @@ -5989,7 +5992,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fucomi_ST0_FT0(cpu_env); gen_helper_fpop(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x3e: /* fcomip */ if (s->cc_op != CC_OP_DYNAMIC) @@ -5997,7 +6000,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fcomi_ST0_FT0(cpu_env); gen_helper_fpop(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x10 ... 0x13: /* fcmovxx */ case 0x18 ... 0x1b: @@ -6277,13 +6280,13 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (!s->pe) { /* real mode */ gen_helper_iret_real(cpu_env, tcg_const_i32(s->dflag)); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); } else if (s->vm86) { if (s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_helper_iret_real(cpu_env, tcg_const_i32(s->dflag)); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); } } else { if (s->cc_op != CC_OP_DYNAMIC) @@ -6291,7 +6294,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_jmp_im(pc_start - s->cs_base); gen_helper_iret_protected(cpu_env, tcg_const_i32(s->dflag), tcg_const_i32(s->pc - s->cs_base)); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); } gen_eob(s); break; @@ -6483,7 +6486,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } } gen_pop_update(s); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); /* abort translation because TF/AC flag may change */ gen_jmp_im(s->pc - s->cs_base); gen_eob(s); @@ -6606,7 +6609,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); break; } - s->cc_op = CC_OP_SARB + ot; + set_cc_op(s, CC_OP_SARB + ot); if (op != 0) { if (mod != 3) gen_op_st_T0_A0(ot + s->mem_index); @@ -6653,7 +6656,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_movi_tl(cpu_cc_dst, 1); gen_set_label(label1); tcg_gen_discard_tl(cpu_cc_src); - s->cc_op = CC_OP_LOGICB + ot; + set_cc_op(s, CC_OP_LOGICB + ot); } tcg_temp_free(t0); } @@ -6666,7 +6669,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_daa(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x2f: /* das */ if (CODE64(s)) @@ -6674,7 +6677,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_das(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x37: /* aaa */ if (CODE64(s)) @@ -6682,7 +6685,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_aaa(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x3f: /* aas */ if (CODE64(s)) @@ -6690,7 +6693,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_helper_aas(cpu_env); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0xd4: /* aam */ if (CODE64(s)) @@ -6700,7 +6703,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base); } else { gen_helper_aam(cpu_env, tcg_const_i32(val)); - s->cc_op = CC_OP_LOGICB; + set_cc_op(s, CC_OP_LOGICB); } break; case 0xd5: /* aad */ @@ -6708,7 +6711,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, goto illegal_op; val = cpu_ldub_code(env, s->pc++); gen_helper_aad(cpu_env, tcg_const_i32(val)); - s->cc_op = CC_OP_LOGICB; + set_cc_op(s, CC_OP_LOGICB); break; /************************/ /* misc */ @@ -6967,8 +6970,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_jmp_im(pc_start - s->cs_base); gen_helper_sysret(cpu_env, tcg_const_i32(s->dflag)); /* condition codes are modified only in long mode */ - if (s->lma) - s->cc_op = CC_OP_EFLAGS; + if (s->lma) { + set_cc_op(s, CC_OP_EFLAGS); + } gen_eob(s); } break; @@ -7053,7 +7057,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } else { gen_helper_verw(cpu_env, cpu_T[0]); } - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; default: goto illegal_op; @@ -7438,7 +7442,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1); gen_op_mov_reg_v(ot, reg, t0); gen_set_label(label1); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); tcg_temp_free(t0); } break; @@ -7681,7 +7685,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_popcnt(cpu_T[0], cpu_env, cpu_T[0], tcg_const_i32(ot)); gen_op_mov_reg_T0(ot, reg); - s->cc_op = CC_OP_EFLAGS; + set_cc_op(s, CC_OP_EFLAGS); break; case 0x10e ... 0x10f: /* 3DNow! instructions, ignore prefixes */ From e207582f6660e0e2d10a2e79e664e456e80b2887 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 12:34:26 -0800 Subject: [PATCH 1097/1634] target-i386: Don't clobber s->cc_op in gen_update_cc_op Use a dirty flag to know whether env->cc_op is up to date, rather than forcing s->cc_op to DYNAMIC and losing info. Signed-off-by: Richard Henderson --- target-i386/translate.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 6df76d6a38..cabdeda371 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -90,6 +90,7 @@ typedef struct DisasContext { #endif int ss32; /* 32 bit stack segment */ CCOp cc_op; /* current CC operation */ + bool cc_op_dirty; int addseg; /* non zero if either DS/ES/SS have a non zero base */ int f_st; /* currently unused */ int vm86; /* vm86 mode */ @@ -173,9 +174,27 @@ enum { OR_A0, /* temporary register used when doing address evaluation */ }; -static inline void set_cc_op(DisasContext *s, CCOp op) +static void set_cc_op(DisasContext *s, CCOp op) { - s->cc_op = op; + if (s->cc_op != op) { + s->cc_op = op; + /* The DYNAMIC setting is translator only, and should never be + stored. Thus we always consider it clean. */ + s->cc_op_dirty = (op != CC_OP_DYNAMIC); + } +} + +static inline void gen_op_set_cc_op(int32_t val) +{ + tcg_gen_movi_i32(cpu_cc_op, val); +} + +static void gen_update_cc_op(DisasContext *s) +{ + if (s->cc_op_dirty) { + gen_op_set_cc_op(s->cc_op); + s->cc_op_dirty = false; + } } static inline void gen_op_movl_T0_0(void) @@ -444,11 +463,6 @@ static inline void gen_op_add_reg_T0(int size, int reg) } } -static inline void gen_op_set_cc_op(int32_t val) -{ - tcg_gen_movi_i32(cpu_cc_op, val); -} - static inline void gen_op_addl_A0_reg_sN(int shift, int reg) { tcg_gen_mov_tl(cpu_tmp0, cpu_regs[reg]); @@ -800,14 +814,6 @@ static inline void gen_movs(DisasContext *s, int ot) gen_op_add_reg_T0(s->aflag, R_EDI); } -static inline void gen_update_cc_op(DisasContext *s) -{ - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - set_cc_op(s, CC_OP_DYNAMIC); - } -} - static void gen_op_update1_cc(void) { tcg_gen_discard_tl(cpu_cc_src); @@ -7816,6 +7822,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, dc->tf = (flags >> TF_SHIFT) & 1; dc->singlestep_enabled = env->singlestep_enabled; dc->cc_op = CC_OP_DYNAMIC; + dc->cc_op_dirty = false; dc->cs_base = cs_base; dc->tb = tb; dc->popl_esp_hack = 0; From 773cdfccb835cc82aca2b2ff34277b4bf58d6bb9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 12:43:12 -0800 Subject: [PATCH 1098/1634] target-i386: Use gen_update_cc_op everywhere All of the conditional calls to gen_op_set_cc_op go away, and gen_op_set_cc_op itself gets inlined into its only remaining caller. Signed-off-by: Richard Henderson --- target-i386/translate.c | 177 +++++++++++++--------------------------- 1 file changed, 57 insertions(+), 120 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index cabdeda371..9dd3081a8f 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -184,15 +184,10 @@ static void set_cc_op(DisasContext *s, CCOp op) } } -static inline void gen_op_set_cc_op(int32_t val) -{ - tcg_gen_movi_i32(cpu_cc_op, val); -} - static void gen_update_cc_op(DisasContext *s) { if (s->cc_op_dirty) { - gen_op_set_cc_op(s->cc_op); + tcg_gen_movi_i32(cpu_cc_op, s->cc_op); s->cc_op_dirty = false; } } @@ -771,8 +766,7 @@ static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip, state_saved = 0; if (s->pe && (s->cpl > s->iopl || s->vm86)) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(cur_eip); state_saved = 1; tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); @@ -790,8 +784,7 @@ static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip, } if(s->flags & HF_SVMI_MASK) { if (!state_saved) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(cur_eip); } svm_flags |= (1 << (4 + ot)); @@ -847,9 +840,7 @@ static void gen_op_update_neg_cc(void) /* compute eflags.C to reg */ static void gen_compute_eflags_c(DisasContext *s, TCGv reg) { - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - } + gen_update_cc_op(s); gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op); tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); } @@ -857,9 +848,7 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg) /* compute all eflags to reg */ static void gen_compute_eflags(DisasContext *s, TCGv reg) { - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - } + gen_update_cc_op(s); gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op); if (TCGV_EQUAL(reg, cpu_cc_src)) { tcg_gen_discard_tl(cpu_cc_dst); @@ -1215,7 +1204,7 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ l2 = gen_jz_ecx_string(s, next_eip); \ gen_ ## op(s, ot); \ gen_op_add_reg_im(s->aflag, R_ECX, -1); \ - gen_op_set_cc_op(s->cc_op); \ + gen_update_cc_op(s); \ gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2); \ if (!s->jmp_opt) \ gen_op_jz_ecx(s->aflag, l2); \ @@ -1449,10 +1438,8 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, gen_op_mov_reg_T0(ot, op1); } - /* update eflags if non zero shift */ - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - } + /* update eflags */ + gen_update_cc_op(s); tcg_gen_mov_tl(t1, cpu_T[0]); @@ -1709,8 +1696,7 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, int is_right) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_compute_eflags(s, cpu_cc_src); assert(s->cc_op == CC_OP_EFLAGS); @@ -1869,8 +1855,7 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1, } /* update eflags */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); label2 = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label2); @@ -2294,9 +2279,7 @@ static inline void gen_jcc(DisasContext *s, int b, { int l1, l2; - if (s->cc_op != CC_OP_DYNAMIC) { - gen_op_set_cc_op(s->cc_op); - } + gen_update_cc_op(s); if (s->jmp_opt) { l1 = gen_new_label(); gen_jcc1(s, b, l1); @@ -2375,8 +2358,7 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip) { if (s->pe && !s->vm86) { /* XXX: optimize by finding processor state dynamically */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(cur_eip); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), cpu_tmp2_i32); @@ -2405,8 +2387,7 @@ gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, /* no SVM activated; fast case */ if (likely(!(s->flags & HF_SVMI_MASK))) return; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_svm_check_intercept_param(cpu_env, tcg_const_i32(type), tcg_const_i64(param)); @@ -2653,8 +2634,7 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(cur_eip); gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno)); s->is_jmp = DISAS_TB_JUMP; @@ -2665,8 +2645,7 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) static void gen_interrupt(DisasContext *s, int intno, target_ulong cur_eip, target_ulong next_eip) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(cur_eip); gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno), tcg_const_i32(next_eip - cur_eip)); @@ -2675,8 +2654,7 @@ static void gen_interrupt(DisasContext *s, int intno, static void gen_debug(DisasContext *s, target_ulong cur_eip) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(cur_eip); gen_helper_debug(cpu_env); s->is_jmp = DISAS_TB_JUMP; @@ -2686,8 +2664,7 @@ static void gen_debug(DisasContext *s, target_ulong cur_eip) if needed */ static void gen_eob(DisasContext *s) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); if (s->tb->flags & HF_INHIBIT_IRQ_MASK) { gen_helper_reset_inhibit_irq(cpu_env); } @@ -4695,8 +4672,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_ldu_T0_A0(OT_WORD + s->mem_index); do_lcall: if (s->pe && !s->vm86) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_lcall_protected(cpu_env, cpu_tmp2_i32, cpu_T[1], @@ -4722,8 +4698,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_ldu_T0_A0(OT_WORD + s->mem_index); do_ljmp: if (s->pe && !s->vm86) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); gen_helper_ljmp_protected(cpu_env, cpu_tmp2_i32, cpu_T[1], @@ -4967,8 +4942,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) goto illegal_op; gen_jmp_im(pc_start - s->cs_base); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); gen_helper_cmpxchg16b(cpu_env, cpu_A0); } else @@ -4977,8 +4951,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (!(s->cpuid_features & CPUID_CX8)) goto illegal_op; gen_jmp_im(pc_start - s->cs_base); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); gen_helper_cmpxchg8b(cpu_env, cpu_A0); } @@ -5651,8 +5624,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } break; case 0x0c: /* fldenv mem */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fldenv(cpu_env, cpu_A0, tcg_const_i32(s->dflag)); break; @@ -5662,8 +5634,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_helper_fldcw(cpu_env, cpu_tmp2_i32); break; case 0x0e: /* fnstenv mem */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fstenv(cpu_env, cpu_A0, tcg_const_i32(s->dflag)); break; @@ -5673,27 +5644,23 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x1d: /* fldt mem */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fldt_ST0(cpu_env, cpu_A0); break; case 0x1f: /* fstpt mem */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fstt_ST0(cpu_env, cpu_A0); gen_helper_fpop(cpu_env); break; case 0x2c: /* frstor mem */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_frstor(cpu_env, cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2e: /* fnsave mem */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fsave(cpu_env, cpu_A0, tcg_const_i32(s->dflag)); break; @@ -5703,14 +5670,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x3c: /* fbld */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fbld_ST0(cpu_env, cpu_A0); break; case 0x3e: /* fbstp */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fbst_ST0(cpu_env, cpu_A0); gen_helper_fpop(cpu_env); @@ -5748,8 +5713,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, switch(rm) { case 0: /* fnop */ /* check exceptions (FreeBSD FPU probe) */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fwait(cpu_env); break; @@ -5930,15 +5894,13 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } break; case 0x1d: /* fucomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fucomi_ST0_FT0(cpu_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x1e: /* fcomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fcomi_ST0_FT0(cpu_env); set_cc_op(s, CC_OP_EFLAGS); @@ -5993,16 +5955,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } break; case 0x3d: /* fucomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fucomi_ST0_FT0(cpu_env); gen_helper_fpop(cpu_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x3e: /* fcomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg)); gen_helper_fcomi_ST0_FT0(cpu_env); gen_helper_fpop(cpu_env); @@ -6255,8 +6215,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, s->pc += 2; do_lret: if (s->pe && !s->vm86) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_lret_protected(cpu_env, tcg_const_i32(s->dflag), tcg_const_i32(val)); @@ -6295,8 +6254,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, set_cc_op(s, CC_OP_EFLAGS); } } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_iret_protected(cpu_env, tcg_const_i32(s->dflag), tcg_const_i32(s->pc - s->cs_base)); @@ -6434,8 +6392,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->vm86 && s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_read_eflags(cpu_T[0], cpu_env); gen_push_T0(s); } @@ -6672,32 +6629,28 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0x27: /* daa */ if (CODE64(s)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_daa(cpu_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x2f: /* das */ if (CODE64(s)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_das(cpu_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x37: /* aaa */ if (CODE64(s)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_aaa(cpu_env); set_cc_op(s, CC_OP_EFLAGS); break; case 0x3f: /* aas */ if (CODE64(s)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_helper_aas(cpu_env); set_cc_op(s, CC_OP_EFLAGS); break; @@ -6739,8 +6692,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, (HF_MP_MASK | HF_TS_MASK)) { gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fwait(cpu_env); } @@ -6759,8 +6711,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0xce: /* into */ if (CODE64(s)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_into(cpu_env, tcg_const_i32(s->pc - pc_start)); break; @@ -6906,8 +6857,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); if (b & 2) { gen_helper_rdmsr(cpu_env); @@ -6917,8 +6867,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } break; case 0x131: /* rdtsc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); if (use_icount) gen_io_start(); @@ -6929,8 +6878,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } break; case 0x133: /* rdpmc */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_rdpmc(cpu_env); break; @@ -6984,8 +6932,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, break; #endif case 0x1a2: /* cpuid */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_cpuid(cpu_env); break; @@ -6993,8 +6940,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start)); s->is_jmp = DISAS_TB_JUMP; @@ -7056,8 +7002,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (!s->pe || s->vm86) goto illegal_op; gen_ldst_modrm(env, s, modrm, OT_WORD, OR_TMP0, 0); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); if (op == 4) { gen_helper_verr(cpu_env, cpu_T[0]); } else { @@ -7095,8 +7040,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); #ifdef TARGET_X86_64 if (s->aflag == 2) { @@ -7156,8 +7100,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 2: /* lgdt */ case 3: /* lidt */ if (mod == 3) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); switch(rm) { case 0: /* VMRUN */ @@ -7285,8 +7228,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); gen_helper_invlpg(cpu_env, cpu_A0); @@ -7319,8 +7261,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 1: /* rdtscp */ if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP)) goto illegal_op; - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); if (use_icount) gen_io_start(); @@ -7436,8 +7377,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, reg = ((modrm >> 3) & 7) | rex_r; gen_ldst_modrm(env, s, modrm, OT_WORD, OR_TMP0, 0); t0 = tcg_temp_local_new(); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); if (b == 0x102) { gen_helper_lar(t0, cpu_env, cpu_T[0]); } else { @@ -7502,8 +7442,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 3: case 4: case 8: - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); if (b & 2) { gen_op_mov_TN_reg(ot, 0, rm); @@ -7592,8 +7531,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, break; } gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fxsave(cpu_env, cpu_A0, tcg_const_i32((s->dflag == 2))); break; @@ -7606,8 +7544,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, break; } gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); + gen_update_cc_op(s); gen_jmp_im(pc_start - s->cs_base); gen_helper_fxrstor(cpu_env, cpu_A0, tcg_const_i32((s->dflag == 2))); From 1608ecca95188dcf4f78072be48f41dbe2062b25 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 5 Oct 2012 18:42:59 +0200 Subject: [PATCH 1099/1634] target-i386: add helper functions to get other flags Introduce new functions to extract PF, SF, OF, ZF in addition to CF. These provide single entry points for optimizing accesses to a single flag. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 9dd3081a8f..9bbe969cd6 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -857,21 +857,49 @@ static void gen_compute_eflags(DisasContext *s, TCGv reg) tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); } +/* compute eflags.P to reg */ +static void gen_compute_eflags_p(DisasContext *s, TCGv reg) +{ + gen_compute_eflags(s, reg); + tcg_gen_shri_tl(reg, reg, 2); + tcg_gen_andi_tl(reg, reg, 1); +} + +/* compute eflags.S to reg */ +static void gen_compute_eflags_s(DisasContext *s, TCGv reg) +{ + gen_compute_eflags(s, reg); + tcg_gen_shri_tl(reg, reg, 7); + tcg_gen_andi_tl(reg, reg, 1); +} + +/* compute eflags.O to reg */ +static void gen_compute_eflags_o(DisasContext *s, TCGv reg) +{ + gen_compute_eflags(s, reg); + tcg_gen_shri_tl(reg, reg, 11); + tcg_gen_andi_tl(reg, reg, 1); +} + +/* compute eflags.Z to reg */ +static void gen_compute_eflags_z(DisasContext *s, TCGv reg) +{ + gen_compute_eflags(s, reg); + tcg_gen_shri_tl(reg, reg, 6); + tcg_gen_andi_tl(reg, reg, 1); +} + static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) { switch(jcc_op) { case JCC_O: - gen_compute_eflags(s, cpu_T[0]); - tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 11); - tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + gen_compute_eflags_o(s, cpu_T[0]); break; case JCC_B: gen_compute_eflags_c(s, cpu_T[0]); break; case JCC_Z: - gen_compute_eflags(s, cpu_T[0]); - tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 6); - tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + gen_compute_eflags_z(s, cpu_T[0]); break; case JCC_BE: gen_compute_eflags(s, cpu_tmp0); @@ -880,14 +908,10 @@ static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_S: - gen_compute_eflags(s, cpu_T[0]); - tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 7); - tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + gen_compute_eflags_s(s, cpu_T[0]); break; case JCC_P: - gen_compute_eflags(s, cpu_T[0]); - tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 2); - tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + gen_compute_eflags_p(s, cpu_T[0]); break; case JCC_L: gen_compute_eflags(s, cpu_tmp0); From d229edce1c58e6bb13d386bef4c31fc2e3850cb6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:03:26 -0800 Subject: [PATCH 1100/1634] target-i386: do not compute eflags multiple times consecutively After calling gen_compute_eflags, leave the computed value in cc_reg_src and set cc_op to CC_OP_EFLAGS. The next few patches will remove anyway most calls to gen_compute_eflags. As a result of this change it is more natural to remove the register argument from gen_compute_eflags and change all the callers. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 72 ++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 9bbe969cd6..6204764a5c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -845,47 +845,48 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg) tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); } -/* compute all eflags to reg */ -static void gen_compute_eflags(DisasContext *s, TCGv reg) +/* compute all eflags to cc_src */ +static void gen_compute_eflags(DisasContext *s) { + if (s->cc_op == CC_OP_EFLAGS) { + return; + } gen_update_cc_op(s); gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op); - if (TCGV_EQUAL(reg, cpu_cc_src)) { - tcg_gen_discard_tl(cpu_cc_dst); - set_cc_op(s, CC_OP_EFLAGS); - } - tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); + tcg_gen_discard_tl(cpu_cc_dst); + set_cc_op(s, CC_OP_EFLAGS); + tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32); } /* compute eflags.P to reg */ static void gen_compute_eflags_p(DisasContext *s, TCGv reg) { - gen_compute_eflags(s, reg); - tcg_gen_shri_tl(reg, reg, 2); + gen_compute_eflags(s); + tcg_gen_shri_tl(reg, cpu_cc_src, 2); tcg_gen_andi_tl(reg, reg, 1); } /* compute eflags.S to reg */ static void gen_compute_eflags_s(DisasContext *s, TCGv reg) { - gen_compute_eflags(s, reg); - tcg_gen_shri_tl(reg, reg, 7); + gen_compute_eflags(s); + tcg_gen_shri_tl(reg, cpu_cc_src, 7); tcg_gen_andi_tl(reg, reg, 1); } /* compute eflags.O to reg */ static void gen_compute_eflags_o(DisasContext *s, TCGv reg) { - gen_compute_eflags(s, reg); - tcg_gen_shri_tl(reg, reg, 11); + gen_compute_eflags(s); + tcg_gen_shri_tl(reg, cpu_cc_src, 11); tcg_gen_andi_tl(reg, reg, 1); } /* compute eflags.Z to reg */ static void gen_compute_eflags_z(DisasContext *s, TCGv reg) { - gen_compute_eflags(s, reg); - tcg_gen_shri_tl(reg, reg, 6); + gen_compute_eflags(s); + tcg_gen_shri_tl(reg, cpu_cc_src, 6); tcg_gen_andi_tl(reg, reg, 1); } @@ -902,9 +903,9 @@ static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) gen_compute_eflags_z(s, cpu_T[0]); break; case JCC_BE: - gen_compute_eflags(s, cpu_tmp0); - tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 6); - tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + gen_compute_eflags(s); + tcg_gen_shri_tl(cpu_T[0], cpu_cc_src, 6); + tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_cc_src); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_S: @@ -914,18 +915,18 @@ static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) gen_compute_eflags_p(s, cpu_T[0]); break; case JCC_L: - gen_compute_eflags(s, cpu_tmp0); - tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */ - tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 7); /* CC_S */ + gen_compute_eflags(s); + tcg_gen_shri_tl(cpu_T[0], cpu_cc_src, 11); /* CC_O */ + tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 7); /* CC_S */ tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; default: case JCC_LE: - gen_compute_eflags(s, cpu_tmp0); - tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */ - tcg_gen_shri_tl(cpu_tmp4, cpu_tmp0, 7); /* CC_S */ - tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 6); /* CC_Z */ + gen_compute_eflags(s); + tcg_gen_shri_tl(cpu_T[0], cpu_cc_src, 11); /* CC_O */ + tcg_gen_shri_tl(cpu_tmp4, cpu_cc_src, 7); /* CC_S */ + tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 6); /* CC_Z */ tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp4); tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); @@ -1619,7 +1620,7 @@ static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, } /* update eflags. It is needed anyway most of the time, do it always. */ - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); assert(s->cc_op == CC_OP_EFLAGS); label2 = gen_new_label(); @@ -1696,7 +1697,7 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, if (op2 != 0) { /* update eflags */ - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); assert(s->cc_op == CC_OP_EFLAGS); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); @@ -1720,8 +1721,7 @@ static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, int is_right) { - gen_update_cc_op(s); - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); assert(s->cc_op == CC_OP_EFLAGS); /* load */ @@ -6483,7 +6483,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; gen_op_mov_TN_reg(OT_BYTE, 0, R_AH); - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]); @@ -6491,21 +6491,21 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0x9f: /* lahf */ if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) goto illegal_op; - gen_compute_eflags(s, cpu_T[0]); + gen_compute_eflags(s); /* Note: gen_compute_eflags() only gives the condition codes */ - tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 0x02); + tcg_gen_ori_tl(cpu_T[0], cpu_cc_src, 0x02); gen_op_mov_reg_T0(OT_BYTE, R_AH); break; case 0xf5: /* cmc */ - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C); break; case 0xf8: /* clc */ - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C); break; case 0xf9: /* stc */ - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C); break; case 0xfc: /* cld */ @@ -7381,7 +7381,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } else { gen_op_mov_reg_v(ot, rm, t0); } - gen_compute_eflags(s, cpu_cc_src); + gen_compute_eflags(s); tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z); tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2); tcg_temp_free(t0); From ccfcdd09bf91aabe039d2dae0b5ec3a05f083e59 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:07:10 -0800 Subject: [PATCH 1101/1634] target-i386: no need to flush out cc_op before gen_eob This makes code more similar to the other callers of gen_eob, especially loopz/loopnz/jcxz. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 6204764a5c..71104fb926 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2303,8 +2303,8 @@ static inline void gen_jcc(DisasContext *s, int b, { int l1, l2; - gen_update_cc_op(s); if (s->jmp_opt) { + gen_update_cc_op(s); l1 = gen_new_label(); gen_jcc1(s, b, l1); set_cc_op(s, CC_OP_DYNAMIC); @@ -2315,11 +2315,9 @@ static inline void gen_jcc(DisasContext *s, int b, gen_goto_tb(s, 1, val); s->is_jmp = DISAS_TB_JUMP; } else { - l1 = gen_new_label(); l2 = gen_new_label(); gen_jcc1(s, b, l1); - set_cc_op(s, CC_OP_DYNAMIC); gen_jmp_im(next_eip); tcg_gen_br(l2); From b666265b2071e4288110f6553b598efe00246d06 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:26:38 -0800 Subject: [PATCH 1102/1634] target-i386: Move CC discards to set_cc_op This gets us universal coverage, rather than scattering discards around at various places. As a bonus, we do not emit redundant discards e.g. between sequential logic insns. Signed-off-by: Richard Henderson --- target-i386/translate.c | 48 +++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 71104fb926..a767b50b57 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -174,14 +174,48 @@ enum { OR_A0, /* temporary register used when doing address evaluation */ }; +enum { + USES_CC_DST = 1, + USES_CC_SRC = 2, +}; + +/* Bit set if the global variable is live after setting CC_OP to X. */ +static const uint8_t cc_op_live[CC_OP_NB] = { + [CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC, + [CC_OP_EFLAGS] = USES_CC_SRC, + [CC_OP_MULB ... CC_OP_MULQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_ADDB ... CC_OP_ADDQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_ADCB ... CC_OP_ADCQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_SUBB ... CC_OP_SUBQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_SBBB ... CC_OP_SBBQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_LOGICB ... CC_OP_LOGICQ] = USES_CC_DST, + [CC_OP_INCB ... CC_OP_INCQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_DECB ... CC_OP_DECQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_SHLB ... CC_OP_SHLQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_SARB ... CC_OP_SARQ] = USES_CC_DST | USES_CC_SRC, +}; + static void set_cc_op(DisasContext *s, CCOp op) { - if (s->cc_op != op) { - s->cc_op = op; - /* The DYNAMIC setting is translator only, and should never be - stored. Thus we always consider it clean. */ - s->cc_op_dirty = (op != CC_OP_DYNAMIC); + int dead; + + if (s->cc_op == op) { + return; } + + /* Discard CC computation that will no longer be used. */ + dead = cc_op_live[s->cc_op] & ~cc_op_live[op]; + if (dead & USES_CC_DST) { + tcg_gen_discard_tl(cpu_cc_dst); + } + if (dead & USES_CC_SRC) { + tcg_gen_discard_tl(cpu_cc_src); + } + + s->cc_op = op; + /* The DYNAMIC setting is translator only, and should never be + stored. Thus we always consider it clean. */ + s->cc_op_dirty = (op != CC_OP_DYNAMIC); } static void gen_update_cc_op(DisasContext *s) @@ -809,7 +843,6 @@ static inline void gen_movs(DisasContext *s, int ot) static void gen_op_update1_cc(void) { - tcg_gen_discard_tl(cpu_cc_src); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); } @@ -827,7 +860,6 @@ static inline void gen_op_cmpl_T0_T1_cc(void) static inline void gen_op_testl_T0_T1_cc(void) { - tcg_gen_discard_tl(cpu_cc_src); tcg_gen_and_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); } @@ -853,7 +885,6 @@ static void gen_compute_eflags(DisasContext *s) } gen_update_cc_op(s); gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op); - tcg_gen_discard_tl(cpu_cc_dst); set_cc_op(s, CC_OP_EFLAGS); tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32); } @@ -6640,7 +6671,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_mov_reg_T0(ot, reg); tcg_gen_movi_tl(cpu_cc_dst, 1); gen_set_label(label1); - tcg_gen_discard_tl(cpu_cc_src); set_cc_op(s, CC_OP_LOGICB + ot); } tcg_temp_free(t0); From 086c40778485f9a52d41a66fd4ef0d8723a2ac0a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:33:59 -0800 Subject: [PATCH 1103/1634] target-i386: do not call helper to compute ZF/SF ZF, SF and PF can always be computed from CC_DST except in the CC_OP_EFLAGS case (and CC_OP_DYNAMIC, which just resolves to CC_OP_EFLAGS in gen_compute_eflags). Use setcond to compute ZF and SF. We could also use a table lookup to compute PF. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index a767b50b57..026fbd6852 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -900,9 +900,22 @@ static void gen_compute_eflags_p(DisasContext *s, TCGv reg) /* compute eflags.S to reg */ static void gen_compute_eflags_s(DisasContext *s, TCGv reg) { - gen_compute_eflags(s); - tcg_gen_shri_tl(reg, cpu_cc_src, 7); - tcg_gen_andi_tl(reg, reg, 1); + switch (s->cc_op) { + case CC_OP_DYNAMIC: + gen_compute_eflags(s); + /* FALLTHRU */ + case CC_OP_EFLAGS: + tcg_gen_shri_tl(reg, cpu_cc_src, 7); + tcg_gen_andi_tl(reg, reg, 1); + break; + default: + { + int size = (s->cc_op - CC_OP_ADDB) & 3; + TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true); + tcg_gen_setcondi_tl(TCG_COND_LT, reg, t0, 0); + } + break; + } } /* compute eflags.O to reg */ @@ -916,9 +929,21 @@ static void gen_compute_eflags_o(DisasContext *s, TCGv reg) /* compute eflags.Z to reg */ static void gen_compute_eflags_z(DisasContext *s, TCGv reg) { - gen_compute_eflags(s); - tcg_gen_shri_tl(reg, cpu_cc_src, 6); - tcg_gen_andi_tl(reg, reg, 1); + switch (s->cc_op) { + case CC_OP_DYNAMIC: + gen_compute_eflags(s); + /* FALLTHRU */ + case CC_OP_EFLAGS: + tcg_gen_shri_tl(reg, cpu_cc_src, 6); + tcg_gen_andi_tl(reg, reg, 1); + break; + default: + { + int size = (s->cc_op - CC_OP_ADDB) & 3; + TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); + tcg_gen_setcondi_tl(TCG_COND_EQ, reg, t0, 0); + } + } } static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) From 8115f117357a63bff84522caac6c3bcadee0a285 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:37:28 -0800 Subject: [PATCH 1104/1634] target-i386: use inverted setcond when computing NS or NZ Make gen_compute_eflags_z and gen_compute_eflags_s able to compute the inverted condition, and use this in gen_setcc_slow_T0. We cannot do it yet in gen_compute_eflags_c, but prepare the code for it anyway. It is not worthwhile for PF, as usual. shr+and+xor could be replaced by and+setcond. I'm not doing it yet. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 49 ++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 026fbd6852..06aa7bf639 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -870,11 +870,14 @@ static void gen_op_update_neg_cc(void) } /* compute eflags.C to reg */ -static void gen_compute_eflags_c(DisasContext *s, TCGv reg) +static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv) { gen_update_cc_op(s); gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op); tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); + if (inv) { + tcg_gen_xori_tl(reg, reg, 1); + } } /* compute all eflags to cc_src */ @@ -898,7 +901,7 @@ static void gen_compute_eflags_p(DisasContext *s, TCGv reg) } /* compute eflags.S to reg */ -static void gen_compute_eflags_s(DisasContext *s, TCGv reg) +static void gen_compute_eflags_s(DisasContext *s, TCGv reg, bool inv) { switch (s->cc_op) { case CC_OP_DYNAMIC: @@ -907,12 +910,15 @@ static void gen_compute_eflags_s(DisasContext *s, TCGv reg) case CC_OP_EFLAGS: tcg_gen_shri_tl(reg, cpu_cc_src, 7); tcg_gen_andi_tl(reg, reg, 1); + if (inv) { + tcg_gen_xori_tl(reg, reg, 1); + } break; default: { int size = (s->cc_op - CC_OP_ADDB) & 3; TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true); - tcg_gen_setcondi_tl(TCG_COND_LT, reg, t0, 0); + tcg_gen_setcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, reg, t0, 0); } break; } @@ -927,7 +933,7 @@ static void gen_compute_eflags_o(DisasContext *s, TCGv reg) } /* compute eflags.Z to reg */ -static void gen_compute_eflags_z(DisasContext *s, TCGv reg) +static void gen_compute_eflags_z(DisasContext *s, TCGv reg, bool inv) { switch (s->cc_op) { case CC_OP_DYNAMIC: @@ -936,27 +942,33 @@ static void gen_compute_eflags_z(DisasContext *s, TCGv reg) case CC_OP_EFLAGS: tcg_gen_shri_tl(reg, cpu_cc_src, 6); tcg_gen_andi_tl(reg, reg, 1); + if (inv) { + tcg_gen_xori_tl(reg, reg, 1); + } break; default: { int size = (s->cc_op - CC_OP_ADDB) & 3; TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); - tcg_gen_setcondi_tl(TCG_COND_EQ, reg, t0, 0); + tcg_gen_setcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, reg, t0, 0); } + break; } } -static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) +static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op, bool inv) { switch(jcc_op) { case JCC_O: gen_compute_eflags_o(s, cpu_T[0]); break; case JCC_B: - gen_compute_eflags_c(s, cpu_T[0]); + gen_compute_eflags_c(s, cpu_T[0], inv); + inv = false; break; case JCC_Z: - gen_compute_eflags_z(s, cpu_T[0]); + gen_compute_eflags_z(s, cpu_T[0], inv); + inv = false; break; case JCC_BE: gen_compute_eflags(s); @@ -965,7 +977,8 @@ static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; case JCC_S: - gen_compute_eflags_s(s, cpu_T[0]); + gen_compute_eflags_s(s, cpu_T[0], inv); + inv = false; break; case JCC_P: gen_compute_eflags_p(s, cpu_T[0]); @@ -988,6 +1001,9 @@ static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op) tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); break; } + if (inv) { + tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1); + } } /* return true if setcc_slow is not needed (WARNING: must be kept in @@ -1153,7 +1169,7 @@ static inline void gen_jcc1(DisasContext *s, int b, int l1) break; default: slow_jcc: - gen_setcc_slow_T0(s, jcc_op); + gen_setcc_slow_T0(s, jcc_op, false); tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_T[0], 0, l1); break; @@ -1367,7 +1383,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) } switch(op) { case OP_ADCL: - gen_compute_eflags_c(s1, cpu_tmp4); + gen_compute_eflags_c(s1, cpu_tmp4, false); tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4); if (d != OR_TMP0) @@ -1382,7 +1398,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) set_cc_op(s1, CC_OP_DYNAMIC); break; case OP_SBBL: - gen_compute_eflags_c(s1, cpu_tmp4); + gen_compute_eflags_c(s1, cpu_tmp4, false); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4); if (d != OR_TMP0) @@ -1456,7 +1472,7 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_op_mov_TN_reg(ot, 0, d); else gen_op_ld_T0_A0(ot + s1->mem_index); - gen_compute_eflags_c(s1, cpu_cc_src); + gen_compute_eflags_c(s1, cpu_cc_src, false); if (c > 0) { tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1); set_cc_op(s1, CC_OP_INCB + ot); @@ -2407,10 +2423,7 @@ static void gen_setcc(DisasContext *s, int b) worth to */ inv = b & 1; jcc_op = (b >> 1) & 7; - gen_setcc_slow_T0(s, jcc_op); - if (inv) { - tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1); - } + gen_setcc_slow_T0(s, jcc_op, inv); } } @@ -6881,7 +6894,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0xd6: /* salc */ if (CODE64(s)) goto illegal_op; - gen_compute_eflags_c(s, cpu_T[0]); + gen_compute_eflags_c(s, cpu_T[0], false); tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; From 06847f1f1a7cff71f68dc6416cdd729c01ae2305 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:46:02 -0800 Subject: [PATCH 1105/1634] target-i386: convert gen_compute_eflags_c to TCG Do the switch at translation time, converting the helper templates to TCG opcodes. In some cases CF can be computed with a single setcond, though others it may require a little more work. In the CC_OP_DYNAMIC case, compute the whole EFLAGS, same as for ZF/SF/PF. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 109 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 11 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 06aa7bf639..ea1b003749 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -869,17 +869,6 @@ static void gen_op_update_neg_cc(void) tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); } -/* compute eflags.C to reg */ -static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv) -{ - gen_update_cc_op(s); - gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op); - tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); - if (inv) { - tcg_gen_xori_tl(reg, reg, 1); - } -} - /* compute all eflags to cc_src */ static void gen_compute_eflags(DisasContext *s) { @@ -892,6 +881,104 @@ static void gen_compute_eflags(DisasContext *s) tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32); } +/* compute eflags.C to reg */ +static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv) +{ + TCGv t0, t1; + int size; + + switch (s->cc_op) { + case CC_OP_SUBB ... CC_OP_SUBQ: + /* (DATA_TYPE)(CC_DST + CC_SRC) < (DATA_TYPE)CC_SRC */ + size = s->cc_op - CC_OP_SUBB; + t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); + /* If no temporary was used, be careful not to alias t1 and t0. */ + t0 = TCGV_EQUAL(t1, cpu_cc_src) ? cpu_tmp0 : reg; + tcg_gen_add_tl(t0, cpu_cc_dst, cpu_cc_src); + gen_extu(size, t0); + goto add_sub; + + case CC_OP_ADDB ... CC_OP_ADDQ: + /* (DATA_TYPE)CC_DST < (DATA_TYPE)CC_SRC */ + size = s->cc_op - CC_OP_ADDB; + t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); + t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); + add_sub: + tcg_gen_setcond_tl(inv ? TCG_COND_GEU : TCG_COND_LTU, reg, t0, t1); + inv = false; + break; + + case CC_OP_SBBB ... CC_OP_SBBQ: + /* (DATA_TYPE)(CC_DST + CC_SRC + 1) <= (DATA_TYPE)CC_SRC */ + size = s->cc_op - CC_OP_SBBB; + t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); + if (TCGV_EQUAL(t1, reg) && TCGV_EQUAL(reg, cpu_cc_src)) { + tcg_gen_mov_tl(cpu_tmp0, cpu_cc_src); + t1 = cpu_tmp0; + } + + tcg_gen_add_tl(reg, cpu_cc_dst, cpu_cc_src); + tcg_gen_addi_tl(reg, reg, 1); + gen_extu(size, reg); + t0 = reg; + goto adc_sbb; + + case CC_OP_ADCB ... CC_OP_ADCQ: + /* (DATA_TYPE)CC_DST <= (DATA_TYPE)CC_SRC */ + size = s->cc_op - CC_OP_ADCB; + t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); + t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); + adc_sbb: + tcg_gen_setcond_tl(inv ? TCG_COND_GTU : TCG_COND_LEU, reg, t0, t1); + inv = false; + break; + + case CC_OP_LOGICB ... CC_OP_LOGICQ: + tcg_gen_movi_tl(reg, 0); + break; + + case CC_OP_INCB ... CC_OP_INCQ: + case CC_OP_DECB ... CC_OP_DECQ: + if (inv) { + tcg_gen_xori_tl(reg, cpu_cc_src, 1); + } else { + tcg_gen_mov_tl(reg, cpu_cc_src); + } + inv = false; + break; + + case CC_OP_SHLB ... CC_OP_SHLQ: + /* (CC_SRC >> (DATA_BITS - 1)) & 1 */ + size = s->cc_op - CC_OP_SHLB; + tcg_gen_shri_tl(reg, cpu_cc_src, (8 << size) - 1); + tcg_gen_andi_tl(reg, reg, 1); + break; + + case CC_OP_MULB ... CC_OP_MULQ: + tcg_gen_setcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, + reg, cpu_cc_src, 0); + inv = false; + break; + + case CC_OP_EFLAGS: + case CC_OP_SARB ... CC_OP_SARQ: + /* CC_SRC & 1 */ + tcg_gen_andi_tl(reg, cpu_cc_src, 1); + break; + + default: + /* The need to compute only C from CC_OP_DYNAMIC is important + in efficiently implementing e.g. INC at the start of a TB. */ + gen_update_cc_op(s); + gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op); + tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); + break; + } + if (inv) { + tcg_gen_xori_tl(reg, reg, 1); + } +} + /* compute eflags.P to reg */ static void gen_compute_eflags_p(DisasContext *s, TCGv reg) { From 1a5c635947e60167c4626dd274531b8b0eacc2e5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 5 Oct 2012 22:54:34 +0200 Subject: [PATCH 1106/1634] target-i386: change gen_setcc_slow_T0 to gen_setcc_slow Do not hard code the destination register. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index ea1b003749..c510732765 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1043,53 +1043,54 @@ static void gen_compute_eflags_z(DisasContext *s, TCGv reg, bool inv) } } -static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op, bool inv) +static void gen_setcc_slow(DisasContext *s, int jcc_op, TCGv reg, bool inv) { + assert(!TCGV_EQUAL(reg, cpu_cc_src)); switch(jcc_op) { case JCC_O: - gen_compute_eflags_o(s, cpu_T[0]); + gen_compute_eflags_o(s, reg); break; case JCC_B: - gen_compute_eflags_c(s, cpu_T[0], inv); + gen_compute_eflags_c(s, reg, inv); inv = false; break; case JCC_Z: - gen_compute_eflags_z(s, cpu_T[0], inv); + gen_compute_eflags_z(s, reg, inv); inv = false; break; case JCC_BE: gen_compute_eflags(s); - tcg_gen_shri_tl(cpu_T[0], cpu_cc_src, 6); - tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_cc_src); - tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + tcg_gen_shri_tl(reg, cpu_cc_src, 6); + tcg_gen_or_tl(reg, reg, cpu_cc_src); + tcg_gen_andi_tl(reg, reg, 1); break; case JCC_S: - gen_compute_eflags_s(s, cpu_T[0], inv); + gen_compute_eflags_s(s, reg, inv); inv = false; break; case JCC_P: - gen_compute_eflags_p(s, cpu_T[0]); + gen_compute_eflags_p(s, reg); break; case JCC_L: gen_compute_eflags(s); - tcg_gen_shri_tl(cpu_T[0], cpu_cc_src, 11); /* CC_O */ + tcg_gen_shri_tl(reg, cpu_cc_src, 11); /* CC_O */ tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 7); /* CC_S */ - tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0); - tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + tcg_gen_xor_tl(reg, reg, cpu_tmp0); + tcg_gen_andi_tl(reg, reg, 1); break; default: case JCC_LE: gen_compute_eflags(s); - tcg_gen_shri_tl(cpu_T[0], cpu_cc_src, 11); /* CC_O */ + tcg_gen_shri_tl(reg, cpu_cc_src, 11); /* CC_O */ tcg_gen_shri_tl(cpu_tmp4, cpu_cc_src, 7); /* CC_S */ tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 6); /* CC_Z */ - tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp4); - tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); - tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1); + tcg_gen_xor_tl(reg, reg, cpu_tmp4); + tcg_gen_or_tl(reg, reg, cpu_tmp0); + tcg_gen_andi_tl(reg, reg, 1); break; } if (inv) { - tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1); + tcg_gen_xori_tl(reg, reg, 1); } } @@ -1256,7 +1257,7 @@ static inline void gen_jcc1(DisasContext *s, int b, int l1) break; default: slow_jcc: - gen_setcc_slow_T0(s, jcc_op, false); + gen_setcc_slow(s, jcc_op, cpu_T[0], false); tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_T[0], 0, l1); break; @@ -2510,7 +2511,7 @@ static void gen_setcc(DisasContext *s, int b) worth to */ inv = b & 1; jcc_op = (b >> 1) & 7; - gen_setcc_slow_T0(s, jcc_op, inv); + gen_setcc_slow(s, jcc_op, cpu_T[0], inv); } } From 2cb4764577f270eec259123955a6396ad6a2f161 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:49:43 -0800 Subject: [PATCH 1107/1634] target-i386: optimize setbe This is looking at EFLAGS, but it can do so more efficiently with setcond. Reviewed-by: Blue Swirl Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index c510732765..dab69839a7 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1060,10 +1060,9 @@ static void gen_setcc_slow(DisasContext *s, int jcc_op, TCGv reg, bool inv) break; case JCC_BE: gen_compute_eflags(s); - tcg_gen_shri_tl(reg, cpu_cc_src, 6); - tcg_gen_or_tl(reg, reg, cpu_cc_src); - tcg_gen_andi_tl(reg, reg, 1); - break; + tcg_gen_andi_tl(reg, cpu_cc_src, CC_Z | CC_C); + tcg_gen_setcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, reg, reg, 0); + return; case JCC_S: gen_compute_eflags_s(s, reg, inv); inv = false; From be10b289d697420b6e0d8d1a681aa64555066639 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 13:53:51 -0800 Subject: [PATCH 1108/1634] target-i386: optimize setle And allow gen_setcc_slow to operate on cpu_cc_src. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index dab69839a7..fea43c702e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1045,7 +1045,6 @@ static void gen_compute_eflags_z(DisasContext *s, TCGv reg, bool inv) static void gen_setcc_slow(DisasContext *s, int jcc_op, TCGv reg, bool inv) { - assert(!TCGV_EQUAL(reg, cpu_cc_src)); switch(jcc_op) { case JCC_O: gen_compute_eflags_o(s, reg); @@ -1072,20 +1071,18 @@ static void gen_setcc_slow(DisasContext *s, int jcc_op, TCGv reg, bool inv) break; case JCC_L: gen_compute_eflags(s); - tcg_gen_shri_tl(reg, cpu_cc_src, 11); /* CC_O */ - tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 7); /* CC_S */ + tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 11); /* CC_O */ + tcg_gen_shri_tl(reg, cpu_cc_src, 7); /* CC_S */ tcg_gen_xor_tl(reg, reg, cpu_tmp0); tcg_gen_andi_tl(reg, reg, 1); break; default: case JCC_LE: gen_compute_eflags(s); - tcg_gen_shri_tl(reg, cpu_cc_src, 11); /* CC_O */ - tcg_gen_shri_tl(cpu_tmp4, cpu_cc_src, 7); /* CC_S */ - tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 6); /* CC_Z */ - tcg_gen_xor_tl(reg, reg, cpu_tmp4); - tcg_gen_or_tl(reg, reg, cpu_tmp0); - tcg_gen_andi_tl(reg, reg, 1); + tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 4); /* CC_O -> CC_S */ + tcg_gen_xor_tl(reg, cpu_tmp0, cpu_cc_src); + tcg_gen_andi_tl(reg, reg, CC_S | CC_Z); + tcg_gen_setcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, reg, reg, 0); break; } if (inv) { From c365395e9bd2b3bcac48ef562c187ea6ab9820ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 5 Oct 2012 23:00:10 +0200 Subject: [PATCH 1109/1634] target-i386: optimize setcc instructions Reconstruct the arguments for complex conditions involving CC_OP_SUBx (BE, L, LE). In the others do it via setcond and gen_setcc_slow (which is not that slow in many cases). Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 97 ++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 59 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index fea43c702e..5c9211f7db 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1090,55 +1090,55 @@ static void gen_setcc_slow(DisasContext *s, int jcc_op, TCGv reg, bool inv) } } -/* return true if setcc_slow is not needed (WARNING: must be kept in - sync with gen_jcc1) */ -static int is_fast_jcc_case(DisasContext *s, int b) +/* perform a conditional store into register 'reg' according to jump opcode + value 'b'. In the fast case, T0 is guaranted not to be used. */ +static inline void gen_setcc1(DisasContext *s, int b, TCGv reg) { - int jcc_op; + int inv, jcc_op, size, cond; + TCGv t0; + + inv = b & 1; jcc_op = (b >> 1) & 7; - switch(s->cc_op) { - /* we optimize the cmp/jcc case */ + + switch (s->cc_op) { + /* we optimize relational operators for the cmp/jcc case */ case CC_OP_SUBB: case CC_OP_SUBW: case CC_OP_SUBL: case CC_OP_SUBQ: - if (jcc_op == JCC_O || jcc_op == JCC_P) + size = s->cc_op - CC_OP_SUBB; + switch (jcc_op) { + case JCC_BE: + cond = inv ? TCG_COND_GTU : TCG_COND_LEU; + tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); + gen_extu(size, cpu_tmp4); + t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); + tcg_gen_setcond_tl(cond, reg, cpu_tmp4, t0); + break; + + case JCC_L: + cond = inv ? TCG_COND_GE : TCG_COND_LT; + goto fast_jcc_l; + case JCC_LE: + cond = inv ? TCG_COND_GT : TCG_COND_LE; + fast_jcc_l: + tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); + gen_exts(size, cpu_tmp4); + t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, true); + tcg_gen_setcond_tl(cond, reg, cpu_tmp4, t0); + break; + + default: goto slow_jcc; + } break; - /* some jumps are easy to compute */ - case CC_OP_ADDB: - case CC_OP_ADDW: - case CC_OP_ADDL: - case CC_OP_ADDQ: - - case CC_OP_LOGICB: - case CC_OP_LOGICW: - case CC_OP_LOGICL: - case CC_OP_LOGICQ: - - case CC_OP_INCB: - case CC_OP_INCW: - case CC_OP_INCL: - case CC_OP_INCQ: - - case CC_OP_DECB: - case CC_OP_DECW: - case CC_OP_DECL: - case CC_OP_DECQ: - - case CC_OP_SHLB: - case CC_OP_SHLW: - case CC_OP_SHLL: - case CC_OP_SHLQ: - if (jcc_op != JCC_Z && jcc_op != JCC_S) - goto slow_jcc; - break; default: slow_jcc: - return 0; + /* gen_setcc_slow actually generates good code for JC, JZ and JS */ + gen_setcc_slow(s, jcc_op, reg, inv); + break; } - return 1; } /* generate a conditional jump to label 'l1' according to jump opcode @@ -2487,28 +2487,7 @@ static inline void gen_jcc(DisasContext *s, int b, static void gen_setcc(DisasContext *s, int b) { - int inv, jcc_op, l1; - TCGv t0; - - if (is_fast_jcc_case(s, b)) { - /* nominal case: we use a jump */ - /* XXX: make it faster by adding new instructions in TCG */ - t0 = tcg_temp_local_new(); - tcg_gen_movi_tl(t0, 0); - l1 = gen_new_label(); - gen_jcc1(s, b ^ 1, l1); - tcg_gen_movi_tl(t0, 1); - gen_set_label(l1); - tcg_gen_mov_tl(cpu_T[0], t0); - tcg_temp_free(t0); - } else { - /* slow case: it is more efficient not to generate a jump, - although it is questionnable whether this optimization is - worth to */ - inv = b & 1; - jcc_op = (b >> 1) & 7; - gen_setcc_slow(s, jcc_op, cpu_T[0], inv); - } + gen_setcc1(s, b, cpu_T[0]); } static inline void gen_op_movl_T0_seg(int seg_reg) From bec93d7283b635aabaf0bbff67b6da7fc99e020a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 14:21:52 -0800 Subject: [PATCH 1110/1634] target-i386: introduce CCPrepare Introduce a struct that describes how to build a *cond operation that checks for a given x86 condition code. For now, just change gen_compute_eflags_* to return the new struct, generate code for the CCPrepare struct, and go on as before. [rth: Use ctz with the proper width rather than ffs.] Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 147 +++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 54 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 5c9211f7db..06f0fbced0 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -23,6 +23,7 @@ #include #include +#include "qemu/host-utils.h" #include "cpu.h" #include "disas/disas.h" #include "tcg-op.h" @@ -47,6 +48,14 @@ #define REX_B(s) 0 #endif +#ifdef TARGET_X86_64 +# define ctztl ctz64 +# define clztl clz64 +#else +# define ctztl ctz32 +# define clztl clz32 +#endif + //#define MACRO_TEST 1 /* global register indexes */ @@ -881,11 +890,21 @@ static void gen_compute_eflags(DisasContext *s) tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32); } +typedef struct CCPrepare { + TCGCond cond; + TCGv reg; + TCGv reg2; + target_ulong imm; + target_ulong mask; + bool use_reg2; + bool no_setcond; +} CCPrepare; + /* compute eflags.C to reg */ -static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv) +static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) { TCGv t0, t1; - int size; + int size, shift; switch (s->cc_op) { case CC_OP_SUBB ... CC_OP_SUBQ: @@ -904,9 +923,8 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv) t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); add_sub: - tcg_gen_setcond_tl(inv ? TCG_COND_GEU : TCG_COND_LTU, reg, t0, t1); - inv = false; - break; + return (CCPrepare) { .cond = TCG_COND_LTU, .reg = t0, + .reg2 = t1, .mask = -1, .use_reg2 = true }; case CC_OP_SBBB ... CC_OP_SBBQ: /* (DATA_TYPE)(CC_DST + CC_SRC + 1) <= (DATA_TYPE)CC_SRC */ @@ -929,42 +947,33 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv) t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); adc_sbb: - tcg_gen_setcond_tl(inv ? TCG_COND_GTU : TCG_COND_LEU, reg, t0, t1); - inv = false; - break; + return (CCPrepare) { .cond = TCG_COND_LEU, .reg = t0, + .reg2 = t1, .mask = -1, .use_reg2 = true }; case CC_OP_LOGICB ... CC_OP_LOGICQ: - tcg_gen_movi_tl(reg, 0); - break; + return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 }; case CC_OP_INCB ... CC_OP_INCQ: case CC_OP_DECB ... CC_OP_DECQ: - if (inv) { - tcg_gen_xori_tl(reg, cpu_cc_src, 1); - } else { - tcg_gen_mov_tl(reg, cpu_cc_src); - } - inv = false; - break; + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = -1, .no_setcond = true }; case CC_OP_SHLB ... CC_OP_SHLQ: /* (CC_SRC >> (DATA_BITS - 1)) & 1 */ size = s->cc_op - CC_OP_SHLB; - tcg_gen_shri_tl(reg, cpu_cc_src, (8 << size) - 1); - tcg_gen_andi_tl(reg, reg, 1); - break; + shift = (8 << size) - 1; + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = (target_ulong)1 << shift }; case CC_OP_MULB ... CC_OP_MULQ: - tcg_gen_setcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, - reg, cpu_cc_src, 0); - inv = false; - break; + return (CCPrepare) { .cond = TCG_COND_NE, + .reg = cpu_cc_src, .mask = -1 }; case CC_OP_EFLAGS: case CC_OP_SARB ... CC_OP_SARQ: /* CC_SRC & 1 */ - tcg_gen_andi_tl(reg, cpu_cc_src, 1); - break; + return (CCPrepare) { .cond = TCG_COND_NE, + .reg = cpu_cc_src, .mask = CC_C }; default: /* The need to compute only C from CC_OP_DYNAMIC is important @@ -972,74 +981,104 @@ static void gen_compute_eflags_c(DisasContext *s, TCGv reg, bool inv) gen_update_cc_op(s); gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op); tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); - break; - } - if (inv) { - tcg_gen_xori_tl(reg, reg, 1); + return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, + .mask = -1, .no_setcond = true }; } } /* compute eflags.P to reg */ -static void gen_compute_eflags_p(DisasContext *s, TCGv reg) +static CCPrepare gen_prepare_eflags_p(DisasContext *s, TCGv reg) { gen_compute_eflags(s); - tcg_gen_shri_tl(reg, cpu_cc_src, 2); - tcg_gen_andi_tl(reg, reg, 1); + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = CC_P }; } /* compute eflags.S to reg */ -static void gen_compute_eflags_s(DisasContext *s, TCGv reg, bool inv) +static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg) { switch (s->cc_op) { case CC_OP_DYNAMIC: gen_compute_eflags(s); /* FALLTHRU */ case CC_OP_EFLAGS: - tcg_gen_shri_tl(reg, cpu_cc_src, 7); - tcg_gen_andi_tl(reg, reg, 1); - if (inv) { - tcg_gen_xori_tl(reg, reg, 1); - } - break; + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = CC_S }; default: { int size = (s->cc_op - CC_OP_ADDB) & 3; TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true); - tcg_gen_setcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, reg, t0, 0); + return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 }; } - break; } } /* compute eflags.O to reg */ -static void gen_compute_eflags_o(DisasContext *s, TCGv reg) +static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg) { gen_compute_eflags(s); - tcg_gen_shri_tl(reg, cpu_cc_src, 11); - tcg_gen_andi_tl(reg, reg, 1); + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = CC_O }; } /* compute eflags.Z to reg */ -static void gen_compute_eflags_z(DisasContext *s, TCGv reg, bool inv) +static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) { switch (s->cc_op) { case CC_OP_DYNAMIC: gen_compute_eflags(s); /* FALLTHRU */ case CC_OP_EFLAGS: - tcg_gen_shri_tl(reg, cpu_cc_src, 6); - tcg_gen_andi_tl(reg, reg, 1); - if (inv) { - tcg_gen_xori_tl(reg, reg, 1); - } - break; + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = CC_Z }; default: { int size = (s->cc_op - CC_OP_ADDB) & 3; TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); - tcg_gen_setcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, reg, t0, 0); + return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 }; } - break; + } +} + +#define gen_compute_eflags_c(s, reg, inv) \ + gen_do_setcc(reg, gen_prepare_eflags_c(s, reg), inv) +#define gen_compute_eflags_p(s, reg) \ + gen_do_setcc(reg, gen_prepare_eflags_p(s, reg), false) +#define gen_compute_eflags_s(s, reg, inv) \ + gen_do_setcc(reg, gen_prepare_eflags_s(s, reg), inv) +#define gen_compute_eflags_o(s, reg) \ + gen_do_setcc(reg, gen_prepare_eflags_o(s, reg), false) +#define gen_compute_eflags_z(s, reg, inv) \ + gen_do_setcc(reg, gen_prepare_eflags_z(s, reg), inv) + +static void gen_do_setcc(TCGv reg, struct CCPrepare cc, bool inv) +{ + if (inv) { + cc.cond = tcg_invert_cond(cc.cond); + } + + if (cc.no_setcond) { + if (cc.cond == TCG_COND_EQ) { + tcg_gen_xori_tl(reg, cc.reg, 1); + } else { + tcg_gen_mov_tl(reg, cc.reg); + } + return; + } + + if (cc.cond == TCG_COND_NE && !cc.use_reg2 && cc.imm == 0 && + cc.mask != 0 && (cc.mask & (cc.mask - 1)) == 0) { + tcg_gen_shri_tl(reg, cc.reg, ctztl(cc.mask)); + tcg_gen_andi_tl(reg, reg, 1); + return; + } + if (cc.mask != -1) { + tcg_gen_andi_tl(reg, cc.reg, cc.mask); + } + if (cc.use_reg2) { + tcg_gen_setcond_tl(cc.cond, reg, cc.reg, cc.reg2); + } else { + tcg_gen_setcondi_tl(cc.cond, reg, cc.reg, cc.imm); } } From 276e6b5f069e189e204a4320f824daa07db10286 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 14:33:45 -0800 Subject: [PATCH 1111/1634] target-i386: introduce gen_prepare_cc This makes the i386 front-end able to create CCPrepare structs for all condition, not just those that come from a single flag. In particular, JCC_L and JCC_LE can be optimized because gen_prepare_cc is not forced to return a result in bit 0 (unlike gen_setcc_slow). However, for now the slow jcc operations will still go through CC computation in a single-bit temporary, followed by a brcond if the temporary is nonzero. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 91 +++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 06f0fbced0..046d82f43d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1042,14 +1042,6 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) #define gen_compute_eflags_c(s, reg, inv) \ gen_do_setcc(reg, gen_prepare_eflags_c(s, reg), inv) -#define gen_compute_eflags_p(s, reg) \ - gen_do_setcc(reg, gen_prepare_eflags_p(s, reg), false) -#define gen_compute_eflags_s(s, reg, inv) \ - gen_do_setcc(reg, gen_prepare_eflags_s(s, reg), inv) -#define gen_compute_eflags_o(s, reg) \ - gen_do_setcc(reg, gen_prepare_eflags_o(s, reg), false) -#define gen_compute_eflags_z(s, reg, inv) \ - gen_do_setcc(reg, gen_prepare_eflags_z(s, reg), inv) static void gen_do_setcc(TCGv reg, struct CCPrepare cc, bool inv) { @@ -1074,6 +1066,7 @@ static void gen_do_setcc(TCGv reg, struct CCPrepare cc, bool inv) } if (cc.mask != -1) { tcg_gen_andi_tl(reg, cc.reg, cc.mask); + cc.reg = reg; } if (cc.use_reg2) { tcg_gen_setcond_tl(cc.cond, reg, cc.reg, cc.reg2); @@ -1082,58 +1075,50 @@ static void gen_do_setcc(TCGv reg, struct CCPrepare cc, bool inv) } } -static void gen_setcc_slow(DisasContext *s, int jcc_op, TCGv reg, bool inv) +static CCPrepare gen_prepare_cc_slow(DisasContext *s, int jcc_op, TCGv reg) { switch(jcc_op) { case JCC_O: - gen_compute_eflags_o(s, reg); - break; + return gen_prepare_eflags_o(s, reg); case JCC_B: - gen_compute_eflags_c(s, reg, inv); - inv = false; - break; + return gen_prepare_eflags_c(s, reg); case JCC_Z: - gen_compute_eflags_z(s, reg, inv); - inv = false; - break; + return gen_prepare_eflags_z(s, reg); case JCC_BE: gen_compute_eflags(s); - tcg_gen_andi_tl(reg, cpu_cc_src, CC_Z | CC_C); - tcg_gen_setcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, reg, reg, 0); - return; + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = CC_Z | CC_C }; case JCC_S: - gen_compute_eflags_s(s, reg, inv); - inv = false; - break; + return gen_prepare_eflags_s(s, reg); case JCC_P: - gen_compute_eflags_p(s, reg); - break; + return gen_prepare_eflags_p(s, reg); case JCC_L: gen_compute_eflags(s); - tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 11); /* CC_O */ - tcg_gen_shri_tl(reg, cpu_cc_src, 7); /* CC_S */ - tcg_gen_xor_tl(reg, reg, cpu_tmp0); - tcg_gen_andi_tl(reg, reg, 1); - break; + if (TCGV_EQUAL(reg, cpu_cc_src)) { + reg = cpu_tmp0; + } + tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */ + tcg_gen_xor_tl(reg, reg, cpu_cc_src); + return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, .mask = CC_S }; default: case JCC_LE: gen_compute_eflags(s); - tcg_gen_shri_tl(cpu_tmp0, cpu_cc_src, 4); /* CC_O -> CC_S */ - tcg_gen_xor_tl(reg, cpu_tmp0, cpu_cc_src); - tcg_gen_andi_tl(reg, reg, CC_S | CC_Z); - tcg_gen_setcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, reg, reg, 0); - break; - } - if (inv) { - tcg_gen_xori_tl(reg, reg, 1); + if (TCGV_EQUAL(reg, cpu_cc_src)) { + reg = cpu_tmp0; + } + tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */ + tcg_gen_xor_tl(reg, reg, cpu_cc_src); + return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, + .mask = CC_S | CC_Z }; } } /* perform a conditional store into register 'reg' according to jump opcode value 'b'. In the fast case, T0 is guaranted not to be used. */ -static inline void gen_setcc1(DisasContext *s, int b, TCGv reg) +static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) { int inv, jcc_op, size, cond; + CCPrepare cc; TCGv t0; inv = b & 1; @@ -1148,23 +1133,24 @@ static inline void gen_setcc1(DisasContext *s, int b, TCGv reg) size = s->cc_op - CC_OP_SUBB; switch (jcc_op) { case JCC_BE: - cond = inv ? TCG_COND_GTU : TCG_COND_LEU; tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); gen_extu(size, cpu_tmp4); t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); - tcg_gen_setcond_tl(cond, reg, cpu_tmp4, t0); + cc = (CCPrepare) { .cond = TCG_COND_LEU, .reg = cpu_tmp4, + .reg2 = t0, .mask = -1, .use_reg2 = true }; break; case JCC_L: - cond = inv ? TCG_COND_GE : TCG_COND_LT; + cond = TCG_COND_LT; goto fast_jcc_l; case JCC_LE: - cond = inv ? TCG_COND_GT : TCG_COND_LE; + cond = TCG_COND_LE; fast_jcc_l: tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); gen_exts(size, cpu_tmp4); t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, true); - tcg_gen_setcond_tl(cond, reg, cpu_tmp4, t0); + cc = (CCPrepare) { .cond = cond, .reg = cpu_tmp4, + .reg2 = t0, .mask = -1, .use_reg2 = true }; break; default: @@ -1174,12 +1160,20 @@ static inline void gen_setcc1(DisasContext *s, int b, TCGv reg) default: slow_jcc: - /* gen_setcc_slow actually generates good code for JC, JZ and JS */ - gen_setcc_slow(s, jcc_op, reg, inv); + /* gen_prepare_cc_slow actually generates good code for JC, JZ and JS */ + cc = gen_prepare_cc_slow(s, jcc_op, reg); break; } + + if (inv) { + cc.cond = tcg_invert_cond(cc.cond); + } + return cc; } +#define gen_setcc1(s, b, reg) \ + gen_do_setcc(reg, gen_prepare_cc(s, b, reg), false) + /* generate a conditional jump to label 'l1' according to jump opcode value 'b'. In the fast case, T0 is guaranted not to be used. */ static inline void gen_jcc1(DisasContext *s, int b, int l1) @@ -1292,9 +1286,8 @@ static inline void gen_jcc1(DisasContext *s, int b, int l1) break; default: slow_jcc: - gen_setcc_slow(s, jcc_op, cpu_T[0], false); - tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, - cpu_T[0], 0, l1); + gen_setcc1(s, b, cpu_T[0]); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_T[0], 0, l1); break; } } From 943131ca98af142da7b99111b410e741a5d42338 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 7 Oct 2012 15:53:23 +0200 Subject: [PATCH 1112/1634] target-i386: use CCPrepare to generate conditional jumps This simplifies all the jump generation code. CCPrepare allows the code to create an efficient brcond always, so there is no need to duplicate the setcc and jcc code. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 119 +++------------------------------------- 1 file changed, 9 insertions(+), 110 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 046d82f43d..b081fc0cec 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1178,117 +1178,16 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) value 'b'. In the fast case, T0 is guaranted not to be used. */ static inline void gen_jcc1(DisasContext *s, int b, int l1) { - int inv, jcc_op, size, cond; - TCGv t0; + CCPrepare cc = gen_prepare_cc(s, b, cpu_T[0]); - inv = b & 1; - jcc_op = (b >> 1) & 7; - - switch (s->cc_op) { - /* we optimize the cmp/jcc case */ - case CC_OP_SUBB: - case CC_OP_SUBW: - case CC_OP_SUBL: - case CC_OP_SUBQ: - - size = s->cc_op - CC_OP_SUBB; - switch(jcc_op) { - case JCC_Z: - fast_jcc_z: - t0 = gen_ext_tl(cpu_tmp0, cpu_cc_dst, size, false); - tcg_gen_brcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, t0, 0, l1); - break; - case JCC_S: - fast_jcc_s: - t0 = gen_ext_tl(cpu_tmp0, cpu_cc_dst, size, true); - tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, t0, 0, l1); - break; - - case JCC_B: - cond = inv ? TCG_COND_GEU : TCG_COND_LTU; - goto fast_jcc_b; - case JCC_BE: - cond = inv ? TCG_COND_GTU : TCG_COND_LEU; - fast_jcc_b: - tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); - gen_extu(size, cpu_tmp4); - t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); - tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1); - break; - - case JCC_L: - cond = inv ? TCG_COND_GE : TCG_COND_LT; - goto fast_jcc_l; - case JCC_LE: - cond = inv ? TCG_COND_GT : TCG_COND_LE; - fast_jcc_l: - tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); - gen_exts(size, cpu_tmp4); - t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, true); - tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1); - break; - - default: - goto slow_jcc; - } - break; - - /* some jumps are easy to compute */ - case CC_OP_ADDB: - case CC_OP_ADDW: - case CC_OP_ADDL: - case CC_OP_ADDQ: - - case CC_OP_ADCB: - case CC_OP_ADCW: - case CC_OP_ADCL: - case CC_OP_ADCQ: - - case CC_OP_SBBB: - case CC_OP_SBBW: - case CC_OP_SBBL: - case CC_OP_SBBQ: - - case CC_OP_LOGICB: - case CC_OP_LOGICW: - case CC_OP_LOGICL: - case CC_OP_LOGICQ: - - case CC_OP_INCB: - case CC_OP_INCW: - case CC_OP_INCL: - case CC_OP_INCQ: - - case CC_OP_DECB: - case CC_OP_DECW: - case CC_OP_DECL: - case CC_OP_DECQ: - - case CC_OP_SHLB: - case CC_OP_SHLW: - case CC_OP_SHLL: - case CC_OP_SHLQ: - - case CC_OP_SARB: - case CC_OP_SARW: - case CC_OP_SARL: - case CC_OP_SARQ: - switch(jcc_op) { - case JCC_Z: - size = (s->cc_op - CC_OP_ADDB) & 3; - goto fast_jcc_z; - case JCC_S: - size = (s->cc_op - CC_OP_ADDB) & 3; - goto fast_jcc_s; - default: - goto slow_jcc; - } - break; - default: - slow_jcc: - gen_setcc1(s, b, cpu_T[0]); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_T[0], 0, l1); - break; + if (cc.mask != -1) { + tcg_gen_andi_tl(cpu_T[0], cc.reg, cc.mask); + cc.reg = cpu_T[0]; + } + if (cc.use_reg2) { + tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1); + } else { + tcg_gen_brcondi_tl(cc.cond, cc.reg, cc.imm, l1); } } From 69d1aa31f7551050bf918dc22f0fe3307b779186 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 14:41:21 -0800 Subject: [PATCH 1113/1634] target-i386: inline gen_prepare_cc_slow Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 91 +++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index b081fc0cec..0b88eaed78 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1075,44 +1075,6 @@ static void gen_do_setcc(TCGv reg, struct CCPrepare cc, bool inv) } } -static CCPrepare gen_prepare_cc_slow(DisasContext *s, int jcc_op, TCGv reg) -{ - switch(jcc_op) { - case JCC_O: - return gen_prepare_eflags_o(s, reg); - case JCC_B: - return gen_prepare_eflags_c(s, reg); - case JCC_Z: - return gen_prepare_eflags_z(s, reg); - case JCC_BE: - gen_compute_eflags(s); - return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, - .mask = CC_Z | CC_C }; - case JCC_S: - return gen_prepare_eflags_s(s, reg); - case JCC_P: - return gen_prepare_eflags_p(s, reg); - case JCC_L: - gen_compute_eflags(s); - if (TCGV_EQUAL(reg, cpu_cc_src)) { - reg = cpu_tmp0; - } - tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */ - tcg_gen_xor_tl(reg, reg, cpu_cc_src); - return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, .mask = CC_S }; - default: - case JCC_LE: - gen_compute_eflags(s); - if (TCGV_EQUAL(reg, cpu_cc_src)) { - reg = cpu_tmp0; - } - tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */ - tcg_gen_xor_tl(reg, reg, cpu_cc_src); - return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, - .mask = CC_S | CC_Z }; - } -} - /* perform a conditional store into register 'reg' according to jump opcode value 'b'. In the fast case, T0 is guaranted not to be used. */ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) @@ -1125,11 +1087,8 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) jcc_op = (b >> 1) & 7; switch (s->cc_op) { - /* we optimize relational operators for the cmp/jcc case */ - case CC_OP_SUBB: - case CC_OP_SUBW: - case CC_OP_SUBL: - case CC_OP_SUBQ: + case CC_OP_SUBB ... CC_OP_SUBQ: + /* We optimize relational operators for the cmp/jcc case. */ size = s->cc_op - CC_OP_SUBB; switch (jcc_op) { case JCC_BE: @@ -1160,8 +1119,50 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) default: slow_jcc: - /* gen_prepare_cc_slow actually generates good code for JC, JZ and JS */ - cc = gen_prepare_cc_slow(s, jcc_op, reg); + /* This actually generates good code for JC, JZ and JS. */ + switch (jcc_op) { + case JCC_O: + cc = gen_prepare_eflags_o(s, reg); + break; + case JCC_B: + cc = gen_prepare_eflags_c(s, reg); + break; + case JCC_Z: + cc = gen_prepare_eflags_z(s, reg); + break; + case JCC_BE: + gen_compute_eflags(s); + cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = CC_Z | CC_C }; + break; + case JCC_S: + cc = gen_prepare_eflags_s(s, reg); + break; + case JCC_P: + cc = gen_prepare_eflags_p(s, reg); + break; + case JCC_L: + gen_compute_eflags(s); + if (TCGV_EQUAL(reg, cpu_cc_src)) { + reg = cpu_tmp0; + } + tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */ + tcg_gen_xor_tl(reg, reg, cpu_cc_src); + cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, + .mask = CC_S }; + break; + default: + case JCC_LE: + gen_compute_eflags(s); + if (TCGV_EQUAL(reg, cpu_cc_src)) { + reg = cpu_tmp0; + } + tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */ + tcg_gen_xor_tl(reg, reg, cpu_cc_src); + cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, + .mask = CC_S | CC_Z }; + break; + } break; } From cc8b6f5b39ae47a93074a5384faa734bf2a6ae61 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 8 Oct 2012 09:42:48 +0200 Subject: [PATCH 1114/1634] target-i386: cleanup temporary macros for CCPrepare Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 86 +++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 0b88eaed78..c83b56f507 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1040,41 +1040,6 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) } } -#define gen_compute_eflags_c(s, reg, inv) \ - gen_do_setcc(reg, gen_prepare_eflags_c(s, reg), inv) - -static void gen_do_setcc(TCGv reg, struct CCPrepare cc, bool inv) -{ - if (inv) { - cc.cond = tcg_invert_cond(cc.cond); - } - - if (cc.no_setcond) { - if (cc.cond == TCG_COND_EQ) { - tcg_gen_xori_tl(reg, cc.reg, 1); - } else { - tcg_gen_mov_tl(reg, cc.reg); - } - return; - } - - if (cc.cond == TCG_COND_NE && !cc.use_reg2 && cc.imm == 0 && - cc.mask != 0 && (cc.mask & (cc.mask - 1)) == 0) { - tcg_gen_shri_tl(reg, cc.reg, ctztl(cc.mask)); - tcg_gen_andi_tl(reg, reg, 1); - return; - } - if (cc.mask != -1) { - tcg_gen_andi_tl(reg, cc.reg, cc.mask); - cc.reg = reg; - } - if (cc.use_reg2) { - tcg_gen_setcond_tl(cc.cond, reg, cc.reg, cc.reg2); - } else { - tcg_gen_setcondi_tl(cc.cond, reg, cc.reg, cc.imm); - } -} - /* perform a conditional store into register 'reg' according to jump opcode value 'b'. In the fast case, T0 is guaranted not to be used. */ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) @@ -1172,8 +1137,40 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) return cc; } -#define gen_setcc1(s, b, reg) \ - gen_do_setcc(reg, gen_prepare_cc(s, b, reg), false) +static void gen_setcc1(DisasContext *s, int b, TCGv reg) +{ + CCPrepare cc = gen_prepare_cc(s, b, reg); + + if (cc.no_setcond) { + if (cc.cond == TCG_COND_EQ) { + tcg_gen_xori_tl(reg, cc.reg, 1); + } else { + tcg_gen_mov_tl(reg, cc.reg); + } + return; + } + + if (cc.cond == TCG_COND_NE && !cc.use_reg2 && cc.imm == 0 && + cc.mask != 0 && (cc.mask & (cc.mask - 1)) == 0) { + tcg_gen_shri_tl(reg, cc.reg, ctztl(cc.mask)); + tcg_gen_andi_tl(reg, reg, 1); + return; + } + if (cc.mask != -1) { + tcg_gen_andi_tl(reg, cc.reg, cc.mask); + cc.reg = reg; + } + if (cc.use_reg2) { + tcg_gen_setcond_tl(cc.cond, reg, cc.reg, cc.reg2); + } else { + tcg_gen_setcondi_tl(cc.cond, reg, cc.reg, cc.imm); + } +} + +static inline void gen_compute_eflags_c(DisasContext *s, TCGv reg) +{ + gen_setcc1(s, JCC_B << 1, reg); +} /* generate a conditional jump to label 'l1' according to jump opcode value 'b'. In the fast case, T0 is guaranted not to be used. */ @@ -1399,7 +1396,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) } switch(op) { case OP_ADCL: - gen_compute_eflags_c(s1, cpu_tmp4, false); + gen_compute_eflags_c(s1, cpu_tmp4); tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4); if (d != OR_TMP0) @@ -1414,7 +1411,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) set_cc_op(s1, CC_OP_DYNAMIC); break; case OP_SBBL: - gen_compute_eflags_c(s1, cpu_tmp4, false); + gen_compute_eflags_c(s1, cpu_tmp4); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4); if (d != OR_TMP0) @@ -1488,7 +1485,7 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) gen_op_mov_TN_reg(ot, 0, d); else gen_op_ld_T0_A0(ot + s1->mem_index); - gen_compute_eflags_c(s1, cpu_cc_src, false); + gen_compute_eflags_c(s1, cpu_cc_src); if (c > 0) { tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1); set_cc_op(s1, CC_OP_INCB + ot); @@ -2417,11 +2414,6 @@ static inline void gen_jcc(DisasContext *s, int b, } } -static void gen_setcc(DisasContext *s, int b) -{ - gen_setcc1(s, b, cpu_T[0]); -} - static inline void gen_op_movl_T0_seg(int seg_reg) { tcg_gen_ld32u_tl(cpu_T[0], cpu_env, @@ -6431,7 +6423,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0x190 ... 0x19f: /* setcc Gv */ modrm = cpu_ldub_code(env, s->pc++); - gen_setcc(s, b); + gen_setcc1(s, b, cpu_T[0]); gen_ldst_modrm(env, s, modrm, OT_BYTE, OR_TMP0, 1); break; case 0x140 ... 0x14f: /* cmov Gv, Ev */ @@ -6889,7 +6881,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, case 0xd6: /* salc */ if (CODE64(s)) goto illegal_op; - gen_compute_eflags_c(s, cpu_T[0], false); + gen_compute_eflags_c(s, cpu_T[0]); tcg_gen_neg_tl(cpu_T[0], cpu_T[0]); gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; From f32d3781de8328237c2db45ff774cbd4b30134d6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 7 Oct 2012 17:55:26 +0200 Subject: [PATCH 1115/1634] target-i386: introduce gen_cmovcc1 Signed-off-by: Richard Henderson --- target-i386/translate.c | 72 ++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index c83b56f507..4b0a701d8c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2414,6 +2414,40 @@ static inline void gen_jcc(DisasContext *s, int b, } } +static void gen_cmovcc1(CPUX86State *env, DisasContext *s, int ot, int b, + int modrm, int reg) +{ + int l1, mod = (modrm >> 6) & 3; + TCGv t0 = tcg_temp_local_new(); + + if (mod != 3) { + int reg_addr, offset_addr; + gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); + gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); + } else { + int rm = (modrm & 7) | REX_B(s); + gen_op_mov_v_reg(ot, t0, rm); + } + + l1 = gen_new_label(); + gen_jcc1(s, b ^ 1, l1); + switch (ot) { +#ifdef TARGET_X86_64 + case OT_LONG: + tcg_gen_mov_tl(cpu_regs[reg], t0); + gen_set_label(l1); + tcg_gen_ext32u_tl(cpu_regs[reg], cpu_regs[reg]); + break; +#endif + default: + gen_op_mov_reg_v(ot, reg, t0); + gen_set_label(l1); + break; + } + + tcg_temp_free(t0); +} + static inline void gen_op_movl_T0_seg(int seg_reg) { tcg_gen_ld32u_tl(cpu_T[0], cpu_env, @@ -6427,40 +6461,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_ldst_modrm(env, s, modrm, OT_BYTE, OR_TMP0, 1); break; case 0x140 ... 0x14f: /* cmov Gv, Ev */ - { - int l1; - TCGv t0; - - ot = dflag + OT_WORD; - modrm = cpu_ldub_code(env, s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - mod = (modrm >> 6) & 3; - t0 = tcg_temp_local_new(); - if (mod != 3) { - gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); - gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); - } else { - rm = (modrm & 7) | REX_B(s); - gen_op_mov_v_reg(ot, t0, rm); - } -#ifdef TARGET_X86_64 - if (ot == OT_LONG) { - /* XXX: specific Intel behaviour ? */ - l1 = gen_new_label(); - gen_jcc1(s, b ^ 1, l1); - tcg_gen_mov_tl(cpu_regs[reg], t0); - gen_set_label(l1); - tcg_gen_ext32u_tl(cpu_regs[reg], cpu_regs[reg]); - } else -#endif - { - l1 = gen_new_label(); - gen_jcc1(s, b ^ 1, l1); - gen_op_mov_reg_v(ot, reg, t0); - gen_set_label(l1); - } - tcg_temp_free(t0); - } + ot = dflag + OT_WORD; + modrm = cpu_ldub_code(env, s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + gen_cmovcc1(env, s, ot, b, modrm, reg); break; /************************/ From 57eb0cc85469a8948d1036ab830951e63aa32f66 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 16 Jan 2013 11:00:14 -0800 Subject: [PATCH 1116/1634] target-i386: expand cmov via movcond Signed-off-by: Richard Henderson --- target-i386/translate.c | 45 ++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 4b0a701d8c..9d5467dbfb 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2417,35 +2417,30 @@ static inline void gen_jcc(DisasContext *s, int b, static void gen_cmovcc1(CPUX86State *env, DisasContext *s, int ot, int b, int modrm, int reg) { - int l1, mod = (modrm >> 6) & 3; - TCGv t0 = tcg_temp_local_new(); + CCPrepare cc; - if (mod != 3) { - int reg_addr, offset_addr; - gen_lea_modrm(env, s, modrm, ®_addr, &offset_addr); - gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); - } else { - int rm = (modrm & 7) | REX_B(s); - gen_op_mov_v_reg(ot, t0, rm); + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + + cc = gen_prepare_cc(s, b, cpu_T[1]); + if (cc.mask != -1) { + TCGv t0 = tcg_temp_new(); + tcg_gen_andi_tl(t0, cc.reg, cc.mask); + cc.reg = t0; + } + if (!cc.use_reg2) { + cc.reg2 = tcg_const_tl(cc.imm); } - l1 = gen_new_label(); - gen_jcc1(s, b ^ 1, l1); - switch (ot) { -#ifdef TARGET_X86_64 - case OT_LONG: - tcg_gen_mov_tl(cpu_regs[reg], t0); - gen_set_label(l1); - tcg_gen_ext32u_tl(cpu_regs[reg], cpu_regs[reg]); - break; -#endif - default: - gen_op_mov_reg_v(ot, reg, t0); - gen_set_label(l1); - break; - } + tcg_gen_movcond_tl(cc.cond, cpu_T[0], cc.reg, cc.reg2, + cpu_T[0], cpu_regs[reg]); + gen_op_mov_reg_T0(ot, reg); - tcg_temp_free(t0); + if (cc.mask != -1) { + tcg_temp_free(cc.reg); + } + if (!cc.use_reg2) { + tcg_temp_free(cc.reg2); + } } static inline void gen_op_movl_T0_seg(int seg_reg) From 3b9d3cf1609ec98411508c1e8b6dde711117825f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 12 Oct 2012 15:04:10 +0200 Subject: [PATCH 1117/1634] target-i386: kill cpu_T3 It is almost unused, and it is simpler to pass a TCG value directly to gen_shiftd_rm_T1_T3. This value is then written to t2 without going through a temporary register. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 9d5467dbfb..60c1fdd29a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -64,7 +64,7 @@ static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst; static TCGv_i32 cpu_cc_op; static TCGv cpu_regs[CPU_NB_REGS]; /* local temps */ -static TCGv cpu_T[2], cpu_T3; +static TCGv cpu_T[2]; /* local register indexes (only used inside old micro ops) */ static TCGv cpu_tmp0, cpu_tmp4; static TCGv_ptr cpu_ptr0, cpu_ptr1; @@ -1858,8 +1858,8 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, } /* XXX: add faster immediate case */ -static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1, - int is_right) +static void gen_shiftd_rm_T1(DisasContext *s, int ot, int op1, + int is_right, TCGv count) { int label1, label2, data_bits; target_ulong mask; @@ -1883,10 +1883,8 @@ static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1, gen_op_mov_v_reg(ot, t0, op1); } - tcg_gen_andi_tl(cpu_T3, cpu_T3, mask); - + tcg_gen_andi_tl(t2, count, mask); tcg_gen_mov_tl(t1, cpu_T[1]); - tcg_gen_mov_tl(t2, cpu_T3); /* Must test zero case to avoid using undefined behaviour in TCG shifts. */ @@ -5583,12 +5581,12 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, gen_op_mov_TN_reg(ot, 1, reg); if (shift) { - val = cpu_ldub_code(env, s->pc++); - tcg_gen_movi_tl(cpu_T3, val); + TCGv imm = tcg_const_tl(cpu_ldub_code(env, s->pc++)); + gen_shiftd_rm_T1(s, ot, opreg, op, imm); + tcg_temp_free(imm); } else { - tcg_gen_mov_tl(cpu_T3, cpu_regs[R_ECX]); + gen_shiftd_rm_T1(s, ot, opreg, op, cpu_regs[R_ECX]); } - gen_shiftd_rm_T1_T3(s, ot, opreg, op); break; /************************/ @@ -7869,7 +7867,6 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, cpu_T[0] = tcg_temp_new(); cpu_T[1] = tcg_temp_new(); cpu_A0 = tcg_temp_new(); - cpu_T3 = tcg_temp_new(); cpu_tmp0 = tcg_temp_new(); cpu_tmp1_i64 = tcg_temp_new_i64(); From 63633fe6eb15107d688f3b7f61a4b379f57fc4ca Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 14:51:34 -0800 Subject: [PATCH 1118/1634] target-i386: use gen_op for cmps/scas Replace low-level ops with a higher-level "cmp %al, (A0)" in the case of scas, and "cmp T0, (A0)" in the case of cmps. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 60c1fdd29a..f8d5e68742 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -123,6 +123,7 @@ typedef struct DisasContext { static void gen_eob(DisasContext *s); static void gen_jmp(DisasContext *s, target_ulong eip); static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num); +static void gen_op(DisasContext *s1, int op, int ot, int d); /* i386 arith/logic operations */ enum { @@ -861,12 +862,6 @@ static void gen_op_update2_cc(void) tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); } -static inline void gen_op_cmpl_T0_T1_cc(void) -{ - tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); - tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); -} - static inline void gen_op_testl_T0_T1_cc(void) { tcg_gen_and_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); @@ -1224,26 +1219,22 @@ static inline void gen_lods(DisasContext *s, int ot) static inline void gen_scas(DisasContext *s, int ot) { - gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); gen_string_movl_A0_EDI(s); gen_op_ld_T1_A0(ot + s->mem_index); - gen_op_cmpl_T0_T1_cc(); + gen_op(s, OP_CMPL, ot, R_EAX); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_EDI); - set_cc_op(s, CC_OP_SUBB + ot); } static inline void gen_cmps(DisasContext *s, int ot) { - gen_string_movl_A0_ESI(s); - gen_op_ld_T0_A0(ot + s->mem_index); gen_string_movl_A0_EDI(s); gen_op_ld_T1_A0(ot + s->mem_index); - gen_op_cmpl_T0_T1_cc(); + gen_string_movl_A0_ESI(s); + gen_op(s, OP_CMPL, ot, OR_TMP0); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_ESI); gen_op_add_reg_T0(s->aflag, R_EDI); - set_cc_op(s, CC_OP_SUBB + ot); } static inline void gen_ins(DisasContext *s, int ot) @@ -1472,7 +1463,8 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) set_cc_op(s1, CC_OP_LOGICB + ot); break; case OP_CMPL: - gen_op_cmpl_T0_T1_cc(); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); set_cc_op(s1, CC_OP_SUBB + ot); break; } From dc259201f8b471f27136ffe50cc7019c8311ccb6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 15:01:35 -0800 Subject: [PATCH 1119/1634] target-i386: introduce gen_jcc1_noeob A jump that ends a basic block or otherwise falls back to CC_OP_DYNAMIC will always have to call gen_op_set_cc_op. However, not all jumps end a basic block, so introduce a variant that does not do this. This was partially undone earlier (i386: drop cc_op argument of gen_jcc1), redo it now also to prepare for the introduction of src2. Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index f8d5e68742..948a04831a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1169,7 +1169,7 @@ static inline void gen_compute_eflags_c(DisasContext *s, TCGv reg) /* generate a conditional jump to label 'l1' according to jump opcode value 'b'. In the fast case, T0 is guaranted not to be used. */ -static inline void gen_jcc1(DisasContext *s, int b, int l1) +static inline void gen_jcc1_noeob(DisasContext *s, int b, int l1) { CCPrepare cc = gen_prepare_cc(s, b, cpu_T[0]); @@ -1184,6 +1184,26 @@ static inline void gen_jcc1(DisasContext *s, int b, int l1) } } +/* Generate a conditional jump to label 'l1' according to jump opcode + value 'b'. In the fast case, T0 is guaranted not to be used. + A translation block must end soon. */ +static inline void gen_jcc1(DisasContext *s, int b, int l1) +{ + CCPrepare cc = gen_prepare_cc(s, b, cpu_T[0]); + + gen_update_cc_op(s); + if (cc.mask != -1) { + tcg_gen_andi_tl(cpu_T[0], cc.reg, cc.mask); + cc.reg = cpu_T[0]; + } + set_cc_op(s, CC_OP_DYNAMIC); + if (cc.use_reg2) { + tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1); + } else { + tcg_gen_brcondi_tl(cc.cond, cc.reg, cc.imm, l1); + } +} + /* XXX: does not work with gdbstub "ice" single step - not a serious problem */ static int gen_jz_ecx_string(DisasContext *s, target_ulong next_eip) @@ -1310,7 +1330,6 @@ static inline void gen_repz_ ## op(DisasContext *s, int ot, \ if (!s->jmp_opt) \ gen_op_jz_ecx(s->aflag, l2); \ gen_jmp(s, cur_eip); \ - set_cc_op(s, CC_OP_DYNAMIC); \ } GEN_REPZ(movs) @@ -2379,11 +2398,9 @@ static inline void gen_jcc(DisasContext *s, int b, int l1, l2; if (s->jmp_opt) { - gen_update_cc_op(s); l1 = gen_new_label(); gen_jcc1(s, b, l1); - set_cc_op(s, CC_OP_DYNAMIC); - + gen_goto_tb(s, 0, next_eip); gen_set_label(l1); @@ -6077,7 +6094,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, }; op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1); l1 = gen_new_label(); - gen_jcc1(s, op1, l1); + gen_jcc1_noeob(s, op1, l1); gen_helper_fmov_ST0_STN(cpu_env, tcg_const_i32(opreg)); gen_set_label(l1); } From 891a5133f1637296c3823229180b5851132ed5f5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 18 Jan 2013 10:06:55 -0800 Subject: [PATCH 1120/1634] target-i386: Update cc_op before TCG branches Placing the CC_OP_DYNAMIC at the join is less effective than before the branch, as the branch will have forced global registers to their home locations. This way we have a chance to discard CC_SRC2 before it gets stored. Signed-off-by: Richard Henderson --- target-i386/translate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 948a04831a..7f2d65f250 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1559,8 +1559,9 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, gen_op_mov_reg_T0(ot, op1); } - /* update eflags */ + /* Update eflags data because we cannot predict flags afterward. */ gen_update_cc_op(s); + set_cc_op(s, CC_OP_DYNAMIC); tcg_gen_mov_tl(t1, cpu_T[0]); @@ -1587,7 +1588,6 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, } gen_set_label(shift_label); - set_cc_op(s, CC_OP_DYNAMIC); /* cannot predict flags after */ tcg_temp_free(t0); tcg_temp_free(t1); @@ -1972,8 +1972,9 @@ static void gen_shiftd_rm_T1(DisasContext *s, int ot, int op1, gen_op_mov_reg_v(ot, op1, t0); } - /* update eflags */ + /* Update eflags data because we cannot predict flags afterward. */ gen_update_cc_op(s); + set_cc_op(s, CC_OP_DYNAMIC); label2 = gen_new_label(); tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label2); @@ -1986,7 +1987,6 @@ static void gen_shiftd_rm_T1(DisasContext *s, int ot, int op1, tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot); } gen_set_label(label2); - set_cc_op(s, CC_OP_DYNAMIC); /* cannot predict flags after */ tcg_temp_free(t0); tcg_temp_free(t1); From a3251186fc6a04d421e9c4b65aa04ec32379ec38 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 15:43:03 -0800 Subject: [PATCH 1121/1634] target-i386: optimize flags checking after sub using CC_SRCT After a comparison or subtraction, the original value of the LHS will currently be reconstructed using an addition. However, in most cases it is already available: store it in a temp-local variable and save 1 or 2 TCG ops (2 if the result of the addition needs to be extended). The temp-local can be declared dead as soon as the cc_op changes again, or also before the translation block ends because gen_prepare_cc will always make a copy before returning it. All this magic, plus copy propagation and dead-code elimination, ensures that the temp local will (almost) never be spilled. Example (cmp $0x21,%rax + jbe): Before After ---------------------------------------------------------------------------- movi_i64 tmp1,$0x21 movi_i64 tmp1,$0x21 movi_i64 cc_src,$0x21 movi_i64 cc_src,$0x21 sub_i64 cc_dst,rax,tmp1 sub_i64 cc_dst,rax,tmp1 add_i64 tmp7,cc_dst,cc_src movi_i32 cc_op,$0x11 movi_i32 cc_op,$0x11 brcond_i64 tmp7,cc_src,leu,$0x0 discard loc11 brcond_i64 rax,cc_src,leu,$0x0 Before After ---------------------------------------------------------------------------- mov (%r14),%rbp mov (%r14),%rbp mov %rbp,%rbx mov %rbp,%rbx sub $0x21,%rbx sub $0x21,%rbx lea 0x21(%rbx),%r12 movl $0x11,0xa0(%r14) movl $0x11,0xa0(%r14) movq $0x21,0x90(%r14) movq $0x21,0x90(%r14) mov %rbx,0x98(%r14) mov %rbx,0x98(%r14) cmp $0x21,%r12 | cmp $0x21,%rbp jbe ... jbe ... Signed-off-by: Paolo Bonzini Signed-off-by: Richard Henderson --- target-i386/translate.c | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 7f2d65f250..31e3442442 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -60,7 +60,8 @@ /* global register indexes */ static TCGv_ptr cpu_env; -static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst; +static TCGv cpu_A0; +static TCGv cpu_cc_src, cpu_cc_dst, cpu_cc_srcT; static TCGv_i32 cpu_cc_op; static TCGv cpu_regs[CPU_NB_REGS]; /* local temps */ @@ -185,8 +186,9 @@ enum { }; enum { - USES_CC_DST = 1, - USES_CC_SRC = 2, + USES_CC_DST = 1, + USES_CC_SRC = 2, + USES_CC_SRCT = 4, }; /* Bit set if the global variable is live after setting CC_OP to X. */ @@ -196,7 +198,7 @@ static const uint8_t cc_op_live[CC_OP_NB] = { [CC_OP_MULB ... CC_OP_MULQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_ADDB ... CC_OP_ADDQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_ADCB ... CC_OP_ADCQ] = USES_CC_DST | USES_CC_SRC, - [CC_OP_SUBB ... CC_OP_SUBQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_SUBB ... CC_OP_SUBQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRCT, [CC_OP_SBBB ... CC_OP_SBBQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_LOGICB ... CC_OP_LOGICQ] = USES_CC_DST, [CC_OP_INCB ... CC_OP_INCQ] = USES_CC_DST | USES_CC_SRC, @@ -221,6 +223,9 @@ static void set_cc_op(DisasContext *s, CCOp op) if (dead & USES_CC_SRC) { tcg_gen_discard_tl(cpu_cc_src); } + if (dead & USES_CC_SRCT) { + tcg_gen_discard_tl(cpu_cc_srcT); + } s->cc_op = op; /* The DYNAMIC setting is translator only, and should never be @@ -869,8 +874,9 @@ static inline void gen_op_testl_T0_T1_cc(void) static void gen_op_update_neg_cc(void) { - tcg_gen_neg_tl(cpu_cc_src, cpu_T[0]); tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + tcg_gen_neg_tl(cpu_cc_src, cpu_T[0]); + tcg_gen_movi_tl(cpu_cc_srcT, 0); } /* compute all eflags to cc_src */ @@ -903,12 +909,12 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) switch (s->cc_op) { case CC_OP_SUBB ... CC_OP_SUBQ: - /* (DATA_TYPE)(CC_DST + CC_SRC) < (DATA_TYPE)CC_SRC */ + /* (DATA_TYPE)CC_SRCT < (DATA_TYPE)CC_SRC */ size = s->cc_op - CC_OP_SUBB; t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); /* If no temporary was used, be careful not to alias t1 and t0. */ t0 = TCGV_EQUAL(t1, cpu_cc_src) ? cpu_tmp0 : reg; - tcg_gen_add_tl(t0, cpu_cc_dst, cpu_cc_src); + tcg_gen_mov_tl(t0, cpu_cc_srcT); gen_extu(size, t0); goto add_sub; @@ -1052,7 +1058,7 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) size = s->cc_op - CC_OP_SUBB; switch (jcc_op) { case JCC_BE: - tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); + tcg_gen_mov_tl(cpu_tmp4, cpu_cc_srcT); gen_extu(size, cpu_tmp4); t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); cc = (CCPrepare) { .cond = TCG_COND_LEU, .reg = cpu_tmp4, @@ -1065,7 +1071,7 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) case JCC_LE: cond = TCG_COND_LE; fast_jcc_l: - tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src); + tcg_gen_mov_tl(cpu_tmp4, cpu_cc_srcT); gen_exts(size, cpu_tmp4); t0 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, true); cc = (CCPrepare) { .cond = cond, .reg = cpu_tmp4, @@ -1421,6 +1427,10 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) set_cc_op(s1, CC_OP_DYNAMIC); break; case OP_SBBL: + /* + * No need to store cpu_cc_srcT, because it is used only + * when the cc_op is known. + */ gen_compute_eflags_c(s1, cpu_tmp4); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4); @@ -1445,6 +1455,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) set_cc_op(s1, CC_OP_ADDB + ot); break; case OP_SUBL: + tcg_gen_mov_tl(cpu_cc_srcT, cpu_T[0]); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); if (d != OR_TMP0) gen_op_mov_reg_T0(ot, d); @@ -1483,6 +1494,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) break; case OP_CMPL: tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_srcT, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); set_cc_op(s1, CC_OP_SUBB + ot); break; @@ -2799,8 +2811,9 @@ static void gen_eob(DisasContext *s) direct call to the next block may occur */ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) { + gen_update_cc_op(s); + set_cc_op(s, CC_OP_DYNAMIC); if (s->jmp_opt) { - gen_update_cc_op(s); gen_goto_tb(s, tb_num, eip); s->is_jmp = DISAS_TB_JUMP; } else { @@ -5017,9 +5030,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, rm = 0; /* avoid warning */ } label1 = gen_new_label(); - tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0); + tcg_gen_mov_tl(t2, cpu_regs[R_EAX]); + gen_extu(ot, t0); gen_extu(ot, t2); - tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1); + tcg_gen_brcond_tl(TCG_COND_EQ, t2, t0, label1); label2 = gen_new_label(); if (mod == 3) { gen_op_mov_reg_v(ot, R_EAX, t0); @@ -5038,7 +5052,8 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } gen_set_label(label2); tcg_gen_mov_tl(cpu_cc_src, t0); - tcg_gen_mov_tl(cpu_cc_dst, t2); + tcg_gen_mov_tl(cpu_cc_srcT, t2); + tcg_gen_sub_tl(cpu_cc_dst, t2, t0); set_cc_op(s, CC_OP_SUBB + ot); tcg_temp_free(t0); tcg_temp_free(t1); @@ -7746,10 +7761,10 @@ void optimize_flags_init(void) cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUX86State, cc_op), "cc_op"); - cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_src), - "cc_src"); cpu_cc_dst = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_dst), "cc_dst"); + cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_src), + "cc_src"); #ifdef TARGET_X86_64 cpu_regs[R_EAX] = tcg_global_mem_new_i64(TCG_AREG0, @@ -7885,6 +7900,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, cpu_tmp5 = tcg_temp_new(); cpu_ptr0 = tcg_temp_new_ptr(); cpu_ptr1 = tcg_temp_new_ptr(); + cpu_cc_srcT = tcg_temp_local_new(); gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE; From 8601c0b6c553a018fc62007efa8ac2a71d77f449 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 16:06:38 -0800 Subject: [PATCH 1122/1634] target-i386: Don't reference ENV through most of cc helpers In preparation for making this a const helper. By using the proper types in the parameters to the helper functions, we get to avoid quite a lot of subsequent casting. Signed-off-by: Richard Henderson --- target-i386/cc_helper.c | 243 +++++++++++++------------------ target-i386/cc_helper_template.h | 237 ++++++++++++------------------ 2 files changed, 189 insertions(+), 291 deletions(-) diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c index 9422003f24..61427ddeac 100644 --- a/target-i386/cc_helper.c +++ b/target-i386/cc_helper.c @@ -75,125 +75,108 @@ const uint8_t parity_table[256] = { #endif -static int compute_all_eflags(CPUX86State *env) -{ - return CC_SRC; -} - -static int compute_c_eflags(CPUX86State *env) -{ - return CC_SRC & CC_C; -} - uint32_t helper_cc_compute_all(CPUX86State *env, int op) { + target_ulong dst = CC_DST, src1 = CC_SRC; + switch (op) { default: /* should never happen */ return 0; case CC_OP_EFLAGS: - return compute_all_eflags(env); + return src1; case CC_OP_MULB: - return compute_all_mulb(env); + return compute_all_mulb(dst, src1); case CC_OP_MULW: - return compute_all_mulw(env); + return compute_all_mulw(dst, src1); case CC_OP_MULL: - return compute_all_mull(env); + return compute_all_mull(dst, src1); case CC_OP_ADDB: - return compute_all_addb(env); + return compute_all_addb(dst, src1); case CC_OP_ADDW: - return compute_all_addw(env); + return compute_all_addw(dst, src1); case CC_OP_ADDL: - return compute_all_addl(env); + return compute_all_addl(dst, src1); case CC_OP_ADCB: - return compute_all_adcb(env); + return compute_all_adcb(dst, src1); case CC_OP_ADCW: - return compute_all_adcw(env); + return compute_all_adcw(dst, src1); case CC_OP_ADCL: - return compute_all_adcl(env); + return compute_all_adcl(dst, src1); case CC_OP_SUBB: - return compute_all_subb(env); + return compute_all_subb(dst, src1); case CC_OP_SUBW: - return compute_all_subw(env); + return compute_all_subw(dst, src1); case CC_OP_SUBL: - return compute_all_subl(env); + return compute_all_subl(dst, src1); case CC_OP_SBBB: - return compute_all_sbbb(env); + return compute_all_sbbb(dst, src1); case CC_OP_SBBW: - return compute_all_sbbw(env); + return compute_all_sbbw(dst, src1); case CC_OP_SBBL: - return compute_all_sbbl(env); + return compute_all_sbbl(dst, src1); case CC_OP_LOGICB: - return compute_all_logicb(env); + return compute_all_logicb(dst, src1); case CC_OP_LOGICW: - return compute_all_logicw(env); + return compute_all_logicw(dst, src1); case CC_OP_LOGICL: - return compute_all_logicl(env); + return compute_all_logicl(dst, src1); case CC_OP_INCB: - return compute_all_incb(env); + return compute_all_incb(dst, src1); case CC_OP_INCW: - return compute_all_incw(env); + return compute_all_incw(dst, src1); case CC_OP_INCL: - return compute_all_incl(env); + return compute_all_incl(dst, src1); case CC_OP_DECB: - return compute_all_decb(env); + return compute_all_decb(dst, src1); case CC_OP_DECW: - return compute_all_decw(env); + return compute_all_decw(dst, src1); case CC_OP_DECL: - return compute_all_decl(env); + return compute_all_decl(dst, src1); case CC_OP_SHLB: - return compute_all_shlb(env); + return compute_all_shlb(dst, src1); case CC_OP_SHLW: - return compute_all_shlw(env); + return compute_all_shlw(dst, src1); case CC_OP_SHLL: - return compute_all_shll(env); + return compute_all_shll(dst, src1); case CC_OP_SARB: - return compute_all_sarb(env); + return compute_all_sarb(dst, src1); case CC_OP_SARW: - return compute_all_sarw(env); + return compute_all_sarw(dst, src1); case CC_OP_SARL: - return compute_all_sarl(env); + return compute_all_sarl(dst, src1); #ifdef TARGET_X86_64 case CC_OP_MULQ: - return compute_all_mulq(env); - + return compute_all_mulq(dst, src1); case CC_OP_ADDQ: - return compute_all_addq(env); - + return compute_all_addq(dst, src1); case CC_OP_ADCQ: - return compute_all_adcq(env); - + return compute_all_adcq(dst, src1); case CC_OP_SUBQ: - return compute_all_subq(env); - + return compute_all_subq(dst, src1); case CC_OP_SBBQ: - return compute_all_sbbq(env); - + return compute_all_sbbq(dst, src1); case CC_OP_LOGICQ: - return compute_all_logicq(env); - + return compute_all_logicq(dst, src1); case CC_OP_INCQ: - return compute_all_incq(env); - + return compute_all_incq(dst, src1); case CC_OP_DECQ: - return compute_all_decq(env); - + return compute_all_decq(dst, src1); case CC_OP_SHLQ: - return compute_all_shlq(env); - + return compute_all_shlq(dst, src1); case CC_OP_SARQ: - return compute_all_sarq(env); + return compute_all_sarq(dst, src1); #endif } } @@ -205,113 +188,85 @@ uint32_t cpu_cc_compute_all(CPUX86State *env, int op) uint32_t helper_cc_compute_c(CPUX86State *env, int op) { + target_ulong dst = CC_DST, src1 = CC_SRC; + switch (op) { default: /* should never happen */ + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_LOGICQ: return 0; case CC_OP_EFLAGS: - return compute_c_eflags(env); - - case CC_OP_MULB: - return compute_c_mull(env); - case CC_OP_MULW: - return compute_c_mull(env); - case CC_OP_MULL: - return compute_c_mull(env); - - case CC_OP_ADDB: - return compute_c_addb(env); - case CC_OP_ADDW: - return compute_c_addw(env); - case CC_OP_ADDL: - return compute_c_addl(env); - - case CC_OP_ADCB: - return compute_c_adcb(env); - case CC_OP_ADCW: - return compute_c_adcw(env); - case CC_OP_ADCL: - return compute_c_adcl(env); - - case CC_OP_SUBB: - return compute_c_subb(env); - case CC_OP_SUBW: - return compute_c_subw(env); - case CC_OP_SUBL: - return compute_c_subl(env); - - case CC_OP_SBBB: - return compute_c_sbbb(env); - case CC_OP_SBBW: - return compute_c_sbbw(env); - case CC_OP_SBBL: - return compute_c_sbbl(env); - - case CC_OP_LOGICB: - return compute_c_logicb(); - case CC_OP_LOGICW: - return compute_c_logicw(); - case CC_OP_LOGICL: - return compute_c_logicl(); + case CC_OP_SARB: + case CC_OP_SARW: + case CC_OP_SARL: + case CC_OP_SARQ: + return src1 & 1; case CC_OP_INCB: - return compute_c_incl(env); case CC_OP_INCW: - return compute_c_incl(env); case CC_OP_INCL: - return compute_c_incl(env); - + case CC_OP_INCQ: case CC_OP_DECB: - return compute_c_incl(env); case CC_OP_DECW: - return compute_c_incl(env); case CC_OP_DECL: - return compute_c_incl(env); + case CC_OP_DECQ: + return src1; + + case CC_OP_MULB: + case CC_OP_MULW: + case CC_OP_MULL: + case CC_OP_MULQ: + return src1 != 0; + + case CC_OP_ADDB: + return compute_c_addb(dst, src1); + case CC_OP_ADDW: + return compute_c_addw(dst, src1); + case CC_OP_ADDL: + return compute_c_addl(dst, src1); + + case CC_OP_ADCB: + return compute_c_adcb(dst, src1); + case CC_OP_ADCW: + return compute_c_adcw(dst, src1); + case CC_OP_ADCL: + return compute_c_adcl(dst, src1); + + case CC_OP_SUBB: + return compute_c_subb(dst, src1); + case CC_OP_SUBW: + return compute_c_subw(dst, src1); + case CC_OP_SUBL: + return compute_c_subl(dst, src1); + + case CC_OP_SBBB: + return compute_c_sbbb(dst, src1); + case CC_OP_SBBW: + return compute_c_sbbw(dst, src1); + case CC_OP_SBBL: + return compute_c_sbbl(dst, src1); case CC_OP_SHLB: - return compute_c_shlb(env); + return compute_c_shlb(dst, src1); case CC_OP_SHLW: - return compute_c_shlw(env); + return compute_c_shlw(dst, src1); case CC_OP_SHLL: - return compute_c_shll(env); - - case CC_OP_SARB: - return compute_c_sarl(env); - case CC_OP_SARW: - return compute_c_sarl(env); - case CC_OP_SARL: - return compute_c_sarl(env); + return compute_c_shll(dst, src1); #ifdef TARGET_X86_64 - case CC_OP_MULQ: - return compute_c_mull(env); - case CC_OP_ADDQ: - return compute_c_addq(env); - + return compute_c_addq(dst, src1); case CC_OP_ADCQ: - return compute_c_adcq(env); - + return compute_c_adcq(dst, src1); case CC_OP_SUBQ: - return compute_c_subq(env); - + return compute_c_subq(dst, src1); case CC_OP_SBBQ: - return compute_c_sbbq(env); - - case CC_OP_LOGICQ: - return compute_c_logicq(); - - case CC_OP_INCQ: - return compute_c_incl(env); - - case CC_OP_DECQ: - return compute_c_incl(env); - + return compute_c_sbbq(dst, src1); case CC_OP_SHLQ: - return compute_c_shlq(env); - - case CC_OP_SARQ: - return compute_c_sarl(env); + return compute_c_shlq(dst, src1); #endif } } diff --git a/target-i386/cc_helper_template.h b/target-i386/cc_helper_template.h index 1f94e11dcf..522b462285 100644 --- a/target-i386/cc_helper_template.h +++ b/target-i386/cc_helper_template.h @@ -18,255 +18,198 @@ */ #define DATA_BITS (1 << (3 + SHIFT)) -#define SIGN_MASK (((target_ulong)1) << (DATA_BITS - 1)) #if DATA_BITS == 8 #define SUFFIX b #define DATA_TYPE uint8_t -#define DATA_MASK 0xff #elif DATA_BITS == 16 #define SUFFIX w #define DATA_TYPE uint16_t -#define DATA_MASK 0xffff #elif DATA_BITS == 32 #define SUFFIX l #define DATA_TYPE uint32_t -#define DATA_MASK 0xffffffff #elif DATA_BITS == 64 #define SUFFIX q #define DATA_TYPE uint64_t -#define DATA_MASK 0xffffffffffffffffULL #else #error unhandled operand size #endif +#define SIGN_MASK (((DATA_TYPE)1) << (DATA_BITS - 1)) + /* dynamic flags computation */ -static int glue(compute_all_add, SUFFIX)(CPUX86State *env) +static int glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { int cf, pf, af, zf, sf, of; - target_long src1, src2; + DATA_TYPE src2 = dst - src1; - src1 = CC_SRC; - src2 = CC_DST - CC_SRC; - cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + cf = dst < src1; + pf = parity_table[(uint8_t)dst]; + af = (dst ^ src1 ^ src2) & CC_A; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } -static int glue(compute_c_add, SUFFIX)(CPUX86State *env) +static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { - int cf; - target_long src1; - - src1 = CC_SRC; - cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; - return cf; + return dst < src1; } -static int glue(compute_all_adc, SUFFIX)(CPUX86State *env) +static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { int cf, pf, af, zf, sf, of; - target_long src1, src2; + DATA_TYPE src2 = dst - src1 - 1; - src1 = CC_SRC; - src2 = CC_DST - CC_SRC - 1; - cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + cf = dst <= src1; + pf = parity_table[(uint8_t)dst]; + af = (dst ^ src1 ^ src2) & 0x10; + zf = (dst == 0) << 6; + sf = lshift(dst, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } -static int glue(compute_c_adc, SUFFIX)(CPUX86State *env) +static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { - int cf; - target_long src1; - - src1 = CC_SRC; - cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; - return cf; + return dst <= src1; } -static int glue(compute_all_sub, SUFFIX)(CPUX86State *env) +static int glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) { int cf, pf, af, zf, sf, of; - target_long src1, src2; + DATA_TYPE src1 = dst + src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + cf = src1 < src2; + pf = parity_table[(uint8_t)dst]; + af = (dst ^ src1 ^ src2) & CC_A; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } -static int glue(compute_c_sub, SUFFIX)(CPUX86State *env) +static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) { - int cf; - target_long src1, src2; + DATA_TYPE src1 = dst + src2; - src1 = CC_DST + CC_SRC; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; - return cf; + return src1 < src2; } -static int glue(compute_all_sbb, SUFFIX)(CPUX86State *env) +static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) { int cf, pf, af, zf, sf, of; - target_long src1, src2; + DATA_TYPE src1 = dst + src2 + 1; - src1 = CC_DST + CC_SRC + 1; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; + cf = src1 <= src2; + pf = parity_table[(uint8_t)dst]; + af = (dst ^ src1 ^ src2) & 0x10; + zf = (dst == 0) << 6; + sf = lshift(dst, 8 - DATA_BITS) & 0x80; + of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } -static int glue(compute_c_sbb, SUFFIX)(CPUX86State *env) +static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) { - int cf; - target_long src1, src2; + DATA_TYPE src1 = dst + src2 + 1; - src1 = CC_DST + CC_SRC + 1; - src2 = CC_SRC; - cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; - return cf; + return src1 <= src2; } -static int glue(compute_all_logic, SUFFIX)(CPUX86State *env) +static int glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { int cf, pf, af, zf, sf, of; cf = 0; - pf = parity_table[(uint8_t)CC_DST]; + pf = parity_table[(uint8_t)dst]; af = 0; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; of = 0; return cf | pf | af | zf | sf | of; } -static int glue(compute_c_logic, SUFFIX)(void) -{ - return 0; -} - -static int glue(compute_all_inc, SUFFIX)(CPUX86State *env) +static int glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { int cf, pf, af, zf, sf, of; - target_long src1, src2; + DATA_TYPE src2; - src1 = CC_DST - 1; + cf = src1; + src1 = dst - 1; src2 = 1; - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; + pf = parity_table[(uint8_t)dst]; + af = (dst ^ src1 ^ src2) & CC_A; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + of = (dst == SIGN_MASK) * CC_O; return cf | pf | af | zf | sf | of; } -#if DATA_BITS == 32 -static int glue(compute_c_inc, SUFFIX)(CPUX86State *env) -{ - return CC_SRC; -} -#endif - -static int glue(compute_all_dec, SUFFIX)(CPUX86State *env) +static int glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { int cf, pf, af, zf, sf, of; - target_long src1, src2; + DATA_TYPE src2; - src1 = CC_DST + 1; + cf = src1; + src1 = dst + 1; src2 = 1; - cf = CC_SRC; - pf = parity_table[(uint8_t)CC_DST]; - af = (CC_DST ^ src1 ^ src2) & 0x10; - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = ((CC_DST & DATA_MASK) == ((target_ulong)SIGN_MASK - 1)) << 11; + pf = parity_table[(uint8_t)dst]; + af = (dst ^ src1 ^ src2) & CC_A; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + of = (dst == SIGN_MASK - 1) * CC_O; return cf | pf | af | zf | sf | of; } -static int glue(compute_all_shl, SUFFIX)(CPUX86State *env) +static int glue(compute_all_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { int cf, pf, af, zf, sf, of; - cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; - pf = parity_table[(uint8_t)CC_DST]; + cf = (src1 >> (DATA_BITS - 1)) & CC_C; + pf = parity_table[(uint8_t)dst]; af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - /* of is defined if shift count == 1 */ - of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + /* of is defined iff shift count == 1 */ + of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } -static int glue(compute_c_shl, SUFFIX)(CPUX86State *env) +static int glue(compute_c_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { - return (CC_SRC >> (DATA_BITS - 1)) & CC_C; + return (src1 >> (DATA_BITS - 1)) & CC_C; } -#if DATA_BITS == 32 -static int glue(compute_c_sar, SUFFIX)(CPUX86State *env) -{ - return CC_SRC & 1; -} -#endif - -static int glue(compute_all_sar, SUFFIX)(CPUX86State *env) +static int glue(compute_all_sar, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { int cf, pf, af, zf, sf, of; - cf = CC_SRC & 1; - pf = parity_table[(uint8_t)CC_DST]; + cf = src1 & 1; + pf = parity_table[(uint8_t)dst]; af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - /* of is defined if shift count == 1 */ - of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + /* of is defined iff shift count == 1 */ + of = lshift(src1 ^ dst, 12 - DATA_BITS) & CC_O; return cf | pf | af | zf | sf | of; } -#if DATA_BITS == 32 -static int glue(compute_c_mul, SUFFIX)(CPUX86State *env) -{ - int cf; - - cf = (CC_SRC != 0); - return cf; -} -#endif - /* NOTE: we compute the flags like the P4. On olders CPUs, only OF and - CF are modified and it is slower to do that. */ -static int glue(compute_all_mul, SUFFIX)(CPUX86State *env) + CF are modified and it is slower to do that. Note as well that we + don't truncate SRC1 for computing carry to DATA_TYPE. */ +static int glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1) { int cf, pf, af, zf, sf, of; - cf = (CC_SRC != 0); - pf = parity_table[(uint8_t)CC_DST]; + cf = (src1 != 0); + pf = parity_table[(uint8_t)dst]; af = 0; /* undefined */ - zf = ((DATA_TYPE)CC_DST == 0) << 6; - sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; - of = cf << 11; + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + of = cf * CC_O; return cf | pf | af | zf | sf | of; } From db9f2597722d5d8bc5f2330f186288d893114338 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 16:10:49 -0800 Subject: [PATCH 1123/1634] target-i386: Make helper_cc_compute_{all,c} const Pass the data in explicitly, rather than indirectly via env. This avoids all sorts of unnecessary register spillage. Signed-off-by: Richard Henderson --- target-i386/cc_helper.c | 12 ++++-------- target-i386/helper.h | 4 ++-- target-i386/translate.c | 31 +++++++++++++++++++++++++++---- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c index 61427ddeac..a5d8181804 100644 --- a/target-i386/cc_helper.c +++ b/target-i386/cc_helper.c @@ -75,10 +75,8 @@ const uint8_t parity_table[256] = { #endif -uint32_t helper_cc_compute_all(CPUX86State *env, int op) +target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, int op) { - target_ulong dst = CC_DST, src1 = CC_SRC; - switch (op) { default: /* should never happen */ return 0; @@ -183,13 +181,11 @@ uint32_t helper_cc_compute_all(CPUX86State *env, int op) uint32_t cpu_cc_compute_all(CPUX86State *env, int op) { - return helper_cc_compute_all(env, op); + return helper_cc_compute_all(CC_DST, CC_SRC, op); } -uint32_t helper_cc_compute_c(CPUX86State *env, int op) +target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, int op) { - target_ulong dst = CC_DST, src1 = CC_SRC; - switch (op) { default: /* should never happen */ case CC_OP_LOGICB: @@ -281,7 +277,7 @@ target_ulong helper_read_eflags(CPUX86State *env) { uint32_t eflags; - eflags = helper_cc_compute_all(env, CC_OP); + eflags = cpu_cc_compute_all(env, CC_OP); eflags |= (DF & DF_MASK); eflags |= env->eflags & ~(VM_MASK | RF_MASK); return eflags; diff --git a/target-i386/helper.h b/target-i386/helper.h index 9ed720d0ed..901ff73c12 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -1,7 +1,7 @@ #include "exec/def-helper.h" -DEF_HELPER_FLAGS_2(cc_compute_all, TCG_CALL_NO_SE, i32, env, int) -DEF_HELPER_FLAGS_2(cc_compute_c, TCG_CALL_NO_SE, i32, env, int) +DEF_HELPER_FLAGS_3(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, int) +DEF_HELPER_FLAGS_3(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, int) DEF_HELPER_0(lock, void) DEF_HELPER_0(unlock, void) diff --git a/target-i386/translate.c b/target-i386/translate.c index 31e3442442..5235aff15e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -882,13 +882,37 @@ static void gen_op_update_neg_cc(void) /* compute all eflags to cc_src */ static void gen_compute_eflags(DisasContext *s) { + TCGv zero, dst, src1; + int live, dead; + if (s->cc_op == CC_OP_EFLAGS) { return; } + + TCGV_UNUSED(zero); + dst = cpu_cc_dst; + src1 = cpu_cc_src; + + /* Take care to not read values that are not live. */ + live = cc_op_live[s->cc_op] & ~USES_CC_SRCT; + dead = live ^ (USES_CC_DST | USES_CC_SRC); + if (dead) { + zero = tcg_const_tl(0); + if (dead & USES_CC_DST) { + dst = zero; + } + if (dead & USES_CC_SRC) { + src1 = zero; + } + } + gen_update_cc_op(s); - gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_env, cpu_cc_op); + gen_helper_cc_compute_all(cpu_cc_src, dst, src1, cpu_cc_op); set_cc_op(s, CC_OP_EFLAGS); - tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32); + + if (dead) { + tcg_temp_free(zero); + } } typedef struct CCPrepare { @@ -980,8 +1004,7 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) /* The need to compute only C from CC_OP_DYNAMIC is important in efficiently implementing e.g. INC at the start of a TB. */ gen_update_cc_op(s); - gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_env, cpu_cc_op); - tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32); + gen_helper_cc_compute_c(reg, cpu_cc_dst, cpu_cc_src, cpu_cc_op); return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, .mask = -1, .no_setcond = true }; } From 988c3eb0d6f41ac13f4ec145c637f12c776de602 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 16:03:16 -0800 Subject: [PATCH 1124/1634] target-i386: Use CC_SRC2 for ADC and SBB Add another slot in ENV and store two of the three inputs. This lets us do less work when carry-out is not needed, and avoids the unpredictable CC_OP after translating these insns. Signed-off-by: Richard Henderson --- target-i386/cc_helper.c | 40 ++++++++-------- target-i386/cc_helper_template.h | 26 ++++++----- target-i386/cpu.h | 10 ++-- target-i386/helper.h | 4 +- target-i386/translate.c | 80 +++++++++++++------------------- 5 files changed, 75 insertions(+), 85 deletions(-) diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c index a5d8181804..218a9b519f 100644 --- a/target-i386/cc_helper.c +++ b/target-i386/cc_helper.c @@ -75,7 +75,8 @@ const uint8_t parity_table[256] = { #endif -target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, int op) +target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, + target_ulong src2, int op) { switch (op) { default: /* should never happen */ @@ -99,11 +100,11 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, int op) return compute_all_addl(dst, src1); case CC_OP_ADCB: - return compute_all_adcb(dst, src1); + return compute_all_adcb(dst, src1, src2); case CC_OP_ADCW: - return compute_all_adcw(dst, src1); + return compute_all_adcw(dst, src1, src2); case CC_OP_ADCL: - return compute_all_adcl(dst, src1); + return compute_all_adcl(dst, src1, src2); case CC_OP_SUBB: return compute_all_subb(dst, src1); @@ -113,11 +114,11 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, int op) return compute_all_subl(dst, src1); case CC_OP_SBBB: - return compute_all_sbbb(dst, src1); + return compute_all_sbbb(dst, src1, src2); case CC_OP_SBBW: - return compute_all_sbbw(dst, src1); + return compute_all_sbbw(dst, src1, src2); case CC_OP_SBBL: - return compute_all_sbbl(dst, src1); + return compute_all_sbbl(dst, src1, src2); case CC_OP_LOGICB: return compute_all_logicb(dst, src1); @@ -160,11 +161,11 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, int op) case CC_OP_ADDQ: return compute_all_addq(dst, src1); case CC_OP_ADCQ: - return compute_all_adcq(dst, src1); + return compute_all_adcq(dst, src1, src2); case CC_OP_SUBQ: return compute_all_subq(dst, src1); case CC_OP_SBBQ: - return compute_all_sbbq(dst, src1); + return compute_all_sbbq(dst, src1, src2); case CC_OP_LOGICQ: return compute_all_logicq(dst, src1); case CC_OP_INCQ: @@ -181,10 +182,11 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, int op) uint32_t cpu_cc_compute_all(CPUX86State *env, int op) { - return helper_cc_compute_all(CC_DST, CC_SRC, op); + return helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, op); } -target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, int op) +target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, + target_ulong src2, int op) { switch (op) { default: /* should never happen */ @@ -225,11 +227,11 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, int op) return compute_c_addl(dst, src1); case CC_OP_ADCB: - return compute_c_adcb(dst, src1); + return compute_c_adcb(dst, src1, src2); case CC_OP_ADCW: - return compute_c_adcw(dst, src1); + return compute_c_adcw(dst, src1, src2); case CC_OP_ADCL: - return compute_c_adcl(dst, src1); + return compute_c_adcl(dst, src1, src2); case CC_OP_SUBB: return compute_c_subb(dst, src1); @@ -239,11 +241,11 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, int op) return compute_c_subl(dst, src1); case CC_OP_SBBB: - return compute_c_sbbb(dst, src1); + return compute_c_sbbb(dst, src1, src2); case CC_OP_SBBW: - return compute_c_sbbw(dst, src1); + return compute_c_sbbw(dst, src1, src2); case CC_OP_SBBL: - return compute_c_sbbl(dst, src1); + return compute_c_sbbl(dst, src1, src2); case CC_OP_SHLB: return compute_c_shlb(dst, src1); @@ -256,11 +258,11 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, int op) case CC_OP_ADDQ: return compute_c_addq(dst, src1); case CC_OP_ADCQ: - return compute_c_adcq(dst, src1); + return compute_c_adcq(dst, src1, src2); case CC_OP_SUBQ: return compute_c_subq(dst, src1); case CC_OP_SBBQ: - return compute_c_sbbq(dst, src1); + return compute_c_sbbq(dst, src1, src2); case CC_OP_SHLQ: return compute_c_shlq(dst, src1); #endif diff --git a/target-i386/cc_helper_template.h b/target-i386/cc_helper_template.h index 522b462285..87f47d2e97 100644 --- a/target-i386/cc_helper_template.h +++ b/target-i386/cc_helper_template.h @@ -58,12 +58,13 @@ static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return dst < src1; } -static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, + DATA_TYPE src3) { int cf, pf, af, zf, sf, of; - DATA_TYPE src2 = dst - src1 - 1; + DATA_TYPE src2 = dst - src1 - src3; - cf = dst <= src1; + cf = (src3 ? dst <= src1 : dst < src1); pf = parity_table[(uint8_t)dst]; af = (dst ^ src1 ^ src2) & 0x10; zf = (dst == 0) << 6; @@ -72,9 +73,10 @@ static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, + DATA_TYPE src3) { - return dst <= src1; + return src3 ? dst <= src1 : dst < src1; } static int glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) @@ -98,12 +100,13 @@ static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) return src1 < src2; } -static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) +static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, + DATA_TYPE src3) { int cf, pf, af, zf, sf, of; - DATA_TYPE src1 = dst + src2 + 1; + DATA_TYPE src1 = dst + src2 + src3; - cf = src1 <= src2; + cf = (src3 ? src1 <= src2 : src1 < src2); pf = parity_table[(uint8_t)dst]; af = (dst ^ src1 ^ src2) & 0x10; zf = (dst == 0) << 6; @@ -112,11 +115,12 @@ static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) return cf | pf | af | zf | sf | of; } -static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) +static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, + DATA_TYPE src3) { - DATA_TYPE src1 = dst + src2 + 1; + DATA_TYPE src1 = dst + src2 + src3; - return src1 <= src2; + return (src3 ? src1 <= src2 : src1 < src2); } static int glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 8c4c605299..1fa9dc8267 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -725,8 +725,9 @@ typedef struct CPUX86State { stored elsewhere */ /* emulator internal eflags handling */ - target_ulong cc_src; target_ulong cc_dst; + target_ulong cc_src; + target_ulong cc_src2; uint32_t cc_op; int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ uint32_t hflags; /* TB flags, see HF_xxx constants. These flags @@ -1116,9 +1117,10 @@ static inline int cpu_mmu_index (CPUX86State *env) #define EIP (env->eip) #define DF (env->df) -#define CC_SRC (env->cc_src) -#define CC_DST (env->cc_dst) -#define CC_OP (env->cc_op) +#define CC_DST (env->cc_dst) +#define CC_SRC (env->cc_src) +#define CC_SRC2 (env->cc_src2) +#define CC_OP (env->cc_op) /* n must be a constant to be efficient */ static inline target_long lshift(target_long x, int n) diff --git a/target-i386/helper.h b/target-i386/helper.h index 901ff73c12..4c46ab1b40 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -1,7 +1,7 @@ #include "exec/def-helper.h" -DEF_HELPER_FLAGS_3(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, int) -DEF_HELPER_FLAGS_3(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, int) +DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) +DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int) DEF_HELPER_0(lock, void) DEF_HELPER_0(unlock, void) diff --git a/target-i386/translate.c b/target-i386/translate.c index 5235aff15e..f667f9333b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -61,7 +61,7 @@ /* global register indexes */ static TCGv_ptr cpu_env; static TCGv cpu_A0; -static TCGv cpu_cc_src, cpu_cc_dst, cpu_cc_srcT; +static TCGv cpu_cc_dst, cpu_cc_src, cpu_cc_src2, cpu_cc_srcT; static TCGv_i32 cpu_cc_op; static TCGv cpu_regs[CPU_NB_REGS]; /* local temps */ @@ -188,18 +188,19 @@ enum { enum { USES_CC_DST = 1, USES_CC_SRC = 2, - USES_CC_SRCT = 4, + USES_CC_SRC2 = 4, + USES_CC_SRCT = 8, }; /* Bit set if the global variable is live after setting CC_OP to X. */ static const uint8_t cc_op_live[CC_OP_NB] = { - [CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC, + [CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2, [CC_OP_EFLAGS] = USES_CC_SRC, [CC_OP_MULB ... CC_OP_MULQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_ADDB ... CC_OP_ADDQ] = USES_CC_DST | USES_CC_SRC, - [CC_OP_ADCB ... CC_OP_ADCQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_ADCB ... CC_OP_ADCQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2, [CC_OP_SUBB ... CC_OP_SUBQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRCT, - [CC_OP_SBBB ... CC_OP_SBBQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_SBBB ... CC_OP_SBBQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2, [CC_OP_LOGICB ... CC_OP_LOGICQ] = USES_CC_DST, [CC_OP_INCB ... CC_OP_INCQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_DECB ... CC_OP_DECQ] = USES_CC_DST | USES_CC_SRC, @@ -223,6 +224,9 @@ static void set_cc_op(DisasContext *s, CCOp op) if (dead & USES_CC_SRC) { tcg_gen_discard_tl(cpu_cc_src); } + if (dead & USES_CC_SRC2) { + tcg_gen_discard_tl(cpu_cc_src2); + } if (dead & USES_CC_SRCT) { tcg_gen_discard_tl(cpu_cc_srcT); } @@ -867,6 +871,13 @@ static void gen_op_update2_cc(void) tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); } +static void gen_op_update3_cc(TCGv reg) +{ + tcg_gen_mov_tl(cpu_cc_src2, reg); + tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); +} + static inline void gen_op_testl_T0_T1_cc(void) { tcg_gen_and_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]); @@ -882,7 +893,7 @@ static void gen_op_update_neg_cc(void) /* compute all eflags to cc_src */ static void gen_compute_eflags(DisasContext *s) { - TCGv zero, dst, src1; + TCGv zero, dst, src1, src2; int live, dead; if (s->cc_op == CC_OP_EFLAGS) { @@ -892,10 +903,11 @@ static void gen_compute_eflags(DisasContext *s) TCGV_UNUSED(zero); dst = cpu_cc_dst; src1 = cpu_cc_src; + src2 = cpu_cc_src2; /* Take care to not read values that are not live. */ live = cc_op_live[s->cc_op] & ~USES_CC_SRCT; - dead = live ^ (USES_CC_DST | USES_CC_SRC); + dead = live ^ (USES_CC_DST | USES_CC_SRC | USES_CC_SRC2); if (dead) { zero = tcg_const_tl(0); if (dead & USES_CC_DST) { @@ -904,10 +916,13 @@ static void gen_compute_eflags(DisasContext *s) if (dead & USES_CC_SRC) { src1 = zero; } + if (dead & USES_CC_SRC2) { + src2 = zero; + } } gen_update_cc_op(s); - gen_helper_cc_compute_all(cpu_cc_src, dst, src1, cpu_cc_op); + gen_helper_cc_compute_all(cpu_cc_src, dst, src1, src2, cpu_cc_op); set_cc_op(s, CC_OP_EFLAGS); if (dead) { @@ -951,30 +966,6 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) return (CCPrepare) { .cond = TCG_COND_LTU, .reg = t0, .reg2 = t1, .mask = -1, .use_reg2 = true }; - case CC_OP_SBBB ... CC_OP_SBBQ: - /* (DATA_TYPE)(CC_DST + CC_SRC + 1) <= (DATA_TYPE)CC_SRC */ - size = s->cc_op - CC_OP_SBBB; - t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); - if (TCGV_EQUAL(t1, reg) && TCGV_EQUAL(reg, cpu_cc_src)) { - tcg_gen_mov_tl(cpu_tmp0, cpu_cc_src); - t1 = cpu_tmp0; - } - - tcg_gen_add_tl(reg, cpu_cc_dst, cpu_cc_src); - tcg_gen_addi_tl(reg, reg, 1); - gen_extu(size, reg); - t0 = reg; - goto adc_sbb; - - case CC_OP_ADCB ... CC_OP_ADCQ: - /* (DATA_TYPE)CC_DST <= (DATA_TYPE)CC_SRC */ - size = s->cc_op - CC_OP_ADCB; - t1 = gen_ext_tl(cpu_tmp0, cpu_cc_src, size, false); - t0 = gen_ext_tl(reg, cpu_cc_dst, size, false); - adc_sbb: - return (CCPrepare) { .cond = TCG_COND_LEU, .reg = t0, - .reg2 = t1, .mask = -1, .use_reg2 = true }; - case CC_OP_LOGICB ... CC_OP_LOGICQ: return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 }; @@ -1004,7 +995,8 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) /* The need to compute only C from CC_OP_DYNAMIC is important in efficiently implementing e.g. INC at the start of a TB. */ gen_update_cc_op(s); - gen_helper_cc_compute_c(reg, cpu_cc_dst, cpu_cc_src, cpu_cc_op); + gen_helper_cc_compute_c(reg, cpu_cc_dst, cpu_cc_src, + cpu_cc_src2, cpu_cc_op); return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg, .mask = -1, .no_setcond = true }; } @@ -1442,18 +1434,10 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) gen_op_mov_reg_T0(ot, d); else gen_op_st_T0_A0(ot + s1->mem_index); - tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); - tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); - tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_ADDB + ot); - set_cc_op(s1, CC_OP_DYNAMIC); + gen_op_update3_cc(cpu_tmp4); + set_cc_op(s1, CC_OP_ADCB + ot); break; case OP_SBBL: - /* - * No need to store cpu_cc_srcT, because it is used only - * when the cc_op is known. - */ gen_compute_eflags_c(s1, cpu_tmp4); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]); tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4); @@ -1461,12 +1445,8 @@ static void gen_op(DisasContext *s1, int op, int ot, int d) gen_op_mov_reg_T0(ot, d); else gen_op_st_T0_A0(ot + s1->mem_index); - tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4); - tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2); - tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_SUBB + ot); - set_cc_op(s1, CC_OP_DYNAMIC); + gen_op_update3_cc(cpu_tmp4); + set_cc_op(s1, CC_OP_SBBB + ot); break; case OP_ADDL: gen_op_addl_T0_T1(); @@ -7788,6 +7768,8 @@ void optimize_flags_init(void) "cc_dst"); cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_src), "cc_src"); + cpu_cc_src2 = tcg_global_mem_new(TCG_AREG0, offsetof(CPUX86State, cc_src2), + "cc_src2"); #ifdef TARGET_X86_64 cpu_regs[R_EAX] = tcg_global_mem_new_i64(TCG_AREG0, From 4a6fd938f5457ee161d2acbd9364608a2a68b7a1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 10 Jan 2013 13:29:23 -0800 Subject: [PATCH 1125/1634] target-i386: Tidy prefix parsing Avoid duplicating switch statement between 32 and 64-bit modes. Signed-off-by: Richard Henderson --- target-i386/translate.c | 134 ++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 82 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index f667f9333b..e5cda94805 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4267,44 +4267,44 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, next_byte: b = cpu_ldub_code(env, s->pc); s->pc++; - /* check prefixes */ + /* Collect prefixes. */ + switch (b) { + case 0xf3: + prefixes |= PREFIX_REPZ; + goto next_byte; + case 0xf2: + prefixes |= PREFIX_REPNZ; + goto next_byte; + case 0xf0: + prefixes |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + s->override = R_CS; + goto next_byte; + case 0x36: + s->override = R_SS; + goto next_byte; + case 0x3e: + s->override = R_DS; + goto next_byte; + case 0x26: + s->override = R_ES; + goto next_byte; + case 0x64: + s->override = R_FS; + goto next_byte; + case 0x65: + s->override = R_GS; + goto next_byte; + case 0x66: + prefixes |= PREFIX_DATA; + goto next_byte; + case 0x67: + prefixes |= PREFIX_ADR; + goto next_byte; #ifdef TARGET_X86_64 - if (CODE64(s)) { - switch (b) { - case 0xf3: - prefixes |= PREFIX_REPZ; - goto next_byte; - case 0xf2: - prefixes |= PREFIX_REPNZ; - goto next_byte; - case 0xf0: - prefixes |= PREFIX_LOCK; - goto next_byte; - case 0x2e: - s->override = R_CS; - goto next_byte; - case 0x36: - s->override = R_SS; - goto next_byte; - case 0x3e: - s->override = R_DS; - goto next_byte; - case 0x26: - s->override = R_ES; - goto next_byte; - case 0x64: - s->override = R_FS; - goto next_byte; - case 0x65: - s->override = R_GS; - goto next_byte; - case 0x66: - prefixes |= PREFIX_DATA; - goto next_byte; - case 0x67: - prefixes |= PREFIX_ADR; - goto next_byte; - case 0x40 ... 0x4f: + case 0x40 ... 0x4f: + if (CODE64(s)) { /* REX prefix */ rex_w = (b >> 3) & 1; rex_r = (b & 0x4) << 1; @@ -4313,58 +4313,28 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, x86_64_hregs = 1; /* select uniform byte register addressing */ goto next_byte; } + break; +#endif + } + + /* Post-process prefixes. */ + if (prefixes & PREFIX_DATA) { + dflag ^= 1; + } + if (prefixes & PREFIX_ADR) { + aflag ^= 1; + } +#ifdef TARGET_X86_64 + if (CODE64(s)) { if (rex_w == 1) { /* 0x66 is ignored if rex.w is set */ dflag = 2; - } else { - if (prefixes & PREFIX_DATA) - dflag ^= 1; } - if (!(prefixes & PREFIX_ADR)) + if (!(prefixes & PREFIX_ADR)) { aflag = 2; - } else -#endif - { - switch (b) { - case 0xf3: - prefixes |= PREFIX_REPZ; - goto next_byte; - case 0xf2: - prefixes |= PREFIX_REPNZ; - goto next_byte; - case 0xf0: - prefixes |= PREFIX_LOCK; - goto next_byte; - case 0x2e: - s->override = R_CS; - goto next_byte; - case 0x36: - s->override = R_SS; - goto next_byte; - case 0x3e: - s->override = R_DS; - goto next_byte; - case 0x26: - s->override = R_ES; - goto next_byte; - case 0x64: - s->override = R_FS; - goto next_byte; - case 0x65: - s->override = R_GS; - goto next_byte; - case 0x66: - prefixes |= PREFIX_DATA; - goto next_byte; - case 0x67: - prefixes |= PREFIX_ADR; - goto next_byte; } - if (prefixes & PREFIX_DATA) - dflag ^= 1; - if (prefixes & PREFIX_ADR) - aflag ^= 1; } +#endif s->prefix = prefixes; s->aflag = aflag; From 701ed211d62b2b0dba732d75997c4bbf37010c1e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 11 Jan 2013 11:35:02 -0800 Subject: [PATCH 1126/1634] target-i386: Decode the VEX prefixes No actual required uses of these encodings yet. Signed-off-by: Richard Henderson --- target-i386/translate.c | 68 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index e5cda94805..f824b9916f 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -37,6 +37,7 @@ #define PREFIX_LOCK 0x04 #define PREFIX_DATA 0x08 #define PREFIX_ADR 0x10 +#define PREFIX_VEX 0x20 #ifdef TARGET_X86_64 #define CODE64(s) ((s)->code64) @@ -98,6 +99,8 @@ typedef struct DisasContext { int code64; /* 64 bit code segment */ int rex_x, rex_b; #endif + int vex_l; /* vex vector length */ + int vex_v; /* vex vvvv register, without 1's compliment. */ int ss32; /* 32 bit stack segment */ CCOp cc_op; /* current CC operation */ bool cc_op_dirty; @@ -4264,6 +4267,8 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, x86_64_hregs = 0; #endif s->rip_offset = 0; /* for relative ip address */ + s->vex_l = 0; + s->vex_v = 0; next_byte: b = cpu_ldub_code(env, s->pc); s->pc++; @@ -4315,6 +4320,63 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } break; #endif + case 0xc5: /* 2-byte VEX */ + case 0xc4: /* 3-byte VEX */ + /* VEX prefixes cannot be used except in 32-bit mode. + Otherwise the instruction is LES or LDS. */ + if (s->code32 && !s->vm86) { + static const int pp_prefix[4] = { + 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ + }; + int vex3, vex2 = cpu_ldub_code(env, s->pc); + + if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) { + /* 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b, + otherwise the instruction is LES or LDS. */ + break; + } + s->pc++; + + /* 4.1.1-4.1.3: No preceeding lock, 66, f2, f3, or rex prefixes. */ + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ + | PREFIX_LOCK | PREFIX_DATA)) { + goto illegal_op; + } +#ifdef TARGET_X86_64 + if (x86_64_hregs) { + goto illegal_op; + } +#endif + rex_r = (~vex2 >> 4) & 8; + if (b == 0xc5) { + vex3 = vex2; + b = cpu_ldub_code(env, s->pc++); + } else { +#ifdef TARGET_X86_64 + s->rex_x = (~vex2 >> 3) & 8; + s->rex_b = (~vex2 >> 2) & 8; +#endif + vex3 = cpu_ldub_code(env, s->pc++); + rex_w = (vex3 >> 7) & 1; + switch (vex2 & 0x1f) { + case 0x01: /* Implied 0f leading opcode bytes. */ + b = cpu_ldub_code(env, s->pc++) | 0x100; + break; + case 0x02: /* Implied 0f 38 leading opcode bytes. */ + b = 0x138; + break; + case 0x03: /* Implied 0f 3a leading opcode bytes. */ + b = 0x13a; + break; + default: /* Reserved for future use. */ + goto illegal_op; + } + } + s->vex_v = (~vex3 >> 3) & 0xf; + s->vex_l = (vex3 >> 2) & 1; + prefixes |= pp_prefix[vex3 & 3] | PREFIX_VEX; + } + break; } /* Post-process prefixes. */ @@ -5461,13 +5523,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } break; case 0xc4: /* les Gv */ - if (CODE64(s)) - goto illegal_op; + /* In CODE64 this is VEX3; see above. */ op = R_ES; goto do_lxx; case 0xc5: /* lds Gv */ - if (CODE64(s)) - goto illegal_op; + /* In CODE64 this is VEX2; see above. */ op = R_DS; goto do_lxx; case 0x1b2: /* lss Gv */ From 111994ee05b810d81dc6abea7fac5280e48dc198 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 10 Jan 2013 12:06:59 -0800 Subject: [PATCH 1127/1634] target-i386: Implement MOVBE Signed-off-by: Richard Henderson --- target-i386/cpu.c | 16 ++++- target-i386/translate.c | 126 +++++++++++++++++++++++++++++++--------- 2 files changed, 112 insertions(+), 30 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index dfcf86e862..0f195337cb 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -389,10 +389,15 @@ typedef struct x86_def_t { CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */ #define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | \ CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT | \ - CPUID_EXT_HYPERVISOR) + CPUID_EXT_MOVBE | CPUID_EXT_HYPERVISOR) /* missing: - CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST, - CPUID_EXT_TM2, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_XSAVE */ + CPUID_EXT_PCLMULQDQ, CPUID_EXT_DTES64, CPUID_EXT_DSCPL, + CPUID_EXT_VMX, CPUID_EXT_SMX, CPUID_EXT_EST, CPUID_EXT_TM2, + CPUID_EXT_CID, CPUID_EXT_FMA, CPUID_EXT_XTPR, CPUID_EXT_PDCM, + CPUID_EXT_PCID, CPUID_EXT_DCA, CPUID_EXT_SSE41, CPUID_EXT_SSE42, + CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AES, + CPUID_EXT_XSAVE, CPUID_EXT_OSXSAVE, CPUID_EXT_AVX, + CPUID_EXT_F16C, CPUID_EXT_RDRAND */ #define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \ CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \ CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT) @@ -402,6 +407,11 @@ typedef struct x86_def_t { CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) #define TCG_SVM_FEATURES 0 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP) + /* missing: + CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_BMI1, CPUID_7_0_EBX_HLE, + CPUID_7_0_EBX_AVX2, CPUID_7_0_EBX_BMI2, CPUID_7_0_EBX_ERMS, + CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, CPUID_7_0_EBX_RDSEED, + CPUID_7_0_EBX_ADX */ /* built-in CPU model definitions */ diff --git a/target-i386/translate.c b/target-i386/translate.c index f824b9916f..5a91ff184a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3837,11 +3837,13 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, reg = ((modrm >> 3) & 7) | rex_r; gen_op_mov_reg_T0(OT_LONG, reg); break; + case 0x138: - if (s->prefix & PREFIX_REPNZ) - goto crc32; case 0x038: b = modrm; + if ((b & 0xf0) == 0xf0) { + goto do_0f_38_fx; + } modrm = cpu_ldub_code(env, s->pc++); rm = modrm & 7; reg = ((modrm >> 3) & 7) | rex_r; @@ -3914,36 +3916,106 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, set_cc_op(s, CC_OP_EFLAGS); } break; - case 0x338: /* crc32 */ - crc32: - b = modrm; + + case 0x238: + case 0x338: + do_0f_38_fx: + /* Various integer extensions at 0f 38 f[0-f]. */ + b = modrm | (b1 << 8); modrm = cpu_ldub_code(env, s->pc++); reg = ((modrm >> 3) & 7) | rex_r; - if (b != 0xf0 && b != 0xf1) + switch (b) { + case 0x3f0: /* crc32 Gd,Eb */ + case 0x3f1: /* crc32 Gd,Ey */ + do_crc32: + if (!(s->cpuid_ext_features & CPUID_EXT_SSE42)) { + goto illegal_op; + } + if ((b & 0xff) == 0xf0) { + ot = OT_BYTE; + } else if (s->dflag != 2) { + ot = (s->prefix & PREFIX_DATA ? OT_WORD : OT_LONG); + } else { + ot = OT_QUAD; + } + + gen_op_mov_TN_reg(OT_LONG, 0, reg); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + gen_helper_crc32(cpu_T[0], cpu_tmp2_i32, + cpu_T[0], tcg_const_i32(8 << ot)); + + ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; + gen_op_mov_reg_T0(ot, reg); + break; + + case 0x1f0: /* crc32 or movbe */ + case 0x1f1: + /* For these insns, the f3 prefix is supposed to have priority + over the 66 prefix, but that's not what we implement above + setting b1. */ + if (s->prefix & PREFIX_REPNZ) { + goto do_crc32; + } + /* FALLTHRU */ + case 0x0f0: /* movbe Gy,My */ + case 0x0f1: /* movbe My,Gy */ + if (!(s->cpuid_ext_features & CPUID_EXT_MOVBE)) { + goto illegal_op; + } + if (s->dflag != 2) { + ot = (s->prefix & PREFIX_DATA ? OT_WORD : OT_LONG); + } else { + ot = OT_QUAD; + } + + /* Load the data incoming to the bswap. Note that the TCG + implementation of bswap requires the input be zero + extended. In the case of the loads, we simply know that + gen_op_ld_v via gen_ldst_modrm does that already. */ + if ((b & 1) == 0) { + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + } else { + switch (ot) { + case OT_WORD: + tcg_gen_ext16u_tl(cpu_T[0], cpu_regs[reg]); + break; + default: + tcg_gen_ext32u_tl(cpu_T[0], cpu_regs[reg]); + break; + case OT_QUAD: + tcg_gen_mov_tl(cpu_T[0], cpu_regs[reg]); + break; + } + } + + switch (ot) { + case OT_WORD: + tcg_gen_bswap16_tl(cpu_T[0], cpu_T[0]); + break; + default: + tcg_gen_bswap32_tl(cpu_T[0], cpu_T[0]); + break; +#ifdef TARGET_X86_64 + case OT_QUAD: + tcg_gen_bswap64_tl(cpu_T[0], cpu_T[0]); + break; +#endif + } + + if ((b & 1) == 0) { + gen_op_mov_reg_T0(ot, reg); + } else { + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1); + } + break; + + default: goto illegal_op; - if (!(s->cpuid_ext_features & CPUID_EXT_SSE42)) - goto illegal_op; - - if (b == 0xf0) - ot = OT_BYTE; - else if (b == 0xf1 && s->dflag != 2) - if (s->prefix & PREFIX_DATA) - ot = OT_WORD; - else - ot = OT_LONG; - else - ot = OT_QUAD; - - gen_op_mov_TN_reg(OT_LONG, 0, reg); - tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); - gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); - gen_helper_crc32(cpu_T[0], cpu_tmp2_i32, - cpu_T[0], tcg_const_i32(8 << ot)); - - ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; - gen_op_mov_reg_T0(ot, reg); + } break; + case 0x03a: case 0x13a: b = modrm; From 7073fbada733c8d10992f00772c9b9299d740e9b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 16:17:10 -0800 Subject: [PATCH 1128/1634] target-i386: Implement ANDN As this is the first of the BMI insns to be implemented, this carries quite a bit more baggage than normal. Signed-off-by: Richard Henderson --- target-i386/cpu.c | 10 +++++----- target-i386/translate.c | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0f195337cb..0cb64ab583 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -406,12 +406,12 @@ typedef struct x86_def_t { #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) #define TCG_SVM_FEATURES 0 -#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP) +#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP \ + CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2) /* missing: - CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_BMI1, CPUID_7_0_EBX_HLE, - CPUID_7_0_EBX_AVX2, CPUID_7_0_EBX_BMI2, CPUID_7_0_EBX_ERMS, - CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, CPUID_7_0_EBX_RDSEED, - CPUID_7_0_EBX_ADX */ + CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, + CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, + CPUID_7_0_EBX_RDSEED, CPUID_7_0_EBX_ADX */ /* built-in CPU model definitions */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 5a91ff184a..01ff13154d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2955,8 +2955,9 @@ static const SSEFunc_0_epp sse_op_table1[256][4] = { [0xc6] = { (SSEFunc_0_epp)gen_helper_shufps, (SSEFunc_0_epp)gen_helper_shufpd }, /* XXX: casts */ - [0x38] = { SSE_SPECIAL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* SSSE3/SSE4 */ - [0x3a] = { SSE_SPECIAL, SSE_SPECIAL }, /* SSSE3/SSE4 */ + /* SSSE3, SSE4, MOVBE, CRC32, BMI1, BMI2, ADX. */ + [0x38] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, + [0x3a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* MMX ops and their SSE extensions */ [0x60] = MMX_OP2(punpcklbw), @@ -4011,6 +4012,20 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } break; + case 0x0f2: /* andn Gy, By, Ey */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + tcg_gen_andc_tl(cpu_T[0], cpu_regs[s->vex_v], cpu_T[0]); + gen_op_mov_reg_T0(ot, reg); + gen_op_update1_cc(); + set_cc_op(s, CC_OP_LOGICB + ot); + break; + default: goto illegal_op; } From c7ab7565bc6d52cc140230aa4d0533d13d89c8b1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 16:21:33 -0800 Subject: [PATCH 1129/1634] target-i386: Implement BEXTR Signed-off-by: Richard Henderson --- target-i386/translate.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index 01ff13154d..d742fe3693 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4026,6 +4026,46 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, set_cc_op(s, CC_OP_LOGICB + ot); break; + case 0x0f7: /* bextr Gy, Ey, By */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + { + TCGv bound, zero; + + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + /* Extract START, and shift the operand. + Shifts larger than operand size get zeros. */ + tcg_gen_ext8u_tl(cpu_A0, cpu_regs[s->vex_v]); + tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_A0); + + bound = tcg_const_tl(ot == OT_QUAD ? 63 : 31); + zero = tcg_const_tl(0); + tcg_gen_movcond_tl(TCG_COND_LEU, cpu_T[0], cpu_A0, bound, + cpu_T[0], zero); + tcg_temp_free(zero); + + /* Extract the LEN into a mask. Lengths larger than + operand size get all ones. */ + tcg_gen_shri_tl(cpu_A0, cpu_regs[s->vex_v], 8); + tcg_gen_ext8u_tl(cpu_A0, cpu_A0); + tcg_gen_movcond_tl(TCG_COND_LEU, cpu_A0, cpu_A0, bound, + cpu_A0, bound); + tcg_temp_free(bound); + tcg_gen_movi_tl(cpu_T[1], 1); + tcg_gen_shl_tl(cpu_T[1], cpu_T[1], cpu_A0); + tcg_gen_subi_tl(cpu_T[1], cpu_T[1], 1); + tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + + gen_op_mov_reg_T0(ot, reg); + gen_op_update1_cc(); + set_cc_op(s, CC_OP_LOGICB + ot); + } + break; + default: goto illegal_op; } From bc4b43dc2fe88712ad921c05fc1ab9ebc4cb6778 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 16:44:37 -0800 Subject: [PATCH 1130/1634] target-i386: Implement BLSR, BLSMSK, BLSI Do all of group 17 at one time for ease. Signed-off-by: Richard Henderson --- target-i386/cc_helper.c | 18 ++++++++++++ target-i386/cc_helper_template.h | 18 ++++++++++++ target-i386/cpu.h | 5 ++++ target-i386/helper.c | 7 ++++- target-i386/translate.c | 48 ++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c index 218a9b519f..5ea6a0aeae 100644 --- a/target-i386/cc_helper.c +++ b/target-i386/cc_helper.c @@ -155,6 +155,13 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, case CC_OP_SARL: return compute_all_sarl(dst, src1); + case CC_OP_BMILGB: + return compute_all_bmilgb(dst, src1); + case CC_OP_BMILGW: + return compute_all_bmilgw(dst, src1); + case CC_OP_BMILGL: + return compute_all_bmilgl(dst, src1); + #ifdef TARGET_X86_64 case CC_OP_MULQ: return compute_all_mulq(dst, src1); @@ -176,6 +183,8 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, return compute_all_shlq(dst, src1); case CC_OP_SARQ: return compute_all_sarq(dst, src1); + case CC_OP_BMILGQ: + return compute_all_bmilgq(dst, src1); #endif } } @@ -254,6 +263,13 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, case CC_OP_SHLL: return compute_c_shll(dst, src1); + case CC_OP_BMILGB: + return compute_c_bmilgb(dst, src1); + case CC_OP_BMILGW: + return compute_c_bmilgw(dst, src1); + case CC_OP_BMILGL: + return compute_c_bmilgl(dst, src1); + #ifdef TARGET_X86_64 case CC_OP_ADDQ: return compute_c_addq(dst, src1); @@ -265,6 +281,8 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, return compute_c_sbbq(dst, src1, src2); case CC_OP_SHLQ: return compute_c_shlq(dst, src1); + case CC_OP_BMILGQ: + return compute_c_bmilgq(dst, src1); #endif } } diff --git a/target-i386/cc_helper_template.h b/target-i386/cc_helper_template.h index 87f47d2e97..607311f195 100644 --- a/target-i386/cc_helper_template.h +++ b/target-i386/cc_helper_template.h @@ -217,6 +217,24 @@ static int glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1) return cf | pf | af | zf | sf | of; } +static int glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +{ + int cf, pf, af, zf, sf, of; + + cf = (src1 == 0); + pf = 0; /* undefined */ + af = 0; /* undefined */ + zf = (dst == 0) * CC_Z; + sf = lshift(dst, 8 - DATA_BITS) & CC_S; + of = 0; + return cf | pf | af | zf | sf | of; +} + +static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +{ + return src1 == 0; +} + #undef DATA_BITS #undef SIGN_MASK #undef DATA_TYPE diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1fa9dc8267..960676bebd 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -636,6 +636,11 @@ typedef enum { CC_OP_SARL, CC_OP_SARQ, + CC_OP_BMILGB, /* Z,S via CC_DST, C = SRC==0; O=0; P,A undefined */ + CC_OP_BMILGW, + CC_OP_BMILGL, + CC_OP_BMILGQ, + CC_OP_NB, } CCOp; diff --git a/target-i386/helper.c b/target-i386/helper.c index 4bf9db7f7d..74d600f483 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -55,7 +55,7 @@ int cpu_x86_support_mca_broadcast(CPUX86State *env) /***********************************************************/ /* x86 debug */ -static const char *cc_op_str[] = { +static const char *cc_op_str[CC_OP_NB] = { "DYNAMIC", "EFLAGS", @@ -108,6 +108,11 @@ static const char *cc_op_str[] = { "SARW", "SARL", "SARQ", + + "BMILGB", + "BMILGW", + "BMILGL", + "BMILGQ", }; static void diff --git a/target-i386/translate.c b/target-i386/translate.c index d742fe3693..2322d5c838 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -209,6 +209,7 @@ static const uint8_t cc_op_live[CC_OP_NB] = { [CC_OP_DECB ... CC_OP_DECQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_SHLB ... CC_OP_SHLQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_SARB ... CC_OP_SARQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_BMILGB ... CC_OP_BMILGQ] = USES_CC_DST | USES_CC_SRC, }; static void set_cc_op(DisasContext *s, CCOp op) @@ -988,6 +989,11 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, .mask = -1 }; + case CC_OP_BMILGB ... CC_OP_BMILGQ: + size = s->cc_op - CC_OP_BMILGB; + t0 = gen_ext_tl(reg, cpu_cc_src, size, false); + return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 }; + case CC_OP_EFLAGS: case CC_OP_SARB ... CC_OP_SARQ: /* CC_SRC & 1 */ @@ -4066,6 +4072,48 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } break; + case 0x0f3: + case 0x1f3: + case 0x2f3: + case 0x3f3: /* Group 17 */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + + switch (reg & 7) { + case 1: /* blsr By,Ey */ + tcg_gen_neg_tl(cpu_T[1], cpu_T[0]); + tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + gen_op_mov_reg_T0(ot, s->vex_v); + gen_op_update2_cc(); + set_cc_op(s, CC_OP_BMILGB + ot); + break; + + case 2: /* blsmsk By,Ey */ + tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); + tcg_gen_subi_tl(cpu_T[0], cpu_T[0], 1); + tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_cc_src); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + set_cc_op(s, CC_OP_BMILGB + ot); + break; + + case 3: /* blsi By, Ey */ + tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); + tcg_gen_subi_tl(cpu_T[0], cpu_T[0], 1); + tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_cc_src); + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + set_cc_op(s, CC_OP_BMILGB + ot); + break; + + default: + goto illegal_op; + } + break; + default: goto illegal_op; } From 02ea1e6b4fab803551bbea47eea29bc7709ba008 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 17:01:10 -0800 Subject: [PATCH 1131/1634] target-i386: Implement BZHI Signed-off-by: Richard Henderson --- target-i386/translate.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index 2322d5c838..2bb8d9f8c3 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4072,6 +4072,33 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } break; + case 0x0f5: /* bzhi Gy, Ey, By */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + tcg_gen_ext8u_tl(cpu_T[1], cpu_regs[s->vex_v]); + { + TCGv bound = tcg_const_tl(ot == OT_QUAD ? 63 : 31); + /* Note that since we're using BMILG (in order to get O + cleared) we need to store the inverse into C. */ + tcg_gen_setcond_tl(TCG_COND_LT, cpu_cc_src, + cpu_T[1], bound); + tcg_gen_movcond_tl(TCG_COND_GT, cpu_T[1], cpu_T[1], + bound, bound, cpu_T[1]); + tcg_temp_free(bound); + } + tcg_gen_movi_tl(cpu_A0, -1); + tcg_gen_shl_tl(cpu_A0, cpu_A0, cpu_T[1]); + tcg_gen_andc_tl(cpu_T[0], cpu_T[0], cpu_A0); + gen_op_mov_reg_T0(ot, reg); + gen_op_update1_cc(); + set_cc_op(s, CC_OP_BMILGB + ot); + break; + case 0x0f3: case 0x1f3: case 0x2f3: From 5f1f4b177152286102475f9bffc359002a14d9c9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 18:06:18 -0800 Subject: [PATCH 1132/1634] target-i386: Implement MULX Signed-off-by: Richard Henderson --- target-i386/helper.h | 1 + target-i386/int_helper.c | 7 +++++++ target-i386/translate.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/target-i386/helper.h b/target-i386/helper.h index 4c46ab1b40..d750754742 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -19,6 +19,7 @@ DEF_HELPER_2(imulq_EAX_T0, void, env, tl) DEF_HELPER_3(imulq_T0_T1, tl, env, tl, tl) DEF_HELPER_2(divq_EAX, void, env, tl) DEF_HELPER_2(idivq_EAX, void, env, tl) +DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, tl, tl, tl) #endif DEF_HELPER_2(aam, void, env, int) diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c index 84b812dcca..4ec8cb78d2 100644 --- a/target-i386/int_helper.c +++ b/target-i386/int_helper.c @@ -385,6 +385,13 @@ void helper_mulq_EAX_T0(CPUX86State *env, target_ulong t0) CC_SRC = r1; } +target_ulong helper_umulh(target_ulong t0, target_ulong t1) +{ + uint64_t h, l; + mulu64(&l, &h, t0, t1); + return h; +} + void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0) { uint64_t r0, r1; diff --git a/target-i386/translate.c b/target-i386/translate.c index 2bb8d9f8c3..3017d63163 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4099,6 +4099,45 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, set_cc_op(s, CC_OP_BMILGB + ot); break; + case 0x3f6: /* mulx By, Gy, rdx, Ey */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + switch (ot) { + TCGv_i64 t0, t1; + default: + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); +#ifdef TARGET_X86_64 + tcg_gen_ext32u_i64(t0, cpu_T[0]); + tcg_gen_ext32u_i64(t1, cpu_regs[R_EDX]); +#else + tcg_gen_extu_i32_i64(t0, cpu_T[0]); + tcg_gen_extu_i32_i64(t0, cpu_regs[R_EDX]); +#endif + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_trunc_i64_tl(cpu_T[0], t0); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_tl(cpu_T[1], t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + gen_op_mov_reg_T0(OT_LONG, s->vex_v); + gen_op_mov_reg_T1(OT_LONG, reg); + break; +#ifdef TARGET_X86_64 + case OT_QUAD: + tcg_gen_mov_tl(cpu_T[1], cpu_regs[R_EDX]); + tcg_gen_mul_tl(cpu_regs[s->vex_v], cpu_T[0], cpu_T[1]); + gen_helper_umulh(cpu_regs[reg], cpu_T[0], cpu_T[1]); + break; +#endif + } + break; + case 0x0f3: case 0x1f3: case 0x2f3: From 0592f74a75ab695efd48a151219667adc0fa7cc4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 18:09:43 -0800 Subject: [PATCH 1133/1634] target-i386: Implement PDEP, PEXT Signed-off-by: Richard Henderson --- target-i386/helper.h | 3 +++ target-i386/int_helper.c | 32 ++++++++++++++++++++++++++++++++ target-i386/translate.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/target-i386/helper.h b/target-i386/helper.h index d750754742..81e0fbdd6d 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -194,9 +194,12 @@ DEF_HELPER_3(fsave, void, env, tl, int) DEF_HELPER_3(frstor, void, env, tl, int) DEF_HELPER_3(fxsave, void, env, tl, int) DEF_HELPER_3(fxrstor, void, env, tl, int) + DEF_HELPER_1(bsf, tl, tl) DEF_HELPER_1(bsr, tl, tl) DEF_HELPER_2(lzcnt, tl, tl, int) +DEF_HELPER_FLAGS_2(pdep, TCG_CALL_NO_RWG_SE, tl, tl, tl) +DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl) /* MMX/SSE */ diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c index 4ec8cb78d2..527af40281 100644 --- a/target-i386/int_helper.c +++ b/target-i386/int_helper.c @@ -488,6 +488,38 @@ target_ulong helper_bsr(target_ulong t0) return helper_lzcnt(t0, 0); } +#if TARGET_LONG_BITS == 32 +# define ctztl ctz32 +#else +# define ctztl ctz64 +#endif + +target_ulong helper_pdep(target_ulong src, target_ulong mask) +{ + target_ulong dest = 0; + int i, o; + + for (i = 0; mask != 0; i++) { + o = ctztl(mask); + mask &= mask - 1; + dest |= ((src >> i) & 1) << o; + } + return dest; +} + +target_ulong helper_pext(target_ulong src, target_ulong mask) +{ + target_ulong dest = 0; + int i, o; + + for (o = 0; mask != 0; o++) { + i = ctztl(mask); + mask &= mask - 1; + dest |= ((src >> i) & 1) << o; + } + return dest; +} + #define SHIFT 0 #include "shift_helper_template.h" #undef SHIFT diff --git a/target-i386/translate.c b/target-i386/translate.c index 3017d63163..51016fedd5 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4138,6 +4138,42 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, } break; + case 0x3f5: /* pdep Gy, By, Ey */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + /* Note that by zero-extending the mask operand, we + automatically handle zero-extending the result. */ + if (s->dflag == 2) { + tcg_gen_mov_tl(cpu_T[1], cpu_regs[s->vex_v]); + } else { + tcg_gen_ext32u_tl(cpu_T[1], cpu_regs[s->vex_v]); + } + gen_helper_pdep(cpu_regs[reg], cpu_T[0], cpu_T[1]); + break; + + case 0x2f5: /* pext Gy, By, Ey */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + /* Note that by zero-extending the mask operand, we + automatically handle zero-extending the result. */ + if (s->dflag == 2) { + tcg_gen_mov_tl(cpu_T[1], cpu_regs[s->vex_v]); + } else { + tcg_gen_ext32u_tl(cpu_T[1], cpu_regs[s->vex_v]); + } + gen_helper_pext(cpu_regs[reg], cpu_T[0], cpu_T[1]); + break; + case 0x0f3: case 0x1f3: case 0x2f3: From 4a554890e479a43568de8b5354d9ca8583f5ec7f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 18:12:13 -0800 Subject: [PATCH 1134/1634] target-i386: Implement SHLX, SARX, SHRX Signed-off-by: Richard Henderson --- target-i386/translate.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index 51016fedd5..c1a2886acc 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4174,6 +4174,37 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, gen_helper_pext(cpu_regs[reg], cpu_T[0], cpu_T[1]); break; + case 0x1f7: /* shlx Gy, Ey, By */ + case 0x2f7: /* sarx Gy, Ey, By */ + case 0x3f7: /* shrx Gy, Ey, By */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = (s->dflag == 2 ? OT_QUAD : OT_LONG); + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + if (ot == OT_QUAD) { + tcg_gen_andi_tl(cpu_T[1], cpu_regs[s->vex_v], 63); + } else { + tcg_gen_andi_tl(cpu_T[1], cpu_regs[s->vex_v], 31); + } + if (b == 0x1f7) { + tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } else if (b == 0x2f7) { + if (ot != OT_QUAD) { + tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); + } + tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } else { + if (ot != OT_QUAD) { + tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]); + } + tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } + gen_op_mov_reg_T0(ot, reg); + break; + case 0x0f3: case 0x1f3: case 0x2f3: From e2c3c2c551bccd843135eab1ba202f8d2f86800b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 16 Jan 2013 14:55:09 -0800 Subject: [PATCH 1135/1634] target-i386: Implement RORX Signed-off-by: Richard Henderson --- target-i386/translate.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index c1a2886acc..68e30e699e 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4433,6 +4433,38 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); sse_fn_eppi(cpu_env, cpu_ptr0, cpu_ptr1, tcg_const_i32(val)); break; + + case 0x33a: + /* Various integer extensions at 0f 3a f[0-f]. */ + b = modrm | (b1 << 8); + modrm = cpu_ldub_code(env, s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + + switch (b) { + case 0x3f0: /* rorx Gy,Ey, Ib */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2) + || !(s->prefix & PREFIX_VEX) + || s->vex_l != 0) { + goto illegal_op; + } + ot = s->dflag == 2 ? OT_QUAD : OT_LONG; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + b = cpu_ldub_code(env, s->pc++); + if (ot == OT_QUAD) { + tcg_gen_rotri_tl(cpu_T[0], cpu_T[0], b & 63); + } else { + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_rotri_i32(cpu_tmp2_i32, cpu_tmp2_i32, b & 31); + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + } + gen_op_mov_reg_T0(ot, reg); + break; + + default: + goto illegal_op; + } + break; + default: goto illegal_op; } From 62162fff598f941c198b16b4e8814015ec5a0bef Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Feb 2013 09:53:17 +0100 Subject: [PATCH 1136/1634] usb: Makefile cleanup Group files, sprinkle in some comments. Signed-off-by: Gerd Hoffmann --- hw/usb/Makefile.objs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index d1bbbc06e7..bfe5e5f875 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -1,14 +1,27 @@ +# usb subsystem core +common-obj-y += core.o combined-packet.o bus.o desc.o +common-obj-y += libhw.o + +# usb host adapters common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o -common-obj-y += libhw.o +# emulated usb devices +common-obj-y += dev-hub.o +common-obj-y += dev-hid.o +common-obj-y += dev-wacom.o +common-obj-y += dev-storage.o +common-obj-y += dev-uas.o +common-obj-y += dev-smartcard-reader.o +common-obj-y += dev-audio.o +common-obj-y += dev-serial.o +common-obj-y += dev-network.o +common-obj-y += dev-bluetooth.o + +# usb redirection common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o -common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o -common-obj-y += host-$(HOST_USB).o dev-bluetooth.o -common-obj-y += dev-hid.o dev-storage.o dev-wacom.o -common-obj-y += dev-serial.o dev-network.o dev-audio.o -common-obj-y += dev-smartcard-reader.o -common-obj-y += dev-uas.o +# usb pass-through +common-obj-y += host-$(HOST_USB).o From f4ece4046344230a3a030ef1e494599eaf0a5935 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Feb 2013 10:48:34 +0100 Subject: [PATCH 1137/1634] fix scripts/make_device_config.sh Make it handle multiple include statements in a file: (1) The printf needs a space so the include files will be separated. (2) Also $f can contain multiple failes, so redirection will not work and we have to use cat to process all files. Signed-off-by: Gerd Hoffmann --- scripts/make_device_config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh index 0778fe2a42..81fe94259d 100644 --- a/scripts/make_device_config.sh +++ b/scripts/make_device_config.sh @@ -18,7 +18,7 @@ process_includes () { f=$src while [ -n "$f" ] ; do - f=`tr -d '\r' < $f | awk '/^include / {printf "'$src_dir'/%s", $2}'` + f=`cat $f | tr -d '\r' | awk '/^include / {printf "'$src_dir'/%s ", $2}'` [ $? = 0 ] || exit 1 all_includes="$all_includes $f" done From 6c83f81542e4fda1777a74e4647a69086e44357c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Feb 2013 10:49:43 +0100 Subject: [PATCH 1138/1634] make usb devices configurable Leave the core usb devices (usb hub, tablet, mouse, keyboard) enabled unconditionally. Make the other ones configurable. Exceptions: - bluetooth: not qdevified yet, has a vl.c dependency because of that, thus disabling isn't as easy as not linking the object file. - smardcard: ccid-card-emulated depends on that one *and* CONFIG_SMARTCARD_NSS. So it isn't a one-liner and comes as separate patch because of that. Signed-off-by: Gerd Hoffmann --- default-configs/alpha-softmmu.mak | 1 + default-configs/arm-softmmu.mak | 1 + default-configs/i386-softmmu.mak | 1 + default-configs/m68k-softmmu.mak | 1 + default-configs/mips-softmmu.mak | 1 + default-configs/mips64-softmmu.mak | 1 + default-configs/mips64el-softmmu.mak | 1 + default-configs/mipsel-softmmu.mak | 1 + default-configs/ppc-softmmu.mak | 1 + default-configs/ppc64-softmmu.mak | 1 + default-configs/ppcemb-softmmu.mak | 1 + default-configs/sh4-softmmu.mak | 1 + default-configs/sh4eb-softmmu.mak | 1 + default-configs/sparc64-softmmu.mak | 1 + default-configs/usb.mak | 8 ++++++++ default-configs/x86_64-softmmu.mak | 1 + hw/usb/Makefile.objs | 20 ++++++++++++-------- 17 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 default-configs/usb.mak diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak index 501dd413b7..2dbee94c89 100644 --- a/default-configs/alpha-softmmu.mak +++ b/default-configs/alpha-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for alpha-softmmu include pci.mak +include usb.mak CONFIG_SERIAL=y CONFIG_I8254=y CONFIG_PCKBD=y diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 2f1a5c9943..b40f7b08e2 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for arm-softmmu include pci.mak +include usb.mak CONFIG_GDBSTUB_XML=y CONFIG_VGA=y CONFIG_ISA_MMIO=y diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 2c78175ae7..1b23025a98 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for i386-softmmu include pci.mak +include usb.mak CONFIG_VGA=y CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y diff --git a/default-configs/m68k-softmmu.mak b/default-configs/m68k-softmmu.mak index 3e2ec3716c..778ea82a10 100644 --- a/default-configs/m68k-softmmu.mak +++ b/default-configs/m68k-softmmu.mak @@ -1,5 +1,6 @@ # Default configuration for m68k-softmmu include pci.mak +include usb.mak CONFIG_GDBSTUB_XML=y CONFIG_PTIMER=y diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index a271b1c6da..4f04a33732 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for mips-softmmu include pci.mak +include usb.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index 0510bb6a53..a5b6c3c36a 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for mips64-softmmu include pci.mak +include usb.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index ed3bed3b8d..a0e6de8e68 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for mips64el-softmmu include pci.mak +include usb.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index fa3a2cacdd..753dd76a21 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for mipsel-softmmu include pci.mak +include usb.mak CONFIG_ISA_MMIO=y CONFIG_ESP=y CONFIG_VGA=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index 1f4a1cff61..f9f8a8159b 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for ppc-softmmu include pci.mak +include usb.mak CONFIG_GDBSTUB_XML=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index 5ff406caa5..dc44294378 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for ppc64-softmmu include pci.mak +include usb.mak CONFIG_GDBSTUB_XML=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index aaa9cdc1f7..1c6bcf93fc 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for ppcemb-softmmu include pci.mak +include usb.mak CONFIG_GDBSTUB_XML=y CONFIG_ISA_MMIO=y CONFIG_ESCC=y diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak index 5c69acc5f5..e08b2ee106 100644 --- a/default-configs/sh4-softmmu.mak +++ b/default-configs/sh4-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for sh4-softmmu include pci.mak +include usb.mak CONFIG_SERIAL=y CONFIG_PTIMER=y CONFIG_PFLASH_CFI02=y diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak index 7cdc122201..3a8453552b 100644 --- a/default-configs/sh4eb-softmmu.mak +++ b/default-configs/sh4eb-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for sh4eb-softmmu include pci.mak +include usb.mak CONFIG_SERIAL=y CONFIG_PTIMER=y CONFIG_PFLASH_CFI02=y diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak index 03e8b42712..2145b6b29f 100644 --- a/default-configs/sparc64-softmmu.mak +++ b/default-configs/sparc64-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for sparc64-softmmu include pci.mak +include usb.mak CONFIG_ISA_MMIO=y CONFIG_M48T59=y CONFIG_PTIMER=y diff --git a/default-configs/usb.mak b/default-configs/usb.mak new file mode 100644 index 0000000000..1bf9075e85 --- /dev/null +++ b/default-configs/usb.mak @@ -0,0 +1,8 @@ +CONFIG_USB_TABLET_WACOM=y +CONFIG_USB_STORAGE_BOT=y +CONFIG_USB_STORAGE_UAS=y +CONFIG_USB_SMARTCARD=y +CONFIG_USB_AUDIO=y +CONFIG_USB_SERIAL=y +CONFIG_USB_NETWORK=y +CONFIG_USB_BLUETOOTH=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 233a8564eb..3392f5abd6 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -1,6 +1,7 @@ # Default configuration for x86_64-softmmu include pci.mak +include usb.mak CONFIG_VGA=y CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index bfe5e5f875..00998b5073 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -11,14 +11,18 @@ common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o # emulated usb devices common-obj-y += dev-hub.o common-obj-y += dev-hid.o -common-obj-y += dev-wacom.o -common-obj-y += dev-storage.o -common-obj-y += dev-uas.o -common-obj-y += dev-smartcard-reader.o -common-obj-y += dev-audio.o -common-obj-y += dev-serial.o -common-obj-y += dev-network.o -common-obj-y += dev-bluetooth.o +common-obj-$(CONFIG_USB_TABLET_WACOM) += dev-wacom.o +common-obj-$(CONFIG_USB_STORAGE_BOT) += dev-storage.o +common-obj-$(CONFIG_USB_STORAGE_UAS) += dev-uas.o +common-obj-$(CONFIG_USB_AUDIO) += dev-audio.o +common-obj-$(CONFIG_USB_SERIAL) += dev-serial.o +common-obj-$(CONFIG_USB_NETWORK) += dev-network.o + +# FIXME: make configurable too +CONFIG_USB_BLUETOOTH := y +CONFIG_USB_SMARTCARD := y +common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o +common-obj-$(CONFIG_USB_SMARTCARD) += dev-smartcard-reader.o # usb redirection common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o From 07d17e772095ee2b1171498536e5671a97920149 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 1 Feb 2013 11:08:24 +0100 Subject: [PATCH 1139/1634] allow disabling usb smartcard support Signed-off-by: Gerd Hoffmann --- hw/Makefile.objs | 2 ++ hw/usb/Makefile.objs | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 447e32a42e..a1f3a808ac 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -38,8 +38,10 @@ common-obj-$(CONFIG_DMA) += dma.o common-obj-$(CONFIG_I82374) += i82374.o common-obj-$(CONFIG_HPET) += hpet.o common-obj-$(CONFIG_APPLESMC) += applesmc.o +ifeq ($(CONFIG_USB_SMARTCARD),y) common-obj-y += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o +endif common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-y += fifo.o common-obj-y += pam.o diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 00998b5073..c1e40d7d31 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -20,7 +20,6 @@ common-obj-$(CONFIG_USB_NETWORK) += dev-network.o # FIXME: make configurable too CONFIG_USB_BLUETOOTH := y -CONFIG_USB_SMARTCARD := y common-obj-$(CONFIG_USB_BLUETOOTH) += dev-bluetooth.o common-obj-$(CONFIG_USB_SMARTCARD) += dev-smartcard-reader.o From 9db7c41419e89adee5650a5868ac91e83614abf5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 22 Jan 2013 14:17:05 +0100 Subject: [PATCH 1140/1634] usb-storage: use scsi_req_enqueue return value Signed-off-by: Gerd Hoffmann --- hw/usb/dev-storage.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index b89d00f7cf..d3f01aa2a7 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -400,6 +400,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; SCSIDevice *scsi_dev; + uint32_t len; switch (p->pid) { case USB_TOKEN_OUT: @@ -441,8 +442,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) #ifdef DEBUG_MSD scsi_req_print(s->req); #endif - scsi_req_enqueue(s->req); - if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { + len = scsi_req_enqueue(s->req); + if (len) { scsi_req_continue(s->req); } break; From 4075975d832c55abdfc951726e54f9a28a2421c8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 23 Jan 2013 14:15:38 +0100 Subject: [PATCH 1141/1634] usb-host: move legacy cmd line bits The code handling the "-usbdevice host:..." legacy command line syntax is moved to the new hw/usb/host-legacy.c file. Signed-off-by: Gerd Hoffmann --- configure | 2 +- hw/usb/Makefile.objs | 2 +- hw/usb/host-legacy.c | 144 +++++++++++++++++++++++++++++++++++++++++++ hw/usb/host-linux.c | 101 +----------------------------- hw/usb/host.h | 44 +++++++++++++ 5 files changed, 191 insertions(+), 102 deletions(-) create mode 100644 hw/usb/host-legacy.c create mode 100644 hw/usb/host.h diff --git a/configure b/configure index bf5970f74b..42cb3144a5 100755 --- a/configure +++ b/configure @@ -3723,7 +3723,7 @@ fi # USB host support case "$usb" in linux) - echo "HOST_USB=linux" >> $config_host_mak + echo "HOST_USB=linux legacy" >> $config_host_mak ;; bsd) echo "HOST_USB=bsd" >> $config_host_mak diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index c1e40d7d31..e63e287ce0 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -27,4 +27,4 @@ common-obj-$(CONFIG_USB_SMARTCARD) += dev-smartcard-reader.o common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o # usb pass-through -common-obj-y += host-$(HOST_USB).o +common-obj-y += $(patsubst %,host-%.o,$(HOST_USB)) diff --git a/hw/usb/host-legacy.c b/hw/usb/host-legacy.c new file mode 100644 index 0000000000..3a5f705721 --- /dev/null +++ b/hw/usb/host-legacy.c @@ -0,0 +1,144 @@ +/* + * Linux host USB redirector + * + * Copyright (c) 2005 Fabrice Bellard + * + * Copyright (c) 2008 Max Krasnyansky + * Support for host device auto connect & disconnect + * Major rewrite to support fully async operation + * + * Copyright 2008 TJ + * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition + * to the legacy /proc/bus/usb USB device discovery and handling + * + * 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 "qemu-common.h" +#include "hw/usb.h" +#include "hw/usb/host.h" + +/* + * Autoconnect filter + * Format: + * auto:bus:dev[:vid:pid] + * auto:bus.dev[:vid:pid] + * + * bus - bus number (dec, * means any) + * dev - device number (dec, * means any) + * vid - vendor id (hex, * means any) + * pid - product id (hex, * means any) + * + * See 'lsusb' output. + */ +static int parse_filter(const char *spec, struct USBAutoFilter *f) +{ + enum { BUS, DEV, VID, PID, DONE }; + const char *p = spec; + int i; + + f->bus_num = 0; + f->addr = 0; + f->vendor_id = 0; + f->product_id = 0; + + for (i = BUS; i < DONE; i++) { + p = strpbrk(p, ":."); + if (!p) { + break; + } + p++; + + if (*p == '*') { + continue; + } + switch (i) { + case BUS: + f->bus_num = strtol(p, NULL, 10); + break; + case DEV: + f->addr = strtol(p, NULL, 10); + break; + case VID: + f->vendor_id = strtol(p, NULL, 16); + break; + case PID: + f->product_id = strtol(p, NULL, 16); + break; + } + } + + if (i < DEV) { + fprintf(stderr, "husb: invalid auto filter spec %s\n", spec); + return -1; + } + + return 0; +} + +USBDevice *usb_host_device_open(USBBus *bus, const char *devname) +{ + struct USBAutoFilter filter; + USBDevice *dev; + char *p; + + dev = usb_create(bus, "usb-host"); + + if (strstr(devname, "auto:")) { + if (parse_filter(devname, &filter) < 0) { + goto fail; + } + } else { + p = strchr(devname, '.'); + if (p) { + filter.bus_num = strtoul(devname, NULL, 0); + filter.addr = strtoul(p + 1, NULL, 0); + filter.vendor_id = 0; + filter.product_id = 0; + } else { + p = strchr(devname, ':'); + if (p) { + filter.bus_num = 0; + filter.addr = 0; + filter.vendor_id = strtoul(devname, NULL, 16); + filter.product_id = strtoul(p + 1, NULL, 16); + } else { + goto fail; + } + } + } + + qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num); + qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr); + qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id); + qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id); + qdev_init_nofail(&dev->qdev); + return dev; + +fail: + qdev_free(&dev->qdev); + return NULL; +} + +static void usb_host_register_types(void) +{ + usb_legacy_register("usb-host", "host", usb_host_device_open); +} + +type_init(usb_host_register_types) diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index a2cff8a74d..c18a6c8046 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -43,6 +43,7 @@ #include #include "hw/usb.h" #include "hw/usb/desc.h" +#include "hw/usb/host.h" /* We redefine it to avoid version problems */ struct usb_ctrltransfer { @@ -87,14 +88,6 @@ struct endp_data { int inflight; }; -struct USBAutoFilter { - uint32_t bus_num; - uint32_t addr; - char *port; - uint32_t vendor_id; - uint32_t product_id; -}; - enum USBHostDeviceOptions { USB_HOST_OPT_PIPELINE, }; @@ -131,7 +124,6 @@ typedef struct USBHostDevice { static QTAILQ_HEAD(, USBHostDevice) hostdevs = QTAILQ_HEAD_INITIALIZER(hostdevs); static int usb_host_close(USBHostDevice *dev); -static int parse_filter(const char *spec, struct USBAutoFilter *f); static void usb_host_auto_check(void *unused); static int usb_host_read_file(char *line, size_t line_size, const char *device_file, const char *device_name); @@ -1544,51 +1536,10 @@ static const TypeInfo usb_host_dev_info = { static void usb_host_register_types(void) { type_register_static(&usb_host_dev_info); - usb_legacy_register("usb-host", "host", usb_host_device_open); } type_init(usb_host_register_types) -USBDevice *usb_host_device_open(USBBus *bus, const char *devname) -{ - struct USBAutoFilter filter; - USBDevice *dev; - char *p; - - dev = usb_create(bus, "usb-host"); - - if (strstr(devname, "auto:")) { - if (parse_filter(devname, &filter) < 0) { - goto fail; - } - } else { - if ((p = strchr(devname, '.'))) { - filter.bus_num = strtoul(devname, NULL, 0); - filter.addr = strtoul(p + 1, NULL, 0); - filter.vendor_id = 0; - filter.product_id = 0; - } else if ((p = strchr(devname, ':'))) { - filter.bus_num = 0; - filter.addr = 0; - filter.vendor_id = strtoul(devname, NULL, 16); - filter.product_id = strtoul(p + 1, NULL, 16); - } else { - goto fail; - } - } - - qdev_prop_set_uint32(&dev->qdev, "hostbus", filter.bus_num); - qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr); - qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id); - qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id); - qdev_init_nofail(&dev->qdev); - return dev; - -fail: - qdev_free(&dev->qdev); - return NULL; -} - int usb_host_device_close(const char *devname) { #if 0 @@ -1840,56 +1791,6 @@ static void usb_host_auto_check(void *unused) qemu_mod_timer(usb_auto_timer, qemu_get_clock_ms(rt_clock) + 2000); } -/* - * Autoconnect filter - * Format: - * auto:bus:dev[:vid:pid] - * auto:bus.dev[:vid:pid] - * - * bus - bus number (dec, * means any) - * dev - device number (dec, * means any) - * vid - vendor id (hex, * means any) - * pid - product id (hex, * means any) - * - * See 'lsusb' output. - */ -static int parse_filter(const char *spec, struct USBAutoFilter *f) -{ - enum { BUS, DEV, VID, PID, DONE }; - const char *p = spec; - int i; - - f->bus_num = 0; - f->addr = 0; - f->vendor_id = 0; - f->product_id = 0; - - for (i = BUS; i < DONE; i++) { - p = strpbrk(p, ":."); - if (!p) { - break; - } - p++; - - if (*p == '*') { - continue; - } - switch(i) { - case BUS: f->bus_num = strtol(p, NULL, 10); break; - case DEV: f->addr = strtol(p, NULL, 10); break; - case VID: f->vendor_id = strtol(p, NULL, 16); break; - case PID: f->product_id = strtol(p, NULL, 16); break; - } - } - - if (i < DEV) { - fprintf(stderr, "husb: invalid auto filter spec %s\n", spec); - return -1; - } - - return 0; -} - /**********************/ /* USB host device info */ diff --git a/hw/usb/host.h b/hw/usb/host.h new file mode 100644 index 0000000000..048ff3b482 --- /dev/null +++ b/hw/usb/host.h @@ -0,0 +1,44 @@ +/* + * Linux host USB redirector + * + * Copyright (c) 2005 Fabrice Bellard + * + * Copyright (c) 2008 Max Krasnyansky + * Support for host device auto connect & disconnect + * Major rewrite to support fully async operation + * + * Copyright 2008 TJ + * Added flexible support for /dev/bus/usb /sys/bus/usb/devices in addition + * to the legacy /proc/bus/usb USB device discovery and handling + * + * 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. + */ + +#ifndef QEMU_USB_HOST_H +#define QEMU_USB_HOST_H + +struct USBAutoFilter { + uint32_t bus_num; + uint32_t addr; + char *port; + uint32_t vendor_id; + uint32_t product_id; +}; + +#endif /* QEMU_USB_HOST_H */ From 1a3973b33d36583d7194798f789a37759a13e269 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Nov 2012 13:02:47 +0100 Subject: [PATCH 1142/1634] usb-host: remove usb_host_device_close Nobody implements that anyway. Signed-off-by: Gerd Hoffmann --- hw/usb.h | 1 - hw/usb/host-bsd.c | 6 ------ hw/usb/host-linux.c | 24 ------------------------ hw/usb/host-stub.c | 5 ----- vl.c | 5 +++-- 5 files changed, 3 insertions(+), 38 deletions(-) diff --git a/hw/usb.h b/hw/usb.h index bc42639b16..90024a4515 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -434,7 +434,6 @@ int set_usb_string(uint8_t *buf, const char *str); /* usb-linux.c */ USBDevice *usb_host_device_open(USBBus *bus, const char *devname); -int usb_host_device_close(const char *devname); void usb_host_info(Monitor *mon, const QDict *qdict); /* usb-bt.c */ diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index 07f0e01cc0..39f22810b3 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -637,9 +637,3 @@ void usb_host_info(Monitor *mon, const QDict *qdict) { usb_host_scan(mon, usb_host_info_device); } - -/* XXX add this */ -int usb_host_device_close(const char *devname) -{ - return 0; -} diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index c18a6c8046..b67aeba096 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1540,30 +1540,6 @@ static void usb_host_register_types(void) type_init(usb_host_register_types) -int usb_host_device_close(const char *devname) -{ -#if 0 - char product_name[PRODUCT_NAME_SZ]; - int bus_num, addr; - USBHostDevice *s; - - if (strstr(devname, "auto:")) { - return usb_host_auto_del(devname); - } - if (usb_host_find_device(&bus_num, &addr, product_name, - sizeof(product_name), devname) < 0) { - return -1; - } - s = hostdev_find(bus_num, addr); - if (s) { - usb_device_delete_addr(s->bus_num, s->dev.addr); - return 0; - } -#endif - - return -1; -} - /* * Read sys file-system device file * diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c index 8affba76c1..28d8032caf 100644 --- a/hw/usb/host-stub.c +++ b/hw/usb/host-stub.c @@ -45,8 +45,3 @@ USBDevice *usb_host_device_open(USBBus *bus, const char *devname) { return NULL; } - -int usb_host_device_close(const char *devname) -{ - return 0; -} diff --git a/vl.c b/vl.c index c5b0eea29b..955d2ffe0f 100644 --- a/vl.c +++ b/vl.c @@ -1427,8 +1427,9 @@ static int usb_device_del(const char *devname) int bus_num, addr; const char *p; - if (strstart(devname, "host:", &p)) - return usb_host_device_close(p); + if (strstart(devname, "host:", &p)) { + return -1; + } if (!usb_enabled(false)) { return -1; From e382d966d06d2989fc28eec8cfdcc2fd99ebfbb7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Dec 2012 13:40:59 +0100 Subject: [PATCH 1143/1634] usb: add usb_ep_set_halted Signed-off-by: Gerd Hoffmann --- hw/usb.h | 1 + hw/usb/core.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/hw/usb.h b/hw/usb.h index 90024a4515..af86fbd086 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -417,6 +417,7 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep, uint16_t raw); int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep); void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled); +void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted); USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, uint64_t id); diff --git a/hw/usb/core.c b/hw/usb/core.c index d057aab900..5517797c8a 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -755,6 +755,12 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled) uep->pipeline = enabled; } +void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + uep->halted = halted; +} + USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, uint64_t id) { From 6a98d1c0f9e4f6a95d6ecd730ae6fdc70d15c73f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 24 Jan 2013 15:38:23 +0100 Subject: [PATCH 1144/1634] usb: make usb_packet_copy operate on combined packets Likewise usb_packet_skip. Also usb_packet_size. Signed-off-by: Gerd Hoffmann --- hw/usb.h | 1 + hw/usb/core.c | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/hw/usb.h b/hw/usb.h index af86fbd086..0d09e02bb0 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -390,6 +390,7 @@ int usb_packet_map(USBPacket *p, QEMUSGList *sgl); void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl); void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes); void usb_packet_skip(USBPacket *p, size_t bytes); +size_t usb_packet_size(USBPacket *p); void usb_packet_cleanup(USBPacket *p); static inline bool usb_packet_is_inflight(USBPacket *p) diff --git a/hw/usb/core.c b/hw/usb/core.c index 5517797c8a..674fef8d21 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -570,15 +570,17 @@ void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len) void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes) { + QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov; + assert(p->actual_length >= 0); - assert(p->actual_length + bytes <= p->iov.size); + assert(p->actual_length + bytes <= iov->size); switch (p->pid) { case USB_TOKEN_SETUP: case USB_TOKEN_OUT: - iov_to_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); + iov_to_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes); break; case USB_TOKEN_IN: - iov_from_buf(p->iov.iov, p->iov.niov, p->actual_length, ptr, bytes); + iov_from_buf(iov->iov, iov->niov, p->actual_length, ptr, bytes); break; default: fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid); @@ -589,14 +591,21 @@ void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes) void usb_packet_skip(USBPacket *p, size_t bytes) { + QEMUIOVector *iov = p->combined ? &p->combined->iov : &p->iov; + assert(p->actual_length >= 0); - assert(p->actual_length + bytes <= p->iov.size); + assert(p->actual_length + bytes <= iov->size); if (p->pid == USB_TOKEN_IN) { - iov_memset(p->iov.iov, p->iov.niov, p->actual_length, 0, bytes); + iov_memset(iov->iov, iov->niov, p->actual_length, 0, bytes); } p->actual_length += bytes; } +size_t usb_packet_size(USBPacket *p) +{ + return p->combined ? p->combined->iov.size : p->iov.size; +} + void usb_packet_cleanup(USBPacket *p) { assert(!usb_packet_is_inflight(p)); From 6ef3ccd18f881a7bece556ff0fe1b0bf70ac2262 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 24 Jan 2013 15:40:37 +0100 Subject: [PATCH 1145/1634] usb-redir: simplify packet copy usb_packet_copy can handle combined packets now, so it isn't needed to special-case them any more. Also use the new usb_packet_size() function. Signed-off-by: Gerd Hoffmann --- hw/usb/redirect.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 8c0ead07c5..7078403904 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -737,7 +737,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { struct usb_redir_bulk_packet_header bulk_packet; - size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; + size_t size = usb_packet_size(p); const int maxp = dev->endpoint[EP2I(ep)].max_packet_size; if (usbredir_already_in_flight(dev, p->id)) { @@ -771,12 +771,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, &bulk_packet, NULL, 0); } else { uint8_t buf[size]; - if (p->combined) { - iov_to_buf(p->combined->iov.iov, p->combined->iov.niov, - 0, buf, size); - } else { - usb_packet_copy(p, buf, size); - } + usb_packet_copy(p, buf, size); usbredir_log_data(dev, "bulk data out:", buf, size); usbredirparser_send_bulk_packet(dev->parser, p->id, &bulk_packet, buf, size); @@ -1830,7 +1825,7 @@ static void usbredir_bulk_packet(void *priv, uint64_t id, p = usbredir_find_packet_by_id(dev, ep, id); if (p) { - size_t size = (p->combined) ? p->combined->iov.size : p->iov.size; + size_t size = usb_packet_size(p); usbredir_handle_status(dev, p, bulk_packet->status); if (data_len > 0) { usbredir_log_data(dev, "bulk data in:", data, data_len); @@ -1840,12 +1835,7 @@ static void usbredir_bulk_packet(void *priv, uint64_t id, p->status = USB_RET_BABBLE; data_len = len = size; } - if (p->combined) { - iov_from_buf(p->combined->iov.iov, p->combined->iov.niov, - 0, data, data_len); - } else { - usb_packet_copy(p, data, data_len); - } + usb_packet_copy(p, data, data_len); } p->actual_length = len; if (p->pid == USB_TOKEN_IN && p->ep->pipeline) { From 2e5df36df8d0c3ffe59de254ef016508b27562bb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 28 Jan 2013 15:52:57 +0100 Subject: [PATCH 1146/1634] usb: fix endpoint descriptor ordering Fix the ordering of the endpoint descriptors for superspeed endpoints: The superspeed companion must come first, possible additional descriptors for the endpoint after that. Signed-off-by: Gerd Hoffmann --- hw/usb/desc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/usb/desc.c b/hw/usb/desc.c index b7c32333d7..b389381326 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -225,12 +225,9 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, d->u.endpoint.bRefresh = ep->bRefresh; d->u.endpoint.bSynchAddress = ep->bSynchAddress; } - if (ep->extra) { - memcpy(dest + bLength, ep->extra, extralen); - } if (superlen) { - USBDescriptor *d = (void *)(dest + bLength + extralen); + USBDescriptor *d = (void *)(dest + bLength); d->bLength = 0x06; d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; @@ -243,6 +240,10 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, usb_hi(ep->wBytesPerInterval); } + if (ep->extra) { + memcpy(dest + bLength + superlen, ep->extra, extralen); + } + return bLength + extralen + superlen; } From 8550a02d1239415342959f6a32d178bc05c557cc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 29 Jan 2013 12:44:35 +0100 Subject: [PATCH 1147/1634] usb-core: usb3 streams This patch adds support for usb3 streams to the usb subsystem core. This is just adding a streams field / parameter in a number of places. Signed-off-by: Gerd Hoffmann --- hw/usb.h | 10 ++++++---- hw/usb/core.c | 10 ++++++---- hw/usb/dev-bluetooth.c | 2 +- hw/usb/dev-hid.c | 2 +- hw/usb/dev-hub.c | 10 +++++----- hw/usb/dev-network.c | 2 +- hw/usb/dev-smartcard-reader.c | 2 +- hw/usb/dev-uas.c | 2 +- hw/usb/dev-wacom.c | 4 ++-- hw/usb/hcd-ehci.c | 7 ++++--- hw/usb/hcd-musb.c | 2 +- hw/usb/hcd-ohci.c | 4 ++-- hw/usb/hcd-uhci.c | 2 +- hw/usb/hcd-xhci.c | 9 +++++---- 14 files changed, 37 insertions(+), 31 deletions(-) diff --git a/hw/usb.h b/hw/usb.h index 0d09e02bb0..382496cf82 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -361,6 +361,7 @@ struct USBPacket { int pid; uint64_t id; USBEndpoint *ep; + unsigned int stream; QEMUIOVector iov; uint64_t parameter; /* control transfers */ bool short_not_ok; @@ -383,8 +384,9 @@ struct USBCombinedPacket { void usb_packet_init(USBPacket *p); void usb_packet_set_state(USBPacket *p, USBPacketState state); void usb_packet_check_state(USBPacket *p, USBPacketState expected); -void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id, - bool short_not_ok, bool int_req); +void usb_packet_setup(USBPacket *p, int pid, + USBEndpoint *ep, unsigned int stream, + uint64_t id, bool short_not_ok, bool int_req); void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len); int usb_packet_map(USBPacket *p, QEMUSGList *sgl); void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl); @@ -430,7 +432,7 @@ void usb_attach(USBPort *port); void usb_detach(USBPort *port); void usb_port_reset(USBPort *port); void usb_device_reset(USBDevice *dev); -void usb_wakeup(USBEndpoint *ep); +void usb_wakeup(USBEndpoint *ep, unsigned int stream); void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p); int set_usb_string(uint8_t *buf, const char *str); @@ -489,7 +491,7 @@ struct USBBus { struct USBBusOps { int (*register_companion)(USBBus *bus, USBPort *ports[], uint32_t portcount, uint32_t firstport); - void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep); + void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep, unsigned int stream); }; void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host); diff --git a/hw/usb/core.c b/hw/usb/core.c index 674fef8d21..15a150aea0 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -71,7 +71,7 @@ void usb_device_reset(USBDevice *dev) usb_device_handle_reset(dev); } -void usb_wakeup(USBEndpoint *ep) +void usb_wakeup(USBEndpoint *ep, unsigned int stream) { USBDevice *dev = ep->dev; USBBus *bus = usb_bus_from_device(dev); @@ -80,7 +80,7 @@ void usb_wakeup(USBEndpoint *ep) dev->port->ops->wakeup(dev->port); } if (bus->ops->wakeup_endpoint) { - bus->ops->wakeup_endpoint(bus, ep); + bus->ops->wakeup_endpoint(bus, ep, stream); } } @@ -545,14 +545,16 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state) p->state = state; } -void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep, uint64_t id, - bool short_not_ok, bool int_req) +void usb_packet_setup(USBPacket *p, int pid, + USBEndpoint *ep, unsigned int stream, + uint64_t id, bool short_not_ok, bool int_req) { assert(!usb_packet_is_inflight(p)); assert(p->iov.iov != NULL); p->id = id; p->pid = pid; p->ep = ep; + p->stream = stream; p->status = USB_RET_SUCCESS; p->actual_length = 0; p->parameter = 0; diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index adbf9d4697..0f8aa48c85 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -478,7 +478,7 @@ static void usb_bt_out_hci_packet_event(void *opaque, struct USBBtState *s = (struct USBBtState *) opaque; if (s->evt.len == 0) { - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } usb_bt_fifo_enqueue(&s->evt, data, len); } diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 29b64819ab..9701048887 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -423,7 +423,7 @@ static void usb_hid_changed(HIDState *hs) { USBHIDState *us = container_of(hs, USBHIDState, hid); - usb_wakeup(us->intr); + usb_wakeup(us->intr, 0); } static void usb_hid_handle_reset(USBDevice *dev) diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 79f2f46d55..504c98c350 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -164,7 +164,7 @@ static void usb_hub_attach(USBPort *port1) } else { port->wPortStatus &= ~PORT_STAT_LOW_SPEED; } - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } static void usb_hub_detach(USBPort *port1) @@ -173,7 +173,7 @@ static void usb_hub_detach(USBPort *port1) USBHubPort *port = &s->ports[port1->index]; trace_usb_hub_detach(s->dev.addr, port1->index + 1); - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); /* Let upstream know the device on this port is gone */ s->dev.port->ops->child_detach(s->dev.port, port1->dev); @@ -184,7 +184,7 @@ static void usb_hub_detach(USBPort *port1) port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } static void usb_hub_child_detach(USBPort *port1, USBDevice *child) @@ -202,7 +202,7 @@ static void usb_hub_wakeup(USBPort *port1) if (port->wPortStatus & PORT_STAT_SUSPEND) { port->wPortChange |= PORT_STAT_C_SUSPEND; - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } } @@ -364,7 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, port->wPortChange |= PORT_STAT_C_RESET; /* set enable bit */ port->wPortStatus |= PORT_STAT_ENABLE; - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } break; case PORT_POWER: diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index a01a5e793a..c08718b679 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -855,7 +855,7 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length) g_malloc0(sizeof(struct rndis_response) + length); if (QTAILQ_EMPTY(&s->rndis_resp)) { - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 979a473b37..caebc1c3ff 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -839,7 +839,7 @@ static void ccid_on_slot_change(USBCCIDState *s, bool full) s->bmSlotICCState |= SLOT_0_CHANGED_MASK; } s->notify_slot_change = true; - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } static void ccid_write_data_block_error( diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index d904d1a40b..316c388c5b 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -276,7 +276,7 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length) } else { USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN, UAS_PIPE_ID_STATUS); - usb_wakeup(ep); + usb_wakeup(ep, 0); } } diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index ab9fa2ef48..3be5cdefda 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -138,7 +138,7 @@ static void usb_mouse_event(void *opaque, s->dz += dz1; s->buttons_state = buttons_state; s->changed = 1; - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } static void usb_wacom_event(void *opaque, @@ -152,7 +152,7 @@ static void usb_wacom_event(void *opaque, s->dz += dz; s->buttons_state = buttons_state; s->changed = 1; - usb_wakeup(s->intr); + usb_wakeup(s->intr, 0); } static inline int int_clamp(int val, int vmin, int vmax) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 70406592ef..5176251cb4 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -874,7 +874,8 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], return 0; } -static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) +static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep, + unsigned int stream) { EHCIState *s = container_of(bus, EHCIState, bus); uint32_t portsc = s->portsc[ep->dev->port->index]; @@ -1420,7 +1421,7 @@ static int ehci_execute(EHCIPacket *p, const char *action) } spd = (p->pid == USB_TOKEN_IN && NLPTR_TBIT(p->qtd.altnext) == 0); - usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr, spd, + usb_packet_setup(&p->packet, p->pid, ep, 0, p->qtdaddr, spd, (p->qtd.token & QTD_TOKEN_IOC) != 0); usb_packet_map(&p->packet, &p->sgl); p->async = EHCI_ASYNC_INITIALIZED; @@ -1493,7 +1494,7 @@ static int ehci_process_itd(EHCIState *ehci, dev = ehci_find_device(ehci, devaddr); ep = usb_ep_get(dev, pid, endp); if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) { - usb_packet_setup(&ehci->ipacket, pid, ep, addr, false, + usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false, (itd->transact[i] & ITD_XACT_IOC) != 0); usb_packet_map(&ehci->ipacket, &ehci->isgl); usb_handle_packet(dev, &ehci->ipacket); diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c index 64e9e834bf..7968e17c34 100644 --- a/hw/usb/hcd-musb.c +++ b/hw/usb/hcd-musb.c @@ -625,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep, /* A wild guess on the FADDR semantics... */ dev = usb_find_device(&s->port, ep->faddr[idx]); uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf); - usb_packet_setup(&ep->packey[dir].p, pid, uep, + usb_packet_setup(&ep->packey[dir].p, pid, uep, 0, (dev->addr << 16) | (uep->nr << 8) | pid, false, true); usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len); ep->packey[dir].ep = ep; diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index dd9967b13d..51241cda78 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -830,7 +830,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, OHCI_BM(iso_td.flags, TD_DI) == 0; dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); - usb_packet_setup(&ohci->usb_packet, pid, ep, addr, false, int_req); + usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); usb_handle_packet(dev, &ohci->usb_packet); if (ohci->usb_packet.status == USB_RET_ASYNC) { @@ -1034,7 +1034,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) } dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA)); ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN)); - usb_packet_setup(&ohci->usb_packet, pid, ep, addr, !flag_r, + usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r, OHCI_BM(td.flags, TD_DI) == 0); usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); usb_handle_packet(dev, &ohci->usb_packet); diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 60645aa21f..f8c42864d1 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -879,7 +879,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, max_len = ((td->token >> 21) + 1) & 0x7ff; spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0); - usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd, + usb_packet_setup(&async->packet, pid, q->ep, 0, td_addr, spd, (td->ctrl & TD_CTRL_IOC) != 0); qemu_sglist_add(&async->sgl, td->buffer, max_len); usb_packet_map(&async->packet, &async->sgl); diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 5fb0c488e8..b8247f3a7c 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1518,8 +1518,8 @@ static int xhci_setup_packet(XHCITransfer *xfer) } xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */ - usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr, false, - xfer->int_req); + usb_packet_setup(&xfer->packet, dir, ep, 0, + xfer->trbs[0].addr, false, xfer->int_req); usb_packet_map(&xfer->packet, &xfer->sgl); DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", xfer->packet.pid, dev->addr, ep->nr); @@ -1977,7 +1977,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, DPRINTF("xhci: device address is %d\n", slot->devaddr); usb_device_reset(dev); usb_packet_setup(&p, USB_TOKEN_OUT, - usb_ep_get(dev, USB_TOKEN_OUT, 0), + usb_ep_get(dev, USB_TOKEN_OUT, 0), 0, 0, false, false); usb_device_handle_control(dev, &p, DeviceOutRequest | USB_REQ_SET_ADDRESS, @@ -3033,7 +3033,8 @@ static int xhci_find_epid(USBEndpoint *ep) } } -static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) +static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep, + unsigned int stream) { XHCIState *xhci = container_of(bus, XHCIState, bus); int slotid; From 024426acc0a2707a85faa1983499647649d6d2db Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Jan 2013 17:23:44 +0100 Subject: [PATCH 1148/1634] usb-xhci: usb3 streams Add streams support to the xhci emulation. No secondary streams yet, only linear stream arays are supported for now. Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-xhci.c | 268 ++++++++++++++++++++++++++++++++++++++-------- trace-events | 6 +- 2 files changed, 226 insertions(+), 48 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index b8247f3a7c..5796102f3a 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -34,8 +34,8 @@ #else #define DPRINTF(...) do {} while (0) #endif -#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ - __func__, __LINE__); abort(); } while (0) +#define FIXME(_msg) do { fprintf(stderr, "FIXME %s:%d %s\n", \ + __func__, __LINE__, _msg); abort(); } while (0) #define MAXPORTS_2 15 #define MAXPORTS_3 15 @@ -301,6 +301,8 @@ typedef enum TRBCCode { #define SLOT_CONTEXT_ENTRIES_SHIFT 27 typedef struct XHCIState XHCIState; +typedef struct XHCIStreamContext XHCIStreamContext; +typedef struct XHCIEPContext XHCIEPContext; #define get_field(data, field) \ (((data) >> field##_SHIFT) & field##_MASK) @@ -351,6 +353,7 @@ typedef struct XHCITransfer { unsigned int iso_pkts; unsigned int slotid; unsigned int epid; + unsigned int streamid; bool in_xfer; bool iso_xfer; @@ -367,7 +370,14 @@ typedef struct XHCITransfer { uint64_t mfindex_kick; } XHCITransfer; -typedef struct XHCIEPContext { +struct XHCIStreamContext { + dma_addr_t pctx; + unsigned int sct; + XHCIRing ring; + XHCIStreamContext *sstreams; +}; + +struct XHCIEPContext { XHCIState *xhci; unsigned int slotid; unsigned int epid; @@ -382,11 +392,17 @@ typedef struct XHCIEPContext { unsigned int max_psize; uint32_t state; + /* streams */ + unsigned int max_pstreams; + bool lsa; + unsigned int nr_pstreams; + XHCIStreamContext *pstreams; + /* iso xfer scheduling */ unsigned int interval; int64_t mfindex_last; QEMUTimer *kick_timer; -} XHCIEPContext; +}; typedef struct XHCISlot { bool enabled; @@ -482,7 +498,7 @@ enum xhci_flags { }; static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, - unsigned int epid); + unsigned int epid, unsigned int streamid); static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid); static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v); @@ -1068,18 +1084,116 @@ static void xhci_stop(XHCIState *xhci) xhci->crcr_low &= ~CRCR_CRR; } +static XHCIStreamContext *xhci_alloc_stream_contexts(unsigned count, + dma_addr_t base) +{ + XHCIStreamContext *stctx; + unsigned int i; + + stctx = g_new0(XHCIStreamContext, count); + for (i = 0; i < count; i++) { + stctx[i].pctx = base + i * 16; + stctx[i].sct = -1; + } + return stctx; +} + +static void xhci_reset_streams(XHCIEPContext *epctx) +{ + unsigned int i; + + for (i = 0; i < epctx->nr_pstreams; i++) { + epctx->pstreams[i].sct = -1; + g_free(epctx->pstreams[i].sstreams); + } +} + +static void xhci_alloc_streams(XHCIEPContext *epctx, dma_addr_t base) +{ + assert(epctx->pstreams == NULL); + epctx->nr_pstreams = 2 << epctx->max_pstreams; + epctx->pstreams = xhci_alloc_stream_contexts(epctx->nr_pstreams, base); +} + +static void xhci_free_streams(XHCIEPContext *epctx) +{ + int i; + + assert(epctx->pstreams != NULL); + + if (!epctx->lsa) { + for (i = 0; i < epctx->nr_pstreams; i++) { + g_free(epctx->pstreams[i].sstreams); + } + } + g_free(epctx->pstreams); + epctx->pstreams = NULL; + epctx->nr_pstreams = 0; +} + +static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx, + unsigned int streamid, + uint32_t *cc_error) +{ + XHCIStreamContext *sctx; + dma_addr_t base; + uint32_t ctx[2], sct; + + assert(streamid != 0); + if (epctx->lsa) { + if (streamid >= epctx->nr_pstreams) { + *cc_error = CC_INVALID_STREAM_ID_ERROR; + return NULL; + } + sctx = epctx->pstreams + streamid; + } else { + FIXME("secondary streams not implemented yet"); + } + + if (sctx->sct == -1) { + xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx)); + fprintf(stderr, "%s: init sctx #%d @ %lx: %08x %08x\n", __func__, + streamid, sctx->pctx, ctx[0], ctx[1]); + sct = (ctx[0] >> 1) & 0x07; + if (epctx->lsa && sct != 1) { + *cc_error = CC_INVALID_STREAM_TYPE_ERROR; + return NULL; + } + sctx->sct = sct; + base = xhci_addr64(ctx[0] & ~0xf, ctx[1]); + xhci_ring_init(epctx->xhci, &sctx->ring, base); + } + return sctx; +} + static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, - uint32_t state) + XHCIStreamContext *sctx, uint32_t state) { uint32_t ctx[5]; + uint32_t ctx2[2]; + fprintf(stderr, "%s: epid %d, state %d\n", + __func__, epctx->epid, state); xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); ctx[0] &= ~EP_STATE_MASK; ctx[0] |= state; - ctx[2] = epctx->ring.dequeue | epctx->ring.ccs; - ctx[3] = (epctx->ring.dequeue >> 16) >> 16; - DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n", - epctx->pctx, state, ctx[3], ctx[2]); + + /* update ring dequeue ptr */ + if (epctx->nr_pstreams) { + if (sctx != NULL) { + xhci_dma_read_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2)); + ctx2[0] &= 0xe; + ctx2[0] |= sctx->ring.dequeue | sctx->ring.ccs; + ctx2[1] = (sctx->ring.dequeue >> 16) >> 16; + xhci_dma_write_u32s(xhci, sctx->pctx, ctx2, sizeof(ctx2)); + } + } else { + ctx[2] = epctx->ring.dequeue | epctx->ring.ccs; + ctx[3] = (epctx->ring.dequeue >> 16) >> 16; + DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n", + epctx->pctx, state, ctx[3], ctx[2]); + } + xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); epctx->state = state; } @@ -1087,7 +1201,7 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, static void xhci_ep_kick_timer(void *opaque) { XHCIEPContext *epctx = opaque; - xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid); + xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0); } static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, @@ -1117,16 +1231,22 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, slot->eps[epid-1] = epctx; dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]); - xhci_ring_init(xhci, &epctx->ring, dequeue); - epctx->ring.ccs = ctx[2] & 1; epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK; DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type); epctx->pctx = pctx; epctx->max_psize = ctx[1]>>16; epctx->max_psize *= 1+((ctx[1]>>8)&0xff); + epctx->max_pstreams = (ctx[0] >> 10) & 0xf; + epctx->lsa = (ctx[0] >> 15) & 1; DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n", epid/2, epid%2, epctx->max_psize); + if (epctx->max_pstreams) { + xhci_alloc_streams(epctx, dequeue); + } else { + xhci_ring_init(xhci, &epctx->ring, dequeue); + epctx->ring.ccs = ctx[2] & 1; + } for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { usb_packet_init(&epctx->transfers[i].packet); } @@ -1227,7 +1347,11 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, epctx = slot->eps[epid-1]; - xhci_set_ep_state(xhci, epctx, EP_DISABLED); + if (epctx->nr_pstreams) { + xhci_free_streams(epctx); + } + + xhci_set_ep_state(xhci, epctx, NULL, EP_DISABLED); qemu_free_timer(epctx->kick_timer); g_free(epctx); @@ -1264,7 +1388,11 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid, epctx = slot->eps[epid-1]; - xhci_set_ep_state(xhci, epctx, EP_STOPPED); + xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED); + + if (epctx->nr_pstreams) { + xhci_reset_streams(epctx); + } return CC_SUCCESS; } @@ -1315,16 +1443,22 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, return CC_USB_TRANSACTION_ERROR; } - xhci_set_ep_state(xhci, epctx, EP_STOPPED); + xhci_set_ep_state(xhci, epctx, NULL, EP_STOPPED); + + if (epctx->nr_pstreams) { + xhci_reset_streams(epctx); + } return CC_SUCCESS; } static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, - unsigned int epid, uint64_t pdequeue) + unsigned int epid, unsigned int streamid, + uint64_t pdequeue) { XHCISlot *slot; XHCIEPContext *epctx; + XHCIStreamContext *sctx; dma_addr_t dequeue; assert(slotid >= 1 && slotid <= xhci->numslots); @@ -1334,7 +1468,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, return CC_TRB_ERROR; } - trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue); + trace_usb_xhci_ep_set_dequeue(slotid, epid, streamid, pdequeue); dequeue = xhci_mask64(pdequeue); slot = &xhci->slots[slotid-1]; @@ -1346,16 +1480,26 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, epctx = slot->eps[epid-1]; - if (epctx->state != EP_STOPPED) { fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid); return CC_CONTEXT_STATE_ERROR; } - xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF); - epctx->ring.ccs = dequeue & 1; + if (epctx->nr_pstreams) { + uint32_t err; + sctx = xhci_find_stream(epctx, streamid, &err); + if (sctx == NULL) { + return err; + } + xhci_ring_init(xhci, &sctx->ring, dequeue & ~0xf); + sctx->ring.ccs = dequeue & 1; + } else { + sctx = NULL; + xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF); + epctx->ring.ccs = dequeue & 1; + } - xhci_set_ep_state(xhci, epctx, EP_STOPPED); + xhci_set_ep_state(xhci, epctx, sctx, EP_STOPPED); return CC_SUCCESS; } @@ -1484,12 +1628,22 @@ static void xhci_stall_ep(XHCITransfer *xfer) XHCIState *xhci = xfer->xhci; XHCISlot *slot = &xhci->slots[xfer->slotid-1]; XHCIEPContext *epctx = slot->eps[xfer->epid-1]; + uint32_t err; + XHCIStreamContext *sctx; - epctx->ring.dequeue = xfer->trbs[0].addr; - epctx->ring.ccs = xfer->trbs[0].ccs; - xhci_set_ep_state(xhci, epctx, EP_HALTED); - DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid); - DPRINTF("xhci: will continue at "DMA_ADDR_FMT"\n", epctx->ring.dequeue); + if (epctx->nr_pstreams) { + sctx = xhci_find_stream(epctx, xfer->streamid, &err); + if (sctx == NULL) { + return; + } + sctx->ring.dequeue = xfer->trbs[0].addr; + sctx->ring.ccs = xfer->trbs[0].ccs; + xhci_set_ep_state(xhci, epctx, sctx, EP_HALTED); + } else { + epctx->ring.dequeue = xfer->trbs[0].addr; + epctx->ring.ccs = xfer->trbs[0].ccs; + xhci_set_ep_state(xhci, epctx, NULL, EP_HALTED); + } } static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, @@ -1518,7 +1672,7 @@ static int xhci_setup_packet(XHCITransfer *xfer) } xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */ - usb_packet_setup(&xfer->packet, dir, ep, 0, + usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid, xfer->trbs[0].addr, false, xfer->int_req); usb_packet_map(&xfer->packet, &xfer->sgl); DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", @@ -1572,7 +1726,7 @@ static int xhci_complete_packet(XHCITransfer *xfer) default: fprintf(stderr, "%s: FIXME: status = %d\n", __func__, xfer->packet.status); - FIXME(); + FIXME("unhandled USB_RET_*"); } return 0; } @@ -1585,7 +1739,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) trb_setup = &xfer->trbs[0]; trb_status = &xfer->trbs[xfer->trb_count-1]; - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid); /* at most one Event Data TRB allowed after STATUS */ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { @@ -1627,7 +1781,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { - xhci_kick_ep(xhci, xfer->slotid, xfer->epid); + xhci_kick_ep(xhci, xfer->slotid, xfer->epid, 0); } return 0; } @@ -1710,26 +1864,29 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx xhci_complete_packet(xfer); if (!xfer->running_async && !xfer->running_retry) { - xhci_kick_ep(xhci, xfer->slotid, xfer->epid); + xhci_kick_ep(xhci, xfer->slotid, xfer->epid, xfer->streamid); } return 0; } static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) { - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, xfer->streamid); return xhci_submit(xhci, xfer, epctx); } -static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) +static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid, unsigned int streamid) { + XHCIStreamContext *stctx; XHCIEPContext *epctx; + XHCIRing *ring; USBEndpoint *ep = NULL; uint64_t mfindex; int length; int i; - trace_usb_xhci_ep_kick(slotid, epid); + trace_usb_xhci_ep_kick(slotid, epid, streamid); assert(slotid >= 1 && slotid <= xhci->numslots); assert(epid >= 1 && epid <= 31); @@ -1782,14 +1939,28 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid return; } - xhci_set_ep_state(xhci, epctx, EP_RUNNING); + + if (epctx->nr_pstreams) { + uint32_t err; + stctx = xhci_find_stream(epctx, streamid, &err); + if (stctx == NULL) { + return; + } + ring = &stctx->ring; + xhci_set_ep_state(xhci, epctx, stctx, EP_RUNNING); + } else { + ring = &epctx->ring; + streamid = 0; + xhci_set_ep_state(xhci, epctx, NULL, EP_RUNNING); + } + assert(ring->base != 0); while (1) { XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; if (xfer->running_async || xfer->running_retry) { break; } - length = xhci_ring_chain_length(xhci, &epctx->ring); + length = xhci_ring_chain_length(xhci, ring); if (length < 0) { break; } else if (length == 0) { @@ -1808,11 +1979,12 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid xfer->trb_count = length; for (i = 0; i < length; i++) { - assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL)); + assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL)); } xfer->xhci = xhci; xfer->epid = epid; xfer->slotid = slotid; + xfer->streamid = streamid; if (epid == 1) { if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) { @@ -2357,11 +2529,14 @@ static void xhci_process_commands(XHCIState *xhci) } break; case CR_SET_TR_DEQUEUE: + fprintf(stderr, "%s: CR_SET_TR_DEQUEUE\n", __func__); slotid = xhci_get_slot(xhci, &event, &trb); if (slotid) { unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) & TRB_CR_EPID_MASK; - event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid, + unsigned int streamid = (trb.status >> 16) & 0xffff; + event.ccode = xhci_set_ep_dequeue(xhci, slotid, + epid, streamid, trb.parameter); } break; @@ -2554,9 +2729,9 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) break; case 0x10: /* HCCPARAMS */ if (sizeof(dma_addr_t) == 4) { - ret = 0x00081000; + ret = 0x00087000; } else { - ret = 0x00081001; + ret = 0x00087001; } break; case 0x14: /* DBOFF */ @@ -2880,6 +3055,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg, uint64_t val, unsigned size) { XHCIState *xhci = ptr; + unsigned int epid, streamid; trace_usb_xhci_doorbell_write(reg, val); @@ -2898,13 +3074,15 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg, (uint32_t)val); } } else { + epid = val & 0xff; + streamid = (val >> 16) & 0xffff; if (reg > xhci->numslots) { fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg); - } else if (val > 31) { + } else if (epid > 31) { fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", (int)reg, (uint32_t)val); } else { - xhci_kick_ep(xhci, reg, val); + xhci_kick_ep(xhci, reg, epid, streamid); } } } @@ -2988,7 +3166,7 @@ static void xhci_complete(USBPort *port, USBPacket *packet) return; } xhci_complete_packet(xfer); - xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid); + xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid, xfer->streamid); } static void xhci_child_detach(USBPort *uport, USBDevice *child) @@ -3045,7 +3223,7 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep, DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr); return; } - xhci_kick_ep(xhci, slotid, xhci_find_epid(ep)); + xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream); } static USBBusOps xhci_bus_ops = { diff --git a/trace-events b/trace-events index 1011f27676..a27ae43032 100644 --- a/trace-events +++ b/trace-events @@ -370,11 +370,11 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d" usb_xhci_slot_reset(uint32_t slotid) "slotid %d" usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" -usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64 -usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint32_t streamid, uint64_t param) "slotid %d, epid %d, streamid %d, ptr %016" PRIx64 +usb_xhci_ep_kick(uint32_t slotid, uint32_t epid, uint32_t streamid) "slotid %d, epid %d, streamid %d" usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" -usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d" +usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t streamid) "%p: slotid %d, epid %d, streamid %d" usb_xhci_xfer_async(void *xfer) "%p" usb_xhci_xfer_nak(void *xfer) "%p" usb_xhci_xfer_retry(void *xfer) "%p" From 89a453d4a5c195e6d0a3c3d4fcaacb447447115f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Jan 2013 17:38:59 +0100 Subject: [PATCH 1149/1634] uas-uas: usb3 streams Add usb3 streams support to the uas (usb attached scsi) emulation. Signed-off-by: Gerd Hoffmann --- hw/usb/dev-uas.c | 247 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 205 insertions(+), 42 deletions(-) diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 316c388c5b..1ac5117ba7 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -99,6 +99,9 @@ typedef struct { /* --------------------------------------------------------------------- */ +#define UAS_STREAM_BM_ATTR 4 +#define UAS_MAX_STREAMS (1 << UAS_STREAM_BM_ATTR) + typedef struct UASDevice UASDevice; typedef struct UASRequest UASRequest; typedef struct UASStatus UASStatus; @@ -106,12 +109,18 @@ typedef struct UASStatus UASStatus; struct UASDevice { USBDevice dev; SCSIBus bus; - UASRequest *datain; - UASRequest *dataout; - USBPacket *status; QEMUBH *status_bh; QTAILQ_HEAD(, UASStatus) results; QTAILQ_HEAD(, UASRequest) requests; + + /* usb 2.0 only */ + USBPacket *status2; + UASRequest *datain2; + UASRequest *dataout2; + + /* usb 3.0 only */ + USBPacket *data3[UAS_MAX_STREAMS]; + USBPacket *status3[UAS_MAX_STREAMS]; }; struct UASRequest { @@ -132,6 +141,7 @@ struct UASRequest { }; struct UASStatus { + uint32_t stream; uas_ui status; uint32_t length; QTAILQ_ENTRY(UASStatus) next; @@ -144,6 +154,7 @@ enum { STR_PRODUCT, STR_SERIALNUMBER, STR_CONFIG_HIGH, + STR_CONFIG_SUPER, }; static const USBDescStrings desc_strings = { @@ -151,6 +162,7 @@ static const USBDescStrings desc_strings = { [STR_PRODUCT] = "USB Attached SCSI HBA", [STR_SERIALNUMBER] = "27842", [STR_CONFIG_HIGH] = "High speed config (usb 2.0)", + [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)", }; static const USBDescIface desc_iface_high = { @@ -204,6 +216,64 @@ static const USBDescIface desc_iface_high = { } }; +static const USBDescIface desc_iface_super = { + .bInterfaceNumber = 0, + .bNumEndpoints = 4, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = 0x06, /* SCSI */ + .bInterfaceProtocol = 0x62, /* UAS */ + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_COMMAND, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + .bMaxBurst = 15, + .extra = (uint8_t[]) { + 0x04, /* u8 bLength */ + 0x24, /* u8 bDescriptorType */ + UAS_PIPE_ID_COMMAND, + 0x00, /* u8 bReserved */ + }, + },{ + .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_STATUS, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + .bMaxBurst = 15, + .bmAttributes_super = UAS_STREAM_BM_ATTR, + .extra = (uint8_t[]) { + 0x04, /* u8 bLength */ + 0x24, /* u8 bDescriptorType */ + UAS_PIPE_ID_STATUS, + 0x00, /* u8 bReserved */ + }, + },{ + .bEndpointAddress = USB_DIR_IN | UAS_PIPE_ID_DATA_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + .bMaxBurst = 15, + .bmAttributes_super = UAS_STREAM_BM_ATTR, + .extra = (uint8_t[]) { + 0x04, /* u8 bLength */ + 0x24, /* u8 bDescriptorType */ + UAS_PIPE_ID_DATA_IN, + 0x00, /* u8 bReserved */ + }, + },{ + .bEndpointAddress = USB_DIR_OUT | UAS_PIPE_ID_DATA_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + .bMaxBurst = 15, + .bmAttributes_super = UAS_STREAM_BM_ATTR, + .extra = (uint8_t[]) { + 0x04, /* u8 bLength */ + 0x24, /* u8 bDescriptorType */ + UAS_PIPE_ID_DATA_OUT, + 0x00, /* u8 bReserved */ + }, + }, + } +}; + static const USBDescDevice desc_device_high = { .bcdUSB = 0x0200, .bMaxPacketSize0 = 64, @@ -220,6 +290,22 @@ static const USBDescDevice desc_device_high = { }, }; +static const USBDescDevice desc_device_super = { + .bcdUSB = 0x0300, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_SUPER, + .bmAttributes = 0xc0, + .nif = 1, + .ifs = &desc_iface_super, + }, + }, +}; + static const USBDesc desc = { .id = { .idVendor = 0x46f4, /* CRC16() of "QEMU" */ @@ -229,45 +315,68 @@ static const USBDesc desc = { .iProduct = STR_PRODUCT, .iSerialNumber = STR_SERIALNUMBER, }, - .high = &desc_device_high, - .str = desc_strings, + .high = &desc_device_high, + .super = &desc_device_super, + .str = desc_strings, }; /* --------------------------------------------------------------------- */ -static UASStatus *usb_uas_alloc_status(uint8_t id, uint16_t tag) +static bool uas_using_streams(UASDevice *uas) +{ + return uas->dev.speed == USB_SPEED_SUPER; +} + +/* --------------------------------------------------------------------- */ + +static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag) { UASStatus *st = g_new0(UASStatus, 1); st->status.hdr.id = id; st->status.hdr.tag = cpu_to_be16(tag); st->length = sizeof(uas_ui_header); + if (uas_using_streams(uas)) { + st->stream = tag; + } return st; } static void usb_uas_send_status_bh(void *opaque) { UASDevice *uas = opaque; - UASStatus *st = QTAILQ_FIRST(&uas->results); - USBPacket *p = uas->status; + UASStatus *st; + USBPacket *p; - assert(p != NULL); - assert(st != NULL); + while ((st = QTAILQ_FIRST(&uas->results)) != NULL) { + if (uas_using_streams(uas)) { + p = uas->status3[st->stream]; + uas->status3[st->stream] = NULL; + } else { + p = uas->status2; + uas->status2 = NULL; + } + if (p == NULL) { + break; + } - uas->status = NULL; - usb_packet_copy(p, &st->status, st->length); - QTAILQ_REMOVE(&uas->results, st, next); - g_free(st); + usb_packet_copy(p, &st->status, st->length); + QTAILQ_REMOVE(&uas->results, st, next); + g_free(st); - p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ - usb_packet_complete(&uas->dev, p); + p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */ + usb_packet_complete(&uas->dev, p); + } } static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length) { + USBPacket *p = uas_using_streams(uas) ? + uas->status3[st->stream] : uas->status2; + st->length += length; QTAILQ_INSERT_TAIL(&uas->results, st, next); - if (uas->status) { + if (p) { /* * Just schedule bh make sure any in-flight data transaction * is finished before completing (sending) the status packet. @@ -276,14 +385,14 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length) } else { USBEndpoint *ep = usb_ep_get(&uas->dev, USB_TOKEN_IN, UAS_PIPE_ID_STATUS); - usb_wakeup(ep, 0); + usb_wakeup(ep, st->stream); } } static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, uint8_t code, uint16_t add_info) { - UASStatus *st = usb_uas_alloc_status(UAS_UI_RESPONSE, tag); + UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag); trace_usb_uas_response(uas->dev.addr, tag, code); st->status.response.response_code = code; @@ -293,7 +402,7 @@ static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, static void usb_uas_queue_sense(UASRequest *req, uint8_t status) { - UASStatus *st = usb_uas_alloc_status(UAS_UI_SENSE, req->tag); + UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_SENSE, req->tag); int len, slen = 0; trace_usb_uas_sense(req->uas->dev.addr, req->tag, status); @@ -310,7 +419,8 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status) static void usb_uas_queue_read_ready(UASRequest *req) { - UASStatus *st = usb_uas_alloc_status(UAS_UI_READ_READY, req->tag); + UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY, + req->tag); trace_usb_uas_read_ready(req->uas->dev.addr, req->tag); usb_uas_queue_status(req->uas, st, 0); @@ -318,7 +428,8 @@ static void usb_uas_queue_read_ready(UASRequest *req) static void usb_uas_queue_write_ready(UASRequest *req) { - UASStatus *st = usb_uas_alloc_status(UAS_UI_WRITE_READY, req->tag); + UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_WRITE_READY, + req->tag); trace_usb_uas_write_ready(req->uas->dev.addr, req->tag); usb_uas_queue_status(req->uas, st, 0); @@ -381,18 +492,22 @@ static void usb_uas_start_next_transfer(UASDevice *uas) { UASRequest *req; + if (uas_using_streams(uas)) { + return; + } + QTAILQ_FOREACH(req, &uas->requests, next) { if (req->active || req->complete) { continue; } - if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain == NULL) { - uas->datain = req; + if (req->req->cmd.mode == SCSI_XFER_FROM_DEV && uas->datain2 == NULL) { + uas->datain2 = req; usb_uas_queue_read_ready(req); req->active = true; return; } - if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout == NULL) { - uas->dataout = req; + if (req->req->cmd.mode == SCSI_XFER_TO_DEV && uas->dataout2 == NULL) { + uas->dataout2 = req; usb_uas_queue_write_ready(req); req->active = true; return; @@ -417,11 +532,11 @@ static void usb_uas_scsi_free_request(SCSIBus *bus, void *priv) UASRequest *req = priv; UASDevice *uas = req->uas; - if (req == uas->datain) { - uas->datain = NULL; + if (req == uas->datain2) { + uas->datain2 = NULL; } - if (req == uas->dataout) { - uas->dataout = NULL; + if (req == uas->dataout2) { + uas->dataout2 = NULL; } QTAILQ_REMOVE(&uas->requests, req, next); g_free(req); @@ -522,12 +637,25 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p) { UASDevice *uas = DO_UPCAST(UASDevice, dev, dev); UASRequest *req, *nreq; + int i; - if (uas->status == p) { - uas->status = NULL; + if (uas->status2 == p) { + uas->status2 = NULL; qemu_bh_cancel(uas->status_bh); return; } + if (uas_using_streams(uas)) { + for (i = 0; i < UAS_MAX_STREAMS; i++) { + if (uas->status3[i] == p) { + uas->status3[i] = NULL; + return; + } + if (uas->data3[i] == p) { + uas->data3[i] = NULL; + return; + } + } + } QTAILQ_FOREACH_SAFE(req, &uas->requests, next, nreq) { if (req->data == p) { req->data = NULL; @@ -555,9 +683,18 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui) usb_uas_get_lun(req->lun), req->lun >> 32, req->lun & 0xffffffff); QTAILQ_INSERT_TAIL(&uas->requests, req, next); + if (uas_using_streams(uas) && uas->data3[req->tag] != NULL) { + req->data = uas->data3[req->tag]; + req->data_async = true; + uas->data3[req->tag] = NULL; + } + req->req = scsi_req_new(req->dev, req->tag, usb_uas_get_lun(req->lun), ui->command.cdb, req); +#if 1 + scsi_req_print(req->req); +#endif len = scsi_req_enqueue(req->req); if (len) { req->data_size = len; @@ -669,12 +806,26 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) } break; case UAS_PIPE_ID_STATUS: - st = QTAILQ_FIRST(&uas->results); - if (st == NULL) { - assert(uas->status == NULL); - uas->status = p; - p->status = USB_RET_ASYNC; - break; + if (p->stream) { + QTAILQ_FOREACH(st, &uas->results, next) { + if (st->stream == p->stream) { + break; + } + } + if (st == NULL) { + assert(uas->status3[p->stream] == NULL); + uas->status3[p->stream] = p; + p->status = USB_RET_ASYNC; + break; + } + } else { + st = QTAILQ_FIRST(&uas->results); + if (st == NULL) { + assert(uas->status2 == NULL); + uas->status2 = p; + p->status = USB_RET_ASYNC; + break; + } } usb_packet_copy(p, &st->status, st->length); QTAILQ_REMOVE(&uas->results, st, next); @@ -682,11 +833,23 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) break; case UAS_PIPE_ID_DATA_IN: case UAS_PIPE_ID_DATA_OUT: - req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) ? uas->datain : uas->dataout; + if (p->stream) { + req = usb_uas_find_request(uas, p->stream); + } else { + req = (p->ep->nr == UAS_PIPE_ID_DATA_IN) + ? uas->datain2 : uas->dataout2; + } if (req == NULL) { - fprintf(stderr, "%s: no inflight request\n", __func__); - p->status = USB_RET_STALL; - break; + if (p->stream) { + assert(uas->data3[p->stream] == NULL); + uas->data3[p->stream] = p; + p->status = USB_RET_ASYNC; + break; + } else { + fprintf(stderr, "%s: no inflight request\n", __func__); + p->status = USB_RET_STALL; + break; + } } scsi_req_ref(req->req); req->data = p; From cd7f97cafdd80d6bd4950ccfdcd9acb7850184b2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Jan 2013 18:17:33 -0800 Subject: [PATCH 1150/1634] target-i386: Implement ADX extension Signed-off-by: Richard Henderson --- target-i386/cc_helper.c | 30 +++++++++++ target-i386/cpu.c | 4 +- target-i386/cpu.h | 4 ++ target-i386/helper.c | 4 ++ target-i386/translate.c | 109 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 146 insertions(+), 5 deletions(-) diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c index 5ea6a0aeae..6cf57a76b3 100644 --- a/target-i386/cc_helper.c +++ b/target-i386/cc_helper.c @@ -75,6 +75,24 @@ const uint8_t parity_table[256] = { #endif +static target_ulong compute_all_adcx(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + return (src1 & ~CC_C) | (dst * CC_C); +} + +static target_ulong compute_all_adox(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + return (src1 & ~CC_O) | (src2 * CC_O); +} + +static target_ulong compute_all_adcox(target_ulong dst, target_ulong src1, + target_ulong src2) +{ + return (src1 & ~(CC_C | CC_O)) | (dst * CC_C) | (src2 * CC_O); +} + target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, target_ulong src2, int op) { @@ -162,6 +180,13 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, case CC_OP_BMILGL: return compute_all_bmilgl(dst, src1); + case CC_OP_ADCX: + return compute_all_adcx(dst, src1, src2); + case CC_OP_ADOX: + return compute_all_adox(dst, src1, src2); + case CC_OP_ADCOX: + return compute_all_adcox(dst, src1, src2); + #ifdef TARGET_X86_64 case CC_OP_MULQ: return compute_all_mulq(dst, src1); @@ -210,6 +235,7 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, case CC_OP_SARW: case CC_OP_SARL: case CC_OP_SARQ: + case CC_OP_ADOX: return src1 & 1; case CC_OP_INCB: @@ -228,6 +254,10 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, case CC_OP_MULQ: return src1 != 0; + case CC_OP_ADCX: + case CC_OP_ADCOX: + return dst; + case CC_OP_ADDB: return compute_c_addb(dst, src1); case CC_OP_ADDW: diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0cb64ab583..5582e5f4e6 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -407,11 +407,11 @@ typedef struct x86_def_t { CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) #define TCG_SVM_FEATURES 0 #define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP \ - CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2) + CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX) /* missing: CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, - CPUID_7_0_EBX_RDSEED, CPUID_7_0_EBX_ADX */ + CPUID_7_0_EBX_RDSEED */ /* built-in CPU model definitions */ diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 960676bebd..e0443d8917 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -641,6 +641,10 @@ typedef enum { CC_OP_BMILGL, CC_OP_BMILGQ, + CC_OP_ADCX, /* CC_DST = C, CC_SRC = rest. */ + CC_OP_ADOX, /* CC_DST = O, CC_SRC = rest. */ + CC_OP_ADCOX, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */ + CC_OP_NB, } CCOp; diff --git a/target-i386/helper.c b/target-i386/helper.c index 74d600f483..66c3624733 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -113,6 +113,10 @@ static const char *cc_op_str[CC_OP_NB] = { "BMILGW", "BMILGL", "BMILGQ", + + "ADCX", + "ADOX", + "ADCOX", }; static void diff --git a/target-i386/translate.c b/target-i386/translate.c index 68e30e699e..436658a33a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -210,6 +210,9 @@ static const uint8_t cc_op_live[CC_OP_NB] = { [CC_OP_SHLB ... CC_OP_SHLQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_SARB ... CC_OP_SARQ] = USES_CC_DST | USES_CC_SRC, [CC_OP_BMILGB ... CC_OP_BMILGQ] = USES_CC_DST | USES_CC_SRC, + [CC_OP_ADCX] = USES_CC_DST | USES_CC_SRC, + [CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2, + [CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2, }; static void set_cc_op(DisasContext *s, CCOp op) @@ -994,6 +997,11 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) t0 = gen_ext_tl(reg, cpu_cc_src, size, false); return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 }; + case CC_OP_ADCX: + case CC_OP_ADCOX: + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_dst, + .mask = -1, .no_setcond = true }; + case CC_OP_EFLAGS: case CC_OP_SARB ... CC_OP_SARQ: /* CC_SRC & 1 */ @@ -1027,6 +1035,9 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg) gen_compute_eflags(s); /* FALLTHRU */ case CC_OP_EFLAGS: + case CC_OP_ADCX: + case CC_OP_ADOX: + case CC_OP_ADCOX: return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, .mask = CC_S }; default: @@ -1041,9 +1052,17 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg) /* compute eflags.O to reg */ static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg) { - gen_compute_eflags(s); - return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, - .mask = CC_O }; + switch (s->cc_op) { + case CC_OP_ADOX: + case CC_OP_ADCOX: + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src2, + .mask = -1, .no_setcond = true }; + + default: + gen_compute_eflags(s); + return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, + .mask = CC_O }; + } } /* compute eflags.Z to reg */ @@ -1054,6 +1073,9 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) gen_compute_eflags(s); /* FALLTHRU */ case CC_OP_EFLAGS: + case CC_OP_ADCX: + case CC_OP_ADOX: + case CC_OP_ADCOX: return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, .mask = CC_Z }; default: @@ -4174,6 +4196,87 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, gen_helper_pext(cpu_regs[reg], cpu_T[0], cpu_T[1]); break; + case 0x1f6: /* adcx Gy, Ey */ + case 0x2f6: /* adox Gy, Ey */ + if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_ADX)) { + goto illegal_op; + } else { + TCGv carry_in, carry_out; + int end_op; + + ot = (s->dflag == 2 ? OT_QUAD : OT_LONG); + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + + /* Re-use the carry-out from a previous round. */ + TCGV_UNUSED(carry_in); + carry_out = (b == 0x1f6 ? cpu_cc_dst : cpu_cc_src2); + switch (s->cc_op) { + case CC_OP_ADCX: + if (b == 0x1f6) { + carry_in = cpu_cc_dst; + end_op = CC_OP_ADCX; + } else { + end_op = CC_OP_ADCOX; + } + break; + case CC_OP_ADOX: + if (b == 0x1f6) { + end_op = CC_OP_ADCOX; + } else { + carry_in = cpu_cc_src2; + end_op = CC_OP_ADOX; + } + break; + case CC_OP_ADCOX: + end_op = CC_OP_ADCOX; + carry_in = carry_out; + break; + default: + end_op = (b == 0x1f6 ? CC_OP_ADCX : CC_OP_ADCOX); + break; + } + /* If we can't reuse carry-out, get it out of EFLAGS. */ + if (TCGV_IS_UNUSED(carry_in)) { + if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) { + gen_compute_eflags(s); + } + carry_in = cpu_tmp0; + tcg_gen_shri_tl(carry_in, cpu_cc_src, + ctz32(b == 0x1f6 ? CC_C : CC_O)); + tcg_gen_andi_tl(carry_in, carry_in, 1); + } + + switch (ot) { +#ifdef TARGET_X86_64 + case OT_LONG: + /* If we know TL is 64-bit, and we want a 32-bit + result, just do everything in 64-bit arithmetic. */ + tcg_gen_ext32u_i64(cpu_regs[reg], cpu_regs[reg]); + tcg_gen_ext32u_i64(cpu_T[0], cpu_T[0]); + tcg_gen_add_i64(cpu_T[0], cpu_T[0], cpu_regs[reg]); + tcg_gen_add_i64(cpu_T[0], cpu_T[0], carry_in); + tcg_gen_ext32u_i64(cpu_regs[reg], cpu_T[0]); + tcg_gen_shri_i64(carry_out, cpu_T[0], 32); + break; +#endif + default: + /* Otherwise compute the carry-out in two steps. */ + tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_regs[reg]); + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_tmp4, + cpu_T[0], cpu_regs[reg]); + tcg_gen_add_tl(cpu_regs[reg], cpu_T[0], carry_in); + tcg_gen_setcond_tl(TCG_COND_LTU, carry_out, + cpu_regs[reg], cpu_T[0]); + tcg_gen_or_tl(carry_out, carry_out, cpu_tmp4); + break; + } + /* We began with all flags computed to CC_SRC, and we + have now placed the carry-out in CC_DST. All that + is left is to record the CC_OP. */ + set_cc_op(s, end_op); + } + break; + case 0x1f7: /* shlx Gy, Ey, By */ case 0x2f7: /* sarx Gy, Ey, By */ case 0x3f7: /* shrx Gy, Ey, By */ From f1300734cbca515d30953b2c87e259fa378ea301 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 21 Jan 2013 11:52:26 -0800 Subject: [PATCH 1151/1634] target-i386: Use clz/ctz for bsf/bsr helpers And mark the helpers as NO_RWG_SE. Signed-off-by: Richard Henderson --- target-i386/helper.h | 6 +++--- target-i386/int_helper.c | 45 ++++++++++------------------------------ 2 files changed, 14 insertions(+), 37 deletions(-) diff --git a/target-i386/helper.h b/target-i386/helper.h index 81e0fbdd6d..e1ecdb81e9 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -195,9 +195,9 @@ DEF_HELPER_3(frstor, void, env, tl, int) DEF_HELPER_3(fxsave, void, env, tl, int) DEF_HELPER_3(fxrstor, void, env, tl, int) -DEF_HELPER_1(bsf, tl, tl) -DEF_HELPER_1(bsr, tl, tl) -DEF_HELPER_2(lzcnt, tl, tl, int) +DEF_HELPER_FLAGS_1(bsf, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(bsr, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_2(lzcnt, TCG_CALL_NO_RWG_SE, tl, tl, int) DEF_HELPER_FLAGS_2(pdep, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl) diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c index 527af40281..7bec4ebdd6 100644 --- a/target-i386/int_helper.c +++ b/target-i386/int_helper.c @@ -447,53 +447,30 @@ void helper_idivq_EAX(CPUX86State *env, target_ulong t0) } #endif +#if TARGET_LONG_BITS == 32 +# define ctztl ctz32 +# define clztl clz32 +#else +# define ctztl ctz64 +# define clztl clz64 +#endif + /* bit operations */ target_ulong helper_bsf(target_ulong t0) { - int count; - target_ulong res; - - res = t0; - count = 0; - while ((res & 1) == 0) { - count++; - res >>= 1; - } - return count; + return ctztl(t0); } target_ulong helper_lzcnt(target_ulong t0, int wordsize) { - int count; - target_ulong res, mask; - - if (wordsize > 0 && t0 == 0) { - return wordsize; - } - res = t0; - count = TARGET_LONG_BITS - 1; - mask = (target_ulong)1 << (TARGET_LONG_BITS - 1); - while ((res & mask) == 0) { - count--; - res <<= 1; - } - if (wordsize > 0) { - return wordsize - 1 - count; - } - return count; + return clztl(t0) - (TARGET_LONG_BITS - wordsize); } target_ulong helper_bsr(target_ulong t0) { - return helper_lzcnt(t0, 0); + return clztl(t0) ^ (TARGET_LONG_BITS - 1); } -#if TARGET_LONG_BITS == 32 -# define ctztl ctz32 -#else -# define ctztl ctz64 -#endif - target_ulong helper_pdep(target_ulong src, target_ulong mask) { target_ulong dest = 0; From 321c535105a182501b888f095f7ec4dbb5f3f6ae Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 21 Jan 2013 13:32:02 -0800 Subject: [PATCH 1152/1634] target-i386: Implement tzcnt and fix lzcnt We weren't computing flags for lzcnt at all. At the same time, adjust the implementation of bsf/bsr to avoid the local branch, using movcond instead. Signed-off-by: Richard Henderson --- target-i386/helper.h | 5 +-- target-i386/int_helper.c | 11 ++---- target-i386/translate.c | 84 +++++++++++++++++++++++----------------- 3 files changed, 53 insertions(+), 47 deletions(-) diff --git a/target-i386/helper.h b/target-i386/helper.h index e1ecdb81e9..26a0cc80a4 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -195,9 +195,8 @@ DEF_HELPER_3(frstor, void, env, tl, int) DEF_HELPER_3(fxsave, void, env, tl, int) DEF_HELPER_3(fxrstor, void, env, tl, int) -DEF_HELPER_FLAGS_1(bsf, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_FLAGS_1(bsr, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_FLAGS_2(lzcnt, TCG_CALL_NO_RWG_SE, tl, tl, int) +DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_2(pdep, TCG_CALL_NO_RWG_SE, tl, tl, tl) DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl) diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c index 7bec4ebdd6..3b56075a9d 100644 --- a/target-i386/int_helper.c +++ b/target-i386/int_helper.c @@ -456,19 +456,14 @@ void helper_idivq_EAX(CPUX86State *env, target_ulong t0) #endif /* bit operations */ -target_ulong helper_bsf(target_ulong t0) +target_ulong helper_ctz(target_ulong t0) { return ctztl(t0); } -target_ulong helper_lzcnt(target_ulong t0, int wordsize) +target_ulong helper_clz(target_ulong t0) { - return clztl(t0) - (TARGET_LONG_BITS - wordsize); -} - -target_ulong helper_bsr(target_ulong t0) -{ - return clztl(t0) ^ (TARGET_LONG_BITS - 1); + return clztl(t0); } target_ulong helper_pdep(target_ulong src, target_ulong mask) diff --git a/target-i386/translate.c b/target-i386/translate.c index 436658a33a..97c565f697 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7157,46 +7157,58 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_movi_tl(cpu_cc_dst, 0); } break; - case 0x1bc: /* bsf */ - case 0x1bd: /* bsr */ - { - int label1; - TCGv t0; + case 0x1bc: /* bsf / tzcnt */ + case 0x1bd: /* bsr / lzcnt */ + ot = dflag + OT_WORD; + modrm = cpu_ldub_code(env, s->pc++); + reg = ((modrm >> 3) & 7) | rex_r; + gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); + gen_extu(ot, cpu_T[0]); - ot = dflag + OT_WORD; - modrm = cpu_ldub_code(env, s->pc++); - reg = ((modrm >> 3) & 7) | rex_r; - gen_ldst_modrm(env, s,modrm, ot, OR_TMP0, 0); - gen_extu(ot, cpu_T[0]); - t0 = tcg_temp_local_new(); - tcg_gen_mov_tl(t0, cpu_T[0]); - if ((b & 1) && (prefixes & PREFIX_REPZ) && - (s->cpuid_ext3_features & CPUID_EXT3_ABM)) { - switch(ot) { - case OT_WORD: gen_helper_lzcnt(cpu_T[0], t0, - tcg_const_i32(16)); break; - case OT_LONG: gen_helper_lzcnt(cpu_T[0], t0, - tcg_const_i32(32)); break; - case OT_QUAD: gen_helper_lzcnt(cpu_T[0], t0, - tcg_const_i32(64)); break; - } - gen_op_mov_reg_T0(ot, reg); + /* Note that lzcnt and tzcnt are in different extensions. */ + if ((prefixes & PREFIX_REPZ) + && (b & 1 + ? s->cpuid_ext3_features & CPUID_EXT3_ABM + : s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)) { + int size = 8 << ot; + tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); + if (b & 1) { + /* For lzcnt, reduce the target_ulong result by the + number of zeros that we expect to find at the top. */ + gen_helper_clz(cpu_T[0], cpu_T[0]); + tcg_gen_subi_tl(cpu_T[0], cpu_T[0], TARGET_LONG_BITS - size); } else { - label1 = gen_new_label(); - tcg_gen_movi_tl(cpu_cc_dst, 0); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, label1); - if (b & 1) { - gen_helper_bsr(cpu_T[0], t0); - } else { - gen_helper_bsf(cpu_T[0], t0); - } - gen_op_mov_reg_T0(ot, reg); - tcg_gen_movi_tl(cpu_cc_dst, 1); - gen_set_label(label1); - set_cc_op(s, CC_OP_LOGICB + ot); + /* For tzcnt, a zero input must return the operand size: + force all bits outside the operand size to 1. */ + target_ulong mask = (target_ulong)-2 << (size - 1); + tcg_gen_ori_tl(cpu_T[0], cpu_T[0], mask); + gen_helper_ctz(cpu_T[0], cpu_T[0]); } - tcg_temp_free(t0); + /* For lzcnt/tzcnt, C and Z bits are defined and are + related to the result. */ + gen_op_update1_cc(); + set_cc_op(s, CC_OP_BMILGB + ot); + } else { + /* For bsr/bsf, only the Z bit is defined and it is related + to the input and not the result. */ + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + set_cc_op(s, CC_OP_LOGICB + ot); + if (b & 1) { + /* For bsr, return the bit index of the first 1 bit, + not the count of leading zeros. */ + gen_helper_clz(cpu_T[0], cpu_T[0]); + tcg_gen_xori_tl(cpu_T[0], cpu_T[0], TARGET_LONG_BITS - 1); + } else { + gen_helper_ctz(cpu_T[0], cpu_T[0]); + } + /* ??? The manual says that the output is undefined when the + input is zero, but real hardware leaves it unchanged, and + real programs appear to depend on that. */ + tcg_gen_movi_tl(cpu_tmp0, 0); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_T[0], cpu_cc_dst, cpu_tmp0, + cpu_regs[reg], cpu_T[0]); } + gen_op_mov_reg_T0(ot, reg); break; /************************/ /* bcd */ From 436ff2d227588d42970c4f0ed1cdfcb87c872fba Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Jan 2013 13:38:43 -0800 Subject: [PATCH 1153/1634] target-i386: Add CC_OP_CLR Special case xor with self. We need not even store the known zero into cc_src. Signed-off-by: Richard Henderson --- target-i386/cc_helper.c | 3 +++ target-i386/cpu.h | 2 ++ target-i386/helper.c | 2 ++ target-i386/translate.c | 17 ++++++++++++++--- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c index 6cf57a76b3..9daa1a06b8 100644 --- a/target-i386/cc_helper.c +++ b/target-i386/cc_helper.c @@ -102,6 +102,8 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, case CC_OP_EFLAGS: return src1; + case CC_OP_CLR: + return CC_Z; case CC_OP_MULB: return compute_all_mulb(dst, src1); @@ -228,6 +230,7 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, case CC_OP_LOGICW: case CC_OP_LOGICL: case CC_OP_LOGICQ: + case CC_OP_CLR: return 0; case CC_OP_EFLAGS: diff --git a/target-i386/cpu.h b/target-i386/cpu.h index e0443d8917..493dda8bb6 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -645,6 +645,8 @@ typedef enum { CC_OP_ADOX, /* CC_DST = O, CC_SRC = rest. */ CC_OP_ADCOX, /* CC_DST = C, CC_SRC2 = O, CC_SRC = rest. */ + CC_OP_CLR, /* Z set, all other flags clear. */ + CC_OP_NB, } CCOp; diff --git a/target-i386/helper.c b/target-i386/helper.c index 66c3624733..82a731c77d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -117,6 +117,8 @@ static const char *cc_op_str[CC_OP_NB] = { "ADCX", "ADOX", "ADCOX", + + "CLR", }; static void diff --git a/target-i386/translate.c b/target-i386/translate.c index 97c565f697..007d32602a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -213,6 +213,7 @@ static const uint8_t cc_op_live[CC_OP_NB] = { [CC_OP_ADCX] = USES_CC_DST | USES_CC_SRC, [CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2, [CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2, + [CC_OP_CLR] = 0, }; static void set_cc_op(DisasContext *s, CCOp op) @@ -906,6 +907,11 @@ static void gen_compute_eflags(DisasContext *s) if (s->cc_op == CC_OP_EFLAGS) { return; } + if (s->cc_op == CC_OP_CLR) { + tcg_gen_movi_tl(cpu_cc_src, CC_Z); + set_cc_op(s, CC_OP_EFLAGS); + return; + } TCGV_UNUSED(zero); dst = cpu_cc_dst; @@ -974,6 +980,7 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg) .reg2 = t1, .mask = -1, .use_reg2 = true }; case CC_OP_LOGICB ... CC_OP_LOGICQ: + case CC_OP_CLR: return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 }; case CC_OP_INCB ... CC_OP_INCQ: @@ -1040,6 +1047,8 @@ static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg) case CC_OP_ADCOX: return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, .mask = CC_S }; + case CC_OP_CLR: + return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 }; default: { int size = (s->cc_op - CC_OP_ADDB) & 3; @@ -1057,7 +1066,8 @@ static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg) case CC_OP_ADCOX: return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src2, .mask = -1, .no_setcond = true }; - + case CC_OP_CLR: + return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 }; default: gen_compute_eflags(s); return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, @@ -1078,6 +1088,8 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg) case CC_OP_ADCOX: return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src, .mask = CC_Z }; + case CC_OP_CLR: + return (CCPrepare) { .cond = TCG_COND_ALWAYS, .mask = -1 }; default: { int size = (s->cc_op - CC_OP_ADDB) & 3; @@ -4890,10 +4902,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } else if (op == OP_XORL && rm == reg) { xor_zero: /* xor reg, reg optimisation */ + set_cc_op(s, CC_OP_CLR); gen_op_movl_T0_0(); - set_cc_op(s, CC_OP_LOGICB + ot); gen_op_mov_reg_T0(ot, reg); - gen_op_update1_cc(); break; } else { opreg = rm; From a41f62f592d9ecf97df4a12023760fe082b1ee68 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Jan 2013 17:52:59 -0800 Subject: [PATCH 1154/1634] target-i386: Use movcond to implement shift flags. With this being all straight-line code, it can get deleted when the cc variables die. Signed-off-by: Richard Henderson --- target-i386/translate.c | 106 ++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 58 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 007d32602a..74694d180b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1572,15 +1572,9 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, int is_right, int is_arith) { - target_ulong mask; - int shift_label; - TCGv t0, t1, t2; - - if (ot == OT_QUAD) { - mask = 0x3f; - } else { - mask = 0x1f; - } + target_ulong mask = (ot == OT_QUAD ? 0x3f : 0x1f); + TCGv_i32 z32, s32, oldop; + TCGv z_tl; /* load */ if (op1 == OR_TMP0) { @@ -1589,25 +1583,22 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, gen_op_mov_TN_reg(ot, 0, op1); } - t0 = tcg_temp_local_new(); - t1 = tcg_temp_local_new(); - t2 = tcg_temp_local_new(); - - tcg_gen_andi_tl(t2, cpu_T[1], mask); + tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask); + tcg_gen_subi_tl(cpu_tmp0, cpu_T[1], 1); if (is_right) { if (is_arith) { gen_exts(ot, cpu_T[0]); - tcg_gen_mov_tl(t0, cpu_T[0]); - tcg_gen_sar_tl(cpu_T[0], cpu_T[0], t2); + tcg_gen_sar_tl(cpu_tmp0, cpu_T[0], cpu_tmp0); + tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]); } else { gen_extu(ot, cpu_T[0]); - tcg_gen_mov_tl(t0, cpu_T[0]); - tcg_gen_shr_tl(cpu_T[0], cpu_T[0], t2); + tcg_gen_shr_tl(cpu_tmp0, cpu_T[0], cpu_tmp0); + tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]); } } else { - tcg_gen_mov_tl(t0, cpu_T[0]); - tcg_gen_shl_tl(cpu_T[0], cpu_T[0], t2); + tcg_gen_shl_tl(cpu_tmp0, cpu_T[0], cpu_tmp0); + tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]); } /* store */ @@ -1617,50 +1608,49 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, gen_op_mov_reg_T0(ot, op1); } - /* Update eflags data because we cannot predict flags afterward. */ - gen_update_cc_op(s); + /* Store the results into the CC variables. If we know that the + variable must be dead, store unconditionally. Otherwise we'll + need to not disrupt the current contents. */ + z_tl = tcg_const_tl(0); + if (cc_op_live[s->cc_op] & USES_CC_DST) { + tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_dst, cpu_T[1], z_tl, + cpu_T[0], cpu_cc_dst); + } else { + tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); + } + if (cc_op_live[s->cc_op] & USES_CC_SRC) { + tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_src, cpu_T[1], z_tl, + cpu_tmp0, cpu_cc_src); + } else { + tcg_gen_mov_tl(cpu_cc_src, cpu_tmp0); + } + tcg_temp_free(z_tl); + + /* Get the two potential CC_OP values into temporaries. */ + tcg_gen_movi_i32(cpu_tmp2_i32, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot); + if (s->cc_op == CC_OP_DYNAMIC) { + oldop = cpu_cc_op; + } else { + tcg_gen_movi_i32(cpu_tmp3_i32, s->cc_op); + oldop = cpu_tmp3_i32; + } + + /* Conditionally store the CC_OP value. */ + z32 = tcg_const_i32(0); + s32 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(s32, cpu_T[1]); + tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, s32, z32, cpu_tmp2_i32, oldop); + tcg_temp_free_i32(z32); + tcg_temp_free_i32(s32); + + /* The CC_OP value is no longer predictable. */ set_cc_op(s, CC_OP_DYNAMIC); - - tcg_gen_mov_tl(t1, cpu_T[0]); - - shift_label = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, shift_label); - - tcg_gen_addi_tl(t2, t2, -1); - tcg_gen_mov_tl(cpu_cc_dst, t1); - - if (is_right) { - if (is_arith) { - tcg_gen_sar_tl(cpu_cc_src, t0, t2); - } else { - tcg_gen_shr_tl(cpu_cc_src, t0, t2); - } - } else { - tcg_gen_shl_tl(cpu_cc_src, t0, t2); - } - - if (is_right) { - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot); - } else { - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot); - } - - gen_set_label(shift_label); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); } static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2, int is_right, int is_arith) { - int mask; - - if (ot == OT_QUAD) - mask = 0x3f; - else - mask = 0x1f; + int mask = (ot == OT_QUAD ? 0x3f : 0x1f); /* load */ if (op1 == OR_TMP0) From 34d80a55ff8517fd37bcfea5063b9797e2bd9132 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Jan 2013 19:16:45 -0800 Subject: [PATCH 1155/1634] target-i386: Use movcond to implement rotate flags. With this being all straight-line code, it can get deleted when the cc variables die. Signed-off-by: Richard Henderson --- target-i386/translate.c | 233 ++++++++++++++++++++-------------------- 1 file changed, 119 insertions(+), 114 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 74694d180b..6b109e853b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1698,167 +1698,172 @@ static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2) tcg_gen_shri_tl(ret, arg1, -arg2); } -static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, - int is_right) +static void gen_rot_rm_T1(DisasContext *s, int ot, int op1, int is_right) { - target_ulong mask; - int label1, label2, data_bits; - TCGv t0, t1, t2, a0; - - /* XXX: inefficient, but we must use local temps */ - t0 = tcg_temp_local_new(); - t1 = tcg_temp_local_new(); - t2 = tcg_temp_local_new(); - a0 = tcg_temp_local_new(); - - if (ot == OT_QUAD) - mask = 0x3f; - else - mask = 0x1f; + target_ulong mask = (ot == OT_QUAD ? 0x3f : 0x1f); + TCGv_i32 t0, t1; /* load */ if (op1 == OR_TMP0) { - tcg_gen_mov_tl(a0, cpu_A0); - gen_op_ld_v(ot + s->mem_index, t0, a0); + gen_op_ld_T0_A0(ot + s->mem_index); } else { - gen_op_mov_v_reg(ot, t0, op1); + gen_op_mov_TN_reg(ot, 0, op1); } - tcg_gen_mov_tl(t1, cpu_T[1]); + tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask); - tcg_gen_andi_tl(t1, t1, mask); - - /* Must test zero case to avoid using undefined behaviour in TCG - shifts. */ - label1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label1); - - if (ot <= OT_WORD) - tcg_gen_andi_tl(cpu_tmp0, t1, (1 << (3 + ot)) - 1); - else - tcg_gen_mov_tl(cpu_tmp0, t1); - - gen_extu(ot, t0); - tcg_gen_mov_tl(t2, t0); - - data_bits = 8 << ot; - /* XXX: rely on behaviour of shifts when operand 2 overflows (XXX: - fix TCG definition) */ - if (is_right) { - tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp0); - tcg_gen_subfi_tl(cpu_tmp0, data_bits, cpu_tmp0); - tcg_gen_shl_tl(t0, t0, cpu_tmp0); - } else { - tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp0); - tcg_gen_subfi_tl(cpu_tmp0, data_bits, cpu_tmp0); - tcg_gen_shr_tl(t0, t0, cpu_tmp0); + switch (ot) { + case OT_BYTE: + /* Replicate the 8-bit input so that a 32-bit rotate works. */ + tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]); + tcg_gen_muli_tl(cpu_T[0], cpu_T[0], 0x01010101); + goto do_long; + case OT_WORD: + /* Replicate the 16-bit input so that a 32-bit rotate works. */ + tcg_gen_deposit_tl(cpu_T[0], cpu_T[0], cpu_T[0], 16, 16); + goto do_long; + do_long: +#ifdef TARGET_X86_64 + case OT_LONG: + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); + if (is_right) { + tcg_gen_rotr_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32); + } else { + tcg_gen_rotl_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32); + } + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + break; +#endif + default: + if (is_right) { + tcg_gen_rotr_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } else { + tcg_gen_rotl_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + } + break; } - tcg_gen_or_tl(t0, t0, cpu_tmp4); - gen_set_label(label1); /* store */ if (op1 == OR_TMP0) { - gen_op_st_v(ot + s->mem_index, t0, a0); + gen_op_st_T0_A0(ot + s->mem_index); } else { - gen_op_mov_reg_v(ot, op1, t0); + gen_op_mov_reg_T0(ot, op1); } - - /* update eflags. It is needed anyway most of the time, do it always. */ + + /* We'll need the flags computed into CC_SRC. */ gen_compute_eflags(s); - assert(s->cc_op == CC_OP_EFLAGS); - label2 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label2); - - tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); - tcg_gen_xor_tl(cpu_tmp0, t2, t0); - tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1)); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O); - tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0); + /* The value that was "rotated out" is now present at the other end + of the word. Compute C into CC_DST and O into CC_SRC2. Note that + since we've computed the flags into CC_SRC, these variables are + currently dead. */ if (is_right) { - tcg_gen_shri_tl(t0, t0, data_bits - 1); + tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask - 1); + tcg_gen_shri_tl(cpu_cc_dst, cpu_T[0], mask); + } else { + tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask); + tcg_gen_andi_tl(cpu_cc_dst, cpu_T[0], 1); } - tcg_gen_andi_tl(t0, t0, CC_C); - tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); + tcg_gen_andi_tl(cpu_cc_src2, cpu_cc_src2, 1); + tcg_gen_xor_tl(cpu_cc_src2, cpu_cc_src2, cpu_cc_dst); - gen_set_label(label2); + /* Now conditionally store the new CC_OP value. If the shift count + is 0 we keep the CC_OP_EFLAGS setting so that only CC_SRC is live. + Otherwise reuse CC_OP_ADCOX which have the C and O flags split out + exactly as we computed above. */ + t0 = tcg_const_i32(0); + t1 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t1, cpu_T[1]); + tcg_gen_movi_i32(cpu_tmp2_i32, CC_OP_ADCOX); + tcg_gen_movi_i32(cpu_tmp3_i32, CC_OP_EFLAGS); + tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, t1, t0, + cpu_tmp2_i32, cpu_tmp3_i32); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); - tcg_temp_free(a0); + /* The CC_OP value is no longer predictable. */ + set_cc_op(s, CC_OP_DYNAMIC); } static void gen_rot_rm_im(DisasContext *s, int ot, int op1, int op2, int is_right) { - int mask; - int data_bits; - TCGv t0, t1, a0; - - /* XXX: inefficient, but we must use local temps */ - t0 = tcg_temp_local_new(); - t1 = tcg_temp_local_new(); - a0 = tcg_temp_local_new(); - - if (ot == OT_QUAD) - mask = 0x3f; - else - mask = 0x1f; + int mask = (ot == OT_QUAD ? 0x3f : 0x1f); + int shift; /* load */ if (op1 == OR_TMP0) { - tcg_gen_mov_tl(a0, cpu_A0); - gen_op_ld_v(ot + s->mem_index, t0, a0); + gen_op_ld_T0_A0(ot + s->mem_index); } else { - gen_op_mov_v_reg(ot, t0, op1); + gen_op_mov_TN_reg(ot, 0, op1); } - gen_extu(ot, t0); - tcg_gen_mov_tl(t1, t0); - op2 &= mask; - data_bits = 8 << ot; if (op2 != 0) { - int shift = op2 & ((1 << (3 + ot)) - 1); - if (is_right) { - tcg_gen_shri_tl(cpu_tmp4, t0, shift); - tcg_gen_shli_tl(t0, t0, data_bits - shift); + switch (ot) { +#ifdef TARGET_X86_64 + case OT_LONG: + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + if (is_right) { + tcg_gen_rotri_i32(cpu_tmp2_i32, cpu_tmp2_i32, op2); + } else { + tcg_gen_rotli_i32(cpu_tmp2_i32, cpu_tmp2_i32, op2); + } + tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); + break; +#endif + default: + if (is_right) { + tcg_gen_rotri_tl(cpu_T[0], cpu_T[0], op2); + } else { + tcg_gen_rotli_tl(cpu_T[0], cpu_T[0], op2); + } + break; + case OT_BYTE: + mask = 7; + goto do_shifts; + case OT_WORD: + mask = 15; + do_shifts: + shift = op2 & mask; + if (is_right) { + shift = mask + 1 - shift; + } + gen_extu(ot, cpu_T[0]); + tcg_gen_shli_tl(cpu_tmp0, cpu_T[0], shift); + tcg_gen_shri_tl(cpu_T[0], cpu_T[0], mask + 1 - shift); + tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0); + break; } - else { - tcg_gen_shli_tl(cpu_tmp4, t0, shift); - tcg_gen_shri_tl(t0, t0, data_bits - shift); - } - tcg_gen_or_tl(t0, t0, cpu_tmp4); } /* store */ if (op1 == OR_TMP0) { - gen_op_st_v(ot + s->mem_index, t0, a0); + gen_op_st_T0_A0(ot + s->mem_index); } else { - gen_op_mov_reg_v(ot, op1, t0); + gen_op_mov_reg_T0(ot, op1); } if (op2 != 0) { - /* update eflags */ + /* Compute the flags into CC_SRC. */ gen_compute_eflags(s); - assert(s->cc_op == CC_OP_EFLAGS); - tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C)); - tcg_gen_xor_tl(cpu_tmp0, t1, t0); - tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1)); - tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O); - tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0); + /* The value that was "rotated out" is now present at the other end + of the word. Compute C into CC_DST and O into CC_SRC2. Note that + since we've computed the flags into CC_SRC, these variables are + currently dead. */ if (is_right) { - tcg_gen_shri_tl(t0, t0, data_bits - 1); + tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask - 1); + tcg_gen_shri_tl(cpu_cc_dst, cpu_T[0], mask); + } else { + tcg_gen_shri_tl(cpu_cc_src2, cpu_T[0], mask); + tcg_gen_andi_tl(cpu_cc_dst, cpu_T[0], 1); } - tcg_gen_andi_tl(t0, t0, CC_C); - tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0); + tcg_gen_andi_tl(cpu_cc_src2, cpu_cc_src2, 1); + tcg_gen_xor_tl(cpu_cc_src2, cpu_cc_src2, cpu_cc_dst); + set_cc_op(s, CC_OP_ADCOX); } - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(a0); } /* XXX: add faster immediate = 1 case */ From e2f515cf2f3795b9edb68eee42262e7c5f88fe98 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 14:48:43 -0800 Subject: [PATCH 1156/1634] target-i386: Discard CC_OP computation in set_cc_op also The shift and rotate insns use movcond to set CC_OP, and thus achieve a conditional EFLAGS setting. By discarding CC_OP in a later flags setting insn, we can discard that movcond. Signed-off-by: Richard Henderson --- target-i386/translate.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 6b109e853b..b9a2692991 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -239,10 +239,18 @@ static void set_cc_op(DisasContext *s, CCOp op) tcg_gen_discard_tl(cpu_cc_srcT); } + if (op == CC_OP_DYNAMIC) { + /* The DYNAMIC setting is translator only, and should never be + stored. Thus we always consider it clean. */ + s->cc_op_dirty = false; + } else { + /* Discard any computed CC_OP value (see shifts). */ + if (s->cc_op == CC_OP_DYNAMIC) { + tcg_gen_discard_i32(cpu_cc_op); + } + s->cc_op_dirty = true; + } s->cc_op = op; - /* The DYNAMIC setting is translator only, and should never be - stored. Thus we always consider it clean. */ - s->cc_op_dirty = (op != CC_OP_DYNAMIC); } static void gen_update_cc_op(DisasContext *s) From f437d0a3c24e471a855da33a086fe529e09a06af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 21:06:31 -0800 Subject: [PATCH 1157/1634] target-i386: Use movcond to implement shiftd. With this being all straight-line code, it can get deleted when the cc variables die. Signed-off-by: Richard Henderson --- target-i386/translate.c | 249 +++++++++++++++++----------------------- 1 file changed, 107 insertions(+), 142 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index b9a2692991..439d19efe0 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -72,7 +72,6 @@ static TCGv cpu_tmp0, cpu_tmp4; static TCGv_ptr cpu_ptr0, cpu_ptr1; static TCGv_i32 cpu_tmp2_i32, cpu_tmp3_i32; static TCGv_i64 cpu_tmp1_i64; -static TCGv cpu_tmp5; static uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; @@ -1577,12 +1576,55 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); } +static void gen_shift_flags(DisasContext *s, int ot, TCGv result, TCGv shm1, + TCGv count, bool is_right) +{ + TCGv_i32 z32, s32, oldop; + TCGv z_tl; + + /* Store the results into the CC variables. If we know that the + variable must be dead, store unconditionally. Otherwise we'll + need to not disrupt the current contents. */ + z_tl = tcg_const_tl(0); + if (cc_op_live[s->cc_op] & USES_CC_DST) { + tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_dst, count, z_tl, + result, cpu_cc_dst); + } else { + tcg_gen_mov_tl(cpu_cc_dst, result); + } + if (cc_op_live[s->cc_op] & USES_CC_SRC) { + tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_src, count, z_tl, + shm1, cpu_cc_src); + } else { + tcg_gen_mov_tl(cpu_cc_src, shm1); + } + tcg_temp_free(z_tl); + + /* Get the two potential CC_OP values into temporaries. */ + tcg_gen_movi_i32(cpu_tmp2_i32, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot); + if (s->cc_op == CC_OP_DYNAMIC) { + oldop = cpu_cc_op; + } else { + tcg_gen_movi_i32(cpu_tmp3_i32, s->cc_op); + oldop = cpu_tmp3_i32; + } + + /* Conditionally store the CC_OP value. */ + z32 = tcg_const_i32(0); + s32 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(s32, count); + tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, s32, z32, cpu_tmp2_i32, oldop); + tcg_temp_free_i32(z32); + tcg_temp_free_i32(s32); + + /* The CC_OP value is no longer predictable. */ + set_cc_op(s, CC_OP_DYNAMIC); +} + static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, int is_right, int is_arith) { target_ulong mask = (ot == OT_QUAD ? 0x3f : 0x1f); - TCGv_i32 z32, s32, oldop; - TCGv z_tl; /* load */ if (op1 == OR_TMP0) { @@ -1616,43 +1658,7 @@ static void gen_shift_rm_T1(DisasContext *s, int ot, int op1, gen_op_mov_reg_T0(ot, op1); } - /* Store the results into the CC variables. If we know that the - variable must be dead, store unconditionally. Otherwise we'll - need to not disrupt the current contents. */ - z_tl = tcg_const_tl(0); - if (cc_op_live[s->cc_op] & USES_CC_DST) { - tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_dst, cpu_T[1], z_tl, - cpu_T[0], cpu_cc_dst); - } else { - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - } - if (cc_op_live[s->cc_op] & USES_CC_SRC) { - tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_src, cpu_T[1], z_tl, - cpu_tmp0, cpu_cc_src); - } else { - tcg_gen_mov_tl(cpu_cc_src, cpu_tmp0); - } - tcg_temp_free(z_tl); - - /* Get the two potential CC_OP values into temporaries. */ - tcg_gen_movi_i32(cpu_tmp2_i32, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot); - if (s->cc_op == CC_OP_DYNAMIC) { - oldop = cpu_cc_op; - } else { - tcg_gen_movi_i32(cpu_tmp3_i32, s->cc_op); - oldop = cpu_tmp3_i32; - } - - /* Conditionally store the CC_OP value. */ - z32 = tcg_const_i32(0); - s32 = tcg_temp_new_i32(); - tcg_gen_trunc_tl_i32(s32, cpu_T[1]); - tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, s32, z32, cpu_tmp2_i32, oldop); - tcg_temp_free_i32(z32); - tcg_temp_free_i32(s32); - - /* The CC_OP value is no longer predictable. */ - set_cc_op(s, CC_OP_DYNAMIC); + gen_shift_flags(s, ot, cpu_T[0], cpu_tmp0, cpu_T[1], is_right); } static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2, @@ -1931,128 +1937,88 @@ static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1, /* XXX: add faster immediate case */ static void gen_shiftd_rm_T1(DisasContext *s, int ot, int op1, - int is_right, TCGv count) + bool is_right, TCGv count_in) { - int label1, label2, data_bits; - target_ulong mask; - TCGv t0, t1, t2, a0; - - t0 = tcg_temp_local_new(); - t1 = tcg_temp_local_new(); - t2 = tcg_temp_local_new(); - a0 = tcg_temp_local_new(); - - if (ot == OT_QUAD) - mask = 0x3f; - else - mask = 0x1f; + target_ulong mask = (ot == OT_QUAD ? 63 : 31); + TCGv count; /* load */ if (op1 == OR_TMP0) { - tcg_gen_mov_tl(a0, cpu_A0); - gen_op_ld_v(ot + s->mem_index, t0, a0); + gen_op_ld_T0_A0(ot + s->mem_index); } else { - gen_op_mov_v_reg(ot, t0, op1); + gen_op_mov_TN_reg(ot, 0, op1); } - tcg_gen_andi_tl(t2, count, mask); - tcg_gen_mov_tl(t1, cpu_T[1]); + count = tcg_temp_new(); + tcg_gen_andi_tl(count, count_in, mask); - /* Must test zero case to avoid using undefined behaviour in TCG - shifts. */ - label1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1); - - tcg_gen_addi_tl(cpu_tmp5, t2, -1); - if (ot == OT_WORD) { - /* Note: we implement the Intel behaviour for shift count > 16 */ + switch (ot) { + case OT_WORD: + /* Note: we implement the Intel behaviour for shift count > 16. + This means "shrdw C, B, A" shifts A:B:A >> C. Build the B:A + portion by constructing it as a 32-bit value. */ if (is_right) { - tcg_gen_andi_tl(t0, t0, 0xffff); - tcg_gen_shli_tl(cpu_tmp0, t1, 16); - tcg_gen_or_tl(t0, t0, cpu_tmp0); - tcg_gen_ext32u_tl(t0, t0); - - tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5); - - /* only needed if count > 16, but a test would complicate */ - tcg_gen_subfi_tl(cpu_tmp5, 32, t2); - tcg_gen_shl_tl(cpu_tmp0, t0, cpu_tmp5); - - tcg_gen_shr_tl(t0, t0, t2); - - tcg_gen_or_tl(t0, t0, cpu_tmp0); + tcg_gen_deposit_tl(cpu_tmp0, cpu_T[0], cpu_T[1], 16, 16); + tcg_gen_mov_tl(cpu_T[1], cpu_T[0]); + tcg_gen_mov_tl(cpu_T[0], cpu_tmp0); } else { - /* XXX: not optimal */ - tcg_gen_andi_tl(t0, t0, 0xffff); - tcg_gen_shli_tl(t1, t1, 16); - tcg_gen_or_tl(t1, t1, t0); - tcg_gen_ext32u_tl(t1, t1); - - tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5); - tcg_gen_subfi_tl(cpu_tmp0, 32, cpu_tmp5); - tcg_gen_shr_tl(cpu_tmp5, t1, cpu_tmp0); - tcg_gen_or_tl(cpu_tmp4, cpu_tmp4, cpu_tmp5); - - tcg_gen_shl_tl(t0, t0, t2); - tcg_gen_subfi_tl(cpu_tmp5, 32, t2); - tcg_gen_shr_tl(t1, t1, cpu_tmp5); - tcg_gen_or_tl(t0, t0, t1); + tcg_gen_deposit_tl(cpu_T[1], cpu_T[0], cpu_T[1], 16, 16); } - } else { - data_bits = 8 << ot; + /* FALLTHRU */ +#ifdef TARGET_X86_64 + case OT_LONG: + /* Concatenate the two 32-bit values and use a 64-bit shift. */ + tcg_gen_subi_tl(cpu_tmp0, count, 1); if (is_right) { - if (ot == OT_LONG) - tcg_gen_ext32u_tl(t0, t0); - - tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5); - - tcg_gen_shr_tl(t0, t0, t2); - tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2); - tcg_gen_shl_tl(t1, t1, cpu_tmp5); - tcg_gen_or_tl(t0, t0, t1); - + tcg_gen_concat_tl_i64(cpu_T[0], cpu_T[0], cpu_T[1]); + tcg_gen_shr_i64(cpu_tmp0, cpu_T[0], cpu_tmp0); + tcg_gen_shr_i64(cpu_T[0], cpu_T[0], count); } else { - if (ot == OT_LONG) - tcg_gen_ext32u_tl(t1, t1); - - tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5); - - tcg_gen_shl_tl(t0, t0, t2); - tcg_gen_subfi_tl(cpu_tmp5, data_bits, t2); - tcg_gen_shr_tl(t1, t1, cpu_tmp5); - tcg_gen_or_tl(t0, t0, t1); + tcg_gen_concat_tl_i64(cpu_T[0], cpu_T[1], cpu_T[0]); + tcg_gen_shl_i64(cpu_tmp0, cpu_T[0], cpu_tmp0); + tcg_gen_shl_i64(cpu_T[0], cpu_T[0], count); + tcg_gen_shri_i64(cpu_tmp0, cpu_tmp0, 32); + tcg_gen_shri_i64(cpu_T[0], cpu_T[0], 32); } + break; +#endif + default: + tcg_gen_subi_tl(cpu_tmp0, count, 1); + if (is_right) { + tcg_gen_shr_tl(cpu_tmp0, cpu_T[0], cpu_tmp0); + + tcg_gen_subfi_tl(cpu_tmp4, mask + 1, count); + tcg_gen_shr_tl(cpu_T[0], cpu_T[0], count); + tcg_gen_shl_tl(cpu_T[1], cpu_T[1], cpu_tmp4); + } else { + tcg_gen_shl_tl(cpu_tmp0, cpu_T[0], cpu_tmp0); + if (ot == OT_WORD) { + /* Only needed if count > 16, for Intel behaviour. */ + tcg_gen_subfi_tl(cpu_tmp4, 33, count); + tcg_gen_shr_tl(cpu_tmp4, cpu_T[1], cpu_tmp4); + tcg_gen_or_tl(cpu_tmp0, cpu_tmp0, cpu_tmp4); + } + + tcg_gen_subfi_tl(cpu_tmp4, mask + 1, count); + tcg_gen_shl_tl(cpu_T[0], cpu_T[0], count); + tcg_gen_shr_tl(cpu_T[1], cpu_T[1], cpu_tmp4); + } + tcg_gen_movi_tl(cpu_tmp4, 0); + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_T[1], count, cpu_tmp4, + cpu_tmp4, cpu_T[1]); + tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]); + break; } - tcg_gen_mov_tl(t1, cpu_tmp4); - gen_set_label(label1); /* store */ if (op1 == OR_TMP0) { - gen_op_st_v(ot + s->mem_index, t0, a0); + gen_op_st_T0_A0(ot + s->mem_index); } else { - gen_op_mov_reg_v(ot, op1, t0); + gen_op_mov_reg_T0(ot, op1); } - - /* Update eflags data because we cannot predict flags afterward. */ - gen_update_cc_op(s); - set_cc_op(s, CC_OP_DYNAMIC); - label2 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label2); - - tcg_gen_mov_tl(cpu_cc_src, t1); - tcg_gen_mov_tl(cpu_cc_dst, t0); - if (is_right) { - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot); - } else { - tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot); - } - gen_set_label(label2); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); - tcg_temp_free(a0); + gen_shift_flags(s, ot, cpu_T[0], cpu_tmp0, count, is_right); + tcg_temp_free(count); } static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) @@ -8401,7 +8367,6 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, cpu_tmp2_i32 = tcg_temp_new_i32(); cpu_tmp3_i32 = tcg_temp_new_i32(); cpu_tmp4 = tcg_temp_new(); - cpu_tmp5 = tcg_temp_new(); cpu_ptr0 = tcg_temp_new_ptr(); cpu_ptr1 = tcg_temp_new_ptr(); cpu_cc_srcT = tcg_temp_local_new(); From 87f1361c193c77dad428a7aa9bdce7ae2b76871f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sun, 10 Feb 2013 23:11:05 +0100 Subject: [PATCH 1158/1634] Remove forward declaration of non-existant variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This variable has been removed 5 years ago in 970ac5a3082428dca91171f270dcd95d6f4b2636. Signed-off-by: Hervé Poussineau Signed-off-by: Stefan Hajnoczi --- include/sysemu/sysemu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index 1d9599e5f4..ae49088d42 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -94,7 +94,6 @@ typedef enum DisplayType } DisplayType; extern int autostart; -extern int bios_size; typedef enum { VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL, From b15aaca4303fe009870842dd922a0128b332a2fd Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 11 Feb 2013 17:16:05 +1000 Subject: [PATCH 1159/1634] xilinx_axienet.c: Assert no error when making link This gives an awful silent failure when it doesn't work. Assert against link creation failure. Signed-off-by: Peter Crosthwaite Signed-off-by: Stefan Hajnoczi --- hw/xilinx_axienet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 34e344ce2c..e5d9251b8b 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -869,9 +869,11 @@ static int xilinx_enet_init(SysBusDevice *dev) static void xilinx_enet_initfn(Object *obj) { struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj)); + Error *errp = NULL; object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, - (Object **) &s->tx_dev, NULL); + (Object **) &s->tx_dev, &errp); + assert_no_error(errp); } static Property xilinx_enet_properties[] = { From 499a6165bef56ce3f5297fa7b1abaab32858a34f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 21 Feb 2013 13:34:40 +1100 Subject: [PATCH 1160/1634] Add some missing qtest binaries to .gitignore These binaries are generated during make check on at least some configurations, so att them to .gitignore. Signed-off-by: David Gibson Signed-off-by: Stefan Hajnoczi --- tests/.gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/.gitignore b/tests/.gitignore index 38c94ef1da..fb05c2ae87 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -4,11 +4,18 @@ check-qint check-qjson check-qlist check-qstring +test-aio +test-cutils +test-hbitmap +test-iov +test-mul64 test-qapi-types.[ch] test-qapi-visit.[ch] test-qmp-commands.h test-qmp-commands test-qmp-input-strict test-qmp-marshal.c +test-thread-pool test-x86-cpuid +test-xbzrle *-test From 11e5d738a4c68cd20e90477fa8b7ee873bf3e2c0 Mon Sep 17 00:00:00 2001 From: Alin Tomescu Date: Wed, 20 Feb 2013 21:36:09 -0500 Subject: [PATCH 1161/1634] ppc: fix bamboo >256MB RAM initialization in hw/ppc4xx_devs.c I was trying to launch a PowerPC "bamboo" machine with more than 256MB of RAM with qemu-system-ppc -M bamboo -kernel $kernel -initrd $ramdisk -m 512, but QEMU would just hang. However, when I used -m 256, the machine would boot. I looked through the code in hw/ and it seems there is an error when the RAM memory is setup (if my understanding is correct). After patching it, the machine launched and booted successfully with 512MB of RAM. Signed-off-by: Alin Tomescu Signed-off-by: Stefan Hajnoczi --- hw/ppc4xx_devs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index 5e491bc0b4..b6bb0e166a 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -700,7 +700,7 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks, vmstate_register_ram_global(&ram_memories[i]); ram_bases[i] = base; ram_sizes[i] = bank_size; - base += ram_size; + base += bank_size; size_left -= bank_size; break; } From 159c9836d057d8990e71399e8a431b2b911e2885 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Tue, 19 Feb 2013 17:41:28 -0500 Subject: [PATCH 1162/1634] .gitignore: Ignore optionrom/*.asm Signed-off-by: Cole Robinson Signed-off-by: Stefan Hajnoczi --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 53fe9c3078..27ad002970 100644 --- a/.gitignore +++ b/.gitignore @@ -83,12 +83,15 @@ fsdev/virtfs-proxy-helper.pod patches pc-bios/bios-pq/status pc-bios/vgabios-pq/status +pc-bios/optionrom/linuxboot.asm pc-bios/optionrom/linuxboot.bin pc-bios/optionrom/linuxboot.raw pc-bios/optionrom/linuxboot.img +pc-bios/optionrom/multiboot.asm pc-bios/optionrom/multiboot.bin pc-bios/optionrom/multiboot.raw pc-bios/optionrom/multiboot.img +pc-bios/optionrom/kvmvapic.asm pc-bios/optionrom/kvmvapic.bin pc-bios/optionrom/kvmvapic.raw pc-bios/optionrom/kvmvapic.img From 3960c41f05bf776cc23a4a3b861f729fa65295a5 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 5 Feb 2013 09:30:55 +0100 Subject: [PATCH 1163/1634] check-qjson: More thorough testing of UTF-8 in strings Test cases are scraped from Markus Kuhn's UTF-8 decoder capability and stress test at http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt Unfortunately, both JSON parser and formatter misbehave right now. This test expects current, incorrect results. They're all clearly marked, and are to be replaced by correct ones as the bugs get fixed. See comments in new utf8_string() for details. Signed-off-by: Markus Armbruster Signed-off-by: Luiz Capitulino --- tests/check-qjson.c | 664 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 664 insertions(+) diff --git a/tests/check-qjson.c b/tests/check-qjson.c index 32ffb436df..ec85a0cf2d 100644 --- a/tests/check-qjson.c +++ b/tests/check-qjson.c @@ -1,8 +1,10 @@ /* * Copyright IBM, Corp. 2009 + * Copyright (c) 2013 Red Hat Inc. * * Authors: * Anthony Liguori + * Markus Armbruster , * * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. * See the COPYING.LIB file in the top-level directory. @@ -131,6 +133,667 @@ static void single_quote_string(void) } } +static void utf8_string(void) +{ + /* + * FIXME Current behavior for invalid UTF-8 sequences is + * incorrect. This test expects current, incorrect results. + * They're all marked "bug:" below, and are to be replaced by + * correct ones as the bugs get fixed. + * + * The JSON parser rejects some invalid sequences, but accepts + * others without correcting the problem. + * + * The JSON formatter replaces some invalid sequences by U+FFFF (a + * noncharacter), and goes wonky for others. + * + * For both directions, we should either reject all invalid + * sequences, or minimize overlong sequences and replace all other + * invalid sequences by a suitable replacement character. A + * common choice for replacement is U+FFFD. + * + * Problem: we can't easily deal with embedded U+0000. Parsing + * the JSON string "this \\u0000" is fun" yields "this \0 is fun", + * which gets misinterpreted as NUL-terminated "this ". We should + * consider using overlong encoding \xC0\x80 for U+0000 ("modified + * UTF-8"). + * + * Test cases are scraped from Markus Kuhn's UTF-8 decoder + * capability and stress test at + * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + */ + static const struct { + const char *json_in; + const char *utf8_out; + const char *json_out; /* defaults to @json_in */ + const char *utf8_in; /* defaults to @utf8_out */ + } test_cases[] = { + /* + * Bug markers used here: + * - bug: not corrected + * JSON parser fails to correct invalid sequence(s) + * - bug: rejected + * JSON parser rejects invalid sequence(s) + * We may choose to define this as feature + * - bug: want "\"...\"" + * JSON formatter produces incorrect result, this is the + * correct one, assuming replacement character U+FFFF + * - bug: want "..." (no \") + * JSON parser produces incorrect result, this is the + * correct one, assuming replacement character U+FFFF + * We may choose to reject instead of replace + * Not marked explicitly, but trivial to find: + * - JSON formatter replacing invalid sequence by \\uFFFF is a + * bug if we want it to fail for invalid sequences. + */ + + /* 1 Some correct UTF-8 text */ + { + /* a bit of German */ + "\"Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt" + " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.\"", + "Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt" + " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.", + "\"Falsches \\u00DCben von Xylophonmusik qu\\u00E4lt" + " jeden gr\\u00F6\\u00DFeren Zwerg.\"", + }, + { + /* a bit of Greek */ + "\"\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5\"", + "\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5", + "\"\\u03BA\\u1F79\\u03C3\\u03BC\\u03B5\"", + }, + /* 2 Boundary condition test cases */ + /* 2.1 First possible sequence of a certain length */ + /* 2.1.1 1 byte U+0000 */ + { + "\"\\u0000\"", + "", /* bug: want overlong "\xC0\x80" */ + "\"\"", /* bug: want "\"\\u0000\"" */ + }, + /* 2.1.2 2 bytes U+0080 */ + { + "\"\xC2\x80\"", + "\xC2\x80", + "\"\\u0080\"", + }, + /* 2.1.3 3 bytes U+0800 */ + { + "\"\xE0\xA0\x80\"", + "\xE0\xA0\x80", + "\"\\u0800\"", + }, + /* 2.1.4 4 bytes U+10000 */ + { + "\"\xF0\x90\x80\x80\"", + "\xF0\x90\x80\x80", + "\"\\u0400\\uFFFF\"", /* bug: want "\"\\uD800\\uDC00\"" */ + }, + /* 2.1.5 5 bytes U+200000 */ + { + "\"\xF8\x88\x80\x80\x80\"", + NULL, /* bug: rejected */ + "\"\\u8200\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xF8\x88\x80\x80\x80", + }, + /* 2.1.6 6 bytes U+4000000 */ + { + "\"\xFC\x84\x80\x80\x80\x80\"", + NULL, /* bug: rejected */ + "\"\\uC100\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xFC\x84\x80\x80\x80\x80", + }, + /* 2.2 Last possible sequence of a certain length */ + /* 2.2.1 1 byte U+007F */ + { + "\"\x7F\"", + "\x7F", + "\"\177\"", + }, + /* 2.2.2 2 bytes U+07FF */ + { + "\"\xDF\xBF\"", + "\xDF\xBF", + "\"\\u07FF\"", + }, + /* 2.2.3 3 bytes U+FFFF */ + { + "\"\xEF\xBF\xBF\"", + "\xEF\xBF\xBF", + "\"\\uFFFF\"", + }, + /* 2.2.4 4 bytes U+1FFFFF */ + { + "\"\xF7\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\u7FFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xF7\xBF\xBF\xBF", + }, + /* 2.2.5 5 bytes U+3FFFFFF */ + { + "\"\xFB\xBF\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\uBFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xFB\xBF\xBF\xBF\xBF", + }, + /* 2.2.6 6 bytes U+7FFFFFFF */ + { + "\"\xFD\xBF\xBF\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\uDFFF\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xFD\xBF\xBF\xBF\xBF\xBF", + }, + /* 2.3 Other boundary conditions */ + { + /* U+D7FF */ + "\"\xED\x9F\xBF\"", + "\xED\x9F\xBF", + "\"\\uD7FF\"", + }, + { + /* U+E000 */ + "\"\xEE\x80\x80\"", + "\xEE\x80\x80", + "\"\\uE000\"", + }, + { + /* U+FFFD */ + "\"\xEF\xBF\xBD\"", + "\xEF\xBF\xBD", + "\"\\uFFFD\"", + }, + { + /* U+10FFFF */ + "\"\xF4\x8F\xBF\xBF\"", + "\xF4\x8F\xBF\xBF", + "\"\\u43FF\\uFFFF\"", /* bug: want "\"\\uDBFF\\uDFFF\"" */ + }, + { + /* U+110000 */ + "\"\xF4\x90\x80\x80\"", + "\xF4\x90\x80\x80", + "\"\\u4400\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + }, + /* 3 Malformed sequences */ + /* 3.1 Unexpected continuation bytes */ + /* 3.1.1 First continuation byte */ + { + "\"\x80\"", + "\x80", /* bug: not corrected */ + "\"\\uFFFF\"", + }, + /* 3.1.2 Last continuation byte */ + { + "\"\xBF\"", + "\xBF", /* bug: not corrected */ + "\"\\uFFFF\"", + }, + /* 3.1.3 2 continuation bytes */ + { + "\"\x80\xBF\"", + "\x80\xBF", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\"", + }, + /* 3.1.4 3 continuation bytes */ + { + "\"\x80\xBF\x80\"", + "\x80\xBF\x80", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\\uFFFF\"", + }, + /* 3.1.5 4 continuation bytes */ + { + "\"\x80\xBF\x80\xBF\"", + "\x80\xBF\x80\xBF", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"", + }, + /* 3.1.6 5 continuation bytes */ + { + "\"\x80\xBF\x80\xBF\x80\"", + "\x80\xBF\x80\xBF\x80", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"", + }, + /* 3.1.7 6 continuation bytes */ + { + "\"\x80\xBF\x80\xBF\x80\xBF\"", + "\x80\xBF\x80\xBF\x80\xBF", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"", + }, + /* 3.1.8 7 continuation bytes */ + { + "\"\x80\xBF\x80\xBF\x80\xBF\x80\"", + "\x80\xBF\x80\xBF\x80\xBF\x80", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"", + }, + /* 3.1.9 Sequence of all 64 possible continuation bytes */ + { + "\"\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" + "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7" + "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" + "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7" + "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\"", + /* bug: not corrected */ + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" + "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7" + "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" + "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7" + "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF", + "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"" + }, + /* 3.2 Lonely start characters */ + /* 3.2.1 All 32 first bytes of 2-byte sequences, followed by space */ + { + "\"\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 " + "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF " + "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 " + "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF \"", + NULL, /* bug: rejected */ + "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF " + "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF " + "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF " + "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"", + "\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 " + "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF " + "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 " + "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF ", + }, + /* 3.2.2 All 16 first bytes of 3-byte sequences, followed by space */ + { + "\"\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 " + "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF \"", + /* bug: not corrected */ + "\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 " + "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF ", + "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF " + "\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"", + }, + /* 3.2.3 All 8 first bytes of 4-byte sequences, followed by space */ + { + "\"\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 \"", + NULL, /* bug: rejected */ + "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \\uFFFF \"", + "\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 ", + }, + /* 3.2.4 All 4 first bytes of 5-byte sequences, followed by space */ + { + "\"\xF8 \xF9 \xFA \xFB \"", + NULL, /* bug: rejected */ + "\"\\uFFFF \\uFFFF \\uFFFF \\uFFFF \"", + "\xF8 \xF9 \xFA \xFB ", + }, + /* 3.2.5 All 2 first bytes of 6-byte sequences, followed by space */ + { + "\"\xFC \xFD \"", + NULL, /* bug: rejected */ + "\"\\uFFFF \\uFFFF \"", + "\xFC \xFD ", + }, + /* 3.3 Sequences with last continuation byte missing */ + /* 3.3.1 2-byte sequence with last byte missing (U+0000) */ + { + "\"\xC0\"", + NULL, /* bug: rejected */ + "\"\\uFFFF\"", + "\xC0", + }, + /* 3.3.2 3-byte sequence with last byte missing (U+0000) */ + { + "\"\xE0\x80\"", + "\xE0\x80", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + }, + /* 3.3.3 4-byte sequence with last byte missing (U+0000) */ + { + "\"\xF0\x80\x80\"", + "\xF0\x80\x80", /* bug: not corrected */ + "\"\\u0000\"", /* bug: want "\"\\uFFFF\"" */ + }, + /* 3.3.4 5-byte sequence with last byte missing (U+0000) */ + { + /* invalid */ + "\"\xF8\x80\x80\x80\"", /* bug: not corrected */ + NULL, /* bug: rejected */ + "\"\\u8000\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xF8\x80\x80\x80", + }, + /* 3.3.5 6-byte sequence with last byte missing (U+0000) */ + { + "\"\xFC\x80\x80\x80\x80\"", + NULL, /* bug: rejected */ + "\"\\uC000\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xFC\x80\x80\x80\x80", + }, + /* 3.3.6 2-byte sequence with last byte missing (U+07FF) */ + { + "\"\xDF\"", + "\xDF", /* bug: not corrected */ + "\"\\uFFFF\"", + }, + /* 3.3.7 3-byte sequence with last byte missing (U+FFFF) */ + { + "\"\xEF\xBF\"", + "\xEF\xBF", /* bug: not corrected */ + "\"\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + }, + /* 3.3.8 4-byte sequence with last byte missing (U+1FFFFF) */ + { + "\"\xF7\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\u7FFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xF7\xBF\xBF", + }, + /* 3.3.9 5-byte sequence with last byte missing (U+3FFFFFF) */ + { + "\"\xFB\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\uBFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xFB\xBF\xBF\xBF", + }, + /* 3.3.10 6-byte sequence with last byte missing (U+7FFFFFFF) */ + { + "\"\xFD\xBF\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\uDFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"", */ + "\xFD\xBF\xBF\xBF\xBF", + }, + /* 3.4 Concatenation of incomplete sequences */ + { + "\"\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80" + "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + /* bug: want "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF" + "\\uFFFF\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"" */ + "\"\\u0020\\uFFFF\\u0000\\u8000\\uFFFF\\uC000\\uFFFF\\uFFFF" + "\\u07EF\\uFFFF\\u7FFF\\uBFFF\\uFFFF\\uDFFF\\uFFFF\\uFFFF\"", + "\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80" + "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF", + }, + /* 3.5 Impossible bytes */ + { + "\"\xFE\"", + NULL, /* bug: rejected */ + "\"\\uFFFF\"", + "\xFE", + }, + { + "\"\xFF\"", + NULL, /* bug: rejected */ + "\"\\uFFFF\"", + "\xFF", + }, + { + "\"\xFE\xFE\xFF\xFF\"", + NULL, /* bug: rejected */ + /* bug: want "\"\\uFFFF\\uFFFF\\uFFFF\\uFFFF\"" */ + "\"\\uEFBF\\uFFFF\"", + "\xFE\xFE\xFF\xFF", + }, + /* 4 Overlong sequences */ + /* 4.1 Overlong '/' */ + { + "\"\xC0\xAF\"", + NULL, /* bug: rejected */ + "\"\\u002F\"", /* bug: want "\"/\"" */ + "\xC0\xAF", + }, + { + "\"\xE0\x80\xAF\"", + "\xE0\x80\xAF", /* bug: not corrected */ + "\"\\u002F\"", /* bug: want "\"/\"" */ + }, + { + "\"\xF0\x80\x80\xAF\"", + "\xF0\x80\x80\xAF", /* bug: not corrected */ + "\"\\u0000\\uFFFF\"" /* bug: want "\"/\"" */ + }, + { + "\"\xF8\x80\x80\x80\xAF\"", + NULL, /* bug: rejected */ + "\"\\u8000\\uFFFF\\uFFFF\"", /* bug: want "\"/\"" */ + "\xF8\x80\x80\x80\xAF", + }, + { + "\"\xFC\x80\x80\x80\x80\xAF\"", + NULL, /* bug: rejected */ + "\"\\uC000\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"/\"" */ + "\xFC\x80\x80\x80\x80\xAF", + }, + /* 4.2 Maximum overlong sequences */ + { + /* \U+007F */ + "\"\xC1\xBF\"", + NULL, /* bug: rejected */ + "\"\\u007F\"", /* bug: want "\"\177\"" */ + "\xC1\xBF", + }, + { + /* \U+07FF */ + "\"\xE0\x9F\xBF\"", + "\xE0\x9F\xBF", /* bug: not corrected */ + "\"\\u07FF\"", + }, + { + /* \U+FFFF */ + "\"\xF0\x8F\xBF\xBF\"", + "\xF0\x8F\xBF\xBF", /* bug: not corrected */ + "\"\\u03FF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + }, + { + /* \U+1FFFFF */ + "\"\xF8\x87\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\u81FF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xF8\x87\xBF\xBF\xBF", + }, + { + /* \U+3FFFFFF */ + "\"\xFC\x83\xBF\xBF\xBF\xBF\"", + NULL, /* bug: rejected */ + "\"\\uC0FF\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\uFFFF\"" */ + "\xFC\x83\xBF\xBF\xBF\xBF", + }, + /* 4.3 Overlong representation of the NUL character */ + { + /* \U+0000 */ + "\"\xC0\x80\"", + NULL, /* bug: rejected */ + "\"\\u0000\"", + "\xC0\x80", + }, + { + /* \U+0000 */ + "\"\xE0\x80\x80\"", + "\xE0\x80\x80", /* bug: not corrected */ + "\"\\u0000\"", + }, + { + /* \U+0000 */ + "\"\xF0\x80\x80\x80\"", + "\xF0\x80\x80\x80", /* bug: not corrected */ + "\"\\u0000\\uFFFF\"", /* bug: want "\"\\u0000\"" */ + }, + { + /* \U+0000 */ + "\"\xF8\x80\x80\x80\x80\"", + NULL, /* bug: rejected */ + "\"\\u8000\\uFFFF\\uFFFF\"", /* bug: want "\"\\u0000\"" */ + "\xF8\x80\x80\x80\x80", + }, + { + /* \U+0000 */ + "\"\xFC\x80\x80\x80\x80\x80\"", + NULL, /* bug: rejected */ + "\"\\uC000\\uFFFF\\uFFFF\\uFFFF\"", /* bug: want "\"\\u0000\"" */ + "\xFC\x80\x80\x80\x80\x80", + }, + /* 5 Illegal code positions */ + /* 5.1 Single UTF-16 surrogates */ + { + /* \U+D800 */ + "\"\xED\xA0\x80\"", + "\xED\xA0\x80", /* bug: not corrected */ + "\"\\uD800\"", /* bug: want "\"\\uFFFF\"" */ + }, + { + /* \U+DB7F */ + "\"\xED\xAD\xBF\"", + "\xED\xAD\xBF", /* bug: not corrected */ + "\"\\uDB7F\"", /* bug: want "\"\\uFFFF\"" */ + }, + { + /* \U+DB80 */ + "\"\xED\xAE\x80\"", + "\xED\xAE\x80", /* bug: not corrected */ + "\"\\uDB80\"", /* bug: want "\"\\uFFFF\"" */ + }, + { + /* \U+DBFF */ + "\"\xED\xAF\xBF\"", + "\xED\xAF\xBF", /* bug: not corrected */ + "\"\\uDBFF\"", /* bug: want "\"\\uFFFF\"" */ + }, + { + /* \U+DC00 */ + "\"\xED\xB0\x80\"", + "\xED\xB0\x80", /* bug: not corrected */ + "\"\\uDC00\"", /* bug: want "\"\\uFFFF\"" */ + }, + { + /* \U+DF80 */ + "\"\xED\xBE\x80\"", + "\xED\xBE\x80", /* bug: not corrected */ + "\"\\uDF80\"", /* bug: want "\"\\uFFFF\"" */ + }, + { + /* \U+DFFF */ + "\"\xED\xBF\xBF\"", + "\xED\xBF\xBF", /* bug: not corrected */ + "\"\\uDFFF\"", /* bug: want "\"\\uFFFF\"" */ + }, + /* 5.2 Paired UTF-16 surrogates */ + { + /* \U+D800\U+DC00 */ + "\"\xED\xA0\x80\xED\xB0\x80\"", + "\xED\xA0\x80\xED\xB0\x80", /* bug: not corrected */ + "\"\\uD800\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + { + /* \U+D800\U+DFFF */ + "\"\xED\xA0\x80\xED\xBF\xBF\"", + "\xED\xA0\x80\xED\xBF\xBF", /* bug: not corrected */ + "\"\\uD800\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + { + /* \U+DB7F\U+DC00 */ + "\"\xED\xAD\xBF\xED\xB0\x80\"", + "\xED\xAD\xBF\xED\xB0\x80", /* bug: not corrected */ + "\"\\uDB7F\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + { + /* \U+DB7F\U+DFFF */ + "\"\xED\xAD\xBF\xED\xBF\xBF\"", + "\xED\xAD\xBF\xED\xBF\xBF", /* bug: not corrected */ + "\"\\uDB7F\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + { + /* \U+DB80\U+DC00 */ + "\"\xED\xAE\x80\xED\xB0\x80\"", + "\xED\xAE\x80\xED\xB0\x80", /* bug: not corrected */ + "\"\\uDB80\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + { + /* \U+DB80\U+DFFF */ + "\"\xED\xAE\x80\xED\xBF\xBF\"", + "\xED\xAE\x80\xED\xBF\xBF", /* bug: not corrected */ + "\"\\uDB80\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + { + /* \U+DBFF\U+DC00 */ + "\"\xED\xAF\xBF\xED\xB0\x80\"", + "\xED\xAF\xBF\xED\xB0\x80", /* bug: not corrected */ + "\"\\uDBFF\\uDC00\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + { + /* \U+DBFF\U+DFFF */ + "\"\xED\xAF\xBF\xED\xBF\xBF\"", + "\xED\xAF\xBF\xED\xBF\xBF", /* bug: not corrected */ + "\"\\uDBFF\\uDFFF\"", /* bug: want "\"\\uFFFF\\uFFFF\"" */ + }, + /* 5.3 Other illegal code positions */ + { + /* \U+FFFE */ + "\"\xEF\xBF\xBE\"", + "\xEF\xBF\xBE", /* bug: not corrected */ + "\"\\uFFFE\"", /* bug: not corrected */ + }, + { + /* \U+FFFF */ + "\"\xEF\xBF\xBF\"", + "\xEF\xBF\xBF", /* bug: not corrected */ + "\"\\uFFFF\"", /* bug: not corrected */ + }, + {} + }; + int i; + QObject *obj; + QString *str; + const char *json_in, *utf8_out, *utf8_in, *json_out; + + for (i = 0; test_cases[i].json_in; i++) { + json_in = test_cases[i].json_in; + utf8_out = test_cases[i].utf8_out; + utf8_in = test_cases[i].utf8_in ?: test_cases[i].utf8_out; + json_out = test_cases[i].json_out ?: test_cases[i].json_in; + + obj = qobject_from_json(json_in); + if (utf8_out) { + g_assert(obj); + g_assert(qobject_type(obj) == QTYPE_QSTRING); + str = qobject_to_qstring(obj); + g_assert_cmpstr(qstring_get_str(str), ==, utf8_out); + } else { + g_assert(!obj); + } + qobject_decref(obj); + + obj = QOBJECT(qstring_from_str(utf8_in)); + str = qobject_to_json(obj); + if (json_out) { + g_assert(str); + g_assert_cmpstr(qstring_get_str(str), ==, json_out); + } else { + g_assert(!str); + } + QDECREF(str); + qobject_decref(obj); + + /* + * Disabled, because json_out currently contains the crap + * qobject_to_json() produces. + * FIXME Enable once these bugs have been fixed. + */ + if (0 && json_out != json_in) { + obj = qobject_from_json(json_out); + g_assert(obj); + g_assert(qobject_type(obj) == QTYPE_QSTRING); + str = qobject_to_qstring(obj); + g_assert_cmpstr(qstring_get_str(str), ==, utf8_out); + } + } +} + static void vararg_string(void) { int i; @@ -748,6 +1411,7 @@ int main(int argc, char **argv) g_test_add_func("/literals/string/simple", simple_string); g_test_add_func("/literals/string/escaped", escaped_string); + g_test_add_func("/literals/string/utf8", utf8_string); g_test_add_func("/literals/string/single_quote", single_quote_string); g_test_add_func("/literals/string/vararg", vararg_string); From 134a03e0b3d34b01b68107104c525c3bff1211d4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:24 +0100 Subject: [PATCH 1164/1634] main-loop: fix select_ret uninitialized variable warning Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-2-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- main-loop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main-loop.c b/main-loop.c index 6f52ac39bc..d0d8fe4950 100644 --- a/main-loop.c +++ b/main-loop.c @@ -330,7 +330,8 @@ void qemu_fd_register(int fd) static int os_host_main_loop_wait(uint32_t timeout) { GMainContext *context = g_main_context_default(); - int select_ret, g_poll_ret, ret, i; + int select_ret = 0; + int g_poll_ret, ret, i; PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; From cbff4b342b000a7642125dbdabf61113e05eee44 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:25 +0100 Subject: [PATCH 1165/1634] main-loop: switch to g_poll() on POSIX hosts Use g_poll(3) instead of select(2). Well, this is kind of a cheat. It's true that we're now using g_poll(3) on POSIX hosts but the *_fill() and *_poll() functions are still using rfds/wfds/xfds. We've set the scene to start converting *_fill() and *_poll() functions step-by-step until no more rfds/wfds/xfds users remain. Then we'll drop the temporary gpollfds_from_select() and gpollfds_to_select() functions and be left with native g_poll(2). On Windows things are a little crazy: convert from rfds/wfds/xfds to GPollFDs, back to rfds/wfds/xfds, call select(2), rfds/wfds/xfds back to GPollFDs, and finally back to rfds/wfds/xfds again. This is only temporary and keeps the Windows build working through the following patches. We'll drop this excessive conversion later and be left with a single GPollFDs -> select(2) -> GPollFDs sequence that allows Windows to use select(2) while the rest of QEMU only knows about GPollFD. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-3-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- main-loop.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 8 deletions(-) diff --git a/main-loop.c b/main-loop.c index d0d8fe4950..489b27c1f6 100644 --- a/main-loop.c +++ b/main-loop.c @@ -117,6 +117,8 @@ void qemu_notify_event(void) aio_notify(qemu_aio_context); } +static GArray *gpollfds; + int qemu_init_main_loop(void) { int ret; @@ -133,6 +135,7 @@ int qemu_init_main_loop(void) return ret; } + gpollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD)); qemu_aio_context = aio_context_new(); src = aio_get_g_source(qemu_aio_context); g_source_attach(src, NULL); @@ -146,6 +149,62 @@ static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ static int n_poll_fds; static int max_priority; +/* Load rfds/wfds/xfds into gpollfds. Will be removed a few commits later. */ +static void gpollfds_from_select(void) +{ + int fd; + for (fd = 0; fd <= nfds; fd++) { + int events = 0; + if (FD_ISSET(fd, &rfds)) { + events |= G_IO_IN | G_IO_HUP | G_IO_ERR; + } + if (FD_ISSET(fd, &wfds)) { + events |= G_IO_OUT | G_IO_ERR; + } + if (FD_ISSET(fd, &xfds)) { + events |= G_IO_PRI; + } + if (events) { + GPollFD pfd = { + .fd = fd, + .events = events, + }; + g_array_append_val(gpollfds, pfd); + } + } +} + +/* Store gpollfds revents into rfds/wfds/xfds. Will be removed a few commits + * later. + */ +static void gpollfds_to_select(int ret) +{ + int i; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + + if (ret <= 0) { + return; + } + + for (i = 0; i < gpollfds->len; i++) { + int fd = g_array_index(gpollfds, GPollFD, i).fd; + int revents = g_array_index(gpollfds, GPollFD, i).revents; + + if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) { + FD_SET(fd, &rfds); + } + if (revents & (G_IO_OUT | G_IO_ERR)) { + FD_SET(fd, &wfds); + } + if (revents & G_IO_PRI) { + FD_SET(fd, &xfds); + } + } +} + #ifndef _WIN32 static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds, fd_set *xfds, uint32_t *cur_timeout) @@ -212,22 +271,22 @@ static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds, static int os_host_main_loop_wait(uint32_t timeout) { - struct timeval tv, *tvarg = NULL; int ret; glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout); - if (timeout < UINT32_MAX) { - tvarg = &tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - } - if (timeout > 0) { qemu_mutex_unlock_iothread(); } - ret = select(nfds + 1, &rfds, &wfds, &xfds, tvarg); + /* We'll eventually drop fd_set completely. But for now we still have + * *_fill() and *_poll() functions that use rfds/wfds/xfds. + */ + gpollfds_from_select(); + + ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout); + + gpollfds_to_select(ret); if (timeout > 0) { qemu_mutex_lock_iothread(); @@ -327,6 +386,55 @@ void qemu_fd_register(int fd) FD_CONNECT | FD_WRITE | FD_OOB); } +static int pollfds_fill(GArray *pollfds, fd_set *rfds, fd_set *wfds, + fd_set *xfds) +{ + int nfds = -1; + int i; + + for (i = 0; i < pollfds->len; i++) { + GPollFD *pfd = &g_array_index(pollfds, GPollFD, i); + int fd = pfd->fd; + int events = pfd->events; + if (events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) { + FD_SET(fd, rfds); + nfds = MAX(nfds, fd); + } + if (events & (G_IO_OUT | G_IO_ERR)) { + FD_SET(fd, wfds); + nfds = MAX(nfds, fd); + } + if (events & G_IO_PRI) { + FD_SET(fd, xfds); + nfds = MAX(nfds, fd); + } + } + return nfds; +} + +static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds, + fd_set *wfds, fd_set *xfds) +{ + int i; + + for (i = 0; i < pollfds->len; i++) { + GPollFD *pfd = &g_array_index(pollfds, GPollFD, i); + int fd = pfd->fd; + int revents = 0; + + if (FD_ISSET(fd, rfds)) { + revents |= G_IO_IN | G_IO_HUP | G_IO_ERR; + } + if (FD_ISSET(fd, wfds)) { + revents |= G_IO_OUT | G_IO_ERR; + } + if (FD_ISSET(fd, xfds)) { + revents |= G_IO_PRI; + } + pfd->revents = revents & pfd->events; + } +} + static int os_host_main_loop_wait(uint32_t timeout) { GMainContext *context = g_main_context_default(); @@ -382,12 +490,24 @@ static int os_host_main_loop_wait(uint32_t timeout) * improve socket latency. */ + /* This back-and-forth between GPollFDs and select(2) is temporary. We'll + * drop it in a couple of patches, I promise :). + */ + gpollfds_from_select(); + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + nfds = pollfds_fill(gpollfds, &rfds, &wfds, &xfds); if (nfds >= 0) { select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); if (select_ret != 0) { timeout = 0; } + if (select_ret > 0) { + pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds); + } } + gpollfds_to_select(select_ret); return select_ret || g_poll_ret; } @@ -403,6 +523,7 @@ int main_loop_wait(int nonblocking) } /* poll any events */ + g_array_set_size(gpollfds, 0); /* reset for new iteration */ /* XXX: separate device handlers from system ones */ nfds = -1; FD_ZERO(&rfds); From 48ce11ff972c733afaed3e2a2613a2e56081ec92 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:26 +0100 Subject: [PATCH 1166/1634] main-loop: switch POSIX glib integration to GPollFD Convert glib file descriptor polling from rfds/wfds/xfds to GPollFD. The Windows code still needs poll_fds[] and n_poll_fds but they can now become local variables. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-4-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- main-loop.c | 71 +++++++++++++++++------------------------------------ 1 file changed, 22 insertions(+), 49 deletions(-) diff --git a/main-loop.c b/main-loop.c index 489b27c1f6..c2ede99632 100644 --- a/main-loop.c +++ b/main-loop.c @@ -145,8 +145,6 @@ int qemu_init_main_loop(void) static fd_set rfds, wfds, xfds; static int nfds; -static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ -static int n_poll_fds; static int max_priority; /* Load rfds/wfds/xfds into gpollfds. Will be removed a few commits later. */ @@ -206,65 +204,39 @@ static void gpollfds_to_select(int ret) } #ifndef _WIN32 -static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds, - fd_set *xfds, uint32_t *cur_timeout) +static int glib_pollfds_idx; +static int glib_n_poll_fds; + +static void glib_pollfds_fill(uint32_t *cur_timeout) { GMainContext *context = g_main_context_default(); - int i; int timeout = 0; + int n; g_main_context_prepare(context, &max_priority); - n_poll_fds = g_main_context_query(context, max_priority, &timeout, - poll_fds, ARRAY_SIZE(poll_fds)); - g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds)); - - for (i = 0; i < n_poll_fds; i++) { - GPollFD *p = &poll_fds[i]; - - if ((p->events & G_IO_IN)) { - FD_SET(p->fd, rfds); - *max_fd = MAX(*max_fd, p->fd); - } - if ((p->events & G_IO_OUT)) { - FD_SET(p->fd, wfds); - *max_fd = MAX(*max_fd, p->fd); - } - if ((p->events & G_IO_ERR)) { - FD_SET(p->fd, xfds); - *max_fd = MAX(*max_fd, p->fd); - } - } + glib_pollfds_idx = gpollfds->len; + n = glib_n_poll_fds; + do { + GPollFD *pfds; + glib_n_poll_fds = n; + g_array_set_size(gpollfds, glib_pollfds_idx + glib_n_poll_fds); + pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx); + n = g_main_context_query(context, max_priority, &timeout, pfds, + glib_n_poll_fds); + } while (n != glib_n_poll_fds); if (timeout >= 0 && timeout < *cur_timeout) { *cur_timeout = timeout; } } -static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds, - bool err) +static void glib_pollfds_poll(void) { GMainContext *context = g_main_context_default(); + GPollFD *pfds = &g_array_index(gpollfds, GPollFD, glib_pollfds_idx); - if (!err) { - int i; - - for (i = 0; i < n_poll_fds; i++) { - GPollFD *p = &poll_fds[i]; - - if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) { - p->revents |= G_IO_IN; - } - if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) { - p->revents |= G_IO_OUT; - } - if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) { - p->revents |= G_IO_ERR; - } - } - } - - if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) { + if (g_main_context_check(context, max_priority, pfds, glib_n_poll_fds)) { g_main_context_dispatch(context); } } @@ -273,7 +245,7 @@ static int os_host_main_loop_wait(uint32_t timeout) { int ret; - glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout); + glib_pollfds_fill(&timeout); if (timeout > 0) { qemu_mutex_unlock_iothread(); @@ -292,7 +264,7 @@ static int os_host_main_loop_wait(uint32_t timeout) qemu_mutex_lock_iothread(); } - glib_select_poll(&rfds, &wfds, &xfds, (ret < 0)); + glib_pollfds_poll(); return ret; } #else @@ -438,8 +410,9 @@ static void pollfds_poll(GArray *pollfds, int nfds, fd_set *rfds, static int os_host_main_loop_wait(uint32_t timeout) { GMainContext *context = g_main_context_default(); + GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ int select_ret = 0; - int g_poll_ret, ret, i; + int g_poll_ret, ret, i, n_poll_fds; PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; From cf1d078e4ea094e516faab49678fbea3a34b7848 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:27 +0100 Subject: [PATCH 1167/1634] slirp: slirp/slirp.c coding style cleanup The slirp glue code uses tabs in some places. Since the next patch will modify the file, convert tabs to spaces and fix checkpatch.pl issues. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-5-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- slirp/slirp.c | 594 ++++++++++++++++++++++++++------------------------ 1 file changed, 304 insertions(+), 290 deletions(-) diff --git a/slirp/slirp.c b/slirp/slirp.c index 0e6e232789..5d14e7f865 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -287,135 +287,139 @@ void slirp_select_fill(int *pnfds, global_xfds = NULL; nfds = *pnfds; - /* - * First, TCP sockets - */ - do_slowtimo = 0; + /* + * First, TCP sockets + */ + do_slowtimo = 0; - QTAILQ_FOREACH(slirp, &slirp_instances, entry) { - /* - * *_slowtimo needs calling if there are IP fragments - * in the fragment queue, or there are TCP connections active - */ - do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) || - (&slirp->ipq.ip_link != slirp->ipq.ip_link.next)); + QTAILQ_FOREACH(slirp, &slirp_instances, entry) { + /* + * *_slowtimo needs calling if there are IP fragments + * in the fragment queue, or there are TCP connections active + */ + do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) || + (&slirp->ipq.ip_link != slirp->ipq.ip_link.next)); - for (so = slirp->tcb.so_next; so != &slirp->tcb; - so = so_next) { - so_next = so->so_next; + for (so = slirp->tcb.so_next; so != &slirp->tcb; + so = so_next) { + so_next = so->so_next; - /* - * See if we need a tcp_fasttimo - */ - if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) - time_fasttimo = curtime; /* Flag when we want a fasttimo */ + /* + * See if we need a tcp_fasttimo + */ + if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) { + time_fasttimo = curtime; /* Flag when we want a fasttimo */ + } - /* - * NOFDREF can include still connecting to local-host, - * newly socreated() sockets etc. Don't want to select these. - */ - if (so->so_state & SS_NOFDREF || so->s == -1) - continue; + /* + * NOFDREF can include still connecting to local-host, + * newly socreated() sockets etc. Don't want to select these. + */ + if (so->so_state & SS_NOFDREF || so->s == -1) { + continue; + } - /* - * Set for reading sockets which are accepting - */ - if (so->so_state & SS_FACCEPTCONN) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - continue; - } + /* + * Set for reading sockets which are accepting + */ + if (so->so_state & SS_FACCEPTCONN) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + continue; + } - /* - * Set for writing sockets which are connecting - */ - if (so->so_state & SS_ISFCONNECTING) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - continue; - } + /* + * Set for writing sockets which are connecting + */ + if (so->so_state & SS_ISFCONNECTING) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + continue; + } - /* - * Set for writing if we are connected, can send more, and - * we have something to send - */ - if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); - } + /* + * Set for writing if we are connected, can send more, and + * we have something to send + */ + if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + } - /* - * Set for reading (and urgent data) if we are connected, can - * receive more, and we have room for it XXX /2 ? - */ - if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { - FD_SET(so->s, readfds); - FD_SET(so->s, xfds); - UPD_NFDS(so->s); - } - } + /* + * Set for reading (and urgent data) if we are connected, can + * receive more, and we have room for it XXX /2 ? + */ + if (CONN_CANFRCV(so) && + (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { + FD_SET(so->s, readfds); + FD_SET(so->s, xfds); + UPD_NFDS(so->s); + } + } - /* - * UDP sockets - */ - for (so = slirp->udb.so_next; so != &slirp->udb; - so = so_next) { - so_next = so->so_next; + /* + * UDP sockets + */ + for (so = slirp->udb.so_next; so != &slirp->udb; + so = so_next) { + so_next = so->so_next; - /* - * See if it's timed out - */ - if (so->so_expire) { - if (so->so_expire <= curtime) { - udp_detach(so); - continue; - } else - do_slowtimo = 1; /* Let socket expire */ - } - - /* - * When UDP packets are received from over the - * link, they're sendto()'d straight away, so - * no need for setting for writing - * Limit the number of packets queued by this session - * to 4. Note that even though we try and limit this - * to 4 packets, the session could have more queued - * if the packets needed to be fragmented - * (XXX <= 4 ?) - */ - if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - } - } - - /* - * ICMP sockets - */ - for (so = slirp->icmp.so_next; so != &slirp->icmp; - so = so_next) { - so_next = so->so_next; - - /* - * See if it's timed out - */ - if (so->so_expire) { - if (so->so_expire <= curtime) { - icmp_detach(so); - continue; - } else { - do_slowtimo = 1; /* Let socket expire */ - } - } - - if (so->so_state & SS_ISFCONNECTED) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); - } + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + udp_detach(so); + continue; + } else { + do_slowtimo = 1; /* Let socket expire */ } - } + } - *pnfds = nfds; + /* + * When UDP packets are received from over the + * link, they're sendto()'d straight away, so + * no need for setting for writing + * Limit the number of packets queued by this session + * to 4. Note that even though we try and limit this + * to 4 packets, the session could have more queued + * if the packets needed to be fragmented + * (XXX <= 4 ?) + */ + if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + } + } + + /* + * ICMP sockets + */ + for (so = slirp->icmp.so_next; so != &slirp->icmp; + so = so_next) { + so_next = so->so_next; + + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + icmp_detach(so); + continue; + } else { + do_slowtimo = 1; /* Let socket expire */ + } + } + + if (so->so_state & SS_ISFCONNECTED) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + } + } + } + + *pnfds = nfds; } void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, @@ -436,177 +440,185 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, curtime = qemu_get_clock_ms(rt_clock); QTAILQ_FOREACH(slirp, &slirp_instances, entry) { - /* - * See if anything has timed out - */ - if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) { - tcp_fasttimo(slirp); - time_fasttimo = 0; - } - if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) { - ip_slowtimo(slirp); - tcp_slowtimo(slirp); - last_slowtimo = curtime; - } + /* + * See if anything has timed out + */ + if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) { + tcp_fasttimo(slirp); + time_fasttimo = 0; + } + if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) { + ip_slowtimo(slirp); + tcp_slowtimo(slirp); + last_slowtimo = curtime; + } - /* - * Check sockets - */ - if (!select_error) { - /* - * Check TCP sockets - */ - for (so = slirp->tcb.so_next; so != &slirp->tcb; - so = so_next) { - so_next = so->so_next; - - /* - * FD_ISSET is meaningless on these sockets - * (and they can crash the program) - */ - if (so->so_state & SS_NOFDREF || so->s == -1) - continue; - - /* - * Check for URG data - * This will soread as well, so no need to - * test for readfds below if this succeeds - */ - if (FD_ISSET(so->s, xfds)) - sorecvoob(so); - /* - * Check sockets for reading - */ - else if (FD_ISSET(so->s, readfds)) { - /* - * Check for incoming connections - */ - if (so->so_state & SS_FACCEPTCONN) { - tcp_connect(so); - continue; - } /* else */ - ret = soread(so); - - /* Output it if we read something */ - if (ret > 0) - tcp_output(sototcpcb(so)); - } - - /* - * Check sockets for writing - */ - if (FD_ISSET(so->s, writefds)) { - /* - * Check for non-blocking, still-connecting sockets - */ - if (so->so_state & SS_ISFCONNECTING) { - /* Connected */ - so->so_state &= ~SS_ISFCONNECTING; - - ret = send(so->s, (const void *) &ret, 0, 0); - if (ret < 0) { - /* XXXXX Must fix, zero bytes is a NOP */ - if (errno == EAGAIN || errno == EWOULDBLOCK || - errno == EINPROGRESS || errno == ENOTCONN) - continue; - - /* else failed */ - so->so_state &= SS_PERSISTENT_MASK; - so->so_state |= SS_NOFDREF; - } - /* else so->so_state &= ~SS_ISFCONNECTING; */ - - /* - * Continue tcp_input - */ - tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); - /* continue; */ - } else - ret = sowrite(so); - /* - * XXXXX If we wrote something (a lot), there - * could be a need for a window update. - * In the worst case, the remote will send - * a window probe to get things going again - */ - } - - /* - * Probe a still-connecting, non-blocking socket - * to check if it's still alive - */ -#ifdef PROBE_CONN - if (so->so_state & SS_ISFCONNECTING) { - ret = qemu_recv(so->s, &ret, 0,0); - - if (ret < 0) { - /* XXX */ - if (errno == EAGAIN || errno == EWOULDBLOCK || - errno == EINPROGRESS || errno == ENOTCONN) - continue; /* Still connecting, continue */ - - /* else failed */ - so->so_state &= SS_PERSISTENT_MASK; - so->so_state |= SS_NOFDREF; - - /* tcp_input will take care of it */ - } else { - ret = send(so->s, &ret, 0,0); - if (ret < 0) { - /* XXX */ - if (errno == EAGAIN || errno == EWOULDBLOCK || - errno == EINPROGRESS || errno == ENOTCONN) - continue; - /* else failed */ - so->so_state &= SS_PERSISTENT_MASK; - so->so_state |= SS_NOFDREF; - } else - so->so_state &= ~SS_ISFCONNECTING; - - } - tcp_input((struct mbuf *)NULL, sizeof(struct ip),so); - } /* SS_ISFCONNECTING */ -#endif - } - - /* - * Now UDP sockets. - * Incoming packets are sent straight away, they're not buffered. - * Incoming UDP data isn't buffered either. - */ - for (so = slirp->udb.so_next; so != &slirp->udb; - so = so_next) { - so_next = so->so_next; - - if (so->s != -1 && FD_ISSET(so->s, readfds)) { - sorecvfrom(so); - } - } + /* + * Check sockets + */ + if (!select_error) { + /* + * Check TCP sockets + */ + for (so = slirp->tcb.so_next; so != &slirp->tcb; + so = so_next) { + so_next = so->so_next; /* - * Check incoming ICMP relies. + * FD_ISSET is meaningless on these sockets + * (and they can crash the program) */ - for (so = slirp->icmp.so_next; so != &slirp->icmp; - so = so_next) { - so_next = so->so_next; + if (so->so_state & SS_NOFDREF || so->s == -1) { + continue; + } - if (so->s != -1 && FD_ISSET(so->s, readfds)) { - icmp_receive(so); + /* + * Check for URG data + * This will soread as well, so no need to + * test for readfds below if this succeeds + */ + if (FD_ISSET(so->s, xfds)) { + sorecvoob(so); + } + /* + * Check sockets for reading + */ + else if (FD_ISSET(so->s, readfds)) { + /* + * Check for incoming connections + */ + if (so->so_state & SS_FACCEPTCONN) { + tcp_connect(so); + continue; + } /* else */ + ret = soread(so); + + /* Output it if we read something */ + if (ret > 0) { + tcp_output(sototcpcb(so)); } } - } + + /* + * Check sockets for writing + */ + if (FD_ISSET(so->s, writefds)) { + /* + * Check for non-blocking, still-connecting sockets + */ + if (so->so_state & SS_ISFCONNECTING) { + /* Connected */ + so->so_state &= ~SS_ISFCONNECTING; + + ret = send(so->s, (const void *) &ret, 0, 0); + if (ret < 0) { + /* XXXXX Must fix, zero bytes is a NOP */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) { + continue; + } + + /* else failed */ + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_NOFDREF; + } + /* else so->so_state &= ~SS_ISFCONNECTING; */ + + /* + * Continue tcp_input + */ + tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); + /* continue; */ + } else { + ret = sowrite(so); + } + /* + * XXXXX If we wrote something (a lot), there + * could be a need for a window update. + * In the worst case, the remote will send + * a window probe to get things going again + */ + } + + /* + * Probe a still-connecting, non-blocking socket + * to check if it's still alive + */ +#ifdef PROBE_CONN + if (so->so_state & SS_ISFCONNECTING) { + ret = qemu_recv(so->s, &ret, 0, 0); + + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) { + continue; /* Still connecting, continue */ + } + + /* else failed */ + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_NOFDREF; + + /* tcp_input will take care of it */ + } else { + ret = send(so->s, &ret, 0, 0); + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) { + continue; + } + /* else failed */ + so->so_state &= SS_PERSISTENT_MASK; + so->so_state |= SS_NOFDREF; + } else { + so->so_state &= ~SS_ISFCONNECTING; + } + + } + tcp_input((struct mbuf *)NULL, sizeof(struct ip), so); + } /* SS_ISFCONNECTING */ +#endif + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. + */ + for (so = slirp->udb.so_next; so != &slirp->udb; + so = so_next) { + so_next = so->so_next; + + if (so->s != -1 && FD_ISSET(so->s, readfds)) { + sorecvfrom(so); + } + } + + /* + * Check incoming ICMP relies. + */ + for (so = slirp->icmp.so_next; so != &slirp->icmp; + so = so_next) { + so_next = so->so_next; + + if (so->s != -1 && FD_ISSET(so->s, readfds)) { + icmp_receive(so); + } + } + } if_start(slirp); } - /* clear global file descriptor sets. - * these reside on the stack in vl.c - * so they're unusable if we're not in - * slirp_select_fill or slirp_select_poll. - */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; + /* clear global file descriptor sets. + * these reside on the stack in vl.c + * so they're unusable if we're not in + * slirp_select_fill or slirp_select_poll. + */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; } static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) @@ -827,12 +839,12 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const void *args, ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) { - if (so->s == -1 && so->extra) { - qemu_chr_fe_write(so->extra, buf, len); - return len; - } + if (so->s == -1 && so->extra) { + qemu_chr_fe_write(so->extra, buf, len); + return len; + } - return send(so->s, buf, len, flags); + return send(so->s, buf, len, flags); } static struct socket * @@ -852,18 +864,20 @@ slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port) size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port) { - struct iovec iov[2]; - struct socket *so; + struct iovec iov[2]; + struct socket *so; - so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); + so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); - if (!so || so->so_state & SS_NOFDREF) - return 0; + if (!so || so->so_state & SS_NOFDREF) { + return 0; + } - if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) - return 0; + if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) { + return 0; + } - return sopreprbuf(so, iov, NULL); + return sopreprbuf(so, iov, NULL); } void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port, From 8917c3bdba37d6fe4393db0fad3fabbde9530d6b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:28 +0100 Subject: [PATCH 1168/1634] slirp: switch to GPollFD Slirp uses rfds/wfds/xfds more extensively than other QEMU components. The rarely-used out-of-band TCP data feature is used. That means we need the full table of select(2) to g_poll(3) events: rfds -> G_IO_IN | G_IO_HUP | G_IO_ERR wfds -> G_IO_OUT | G_IO_ERR xfds -> G_IO_PRI I came up with this table by looking at Linux fs/select.c which maps select(2) to poll(2) internally. Another detail to watch out for are the global variables that reference rfds/wfds/xfds during slirp_select_poll(). sofcantrcvmore() and sofcantsendmore() use these globals to clear fd_set bits. When sofcantrcvmore() is called, the wfds bit is cleared so that the write handler will no longer be run for this iteration of the event loop. This actually seems buggy to me since TCP connections can be half-closed and we'd still want to handle data in half-duplex fashion. I think the real intention is to avoid running the read/write handler when the socket has been fully closed. This is indicated with the SS_NOFDREF state bit so we now check for it before invoking the TCP write handler. Note that UDP/ICMP code paths don't care because they are connectionless. Note that slirp/ has a lot of tabs and sometimes mixed tabs with spaces. I followed the style of the surrounding code. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-6-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- main-loop.c | 4 +- slirp/libslirp.h | 6 +-- slirp/main.h | 1 - slirp/slirp.c | 133 ++++++++++++++++++++++++++++------------------- slirp/socket.c | 9 ---- slirp/socket.h | 2 + stubs/slirp.c | 6 +-- 7 files changed, 87 insertions(+), 74 deletions(-) diff --git a/main-loop.c b/main-loop.c index c2ede99632..839e98ff6a 100644 --- a/main-loop.c +++ b/main-loop.c @@ -505,13 +505,13 @@ int main_loop_wait(int nonblocking) #ifdef CONFIG_SLIRP slirp_update_timeout(&timeout); - slirp_select_fill(&nfds, &rfds, &wfds, &xfds); + slirp_pollfds_fill(gpollfds); #endif qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds); ret = os_host_main_loop_wait(timeout); qemu_iohandler_poll(&rfds, &wfds, &xfds, ret); #ifdef CONFIG_SLIRP - slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0)); + slirp_pollfds_poll(gpollfds, (ret < 0)); #endif qemu_run_all_timers(); diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 49609c2ad7..ceabff81b2 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -17,11 +17,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, void slirp_cleanup(Slirp *slirp); void slirp_update_timeout(uint32_t *timeout); -void slirp_select_fill(int *pnfds, - fd_set *readfds, fd_set *writefds, fd_set *xfds); +void slirp_pollfds_fill(GArray *pollfds); -void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, - int select_error); +void slirp_pollfds_poll(GArray *pollfds, int select_error); void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len); diff --git a/slirp/main.h b/slirp/main.h index 66e4f9252f..f2e58cfe2d 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -31,7 +31,6 @@ extern int ctty_closed; extern char *slirp_tty; extern char *exec_shell; extern u_int curtime; -extern fd_set *global_readfds, *global_writefds, *global_xfds; extern struct in_addr loopback_addr; extern unsigned long loopback_mask; extern char *username; diff --git a/slirp/slirp.c b/slirp/slirp.c index 5d14e7f865..bd9b7cb644 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -39,9 +39,6 @@ static const uint8_t special_ethaddr[ETH_ALEN] = { static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; -/* XXX: suppress those select globals */ -fd_set *global_readfds, *global_writefds, *global_xfds; - u_int curtime; static u_int time_fasttimo, last_slowtimo; static int do_slowtimo; @@ -261,7 +258,6 @@ void slirp_cleanup(Slirp *slirp) #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) #define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) -#define UPD_NFDS(x) if (nfds < (x)) nfds = (x) void slirp_update_timeout(uint32_t *timeout) { @@ -270,23 +266,15 @@ void slirp_update_timeout(uint32_t *timeout) } } -void slirp_select_fill(int *pnfds, - fd_set *readfds, fd_set *writefds, fd_set *xfds) +void slirp_pollfds_fill(GArray *pollfds) { Slirp *slirp; struct socket *so, *so_next; - int nfds; if (QTAILQ_EMPTY(&slirp_instances)) { return; } - /* fail safe */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; - - nfds = *pnfds; /* * First, TCP sockets */ @@ -302,8 +290,12 @@ void slirp_select_fill(int *pnfds, for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { + int events = 0; + so_next = so->so_next; + so->pollfds_idx = -1; + /* * See if we need a tcp_fasttimo */ @@ -323,8 +315,12 @@ void slirp_select_fill(int *pnfds, * Set for reading sockets which are accepting */ if (so->so_state & SS_FACCEPTCONN) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); + GPollFD pfd = { + .fd = so->s, + .events = G_IO_IN | G_IO_HUP | G_IO_ERR, + }; + so->pollfds_idx = pollfds->len; + g_array_append_val(pollfds, pfd); continue; } @@ -332,8 +328,12 @@ void slirp_select_fill(int *pnfds, * Set for writing sockets which are connecting */ if (so->so_state & SS_ISFCONNECTING) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); + GPollFD pfd = { + .fd = so->s, + .events = G_IO_OUT | G_IO_ERR, + }; + so->pollfds_idx = pollfds->len; + g_array_append_val(pollfds, pfd); continue; } @@ -342,8 +342,7 @@ void slirp_select_fill(int *pnfds, * we have something to send */ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { - FD_SET(so->s, writefds); - UPD_NFDS(so->s); + events |= G_IO_OUT | G_IO_ERR; } /* @@ -352,9 +351,16 @@ void slirp_select_fill(int *pnfds, */ if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { - FD_SET(so->s, readfds); - FD_SET(so->s, xfds); - UPD_NFDS(so->s); + events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI; + } + + if (events) { + GPollFD pfd = { + .fd = so->s, + .events = events, + }; + so->pollfds_idx = pollfds->len; + g_array_append_val(pollfds, pfd); } } @@ -365,6 +371,8 @@ void slirp_select_fill(int *pnfds, so = so_next) { so_next = so->so_next; + so->pollfds_idx = -1; + /* * See if it's timed out */ @@ -388,8 +396,12 @@ void slirp_select_fill(int *pnfds, * (XXX <= 4 ?) */ if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); + GPollFD pfd = { + .fd = so->s, + .events = G_IO_IN | G_IO_HUP | G_IO_ERR, + }; + so->pollfds_idx = pollfds->len; + g_array_append_val(pollfds, pfd); } } @@ -400,6 +412,8 @@ void slirp_select_fill(int *pnfds, so = so_next) { so_next = so->so_next; + so->pollfds_idx = -1; + /* * See if it's timed out */ @@ -413,17 +427,18 @@ void slirp_select_fill(int *pnfds, } if (so->so_state & SS_ISFCONNECTED) { - FD_SET(so->s, readfds); - UPD_NFDS(so->s); + GPollFD pfd = { + .fd = so->s, + .events = G_IO_IN | G_IO_HUP | G_IO_ERR, + }; + so->pollfds_idx = pollfds->len; + g_array_append_val(pollfds, pfd); } } } - - *pnfds = nfds; } -void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, - int select_error) +void slirp_pollfds_poll(GArray *pollfds, int select_error) { Slirp *slirp; struct socket *so, *so_next; @@ -433,10 +448,6 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, return; } - global_readfds = readfds; - global_writefds = writefds; - global_xfds = xfds; - curtime = qemu_get_clock_ms(rt_clock); QTAILQ_FOREACH(slirp, &slirp_instances, entry) { @@ -462,12 +473,16 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, */ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { + int revents; + so_next = so->so_next; - /* - * FD_ISSET is meaningless on these sockets - * (and they can crash the program) - */ + revents = 0; + if (so->pollfds_idx != -1) { + revents = g_array_index(pollfds, GPollFD, + so->pollfds_idx).revents; + } + if (so->so_state & SS_NOFDREF || so->s == -1) { continue; } @@ -475,15 +490,15 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, /* * Check for URG data * This will soread as well, so no need to - * test for readfds below if this succeeds + * test for G_IO_IN below if this succeeds */ - if (FD_ISSET(so->s, xfds)) { + if (revents & G_IO_PRI) { sorecvoob(so); } /* * Check sockets for reading */ - else if (FD_ISSET(so->s, readfds)) { + else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) { /* * Check for incoming connections */ @@ -502,7 +517,8 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, /* * Check sockets for writing */ - if (FD_ISSET(so->s, writefds)) { + if (!(so->so_state & SS_NOFDREF) && + (revents & (G_IO_OUT | G_IO_ERR))) { /* * Check for non-blocking, still-connecting sockets */ @@ -588,9 +604,18 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, */ for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { + int revents; + so_next = so->so_next; - if (so->s != -1 && FD_ISSET(so->s, readfds)) { + revents = 0; + if (so->pollfds_idx != -1) { + revents = g_array_index(pollfds, GPollFD, + so->pollfds_idx).revents; + } + + if (so->s != -1 && + (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) { sorecvfrom(so); } } @@ -600,9 +625,18 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, */ for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { - so_next = so->so_next; + int revents; - if (so->s != -1 && FD_ISSET(so->s, readfds)) { + so_next = so->so_next; + + revents = 0; + if (so->pollfds_idx != -1) { + revents = g_array_index(pollfds, GPollFD, + so->pollfds_idx).revents; + } + + if (so->s != -1 && + (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) { icmp_receive(so); } } @@ -610,15 +644,6 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, if_start(slirp); } - - /* clear global file descriptor sets. - * these reside on the stack in vl.c - * so they're unusable if we're not in - * slirp_select_fill or slirp_select_poll. - */ - global_readfds = NULL; - global_writefds = NULL; - global_xfds = NULL; } static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) diff --git a/slirp/socket.c b/slirp/socket.c index 77b0c98197..a7ab933c43 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -680,9 +680,6 @@ sofcantrcvmore(struct socket *so) { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,0); - if(global_writefds) { - FD_CLR(so->s,global_writefds); - } } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTSENDMORE) { @@ -698,12 +695,6 @@ sofcantsendmore(struct socket *so) { if ((so->so_state & SS_NOFDREF) == 0) { shutdown(so->s,1); /* send FIN to fhost */ - if (global_readfds) { - FD_CLR(so->s,global_readfds); - } - if (global_xfds) { - FD_CLR(so->s,global_xfds); - } } so->so_state &= ~(SS_ISFCONNECTING); if (so->so_state & SS_FCANTRCVMORE) { diff --git a/slirp/socket.h b/slirp/socket.h index 857b0da311..57e0407ebc 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -20,6 +20,8 @@ struct socket { int s; /* The actual socket */ + int pollfds_idx; /* GPollFD GArray index */ + Slirp *slirp; /* managing slirp instance */ /* XXX union these with not-yet-used sbuf params */ diff --git a/stubs/slirp.c b/stubs/slirp.c index 9a3309a2b9..f1fc833f7a 100644 --- a/stubs/slirp.c +++ b/stubs/slirp.c @@ -5,13 +5,11 @@ void slirp_update_timeout(uint32_t *timeout) { } -void slirp_select_fill(int *pnfds, fd_set *readfds, - fd_set *writefds, fd_set *xfds) +void slirp_pollfds_fill(GArray *pollfds) { } -void slirp_select_poll(fd_set *readfds, fd_set *writefds, - fd_set *xfds, int select_error) +void slirp_pollfds_poll(GArray *pollfds, int select_error) { } From a3e4b4a8091cc4fcf7cb619570c72c54c2d6a6e9 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:29 +0100 Subject: [PATCH 1169/1634] iohandler: switch to GPollFD Convert iohandler_select_fill() and iohandler_select_poll() to use GPollFD instead of rfds/wfds/xfds. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-7-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- include/qemu/main-loop.h | 4 ++-- iohandler.c | 40 ++++++++++++++++++++++++++++++---------- main-loop.c | 4 ++-- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index e8059c3d0a..09952885a9 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -297,8 +297,8 @@ void qemu_mutex_unlock_iothread(void); /* internal interfaces */ void qemu_fd_register(int fd); -void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); -void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc); +void qemu_iohandler_fill(GArray *pollfds); +void qemu_iohandler_poll(GArray *pollfds, int rc); QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); void qemu_bh_schedule_idle(QEMUBH *bh); diff --git a/iohandler.c b/iohandler.c index 2523adc11d..ae2ef8f966 100644 --- a/iohandler.c +++ b/iohandler.c @@ -39,6 +39,7 @@ typedef struct IOHandlerRecord { void *opaque; QLIST_ENTRY(IOHandlerRecord) next; int fd; + int pollfds_idx; bool deleted; } IOHandlerRecord; @@ -78,6 +79,7 @@ int qemu_set_fd_handler2(int fd, ioh->fd_read = fd_read; ioh->fd_write = fd_write; ioh->opaque = opaque; + ioh->pollfds_idx = -1; ioh->deleted = 0; qemu_notify_event(); } @@ -92,38 +94,56 @@ int qemu_set_fd_handler(int fd, return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); } -void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds) +void qemu_iohandler_fill(GArray *pollfds) { IOHandlerRecord *ioh; QLIST_FOREACH(ioh, &io_handlers, next) { + int events = 0; + if (ioh->deleted) continue; if (ioh->fd_read && (!ioh->fd_read_poll || ioh->fd_read_poll(ioh->opaque) != 0)) { - FD_SET(ioh->fd, readfds); - if (ioh->fd > *pnfds) - *pnfds = ioh->fd; + events |= G_IO_IN | G_IO_HUP | G_IO_ERR; } if (ioh->fd_write) { - FD_SET(ioh->fd, writefds); - if (ioh->fd > *pnfds) - *pnfds = ioh->fd; + events |= G_IO_OUT | G_IO_ERR; + } + if (events) { + GPollFD pfd = { + .fd = ioh->fd, + .events = events, + }; + ioh->pollfds_idx = pollfds->len; + g_array_append_val(pollfds, pfd); + } else { + ioh->pollfds_idx = -1; } } } -void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int ret) +void qemu_iohandler_poll(GArray *pollfds, int ret) { if (ret > 0) { IOHandlerRecord *pioh, *ioh; QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { - if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, readfds)) { + int revents = 0; + + if (!ioh->deleted && ioh->pollfds_idx != -1) { + GPollFD *pfd = &g_array_index(pollfds, GPollFD, + ioh->pollfds_idx); + revents = pfd->revents; + } + + if (!ioh->deleted && ioh->fd_read && + (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) { ioh->fd_read(ioh->opaque); } - if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, writefds)) { + if (!ioh->deleted && ioh->fd_write && + (revents & (G_IO_OUT | G_IO_ERR))) { ioh->fd_write(ioh->opaque); } diff --git a/main-loop.c b/main-loop.c index 839e98ff6a..800868a339 100644 --- a/main-loop.c +++ b/main-loop.c @@ -507,9 +507,9 @@ int main_loop_wait(int nonblocking) slirp_update_timeout(&timeout); slirp_pollfds_fill(gpollfds); #endif - qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds); + qemu_iohandler_fill(gpollfds); ret = os_host_main_loop_wait(timeout); - qemu_iohandler_poll(&rfds, &wfds, &xfds, ret); + qemu_iohandler_poll(gpollfds, ret); #ifdef CONFIG_SLIRP slirp_pollfds_poll(gpollfds, (ret < 0)); #endif From 9cbaacf999b01b27dc3a22502705178057af66de Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:30 +0100 Subject: [PATCH 1170/1634] main-loop: drop rfds/wfds/xfds for good Now that all *_fill() and *_poll() functions use GPollFD we no longer need rfds/wfds/xfds or pollfds_from_select()/pollfds_to_select(). >From now on everything uses GPollFD. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-8-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- main-loop.c | 77 ++--------------------------------------------------- 1 file changed, 2 insertions(+), 75 deletions(-) diff --git a/main-loop.c b/main-loop.c index 800868a339..8c9b58c14c 100644 --- a/main-loop.c +++ b/main-loop.c @@ -143,66 +143,8 @@ int qemu_init_main_loop(void) return 0; } -static fd_set rfds, wfds, xfds; -static int nfds; static int max_priority; -/* Load rfds/wfds/xfds into gpollfds. Will be removed a few commits later. */ -static void gpollfds_from_select(void) -{ - int fd; - for (fd = 0; fd <= nfds; fd++) { - int events = 0; - if (FD_ISSET(fd, &rfds)) { - events |= G_IO_IN | G_IO_HUP | G_IO_ERR; - } - if (FD_ISSET(fd, &wfds)) { - events |= G_IO_OUT | G_IO_ERR; - } - if (FD_ISSET(fd, &xfds)) { - events |= G_IO_PRI; - } - if (events) { - GPollFD pfd = { - .fd = fd, - .events = events, - }; - g_array_append_val(gpollfds, pfd); - } - } -} - -/* Store gpollfds revents into rfds/wfds/xfds. Will be removed a few commits - * later. - */ -static void gpollfds_to_select(int ret) -{ - int i; - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - - if (ret <= 0) { - return; - } - - for (i = 0; i < gpollfds->len; i++) { - int fd = g_array_index(gpollfds, GPollFD, i).fd; - int revents = g_array_index(gpollfds, GPollFD, i).revents; - - if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) { - FD_SET(fd, &rfds); - } - if (revents & (G_IO_OUT | G_IO_ERR)) { - FD_SET(fd, &wfds); - } - if (revents & G_IO_PRI) { - FD_SET(fd, &xfds); - } - } -} - #ifndef _WIN32 static int glib_pollfds_idx; static int glib_n_poll_fds; @@ -251,15 +193,8 @@ static int os_host_main_loop_wait(uint32_t timeout) qemu_mutex_unlock_iothread(); } - /* We'll eventually drop fd_set completely. But for now we still have - * *_fill() and *_poll() functions that use rfds/wfds/xfds. - */ - gpollfds_from_select(); - ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout); - gpollfds_to_select(ret); - if (timeout > 0) { qemu_mutex_lock_iothread(); } @@ -417,6 +352,8 @@ static int os_host_main_loop_wait(uint32_t timeout) WaitObjects *w = &wait_objects; gint poll_timeout; static struct timeval tv0; + fd_set rfds, wfds, xfds; + int nfds; /* XXX: need to suppress polling by better using win32 events */ ret = 0; @@ -463,10 +400,6 @@ static int os_host_main_loop_wait(uint32_t timeout) * improve socket latency. */ - /* This back-and-forth between GPollFDs and select(2) is temporary. We'll - * drop it in a couple of patches, I promise :). - */ - gpollfds_from_select(); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); @@ -480,7 +413,6 @@ static int os_host_main_loop_wait(uint32_t timeout) pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds); } } - gpollfds_to_select(select_ret); return select_ret || g_poll_ret; } @@ -498,11 +430,6 @@ int main_loop_wait(int nonblocking) /* poll any events */ g_array_set_size(gpollfds, 0); /* reset for new iteration */ /* XXX: separate device handlers from system ones */ - nfds = -1; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&xfds); - #ifdef CONFIG_SLIRP slirp_update_timeout(&timeout); slirp_pollfds_fill(gpollfds); From d0c8d2c05f67a1a007d87fa3b99254abfa42d06d Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:31 +0100 Subject: [PATCH 1171/1634] aio: extract aio_dispatch() from aio_poll() We will need to loop over AioHandlers calling ->io_read()/->io_write() when aio_poll() is converted from select(2) to g_poll(2). Luckily the code for this already exists, extract it into the new aio_dispatch() function. Two small changes: * aio_poll() checks !node->deleted to avoid calling handlers that have been deleted. * Fix typo 'then' -> 'them' in aio_poll() comment. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-9-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- aio-posix.c | 57 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/aio-posix.c b/aio-posix.c index fe4dbb4523..35131a3ef7 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -129,30 +129,12 @@ bool aio_pending(AioContext *ctx) return false; } -bool aio_poll(AioContext *ctx, bool blocking) +static bool aio_dispatch(AioContext *ctx) { - static struct timeval tv0; AioHandler *node; - fd_set rdfds, wrfds; - int max_fd = -1; - int ret; - bool busy, progress; - - progress = false; + bool progress = false; /* - * If there are callbacks left that have been queued, we need to call then. - * Do not call select in this case, because it is possible that the caller - * does not need a complete flush (as is the case for qemu_aio_wait loops). - */ - if (aio_bh_poll(ctx)) { - blocking = false; - progress = true; - } - - /* - * Then dispatch any pending callbacks from the GSource. - * * We have to walk very carefully in case qemu_aio_set_fd_handler is * called while we're walking. */ @@ -167,11 +149,15 @@ bool aio_poll(AioContext *ctx, bool blocking) node->pfd.revents = 0; /* See comment in aio_pending. */ - if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) { + if (!node->deleted && + (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) && + node->io_read) { node->io_read(node->opaque); progress = true; } - if (revents & (G_IO_OUT | G_IO_ERR) && node->io_write) { + if (!node->deleted && + (revents & (G_IO_OUT | G_IO_ERR)) && + node->io_write) { node->io_write(node->opaque); progress = true; } @@ -186,6 +172,33 @@ bool aio_poll(AioContext *ctx, bool blocking) g_free(tmp); } } + return progress; +} + +bool aio_poll(AioContext *ctx, bool blocking) +{ + static struct timeval tv0; + AioHandler *node; + fd_set rdfds, wrfds; + int max_fd = -1; + int ret; + bool busy, progress; + + progress = false; + + /* + * If there are callbacks left that have been queued, we need to call them. + * Do not call select in this case, because it is possible that the caller + * does not need a complete flush (as is the case for qemu_aio_wait loops). + */ + if (aio_bh_poll(ctx)) { + blocking = false; + progress = true; + } + + if (aio_dispatch(ctx)) { + progress = true; + } if (progress && !blocking) { return true; From 6b5f876252b7aeec43e319afdf17705f512be2bc Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:32 +0100 Subject: [PATCH 1172/1634] aio: convert aio_poll() to g_poll(3) AioHandler already has a GPollFD so we can directly use its events/revents. Add the int pollfds_idx field to AioContext so we can map g_poll(3) results back to AioHandlers. Reuse aio_dispatch() to invoke handlers after g_poll(3). Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-10-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- aio-posix.c | 67 ++++++++++++++++----------------------------- async.c | 2 ++ include/block/aio.h | 3 ++ 3 files changed, 29 insertions(+), 43 deletions(-) diff --git a/aio-posix.c b/aio-posix.c index 35131a3ef7..d755e16ee8 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -25,6 +25,7 @@ struct AioHandler IOHandler *io_write; AioFlushHandler *io_flush; int deleted; + int pollfds_idx; void *opaque; QLIST_ENTRY(AioHandler) node; }; @@ -85,6 +86,7 @@ void aio_set_fd_handler(AioContext *ctx, node->io_write = io_write; node->io_flush = io_flush; node->opaque = opaque; + node->pollfds_idx = -1; node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0); node->pfd.events |= (io_write ? G_IO_OUT : 0); @@ -177,10 +179,7 @@ static bool aio_dispatch(AioContext *ctx) bool aio_poll(AioContext *ctx, bool blocking) { - static struct timeval tv0; AioHandler *node; - fd_set rdfds, wrfds; - int max_fd = -1; int ret; bool busy, progress; @@ -206,12 +205,13 @@ bool aio_poll(AioContext *ctx, bool blocking) ctx->walking_handlers++; - FD_ZERO(&rdfds); - FD_ZERO(&wrfds); + g_array_set_size(ctx->pollfds, 0); - /* fill fd sets */ + /* fill pollfds */ busy = false; QLIST_FOREACH(node, &ctx->aio_handlers, node) { + node->pollfds_idx = -1; + /* If there aren't pending AIO operations, don't invoke callbacks. * Otherwise, if there are no AIO requests, qemu_aio_wait() would * wait indefinitely. @@ -222,13 +222,13 @@ bool aio_poll(AioContext *ctx, bool blocking) } busy = true; } - if (!node->deleted && node->io_read) { - FD_SET(node->pfd.fd, &rdfds); - max_fd = MAX(max_fd, node->pfd.fd + 1); - } - if (!node->deleted && node->io_write) { - FD_SET(node->pfd.fd, &wrfds); - max_fd = MAX(max_fd, node->pfd.fd + 1); + if (!node->deleted && node->pfd.events) { + GPollFD pfd = { + .fd = node->pfd.fd, + .events = node->pfd.events, + }; + node->pollfds_idx = ctx->pollfds->len; + g_array_append_val(ctx->pollfds, pfd); } } @@ -240,41 +240,22 @@ bool aio_poll(AioContext *ctx, bool blocking) } /* wait until next event */ - ret = select(max_fd, &rdfds, &wrfds, NULL, blocking ? NULL : &tv0); + ret = g_poll((GPollFD *)ctx->pollfds->data, + ctx->pollfds->len, + blocking ? -1 : 0); /* if we have any readable fds, dispatch event */ if (ret > 0) { - /* we have to walk very carefully in case - * qemu_aio_set_fd_handler is called while we're walking */ - node = QLIST_FIRST(&ctx->aio_handlers); - while (node) { - AioHandler *tmp; - - ctx->walking_handlers++; - - if (!node->deleted && - FD_ISSET(node->pfd.fd, &rdfds) && - node->io_read) { - node->io_read(node->opaque); - progress = true; - } - if (!node->deleted && - FD_ISSET(node->pfd.fd, &wrfds) && - node->io_write) { - node->io_write(node->opaque); - progress = true; - } - - tmp = node; - node = QLIST_NEXT(node, node); - - ctx->walking_handlers--; - - if (!ctx->walking_handlers && tmp->deleted) { - QLIST_REMOVE(tmp, node); - g_free(tmp); + QLIST_FOREACH(node, &ctx->aio_handlers, node) { + if (node->pollfds_idx != -1) { + GPollFD *pfd = &g_array_index(ctx->pollfds, GPollFD, + node->pollfds_idx); + node->pfd.revents = pfd->revents; } } + if (aio_dispatch(ctx)) { + progress = true; + } } assert(progress || busy); diff --git a/async.c b/async.c index 72d268ae35..f2d47ba96d 100644 --- a/async.c +++ b/async.c @@ -174,6 +174,7 @@ aio_ctx_finalize(GSource *source) aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL); event_notifier_cleanup(&ctx->notifier); + g_array_free(ctx->pollfds, TRUE); } static GSourceFuncs aio_source_funcs = { @@ -198,6 +199,7 @@ AioContext *aio_context_new(void) { AioContext *ctx; ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext)); + ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD)); event_notifier_init(&ctx->notifier, false); aio_set_event_notifier(ctx, &ctx->notifier, (EventNotifierHandler *) diff --git a/include/block/aio.h b/include/block/aio.h index 8eda924599..5b54d383fc 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -63,6 +63,9 @@ typedef struct AioContext { /* Used for aio_notify. */ EventNotifier notifier; + + /* GPollFDs for aio_poll() */ + GArray *pollfds; } AioContext; /* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ From b5a01a70ad49b518c2c4b0f0a37f5435f01ce716 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 20 Feb 2013 11:28:33 +0100 Subject: [PATCH 1173/1634] aio: support G_IO_HUP and G_IO_ERR aio-posix.c could not take advantage of G_IO_HUP and G_IO_ERR because select(2) does not have equivalent events. Now that g_poll(3) is used we can support G_IO_HUP and G_IO_ERR. Signed-off-by: Stefan Hajnoczi Reviewed-by: Laszlo Ersek Message-id: 1361356113-11049-11-git-send-email-stefanha@redhat.com Signed-off-by: Anthony Liguori --- aio-posix.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/aio-posix.c b/aio-posix.c index d755e16ee8..b68eccd40c 100644 --- a/aio-posix.c +++ b/aio-posix.c @@ -88,8 +88,8 @@ void aio_set_fd_handler(AioContext *ctx, node->opaque = opaque; node->pollfds_idx = -1; - node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP : 0); - node->pfd.events |= (io_write ? G_IO_OUT : 0); + node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0); + node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0); } aio_notify(ctx); @@ -112,13 +112,6 @@ bool aio_pending(AioContext *ctx) QLIST_FOREACH(node, &ctx->aio_handlers, node) { int revents; - /* - * FIXME: right now we cannot get G_IO_HUP and G_IO_ERR because - * main-loop.c is still select based (due to the slirp legacy). - * If main-loop.c ever switches to poll, G_IO_ERR should be - * tested too. Dispatching G_IO_ERR to both handlers should be - * okay, since handlers need to be ready for spurious wakeups. - */ revents = node->pfd.revents & node->pfd.events; if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read) { return true; @@ -150,7 +143,6 @@ static bool aio_dispatch(AioContext *ctx) revents = node->pfd.revents & node->pfd.events; node->pfd.revents = 0; - /* See comment in aio_pending. */ if (!node->deleted && (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) && node->io_read) { From 2ca81baa0b3363d57de94f8b80c02a003b361161 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 20 Feb 2013 18:04:01 +0800 Subject: [PATCH 1174/1634] help: add docs for multiqueue tap options Cc: Markus Armbruster Cc: Jason Wang Signed-off-by: Jason Wang Message-id: 1361354641-51969-1-git-send-email-jasowang@redhat.com Signed-off-by: Anthony Liguori --- qapi-schema.json | 6 ++++++ qemu-options.hx | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/qapi-schema.json b/qapi-schema.json index 7275b5dd6a..cd7ea25e4c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2504,6 +2504,9 @@ # # @fd: #optional file descriptor of an already opened tap # +# @fds: #optional multiple file descriptors of already opened multiqueue capable +# tap +# # @script: #optional script to initialize the interface # # @downscript: #optional script to shut down the interface @@ -2518,6 +2521,9 @@ # # @vhostfd: #optional file descriptor of an already opened vhost net device # +# @vhostfds: #optional file descriptors of multiple already opened vhost net +# devices +# # @vhostforce: #optional vhost on for non-MSIX virtio guests # # Since 1.2 diff --git a/qemu-options.hx b/qemu-options.hx index 4bc9c85d9e..2832d82148 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1354,7 +1354,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, "-net tap[,vlan=n][,name=str],ifname=name\n" " connect the host TAP network interface to VLAN 'n'\n" #else - "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n" + "-net tap[,vlan=n][,name=str][,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off]\n" " connect the host TAP network interface to VLAN 'n'\n" " use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n" " to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n" @@ -1363,6 +1363,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, " use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n" " configure it\n" " use 'fd=h' to connect to an already opened TAP interface\n" + " use 'fds=x:y:...:z' to connect to already opened multiqueue capable TAP interfaces\n" " use 'sndbuf=nbytes' to limit the size of the send buffer (the\n" " default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n" " use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag\n" @@ -1371,6 +1372,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, " (only has effect for virtio guests which use MSIX)\n" " use vhostforce=on to force vhost on for non-MSIX virtio guests\n" " use 'vhostfd=h' to connect to an already opened vhost net device\n" + " use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n" "-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n" " connects a host TAP network interface to a host bridge device 'br'\n" " (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n" From ba43da36983a0bff2778abfa2338697da129030c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Feb 2013 16:24:22 +0000 Subject: [PATCH 1175/1634] Remove elderly top level TODO file The top level TODO file hasn't been touched since 2008, so it's now an unhelpful and out of date mix of things that have already been done, things that don't make sense any more and things which could in theory be done but are not in practice important enough (or we'd have done them some time in the last five years). Remove it. The bug tracking system is probably a better place to track TODO items if we want to do so. Signed-off-by: Peter Maydell Message-id: 1361377462-19816-1-git-send-email-peter.maydell@linaro.org Signed-off-by: Anthony Liguori --- TODO | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 TODO diff --git a/TODO b/TODO deleted file mode 100644 index 1d4c638f27..0000000000 --- a/TODO +++ /dev/null @@ -1,37 +0,0 @@ -General: -------- -- cycle counter for all archs -- cpu_interrupt() win32/SMP fix -- merge PIC spurious interrupt patch -- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?) -- config file (at least for windows/Mac OS X) -- update doc: PCI infos. -- basic VGA optimizations -- better code fetch -- do not resize vga if invalid size. -- TLB code protection support for PPC -- disable SMC handling for ARM/SPARC/PPC (not finished) -- see undefined flags for BTx insn -- keyboard output buffer filling timing emulation -- tests for each target CPU -- fix all remaining thread lock issues (must put TBs in a specific invalid - state, find a solution for tb_flush()). - -ppc specific: ------------- -- TLB invalidate not needed if msr_pr changes -- enable shift optimizations ? - -linux-user specific: -------------------- -- remove threading support as it cannot work at this point -- improve IPC syscalls -- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit - issues, fix 16 bit uid issues) -- use kernel traps for unaligned accesses on ARM ? - - -lower priority: --------------- -- int15 ah=86: use better timing -- use -msoft-float on ARM From b1424e0381a7f1c9969079eca4458d5f20bf1859 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 20 Feb 2013 09:37:12 +0100 Subject: [PATCH 1176/1634] vga: fix byteswapping. In case host and guest endianness differ the vga code first creates a shared surface (using qemu_create_displaysurface_from), then goes patch the surface format to indicate that the bytes must be swapped. The switch to pixman broke that hack as the format patching isn't propagated into the pixman image, so ui code using the pixman image directly (such as vnc) uses the wrong format. Fix that by adding a byteswap parameter to qemu_create_displaysurface_from, so we'll use the correct format when creating the surface (and the pixman image) and don't have to patch the format afterwards. [ v2: unbreak xen build ] Cc: qemu-stable@nongnu.org Cc: mark.cave-ayland@ilande.co.uk Cc: agraf@suse.de Signed-off-by: Gerd Hoffmann Message-id: 1361349432-23884-1-git-send-email-kraxel@redhat.com Signed-off-by: Anthony Liguori --- hw/qxl-render.c | 3 ++- hw/vga.c | 18 ++++++++---------- hw/vmware_vga.c | 2 +- hw/xenfb.c | 3 ++- include/ui/console.h | 3 ++- ui/console.c | 9 +++++++-- 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/qxl-render.c b/hw/qxl-render.c index 88e63f8085..455fb91269 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -118,7 +118,8 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.surface.height, qxl->guest_primary.bits_pp, qxl->guest_primary.abs_stride, - qxl->guest_primary.data); + qxl->guest_primary.data, + false); } else { qemu_resize_displaysurface(vga->ds, qxl->guest_primary.surface.width, diff --git a/hw/vga.c b/hw/vga.c index e2ba7f208c..1caf23d7b6 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -1643,6 +1643,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) uint8_t *d; uint32_t v, addr1, addr; vga_draw_line_func *vga_draw_line; +#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) + static const bool byteswap = false; +#else + static const bool byteswap = true; +#endif full_update |= update_basic_params(s); @@ -1685,18 +1690,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) disp_width != s->last_width || height != s->last_height || s->last_depth != depth) { -#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - if (depth == 16 || depth == 32) { -#else - if (depth == 32) { -#endif + if (depth == 32 || (depth == 16 && !byteswap)) { qemu_free_displaysurface(s->ds); s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, s->line_offset, - s->vram_ptr + (s->start_addr * 4)); -#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) - s->ds->surface->pf = qemu_different_endianness_pixelformat(depth); -#endif + s->vram_ptr + (s->start_addr * 4), byteswap); dpy_gfx_resize(s->ds); } else { qemu_console_resize(s->ds, disp_width, height); @@ -1715,7 +1713,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, s->line_offset, - s->vram_ptr + (s->start_addr * 4)); + s->vram_ptr + (s->start_addr * 4), byteswap); dpy_gfx_setdata(s->ds); } diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index cd15ee40a8..8fc201bfb9 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1074,7 +1074,7 @@ static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch, ds_get_height(s->vga.ds), 32, ds_get_linesize(s->vga.ds), - s->vga.vram_ptr); + s->vga.vram_ptr, false); ppm_save(filename, ds, errp); g_free(ds); } diff --git a/hw/xenfb.c b/hw/xenfb.c index 903efd3073..7f1f6b4643 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -756,7 +756,8 @@ static void xenfb_update(void *opaque) qemu_free_displaysurface(xenfb->c.ds); xenfb->c.ds->surface = qemu_create_displaysurface_from (xenfb->width, xenfb->height, xenfb->depth, - xenfb->row_stride, xenfb->pixels + xenfb->offset); + xenfb->row_stride, xenfb->pixels + xenfb->offset, + false); break; default: /* we must convert stuff */ diff --git a/include/ui/console.h b/include/ui/console.h index fc23baa06b..18012f1dc1 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -184,7 +184,8 @@ struct DisplayState { void register_displaystate(DisplayState *ds); DisplayState *get_displaystate(void); DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, - int linesize, uint8_t *data); + int linesize, uint8_t *data, + bool byteswap); PixelFormat qemu_different_endianness_pixelformat(int bpp); PixelFormat qemu_default_pixelformat(int bpp); diff --git a/ui/console.c b/ui/console.c index 0a68836d50..25e06a5cb3 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1339,11 +1339,16 @@ DisplaySurface *qemu_resize_displaysurface(DisplayState *ds, } DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp, - int linesize, uint8_t *data) + int linesize, uint8_t *data, + bool byteswap) { DisplaySurface *surface = g_new0(DisplaySurface, 1); - surface->pf = qemu_default_pixelformat(bpp); + if (byteswap) { + surface->pf = qemu_different_endianness_pixelformat(bpp); + } else { + surface->pf = qemu_default_pixelformat(bpp); + } surface->format = qemu_pixman_get_format(&surface->pf); assert(surface->format != 0); From 3e407de47700cce4babbe0f3ac35677e7b852cf6 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Tue, 19 Feb 2013 14:02:09 +1000 Subject: [PATCH 1177/1634] qom/object.c: Reset interface list on inheritance The QOM framework will attempt the recreate a classes interface list from scratch for each class. This means that a child class should zero out the list of interfaces when cloned from the parent class. Currently the list is memcpy()d from the parent to the child. As the interface list is just a pointer to a list, this means the parent and child will share the same list of interfaces. When the child inits, it will append its own interfaces to the parents list. This is incorrect as the parent should not pick up its childs interfaces. This actually causes an infinite loop at class init time, as the child will iterate through the parent interface list adding each itf to its own list(in type_initialize()). As the list is (erroneously) shared, the new interface instances for the child are appended to the parent, and the iterator never hits the tail and loops forever. Signed-off-by: Peter Crosthwaite Reviewed-by: Paolo Bonzini Message-id: 1f58d2b629d82865dbb2fd5ba8445854049c4382.1361246206.git.peter.crosthwaite@xilinx.com Signed-off-by: Anthony Liguori --- qom/object.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qom/object.c b/qom/object.c index 563e45b0cc..4b72a64337 100644 --- a/qom/object.c +++ b/qom/object.c @@ -245,6 +245,7 @@ static void type_initialize(TypeImpl *ti) g_assert(parent->class_size <= ti->class_size); memcpy(ti->class, parent->class, parent->class_size); + ti->class->interfaces = NULL; for (e = parent->class->interfaces; e; e = e->next) { ObjectClass *iface = e->data; From 00e2ceae6c55bef40f5128a3e606f5c44351e0f9 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Tue, 19 Feb 2013 14:02:10 +1000 Subject: [PATCH 1178/1634] qom/object.c: Allow itf cast with num_itfs = 0 num_interfaces only tells you how many interfaces the concrete child class has (as defined in the TypeInfo). This means if you have a child class which defines no interfaces of its own, but its parent has interfaces you cannot cast to those parent interfaces. Fixed changing the guard to check the class->interfaces list instead (which is a complete flattened list of implemented interfaces). Signed-off-by: Peter Crosthwaite Message-id: a8c2db3b9b1f3c4bb81aca352b69e33260f36545.1361246206.git.peter.crosthwaite@xilinx.com Signed-off-by: Anthony Liguori --- qom/object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qom/object.c b/qom/object.c index 4b72a64337..3d638ff273 100644 --- a/qom/object.c +++ b/qom/object.c @@ -449,7 +449,8 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class, TypeImpl *type = class->type; ObjectClass *ret = NULL; - if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) { + if (type->class->interfaces && + type_is_ancestor(target_type, type_interface)) { int found = 0; GSList *i; From 22bc9a46bda8f5f88626d3fb578f5d55953c9743 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:18 -0600 Subject: [PATCH 1179/1634] build: disable Wstrict-prototypes GTK won't build with strict-prototypes due to gtkitemfactory.h: /* We use () here to mean unspecified arguments. This is deprecated * as of C99, but we can't change it without breaking compatibility. * (Note that if we are included from a C++ program () will mean * (void) so an explicit cast will be needed.) */ typedef void (*GtkItemFactoryCallback) (); Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-2-git-send-email-aliguori@us.ibm.com --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 42cb3144a5..2008978709 100755 --- a/configure +++ b/configure @@ -283,7 +283,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}" # default flags for all hosts QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS" QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS" -QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS" +QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS" QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS" QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/include" if test "$debug_info" = "yes"; then From d82831dbc5471d72785c49b33710436af49bf9ca Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:19 -0600 Subject: [PATCH 1180/1634] console: allow VCs to be overridden by UI We want to expose VCs using a VteTerminal widget. We need access to provide our own CharDriverState in order to do this. Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-3-git-send-email-aliguori@us.ibm.com --- include/ui/console.h | 6 +++++- qemu-char.c | 2 +- ui/console.c | 14 +++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 18012f1dc1..694994b29f 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -443,7 +443,6 @@ void vga_hw_text_update(console_ch_t *chardata); int is_graphic_console(void); int is_fixedsize_console(void); -CharDriverState *text_console_init(QemuOpts *opts); void text_consoles_set_display(DisplayState *ds); void console_select(unsigned int index); void console_color_init(DisplayState *ds); @@ -451,6 +450,11 @@ void qemu_console_resize(DisplayState *ds, int width, int height); void qemu_console_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h); +typedef CharDriverState *(VcHandler)(QemuOpts *); + +CharDriverState *vc_init(QemuOpts *opts); +void register_vc_handler(VcHandler *handler); + /* sdl.c */ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame); diff --git a/qemu-char.c b/qemu-char.c index e4b0f5304f..160decc2f0 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2980,7 +2980,7 @@ static const struct { { .name = "socket", .open = qemu_chr_open_socket }, { .name = "udp", .open = qemu_chr_open_udp }, { .name = "msmouse", .open = qemu_chr_open_msmouse }, - { .name = "vc", .open = text_console_init }, + { .name = "vc", .open = vc_init }, { .name = "memory", .open = qemu_chr_open_ringbuf }, #ifdef _WIN32 { .name = "file", .open = qemu_chr_open_win_file_out }, diff --git a/ui/console.c b/ui/console.c index 25e06a5cb3..0d95f32123 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1537,7 +1537,7 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) chr->init(chr); } -CharDriverState *text_console_init(QemuOpts *opts) +static CharDriverState *text_console_init(QemuOpts *opts) { CharDriverState *chr; QemuConsole *s; @@ -1573,6 +1573,18 @@ CharDriverState *text_console_init(QemuOpts *opts) return chr; } +static VcHandler *vc_handler = text_console_init; + +CharDriverState *vc_init(QemuOpts *opts) +{ + return vc_handler(opts); +} + +void register_vc_handler(VcHandler *handler) +{ + vc_handler = handler; +} + void text_consoles_set_display(DisplayState *ds) { int i; From a4ccabcf6deaeb42c65d5d6d84ba0ceff8003876 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:20 -0600 Subject: [PATCH 1181/1634] ui: add basic GTK gui (v5) This is minimalistic and just contains the basic widget infrastructure. The GUI consists of a menu and a GtkNotebook. To start with, the notebook has its tabs hidden which provides a UI that looks very similar to SDL with the exception of the menu bar. The menu bar allows a user to toggle the visibility of the tabs. Cairo is used for rendering. I used gtk-vnc as a reference. gtk-vnc solves the same basic problems as QEMU since it was originally written as a remote display for QEMU. So for the most part, the approach to rendering and keyboard handling should be pretty solid for GTK. Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-4-git-send-email-aliguori@us.ibm.com --- configure | 31 +++ include/sysemu/sysemu.h | 1 + include/ui/console.h | 4 + ui/Makefile.objs | 3 + ui/gtk.c | 576 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 615 insertions(+) create mode 100644 ui/gtk.c diff --git a/configure b/configure index 2008978709..5ea760b039 100755 --- a/configure +++ b/configure @@ -226,6 +226,7 @@ coroutine="" seccomp="" glusterfs="" virtio_blk_data_plane="" +gtk="" # parse CC options first for opt do @@ -897,6 +898,10 @@ for opt do ;; --enable-virtio-blk-data-plane) virtio_blk_data_plane="yes" ;; + --disable-gtk) gtk="no" + ;; + --enable-gtk) gtk="yes" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -1635,6 +1640,26 @@ if test "$sparse" != "no" ; then fi fi +########################################## +# GTK probe + +if test "$gtk" != "no"; then + if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \ + $pkg_config vte --modversion >/dev/null 2>/dev/null; then + gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null` + gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null` + vte_cflags=`$pkg_config --cflags vte 2>/dev/null` + vte_libs=`$pkg_config --libs vte 2>/dev/null` + libs_softmmu="$gtk_libs $vte_libs $libs_softmmu" + gtk="yes" + else + if test "$gtk" = "yes" ; then + feature_not_found "gtk" + fi + gtk="no" + fi +fi + ########################################## # SDL probe @@ -3301,6 +3326,7 @@ if test "$darwin" = "yes" ; then fi echo "pixman $pixman" echo "SDL support $sdl" +echo "GTK support $gtk" echo "curses support $curses" echo "curl support $curl" echo "mingw32 support $mingw32" @@ -3591,6 +3617,11 @@ if test "$bluez" = "yes" ; then echo "BLUEZ_CFLAGS=$bluez_cflags" >> $config_host_mak fi echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak +if test "$gtk" = "yes" ; then + echo "CONFIG_GTK=y" >> $config_host_mak + echo "GTK_CFLAGS=$gtk_cflags" >> $config_host_mak + echo "VTE_CFLAGS=$vte_cflags" >> $config_host_mak +fi if test "$xen" = "yes" ; then echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index ae49088d42..b19ec952b4 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -89,6 +89,7 @@ typedef enum DisplayType DT_DEFAULT, DT_CURSES, DT_SDL, + DT_GTK, DT_NOGRAPHIC, DT_NONE, } DisplayType; diff --git a/include/ui/console.h b/include/ui/console.h index 694994b29f..c42bca6efe 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -487,4 +487,8 @@ void curses_display_init(DisplayState *ds, int full_screen); int index_from_key(const char *key); int index_from_keycode(int code); +/* gtk.c */ +void early_gtk_display_init(void); +void gtk_display_init(DisplayState *ds); + #endif diff --git a/ui/Makefile.objs b/ui/Makefile.objs index d9db073584..85c50cd89b 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -13,7 +13,10 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o common-obj-$(CONFIG_COCOA) += cocoa.o common-obj-$(CONFIG_CURSES) += curses.o common-obj-$(CONFIG_VNC) += $(vnc-obj-y) +common-obj-$(CONFIG_GTK) += gtk.o $(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS) $(obj)/cocoa.o: $(SRC_PATH)/$(obj)/cocoa.m + +$(obj)/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS) diff --git a/ui/gtk.c b/ui/gtk.c new file mode 100644 index 0000000000..85e7999bce --- /dev/null +++ b/ui/gtk.c @@ -0,0 +1,576 @@ +/* + * GTK UI + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Portions from gtk-vnc: + * + * GTK VNC Widget + * + * Copyright (C) 2006 Anthony Liguori + * Copyright (C) 2009-2010 Daniel P. Berrange + * + * 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.0 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qemu-common.h" +#include "ui/console.h" +#include "sysemu/sysemu.h" +#include "qmp-commands.h" +#include "x_keymap.h" +#include "keymaps.h" + +//#define DEBUG_GTK + +#ifdef DEBUG_GTK +#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) do { } while (0) +#endif + +typedef struct VirtualConsole +{ + GtkWidget *menu_item; + GtkWidget *terminal; + GtkWidget *scrolled_window; + CharDriverState *chr; + int fd; +} VirtualConsole; + +typedef struct GtkDisplayState +{ + GtkWidget *window; + + GtkWidget *menu_bar; + + GtkWidget *file_menu_item; + GtkWidget *file_menu; + GtkWidget *quit_item; + + GtkWidget *view_menu_item; + GtkWidget *view_menu; + GtkWidget *vga_item; + + GtkWidget *show_tabs_item; + + GtkWidget *vbox; + GtkWidget *notebook; + GtkWidget *drawing_area; + cairo_surface_t *surface; + DisplayChangeListener dcl; + DisplayState *ds; + int button_mask; + int last_x; + int last_y; + + double scale_x; + double scale_y; + + GdkCursor *null_cursor; + Notifier mouse_mode_notifier; +} GtkDisplayState; + +static GtkDisplayState *global_state; + +/** Utility Functions **/ + +static void gd_update_cursor(GtkDisplayState *s, gboolean override) +{ + GdkWindow *window; + bool on_vga; + + window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area)); + + on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0); + + if ((override || on_vga) && kbd_mouse_is_absolute()) { + gdk_window_set_cursor(window, s->null_cursor); + } else { + gdk_window_set_cursor(window, NULL); + } +} + +static void gd_update_caption(GtkDisplayState *s) +{ + const char *status = ""; + gchar *title; + + if (!runstate_is_running()) { + status = " [Stopped]"; + } + + if (qemu_name) { + title = g_strdup_printf("QEMU (%s)%s", qemu_name, status); + } else { + title = g_strdup_printf("QEMU%s", status); + } + + gtk_window_set_title(GTK_WINDOW(s->window), title); + + g_free(title); +} + +/** DisplayState Callbacks **/ + +static void gd_update(DisplayState *ds, int x, int y, int w, int h) +{ + GtkDisplayState *s = ds->opaque; + int x1, x2, y1, y2; + + DPRINTF("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h); + + x1 = floor(x * s->scale_x); + y1 = floor(y * s->scale_y); + + x2 = ceil(x * s->scale_x + w * s->scale_x); + y2 = ceil(y * s->scale_y + h * s->scale_y); + + gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1)); +} + +static void gd_refresh(DisplayState *ds) +{ + vga_hw_update(); +} + +static void gd_resize(DisplayState *ds) +{ + GtkDisplayState *s = ds->opaque; + cairo_format_t kind; + int stride; + + DPRINTF("resize(width=%d, height=%d)\n", + ds_get_width(ds), ds_get_height(ds)); + + if (s->surface) { + cairo_surface_destroy(s->surface); + } + + switch (ds->surface->pf.bits_per_pixel) { + case 8: + kind = CAIRO_FORMAT_A8; + break; + case 16: + kind = CAIRO_FORMAT_RGB16_565; + break; + case 32: + kind = CAIRO_FORMAT_RGB24; + break; + default: + g_assert_not_reached(); + break; + } + + stride = cairo_format_stride_for_width(kind, ds_get_width(ds)); + g_assert(ds_get_linesize(ds) == stride); + + s->surface = cairo_image_surface_create_for_data(ds_get_data(ds), + kind, + ds_get_width(ds), + ds_get_height(ds), + ds_get_linesize(ds)); + + gtk_widget_set_size_request(s->drawing_area, + ds_get_width(ds) * s->scale_x, + ds_get_height(ds) * s->scale_y); +} + +/** QEMU Events **/ + +static void gd_change_runstate(void *opaque, int running, RunState state) +{ + GtkDisplayState *s = opaque; + + gd_update_caption(s); +} + +static void gd_mouse_mode_change(Notifier *notify, void *data) +{ + gd_update_cursor(container_of(notify, GtkDisplayState, mouse_mode_notifier), + FALSE); +} + +/** GTK Events **/ + +static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event, + void *opaque) +{ + GtkDisplayState *s = opaque; + + if (!no_quit) { + unregister_displaychangelistener(s->ds, &s->dcl); + qmp_quit(NULL); + return FALSE; + } + + return TRUE; +} + +static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) +{ + GtkDisplayState *s = opaque; + int ww, wh; + int fbw, fbh; + + fbw = ds_get_width(s->ds); + fbh = ds_get_height(s->ds); + + gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh); + + cairo_rectangle(cr, 0, 0, ww, wh); + + if (ww != fbw || wh != fbh) { + s->scale_x = (double)ww / fbw; + s->scale_y = (double)wh / fbh; + cairo_scale(cr, s->scale_x, s->scale_y); + } else { + s->scale_x = 1.0; + s->scale_y = 1.0; + } + + cairo_set_source_surface(cr, s->surface, 0, 0); + cairo_paint(cr); + + return TRUE; +} + +static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose, + void *opaque) +{ + cairo_t *cr; + gboolean ret; + + cr = gdk_cairo_create(gtk_widget_get_window(widget)); + cairo_rectangle(cr, + expose->area.x, + expose->area.y, + expose->area.width, + expose->area.height); + cairo_clip(cr); + + ret = gd_draw_event(widget, cr, opaque); + + cairo_destroy(cr); + + return ret; +} + +static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, + void *opaque) +{ + GtkDisplayState *s = opaque; + int dx, dy; + int x, y; + + x = motion->x / s->scale_x; + y = motion->y / s->scale_y; + + if (kbd_mouse_is_absolute()) { + dx = x * 0x7FFF / (ds_get_width(s->ds) - 1); + dy = y * 0x7FFF / (ds_get_height(s->ds) - 1); + } else if (s->last_x == -1 || s->last_y == -1) { + dx = 0; + dy = 0; + } else { + dx = x - s->last_x; + dy = y - s->last_y; + } + + s->last_x = x; + s->last_y = y; + + if (kbd_mouse_is_absolute()) { + kbd_mouse_event(dx, dy, 0, s->button_mask); + } + + return TRUE; +} + +static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, + void *opaque) +{ + GtkDisplayState *s = opaque; + int dx, dy; + int n; + + if (button->button == 1) { + n = 0x01; + } else if (button->button == 2) { + n = 0x04; + } else if (button->button == 3) { + n = 0x02; + } else { + n = 0x00; + } + + if (button->type == GDK_BUTTON_PRESS) { + s->button_mask |= n; + } else if (button->type == GDK_BUTTON_RELEASE) { + s->button_mask &= ~n; + } + + if (kbd_mouse_is_absolute()) { + dx = s->last_x * 0x7FFF / (ds_get_width(s->ds) - 1); + dy = s->last_y * 0x7FFF / (ds_get_height(s->ds) - 1); + } else { + dx = 0; + dy = 0; + } + + kbd_mouse_event(dx, dy, 0, s->button_mask); + + return TRUE; +} + +static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) +{ + int gdk_keycode; + int qemu_keycode; + + gdk_keycode = key->hardware_keycode; + + if (gdk_keycode < 9) { + qemu_keycode = 0; + } else if (gdk_keycode < 97) { + qemu_keycode = gdk_keycode - 8; + } else if (gdk_keycode < 158) { + qemu_keycode = translate_evdev_keycode(gdk_keycode - 97); + } else if (gdk_keycode == 208) { /* Hiragana_Katakana */ + qemu_keycode = 0x70; + } else if (gdk_keycode == 211) { /* backslash */ + qemu_keycode = 0x73; + } else { + qemu_keycode = 0; + } + + DPRINTF("translated GDK keycode %d to QEMU keycode %d (%s)\n", + gdk_keycode, qemu_keycode, + (key->type == GDK_KEY_PRESS) ? "down" : "up"); + + if (qemu_keycode & SCANCODE_GREY) { + kbd_put_keycode(SCANCODE_EMUL0); + } + + if (key->type == GDK_KEY_PRESS) { + kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK); + } else if (key->type == GDK_KEY_RELEASE) { + kbd_put_keycode(qemu_keycode | SCANCODE_UP); + } else { + g_assert_not_reached(); + } + + return TRUE; +} + +/** Window Menu Actions **/ + +static void gd_menu_quit(GtkMenuItem *item, void *opaque) +{ + qmp_quit(NULL); +} + +static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) { + gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0); + } +} + +static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->show_tabs_item))) { + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), TRUE); + } else { + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); + } +} + +static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, + gpointer data) +{ + GtkDisplayState *s = data; + + if (!gtk_widget_get_realized(s->notebook)) { + return; + } + + gd_update_cursor(s, TRUE); +} + +void early_gtk_display_init(void) +{ +} + +/** Window Creation **/ + +static void gd_connect_signals(GtkDisplayState *s) +{ + g_signal_connect(s->show_tabs_item, "activate", + G_CALLBACK(gd_menu_show_tabs), s); + + g_signal_connect(s->window, "delete-event", + G_CALLBACK(gd_window_close), s); + + g_signal_connect(s->drawing_area, "expose-event", + G_CALLBACK(gd_expose_event), s); + g_signal_connect(s->drawing_area, "motion-notify-event", + G_CALLBACK(gd_motion_event), s); + g_signal_connect(s->drawing_area, "button-press-event", + G_CALLBACK(gd_button_event), s); + g_signal_connect(s->drawing_area, "button-release-event", + G_CALLBACK(gd_button_event), s); + g_signal_connect(s->drawing_area, "key-press-event", + G_CALLBACK(gd_key_event), s); + g_signal_connect(s->drawing_area, "key-release-event", + G_CALLBACK(gd_key_event), s); + + g_signal_connect(s->quit_item, "activate", + G_CALLBACK(gd_menu_quit), s); + g_signal_connect(s->vga_item, "activate", + G_CALLBACK(gd_menu_switch_vc), s); + g_signal_connect(s->notebook, "switch-page", + G_CALLBACK(gd_change_page), s); +} + +static void gd_create_menus(GtkDisplayState *s) +{ + GtkStockItem item; + GtkAccelGroup *accel_group; + GSList *group = NULL; + GtkWidget *separator; + + accel_group = gtk_accel_group_new(); + s->file_menu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group); + s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File"); + + s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); + gtk_stock_lookup(GTK_STOCK_QUIT, &item); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item), + "/File/Quit"); + gtk_accel_map_add_entry("/File/Quit", item.keyval, item.modifier); + + s->view_menu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); + s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View"); + + separator = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(s->view_menu), separator); + + s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA"); + group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item)); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item), + "/View/VGA"); + gtk_accel_map_add_entry("/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK); + gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item); + + separator = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(s->view_menu), separator); + + s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs"); + gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item); + + g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group); + gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group); + + gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu); + gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item); + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu); + gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item); +} + +void gtk_display_init(DisplayState *ds) +{ + GtkDisplayState *s = g_malloc0(sizeof(*s)); + + gtk_init(NULL, NULL); + + ds->opaque = s; + s->ds = ds; + s->dcl.dpy_gfx_update = gd_update; + s->dcl.dpy_gfx_resize = gd_resize; + s->dcl.dpy_refresh = gd_refresh; + + s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + s->vbox = gtk_vbox_new(FALSE, 0); + s->notebook = gtk_notebook_new(); + s->drawing_area = gtk_drawing_area_new(); + s->menu_bar = gtk_menu_bar_new(); + + s->scale_x = 1.0; + s->scale_y = 1.0; + + s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR); + + s->mouse_mode_notifier.notify = gd_mouse_mode_change; + qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier); + qemu_add_vm_change_state_handler(gd_change_runstate, s); + + gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA")); + + gd_create_menus(s); + + gd_connect_signals(s); + + gtk_widget_add_events(s->drawing_area, + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_SCROLL_MASK | + GDK_KEY_PRESS_MASK); + gtk_widget_set_double_buffered(s->drawing_area, FALSE); + gtk_widget_set_can_focus(s->drawing_area, TRUE); + + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); + gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE); + + gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE); + + gd_update_caption(s); + + gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(s->vbox), s->notebook, TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(s->window), s->vbox); + + gtk_widget_show_all(s->window); + + register_displaychangelistener(ds, &s->dcl); + + global_state = s; +} From d861def367b516055dc4c46dc1305143ee653c84 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:21 -0600 Subject: [PATCH 1182/1634] gtk: add virtual console support (v2) This enables VteTerminal to be used to render the text consoles. VteTerminal is the same widget used by gnome-terminal which means it's VT100 emulation is as good as they come. It's also screen reader accessible, supports copy/paste, proper scrolling and most of the other features you would expect from a terminal widget. Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-5-git-send-email-aliguori@us.ibm.com --- ui/gtk.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index 85e7999bce..94f04612f0 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -47,6 +47,7 @@ #include "qmp-commands.h" #include "x_keymap.h" #include "keymaps.h" +#include "char/char.h" //#define DEBUG_GTK @@ -56,6 +57,8 @@ #define DPRINTF(fmt, ...) do { } while (0) #endif +#define MAX_VCS 10 + typedef struct VirtualConsole { GtkWidget *menu_item; @@ -79,6 +82,9 @@ typedef struct GtkDisplayState GtkWidget *view_menu; GtkWidget *vga_item; + int nb_vcs; + VirtualConsole vc[MAX_VCS]; + GtkWidget *show_tabs_item; GtkWidget *vbox; @@ -403,6 +409,15 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque) if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) { gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0); + } else { + int i; + + for (i = 0; i < s->nb_vcs; i++) { + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vc[i].menu_item))) { + gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), i + 1); + break; + } + } } } @@ -421,16 +436,153 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, gpointer data) { GtkDisplayState *s = data; + guint last_page; if (!gtk_widget_get_realized(s->notebook)) { return; } + last_page = gtk_notebook_get_current_page(nb); + + if (last_page) { + gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1); + } + + if (arg2 == 0) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE); + } else { + VirtualConsole *vc = &s->vc[arg2 - 1]; + VteTerminal *term = VTE_TERMINAL(vc->terminal); + int width, height; + + width = 80 * vte_terminal_get_char_width(term); + height = 25 * vte_terminal_get_char_height(term); + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE); + gtk_widget_set_size_request(vc->terminal, width, height); + } + gd_update_cursor(s, TRUE); } +/** Virtual Console Callbacks **/ + +static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + VirtualConsole *vc = chr->opaque; + + return write(vc->fd, buf, len); +} + +static int nb_vcs; +static CharDriverState *vcs[MAX_VCS]; + +static CharDriverState *gd_vc_handler(QemuOpts *opts) +{ + CharDriverState *chr; + + chr = g_malloc0(sizeof(*chr)); + chr->chr_write = gd_vc_chr_write; + + vcs[nb_vcs++] = chr; + + return chr; +} + void early_gtk_display_init(void) { + register_vc_handler(gd_vc_handler); +} + +static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque) +{ + VirtualConsole *vc = opaque; + uint8_t buffer[1024]; + ssize_t len; + + len = read(vc->fd, buffer, sizeof(buffer)); + if (len <= 0) { + return FALSE; + } + + qemu_chr_be_write(vc->chr, buffer, len); + + return TRUE; +} + +static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSList *group) +{ + const char *label; + char buffer[32]; + char path[32]; + VtePty *pty; + GIOChannel *chan; + GtkWidget *scrolled_window; + GtkAdjustment *vadjustment; + int master_fd, slave_fd, ret; + struct termios tty; + + snprintf(buffer, sizeof(buffer), "vc%d", index); + snprintf(path, sizeof(path), "/View/VC%d", index); + + vc->chr = vcs[index]; + + if (vc->chr->label) { + label = vc->chr->label; + } else { + label = buffer; + } + + vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, label); + group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item)); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path); + gtk_accel_map_add_entry(path, GDK_KEY_2 + index, GDK_CONTROL_MASK | GDK_MOD1_MASK); + + vc->terminal = vte_terminal_new(); + + ret = openpty(&master_fd, &slave_fd, NULL, NULL, NULL); + g_assert(ret != -1); + + /* Set raw attributes on the pty. */ + tcgetattr(slave_fd, &tty); + cfmakeraw(&tty); + tcsetattr(slave_fd, TCSAFLUSH, &tty); + + pty = vte_pty_new_foreign(master_fd, NULL); + + vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty); + + vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1); + + vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->terminal)); + + scrolled_window = gtk_scrolled_window_new(NULL, vadjustment); + gtk_container_add(GTK_CONTAINER(scrolled_window), vc->terminal); + + vte_terminal_set_size(VTE_TERMINAL(vc->terminal), 80, 25); + + vc->fd = slave_fd; + vc->chr->opaque = vc; + vc->scrolled_window = scrolled_window; + + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vc->scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), scrolled_window, gtk_label_new(label)); + g_signal_connect(vc->menu_item, "activate", + G_CALLBACK(gd_menu_switch_vc), s); + + gtk_menu_append(GTK_MENU(s->view_menu), vc->menu_item); + + qemu_chr_generic_open(vc->chr); + if (vc->chr->init) { + vc->chr->init(vc->chr); + } + + chan = g_io_channel_unix_new(vc->fd); + g_io_add_watch(chan, G_IO_IN, gd_vc_in, vc); + + return group; } /** Window Creation **/ @@ -470,6 +622,7 @@ static void gd_create_menus(GtkDisplayState *s) GtkAccelGroup *accel_group; GSList *group = NULL; GtkWidget *separator; + int i; accel_group = gtk_accel_group_new(); s->file_menu = gtk_menu_new(); @@ -496,6 +649,13 @@ static void gd_create_menus(GtkDisplayState *s) gtk_accel_map_add_entry("/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK); gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item); + for (i = 0; i < nb_vcs; i++) { + VirtualConsole *vc = &s->vc[i]; + + group = gd_vc_init(s, vc, i, group); + s->nb_vcs++; + } + separator = gtk_separator_menu_item_new(); gtk_menu_append(GTK_MENU(s->view_menu), separator); From 5104a1f65088285ddf870aa641b9061064e8757d Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:22 -0600 Subject: [PATCH 1183/1634] gtk: add support for input grabbing (v2) There is a small deviation from SDL's behavior here. Instead of Ctrl+Alt triggering grab, we now use Ctrl-Alt-g to trigger grab. GTK will not accept Ctrl+Alt as an accelerator since it just consists of modifiers. Having grab as a proper accelerator is important as it allows a user to override the accelerator for accessibility purposes. We also are not automatically grabbing on left-click. Besides the inability to tie mouse clicks to an accelerator, I think this behavior is hard to discover and since it only happens depending on the guest state, it can lead to confusing behavior. This can be changed in the future if there's a strong resistence to dropping left-click-to-grab, but I think we're better off dropping it. Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-6-git-send-email-aliguori@us.ibm.com --- ui/gtk.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 151 insertions(+), 5 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 94f04612f0..0c1ec4db10 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -80,6 +80,8 @@ typedef struct GtkDisplayState GtkWidget *view_menu_item; GtkWidget *view_menu; + GtkWidget *grab_item; + GtkWidget *grab_on_hover_item; GtkWidget *vga_item; int nb_vcs; @@ -108,6 +110,21 @@ static GtkDisplayState *global_state; /** Utility Functions **/ +static bool gd_is_grab_active(GtkDisplayState *s) +{ + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_item)); +} + +static bool gd_grab_on_hover(GtkDisplayState *s) +{ + return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_on_hover_item)); +} + +static bool gd_on_vga(GtkDisplayState *s) +{ + return gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0; +} + static void gd_update_cursor(GtkDisplayState *s, gboolean override) { GdkWindow *window; @@ -115,9 +132,10 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override) window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area)); - on_vga = (gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0); + on_vga = gd_on_vga(s); - if ((override || on_vga) && kbd_mouse_is_absolute()) { + if ((override || on_vga) && + (kbd_mouse_is_absolute() || gd_is_grab_active(s))) { gdk_window_set_cursor(window, s->null_cursor); } else { gdk_window_set_cursor(window, NULL); @@ -128,15 +146,20 @@ static void gd_update_caption(GtkDisplayState *s) { const char *status = ""; gchar *title; + const char *grab = ""; + + if (gd_is_grab_active(s)) { + grab = " - Press Ctrl+Alt+G to release grab"; + } if (!runstate_is_running()) { status = " [Stopped]"; } if (qemu_name) { - title = g_strdup_printf("QEMU (%s)%s", qemu_name, status); + title = g_strdup_printf("QEMU (%s)%s%s", qemu_name, status, grab); } else { - title = g_strdup_printf("QEMU%s", status); + title = g_strdup_printf("QEMU%s%s", status, grab); } gtk_window_set_title(GTK_WINDOW(s->window), title); @@ -262,6 +285,9 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) s->scale_y = 1.0; } + fbw *= s->scale_x; + fbh *= s->scale_y; + cairo_set_source_surface(cr, s->surface, 0, 0); cairo_paint(cr); @@ -313,10 +339,44 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, s->last_x = x; s->last_y = y; - if (kbd_mouse_is_absolute()) { + if (kbd_mouse_is_absolute() || gd_is_grab_active(s)) { kbd_mouse_event(dx, dy, 0, s->button_mask); } + if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) { + GdkDrawable *drawable = GDK_DRAWABLE(gtk_widget_get_window(s->drawing_area)); + GdkDisplay *display = gdk_drawable_get_display(drawable); + GdkScreen *screen = gdk_drawable_get_screen(drawable); + int x = (int)motion->x_root; + int y = (int)motion->y_root; + + /* In relative mode check to see if client pointer hit + * one of the screen edges, and if so move it back by + * 200 pixels. This is important because the pointer + * in the server doesn't correspond 1-for-1, and so + * may still be only half way across the screen. Without + * this warp, the server pointer would thus appear to hit + * an invisible wall */ + if (x == 0) { + x += 200; + } + if (y == 0) { + y += 200; + } + if (x == (gdk_screen_get_width(screen) - 1)) { + x -= 200; + } + if (y == (gdk_screen_get_height(screen) - 1)) { + y -= 200; + } + + if (x != (int)motion->x_root || y != (int)motion->y_root) { + gdk_display_warp_pointer(display, screen, x, y); + s->last_x = -1; + s->last_y = -1; + return FALSE; + } + } return TRUE; } @@ -432,11 +492,49 @@ static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque) } } +static void gd_grab_keyboard(GtkDisplayState *s) +{ + gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)), + FALSE, + GDK_CURRENT_TIME); +} + +static void gd_ungrab_keyboard(GtkDisplayState *s) +{ + gdk_keyboard_ungrab(GDK_CURRENT_TIME); +} + +static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + if (gd_is_grab_active(s)) { + gd_grab_keyboard(s); + gdk_pointer_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)), + FALSE, /* All events to come to our window directly */ + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_SCROLL_MASK, + NULL, /* Allow cursor to move over entire desktop */ + s->null_cursor, + GDK_CURRENT_TIME); + } else { + gd_ungrab_keyboard(s); + gdk_pointer_ungrab(GDK_CURRENT_TIME); + } + + gd_update_caption(s); + gd_update_cursor(s, FALSE); +} + static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, gpointer data) { GtkDisplayState *s = data; guint last_page; + gboolean on_vga; if (!gtk_widget_get_realized(s->notebook)) { return; @@ -448,6 +546,13 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1); } + on_vga = arg2 == 0; + + if (!on_vga) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), + FALSE); + } + if (arg2 == 0) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE); } else { @@ -462,9 +567,33 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, gtk_widget_set_size_request(vc->terminal, width, height); } + gtk_widget_set_sensitive(s->grab_item, on_vga); + gd_update_cursor(s, TRUE); } +static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data) +{ + GtkDisplayState *s = data; + + if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) { + gd_grab_keyboard(s); + } + + return TRUE; +} + +static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data) +{ + GtkDisplayState *s = data; + + if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) { + gd_ungrab_keyboard(s); + } + + return TRUE; +} + /** Virtual Console Callbacks **/ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len) @@ -612,8 +741,14 @@ static void gd_connect_signals(GtkDisplayState *s) G_CALLBACK(gd_menu_quit), s); g_signal_connect(s->vga_item, "activate", G_CALLBACK(gd_menu_switch_vc), s); + g_signal_connect(s->grab_item, "activate", + G_CALLBACK(gd_menu_grab_input), s); g_signal_connect(s->notebook, "switch-page", G_CALLBACK(gd_change_page), s); + g_signal_connect(s->drawing_area, "enter-notify-event", + G_CALLBACK(gd_enter_event), s); + g_signal_connect(s->drawing_area, "leave-notify-event", + G_CALLBACK(gd_leave_event), s); } static void gd_create_menus(GtkDisplayState *s) @@ -639,6 +774,15 @@ static void gd_create_menus(GtkDisplayState *s) gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View"); + s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic("Grab On _Hover"); + gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item); + + s->grab_item = gtk_check_menu_item_new_with_mnemonic("_Grab Input"); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item), + "/View/Grab Input"); + gtk_accel_map_add_entry("/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK); + gtk_menu_append(GTK_MENU(s->view_menu), s->grab_item); + separator = gtk_separator_menu_item_new(); gtk_menu_append(GTK_MENU(s->view_menu), separator); @@ -711,6 +855,8 @@ void gtk_display_init(DisplayState *ds) GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK); gtk_widget_set_double_buffered(s->drawing_area, FALSE); From c61584833c579cd7bf800499124ce3d0e15bfb37 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:23 -0600 Subject: [PATCH 1184/1634] gtk: add support for screen scaling and full screen (v5) Basic menu items to enter full screen mode and zoom in/out. Unlike SDL, we don't allow arbitrary scaling based on window resizing. The current behavior with SDL causes a lot of problems for me. Sometimes I accidentally resize the window a tiny bit while trying to move it (Ubuntu's 1-pixel window decorations don't help here). After that, scaling is now active and if the screen changes size again, badness ensues since the aspect ratio is skewed. Allowing zooming by 25% in and out should cover most use cases. We can add a more flexible scaling later but for now, I think this is a more friendly behavior. Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-7-git-send-email-aliguori@us.ibm.com --- ui/gtk.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 237 insertions(+), 17 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 0c1ec4db10..01a1777674 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -80,6 +80,11 @@ typedef struct GtkDisplayState GtkWidget *view_menu_item; GtkWidget *view_menu; + GtkWidget *full_screen_item; + GtkWidget *zoom_in_item; + GtkWidget *zoom_out_item; + GtkWidget *zoom_fixed_item; + GtkWidget *zoom_fit_item; GtkWidget *grab_item; GtkWidget *grab_on_hover_item; GtkWidget *vga_item; @@ -101,9 +106,11 @@ typedef struct GtkDisplayState double scale_x; double scale_y; + gboolean full_screen; GdkCursor *null_cursor; Notifier mouse_mode_notifier; + gboolean free_scale; } GtkDisplayState; static GtkDisplayState *global_state; @@ -135,7 +142,7 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override) on_vga = gd_on_vga(s); if ((override || on_vga) && - (kbd_mouse_is_absolute() || gd_is_grab_active(s))) { + (s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) { gdk_window_set_cursor(window, s->null_cursor); } else { gdk_window_set_cursor(window, NULL); @@ -173,6 +180,9 @@ static void gd_update(DisplayState *ds, int x, int y, int w, int h) { GtkDisplayState *s = ds->opaque; int x1, x2, y1, y2; + int mx, my; + int fbw, fbh; + int ww, wh; DPRINTF("update(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h); @@ -182,7 +192,20 @@ static void gd_update(DisplayState *ds, int x, int y, int w, int h) x2 = ceil(x * s->scale_x + w * s->scale_x); y2 = ceil(y * s->scale_y + h * s->scale_y); - gtk_widget_queue_draw_area(s->drawing_area, x1, y1, (x2 - x1), (y2 - y1)); + fbw = ds_get_width(s->ds) * s->scale_x; + fbh = ds_get_height(s->ds) * s->scale_y; + + gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); + + mx = my = 0; + if (ww > fbw) { + mx = (ww - fbw) / 2; + } + if (wh > fbh) { + my = (wh - fbh) / 2; + } + + gtk_widget_queue_draw_area(s->drawing_area, mx + x1, my + y1, (x2 - x1), (y2 - y1)); } static void gd_refresh(DisplayState *ds) @@ -227,9 +250,29 @@ static void gd_resize(DisplayState *ds) ds_get_height(ds), ds_get_linesize(ds)); - gtk_widget_set_size_request(s->drawing_area, - ds_get_width(ds) * s->scale_x, - ds_get_height(ds) * s->scale_y); + if (!s->full_screen) { + GtkRequisition req; + double sx, sy; + + if (s->free_scale) { + sx = s->scale_x; + sy = s->scale_y; + + s->scale_y = 1.0; + s->scale_x = 1.0; + } else { + sx = 1.0; + sy = 1.0; + } + + gtk_widget_set_size_request(s->drawing_area, + ds_get_width(ds) * s->scale_x, + ds_get_height(ds) * s->scale_y); + gtk_widget_size_request(s->vbox, &req); + + gtk_window_resize(GTK_WINDOW(s->window), + req.width * sx, req.height * sy); + } } /** QEMU Events **/ @@ -266,29 +309,55 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event, static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) { GtkDisplayState *s = opaque; + int mx, my; int ww, wh; int fbw, fbh; + if (!gtk_widget_get_realized(widget)) { + return FALSE; + } + fbw = ds_get_width(s->ds); fbh = ds_get_height(s->ds); gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh); - cairo_rectangle(cr, 0, 0, ww, wh); - - if (ww != fbw || wh != fbh) { + if (s->full_screen) { s->scale_x = (double)ww / fbw; s->scale_y = (double)wh / fbh; - cairo_scale(cr, s->scale_x, s->scale_y); - } else { - s->scale_x = 1.0; - s->scale_y = 1.0; + } else if (s->free_scale) { + double sx, sy; + + sx = (double)ww / fbw; + sy = (double)wh / fbh; + + s->scale_x = s->scale_y = MIN(sx, sy); } fbw *= s->scale_x; fbh *= s->scale_y; - cairo_set_source_surface(cr, s->surface, 0, 0); + mx = my = 0; + if (ww > fbw) { + mx = (ww - fbw) / 2; + } + if (wh > fbh) { + my = (wh - fbh) / 2; + } + + cairo_rectangle(cr, 0, 0, ww, wh); + + /* Optionally cut out the inner area where the pixmap + will be drawn. This avoids 'flashing' since we're + not double-buffering. Note we're using the undocumented + behaviour of drawing the rectangle from right to left + to cut out the whole */ + cairo_rectangle(cr, mx + fbw, my, + -1 * fbw, fbh); + cairo_fill(cr); + + cairo_scale(cr, s->scale_x, s->scale_y); + cairo_set_source_surface(cr, s->surface, mx / s->scale_x, my / s->scale_y); cairo_paint(cr); return TRUE; @@ -321,9 +390,31 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, GtkDisplayState *s = opaque; int dx, dy; int x, y; + int mx, my; + int fbh, fbw; + int ww, wh; - x = motion->x / s->scale_x; - y = motion->y / s->scale_y; + fbw = ds_get_width(s->ds) * s->scale_x; + fbh = ds_get_height(s->ds) * s->scale_y; + + gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); + + mx = my = 0; + if (ww > fbw) { + mx = (ww - fbw) / 2; + } + if (wh > fbh) { + my = (wh - fbh) / 2; + } + + x = (motion->x - mx) / s->scale_x; + y = (motion->y - my) / s->scale_y; + + if (x < 0 || y < 0 || + x >= ds_get_width(s->ds) || + y >= ds_get_height(s->ds)) { + return TRUE; + } if (kbd_mouse_is_absolute()) { dx = x * 0x7FFF / (ds_get_width(s->ds) - 1); @@ -492,6 +583,90 @@ static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque) } } +static void gd_menu_full_screen(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->full_screen_item))) { + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); + gtk_widget_set_size_request(s->menu_bar, 0, 0); + gtk_widget_set_size_request(s->drawing_area, -1, -1); + gtk_window_fullscreen(GTK_WINDOW(s->window)); + if (gd_on_vga(s)) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE); + } + s->full_screen = TRUE; + } else { + gtk_window_unfullscreen(GTK_WINDOW(s->window)); + gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s); + gtk_widget_set_size_request(s->menu_bar, -1, -1); + gtk_widget_set_size_request(s->drawing_area, + ds_get_width(s->ds), ds_get_height(s->ds)); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE); + s->full_screen = FALSE; + s->scale_x = 1.0; + s->scale_y = 1.0; + } + + gd_update_cursor(s, FALSE); +} + +static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item), + FALSE); + + s->scale_x += .25; + s->scale_y += .25; + + gd_resize(s->ds); +} + +static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item), + FALSE); + + s->scale_x -= .25; + s->scale_y -= .25; + + s->scale_x = MAX(s->scale_x, .25); + s->scale_y = MAX(s->scale_y, .25); + + gd_resize(s->ds); +} + +static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + s->scale_x = 1.0; + s->scale_y = 1.0; + + gd_resize(s->ds); +} + +static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + int ww, wh; + + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) { + s->free_scale = TRUE; + } else { + s->free_scale = FALSE; + } + + gd_resize(s->ds); + + gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); + gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh); +} + static void gd_grab_keyboard(GtkDisplayState *s) { gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)), @@ -551,6 +726,9 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2, if (!on_vga) { gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE); + } else if (s->full_screen) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), + TRUE); } if (arg2 == 0) { @@ -739,6 +917,16 @@ static void gd_connect_signals(GtkDisplayState *s) g_signal_connect(s->quit_item, "activate", G_CALLBACK(gd_menu_quit), s); + g_signal_connect(s->full_screen_item, "activate", + G_CALLBACK(gd_menu_full_screen), s); + g_signal_connect(s->zoom_in_item, "activate", + G_CALLBACK(gd_menu_zoom_in), s); + g_signal_connect(s->zoom_out_item, "activate", + G_CALLBACK(gd_menu_zoom_out), s); + g_signal_connect(s->zoom_fixed_item, "activate", + G_CALLBACK(gd_menu_zoom_fixed), s); + g_signal_connect(s->zoom_fit_item, "activate", + G_CALLBACK(gd_menu_zoom_fit), s); g_signal_connect(s->vga_item, "activate", G_CALLBACK(gd_menu_switch_vc), s); g_signal_connect(s->grab_item, "activate", @@ -774,6 +962,39 @@ static void gd_create_menus(GtkDisplayState *s) gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View"); + s->full_screen_item = gtk_check_menu_item_new_with_mnemonic("_Full Screen"); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item), + "/View/Full Screen"); + gtk_accel_map_add_entry("/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK); + gtk_menu_append(GTK_MENU(s->view_menu), s->full_screen_item); + + separator = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(s->view_menu), separator); + + s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item), + "/View/Zoom In"); + gtk_accel_map_add_entry("/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK); + gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_in_item); + + s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item), + "/View/Zoom Out"); + gtk_accel_map_add_entry("/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK); + gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_out_item); + + s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL); + gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item), + "/View/Zoom Fixed"); + gtk_accel_map_add_entry("/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK); + gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item); + + s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic("Zoom To _Fit"); + gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item); + + separator = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(s->view_menu), separator); + s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic("Grab On _Hover"); gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item); @@ -837,6 +1058,7 @@ void gtk_display_init(DisplayState *ds) s->scale_x = 1.0; s->scale_y = 1.0; + s->free_scale = FALSE; s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR); @@ -865,8 +1087,6 @@ void gtk_display_init(DisplayState *ds) gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE); - gtk_window_set_resizable(GTK_WINDOW(s->window), FALSE); - gd_update_caption(s); gtk_box_pack_start(GTK_BOX(s->vbox), s->menu_bar, FALSE, TRUE, 0); From 834574ea89fa9c3ee0a557a13ad3f50db2509054 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:24 -0600 Subject: [PATCH 1185/1634] gtk: add translation support (v5) This includes a de_DE translation from Kevin Wolf and an it translation from Paolo Bonzini. Cc: Paolo Bonzini Cc: Kevin Wolf Cc: Stefan Hajnoczi Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-8-git-send-email-aliguori@us.ibm.com --- Makefile | 3 +++ configure | 4 +++- po/Makefile | 46 ++++++++++++++++++++++++++++++++++++++++++++++ po/de_DE.po | 45 +++++++++++++++++++++++++++++++++++++++++++++ po/it.po | 45 +++++++++++++++++++++++++++++++++++++++++++++ po/messages.po | 45 +++++++++++++++++++++++++++++++++++++++++++++ ui/gtk.c | 22 +++++++++++++++------- 7 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 po/Makefile create mode 100644 po/de_DE.po create mode 100644 po/it.po create mode 100644 po/messages.po diff --git a/Makefile b/Makefile index 0d9099a473..2262410f0f 100644 --- a/Makefile +++ b/Makefile @@ -313,6 +313,9 @@ ifneq ($(BLOBS),) set -e; for x in $(BLOBS); do \ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \ done +endif +ifeq ($(CONFIG_GTK),y) + $(MAKE) -C po $@ endif $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps" set -e; for x in $(KEYMAPS); do \ diff --git a/configure b/configure index 5ea760b039..0dadd31a3a 100755 --- a/configure +++ b/configure @@ -3243,6 +3243,7 @@ fi qemu_confdir=$sysconfdir$confsuffix qemu_datadir=$datadir$confsuffix +qemu_localedir="$datadir/locale" tools="" if test "$want_tools" = "yes" ; then @@ -3416,6 +3417,7 @@ echo "qemu_localstatedir=$local_statedir" >> $config_host_mak echo "qemu_helperdir=$libexecdir" >> $config_host_mak echo "extra_cflags=$EXTRA_CFLAGS" >> $config_host_mak echo "extra_ldflags=$EXTRA_LDFLAGS" >> $config_host_mak +echo "qemu_localedir=$qemu_localedir" >> $config_host_mak echo "ARCH=$ARCH" >> $config_host_mak if test "$debug_tcg" = "yes" ; then @@ -4336,7 +4338,7 @@ DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS qapi-generated" FILES="Makefile tests/tcg/Makefile qdict-test-data.txt" FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit" -FILES="$FILES tests/tcg/lm32/Makefile" +FILES="$FILES tests/tcg/lm32/Makefile po/Makefile" FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" diff --git a/po/Makefile b/po/Makefile new file mode 100644 index 0000000000..2b4420f178 --- /dev/null +++ b/po/Makefile @@ -0,0 +1,46 @@ +# This makefile is very special as it's meant to build as part of the build +# process and also within the source tree to update the translation files. + +VERSION=$(shell cat ../VERSION) +TRANSLATIONS=de_DE it +SRCS=$(addsuffix .po, $(TRANSLATIONS)) +OBJS=$(addsuffix .mo, $(TRANSLATIONS)) + +SRC_PATH=.. + +-include ../config-host.mak + +vpath %.po $(SRC_PATH)/po + +all: + @echo Use 'make update' to update translation files + @echo or us 'make build' or 'make install' to build and install + @echo the translation files + +update: $(SRCS) + +build: $(OBJS) + +clean: + $(RM) $(OBJS) + +install: $(OBJS) + for obj in $(OBJS); do \ + base=`basename $$obj .mo`; \ + $(INSTALL) -d $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES; \ + $(INSTALL) -m644 $$obj $(DESTDIR)$(prefix)/share/locale/$$base/LC_MESSAGES/qemu.mo; \ + done + +%.mo: + @msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po + +messages.po: $(SRC_PATH)/ui/gtk.c + @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=1.0.50 --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $< + +de_DE.po: messages.po $(SRC_PATH)/ui/gtk.c + @msgmerge $@ $< > $@.bak && mv $@.bak $@ + +it.po: messages.po $(SRC_PATH)/ui/gtk.c + @msgmerge $@ $< > $@.bak && mv $@.bak $@ + +.PHONY: $(SRCS) clean all diff --git a/po/de_DE.po b/po/de_DE.po new file mode 100644 index 0000000000..cb74d7cfec --- /dev/null +++ b/po/de_DE.po @@ -0,0 +1,45 @@ +# German translation for QEMU. +# This file is put in the public domain. +# Kevin Wolf , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: QEMU 1.4.50\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2013-02-08 09:21-0600\n" +"PO-Revision-Date: 2012-02-28 16:00+0100\n" +"Last-Translator: Kevin Wolf \n" +"Language-Team: Deutsch \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" + +#: ../ui/gtk.c:990 +msgid "_File" +msgstr "_Datei" + +#: ../ui/gtk.c:1000 +msgid "_View" +msgstr "_Ansicht" + +#: ../ui/gtk.c:1002 +msgid "_Full Screen" +msgstr "Voll_bild" + +#: ../ui/gtk.c:1029 +msgid "Zoom To _Fit" +msgstr "Auf _Fenstergröße skalieren" + +#: ../ui/gtk.c:1035 +msgid "Grab On _Hover" +msgstr "Tastatur _automatisch einfangen" + +#: ../ui/gtk.c:1038 +msgid "_Grab Input" +msgstr "_Eingabegeräte einfangen" + +#: ../ui/gtk.c:1064 +msgid "Show _Tabs" +msgstr "_Tableiste anzeigen" diff --git a/po/it.po b/po/it.po new file mode 100644 index 0000000000..2b23491aba --- /dev/null +++ b/po/it.po @@ -0,0 +1,45 @@ +# Italian translation for QEMU. +# This file is put in the public domain. +# Paolo Bonzini , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: QEMU 1.4.50\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2013-02-08 09:21-0600\n" +"PO-Revision-Date: 2012-02-27 08:23+0100\n" +"Last-Translator: Paolo Bonzini \n" +"Language-Team: Italian \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: ../ui/gtk.c:990 +msgid "_File" +msgstr "_File" + +#: ../ui/gtk.c:1000 +msgid "_View" +msgstr "_Visualizza" + +#: ../ui/gtk.c:1002 +msgid "_Full Screen" +msgstr "_Schermo intero" + +#: ../ui/gtk.c:1029 +msgid "Zoom To _Fit" +msgstr "Adatta alla _finestra" + +#: ../ui/gtk.c:1035 +msgid "Grab On _Hover" +msgstr "Cattura _automatica input" + +#: ../ui/gtk.c:1038 +msgid "_Grab Input" +msgstr "_Cattura input" + +#: ../ui/gtk.c:1064 +msgid "Show _Tabs" +msgstr "Mostra _tab" diff --git a/po/messages.po b/po/messages.po new file mode 100644 index 0000000000..a90cd6ff9b --- /dev/null +++ b/po/messages.po @@ -0,0 +1,45 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: QEMU 1.4.50\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2013-02-08 09:21-0600\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../ui/gtk.c:990 +msgid "_File" +msgstr "" + +#: ../ui/gtk.c:1000 +msgid "_View" +msgstr "" + +#: ../ui/gtk.c:1002 +msgid "_Full Screen" +msgstr "" + +#: ../ui/gtk.c:1029 +msgid "Zoom To _Fit" +msgstr "" + +#: ../ui/gtk.c:1035 +msgid "Grab On _Hover" +msgstr "" + +#: ../ui/gtk.c:1038 +msgid "_Grab Input" +msgstr "" + +#: ../ui/gtk.c:1064 +msgid "Show _Tabs" +msgstr "" diff --git a/ui/gtk.c b/ui/gtk.c index 01a1777674..ffa9baacf1 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -31,8 +31,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define GETTEXT_PACKAGE "qemu" +#define LOCALEDIR "po" + #include #include +#include #include #include #include @@ -950,7 +954,7 @@ static void gd_create_menus(GtkDisplayState *s) accel_group = gtk_accel_group_new(); s->file_menu = gtk_menu_new(); gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group); - s->file_menu_item = gtk_menu_item_new_with_mnemonic("_File"); + s->file_menu_item = gtk_menu_item_new_with_mnemonic(_("_File")); s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); gtk_stock_lookup(GTK_STOCK_QUIT, &item); @@ -960,9 +964,9 @@ static void gd_create_menus(GtkDisplayState *s) s->view_menu = gtk_menu_new(); gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); - s->view_menu_item = gtk_menu_item_new_with_mnemonic("_View"); + s->view_menu_item = gtk_menu_item_new_with_mnemonic(_("_View")); - s->full_screen_item = gtk_check_menu_item_new_with_mnemonic("_Full Screen"); + s->full_screen_item = gtk_check_menu_item_new_with_mnemonic(_("_Full Screen")); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item), "/View/Full Screen"); gtk_accel_map_add_entry("/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK); @@ -989,16 +993,16 @@ static void gd_create_menus(GtkDisplayState *s) gtk_accel_map_add_entry("/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK); gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item); - s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic("Zoom To _Fit"); + s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit")); gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item); separator = gtk_separator_menu_item_new(); gtk_menu_append(GTK_MENU(s->view_menu), separator); - s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic("Grab On _Hover"); + s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic(_("Grab On _Hover")); gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item); - s->grab_item = gtk_check_menu_item_new_with_mnemonic("_Grab Input"); + s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input")); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item), "/View/Grab Input"); gtk_accel_map_add_entry("/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK); @@ -1024,7 +1028,7 @@ static void gd_create_menus(GtkDisplayState *s) separator = gtk_separator_menu_item_new(); gtk_menu_append(GTK_MENU(s->view_menu), separator); - s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic("Show _Tabs"); + s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs")); gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item); g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group); @@ -1060,6 +1064,10 @@ void gtk_display_init(DisplayState *ds) s->scale_y = 1.0; s->free_scale = FALSE; + setlocale(LC_ALL, ""); + bindtextdomain("qemu", CONFIG_QEMU_LOCALEDIR); + textdomain("qemu"); + s->null_cursor = gdk_cursor_new(GDK_BLANK_CURSOR); s->mouse_mode_notifier.notify = gd_mouse_mode_change; From 15546425c5527ebb08ede399373b705866f1ff84 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:25 -0600 Subject: [PATCH 1186/1634] gtk: make default UI (v5) A user can still enable SDL with '-sdl' or '-display sdl' but start making the default display GTK by default. I'd also like to deprecate the SDL display and remove it in a few releases. Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-9-git-send-email-aliguori@us.ibm.com --- vl.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/vl.c b/vl.c index 955d2ffe0f..0da156e8b4 100644 --- a/vl.c +++ b/vl.c @@ -2206,6 +2206,13 @@ static DisplayType select_display(const char *p) #else fprintf(stderr, "Curses support is disabled\n"); exit(1); +#endif + } else if (strstart(p, "gtk", &opts)) { +#ifdef CONFIG_GTK + display = DT_GTK; +#else + fprintf(stderr, "GTK support is disabled\n"); + exit(1); #endif } else if (strstart(p, "none", &opts)) { display = DT_NONE; @@ -3999,6 +4006,28 @@ int main(int argc, char **argv, char **envp) } } + if (using_spice) { + display_remote++; + } + if (display_type == DT_DEFAULT && !display_remote) { +#if defined(CONFIG_GTK) + display_type = DT_GTK; +#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA) + display_type = DT_SDL; +#elif defined(CONFIG_VNC) + vnc_display = "localhost:0,to=99"; + show_vnc_port = 1; +#else + display_type = DT_NONE; +#endif + } + +#if defined(CONFIG_GTK) + if (display_type == DT_GTK) { + early_gtk_display_init(); + } +#endif + socket_init(); if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0) @@ -4227,20 +4256,6 @@ int main(int argc, char **argv, char **envp) /* just use the first displaystate for the moment */ ds = get_displaystate(); - if (using_spice) - display_remote++; - if (display_type == DT_DEFAULT && !display_remote) { -#if defined(CONFIG_SDL) || defined(CONFIG_COCOA) - display_type = DT_SDL; -#elif defined(CONFIG_VNC) - vnc_display = "localhost:0,to=99"; - show_vnc_port = 1; -#else - display_type = DT_NONE; -#endif - } - - /* init local displays */ switch (display_type) { case DT_NOGRAPHIC: @@ -4258,6 +4273,11 @@ int main(int argc, char **argv, char **envp) case DT_SDL: cocoa_display_init(ds, full_screen); break; +#endif +#if defined(CONFIG_GTK) + case DT_GTK: + gtk_display_init(ds); + break; #endif default: break; From 73d4dc71f3a41131541c73b3ac2a8b160a51842b Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 20 Feb 2013 07:43:26 -0600 Subject: [PATCH 1187/1634] gtk: suppress accelerators from the File menu when grab is active If you're full screen, you probably expect Ctrl-Q to go to the guest, not the host. I think restricting certain menus is the right way to handle this generally speaking. Signed-off-by: Anthony Liguori Message-id: 1361367806-4599-10-git-send-email-aliguori@us.ibm.com --- ui/gtk.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index ffa9baacf1..29156be198 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -78,6 +78,8 @@ typedef struct GtkDisplayState GtkWidget *menu_bar; + GtkAccelGroup *accel_group; + GtkWidget *file_menu_item; GtkWidget *file_menu; GtkWidget *quit_item; @@ -296,6 +298,35 @@ static void gd_mouse_mode_change(Notifier *notify, void *data) /** GTK Events **/ +static gboolean gd_window_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) +{ + GtkDisplayState *s = opaque; + GtkAccelGroupEntry *entries; + guint n_entries = 0; + gboolean propagate_accel = TRUE; + gboolean handled = FALSE; + + entries = gtk_accel_group_query(s->accel_group, key->keyval, + key->state, &n_entries); + if (n_entries) { + const char *quark = g_quark_to_string(entries[0].accel_path_quark); + + if (gd_is_grab_active(s) && strstart(quark, "/File/", NULL)) { + propagate_accel = FALSE; + } + } + + if (!handled && propagate_accel) { + handled = gtk_window_activate_key(GTK_WINDOW(widget), key); + } + + if (!handled) { + handled = gtk_window_propagate_key_event(GTK_WINDOW(widget), key); + } + + return handled; +} + static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event, void *opaque) { @@ -903,6 +934,8 @@ static void gd_connect_signals(GtkDisplayState *s) g_signal_connect(s->show_tabs_item, "activate", G_CALLBACK(gd_menu_show_tabs), s); + g_signal_connect(s->window, "key-press-event", + G_CALLBACK(gd_window_key_event), s); g_signal_connect(s->window, "delete-event", G_CALLBACK(gd_window_close), s); @@ -1033,6 +1066,7 @@ static void gd_create_menus(GtkDisplayState *s) g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group); gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group); + s->accel_group = accel_group; gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu); From cc283e3bf04d2f64eb6ec2ee5bcd36edd779fe89 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 1 Feb 2013 11:12:26 +0100 Subject: [PATCH 1188/1634] migration: change initial value of expected_downtime 0 is a very bad initial value, what we are trying to get is max_downtime, so that is a much better estimation. Signed-off-by: Juan Quintela Reviewed-by: Orit Wasserman --- migration.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migration.c b/migration.c index b1ebb01145..b3f5ba41f5 100644 --- a/migration.c +++ b/migration.c @@ -774,6 +774,8 @@ void migrate_fd_connect(MigrationState *s) s->buffer = NULL; s->buffer_size = 0; s->buffer_capacity = 0; + /* This is a best 1st approximation. ns to ms */ + s->expected_downtime = max_downtime/1000000; s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; s->complete = false; From a3e879cd51c4f614f702117c4b1449f0218c00f3 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 1 Feb 2013 12:39:08 +0100 Subject: [PATCH 1189/1634] migration: calculate end time after we have sent the data Signed-off-by: Juan Quintela Reviewed-by: Orit Wasserman --- migration.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index b3f5ba41f5..b8e412fcc5 100644 --- a/migration.c +++ b/migration.c @@ -673,7 +673,7 @@ static void *buffered_file_thread(void *opaque) qemu_mutex_unlock_iothread(); while (true) { - int64_t current_time = qemu_get_clock_ms(rt_clock); + int64_t current_time; uint64_t pending_size; qemu_mutex_lock_iothread(); @@ -727,6 +727,7 @@ static void *buffered_file_thread(void *opaque) } } qemu_mutex_unlock_iothread(); + current_time = qemu_get_clock_ms(rt_clock); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = s->bytes_xfer; uint64_t time_spent = current_time - initial_time; From 7161082c8d8cf167c508976887a0a63f4db92b51 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 1 Feb 2013 12:41:38 +0100 Subject: [PATCH 1190/1634] migration: don't account sleep time for calculating bandwidth While we are sleeping we are not sending, so we should not use that time to estimate our bandwidth. Signed-off-by: Juan Quintela Reviewed-by: Orit Wasserman --- migration.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index b8e412fcc5..6649e3a689 100644 --- a/migration.c +++ b/migration.c @@ -658,6 +658,7 @@ static void *buffered_file_thread(void *opaque) { MigrationState *s = opaque; int64_t initial_time = qemu_get_clock_ms(rt_clock); + int64_t sleep_time = 0; int64_t max_size = 0; bool last_round = false; int ret; @@ -730,7 +731,7 @@ static void *buffered_file_thread(void *opaque) current_time = qemu_get_clock_ms(rt_clock); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = s->bytes_xfer; - uint64_t time_spent = current_time - initial_time; + uint64_t time_spent = current_time - initial_time - sleep_time; double bandwidth = transferred_bytes / time_spent; max_size = bandwidth * migrate_max_downtime() / 1000000; @@ -739,11 +740,13 @@ static void *buffered_file_thread(void *opaque) transferred_bytes, time_spent, bandwidth, max_size); s->bytes_xfer = 0; + sleep_time = 0; initial_time = current_time; } if (!last_round && (s->bytes_xfer >= s->xfer_limit)) { /* usleep expects microseconds */ g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); + sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } ret = buffered_flush(s); if (ret < 0) { From 90f8ae724a575861f093fbdbfd49a925bcfec327 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 1 Feb 2013 13:22:37 +0100 Subject: [PATCH 1191/1634] migration: calculate expected_downtime We removed the calculation in commit e4ed1541ac9413eac494a03532e34beaf8a7d1c5 Now we add it back. We need to create dirty_bytes_rate because we can't include cpu-all.h from migration.c, and there is no other way to include TARGET_PAGE_SIZE. Signed-off-by: Juan Quintela Reviewed-by: Orit Wasserman --- arch_init.c | 1 + include/migration/migration.h | 1 + migration.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/arch_init.c b/arch_init.c index 8da868b988..8daeafaf5c 100644 --- a/arch_init.c +++ b/arch_init.c @@ -414,6 +414,7 @@ static void migration_bitmap_sync(void) if (end_time > start_time + 1000) { s->dirty_pages_rate = num_dirty_pages_period * 1000 / (end_time - start_time); + s->dirty_bytes_rate = s->dirty_pages_rate * TARGET_PAGE_SIZE; start_time = end_time; num_dirty_pages_period = 0; } diff --git a/include/migration/migration.h b/include/migration/migration.h index a8c9639732..d1214097fe 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -51,6 +51,7 @@ struct MigrationState int64_t downtime; int64_t expected_downtime; int64_t dirty_pages_rate; + int64_t dirty_bytes_rate; bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; bool complete; diff --git a/migration.c b/migration.c index 6649e3a689..11725ae3fc 100644 --- a/migration.c +++ b/migration.c @@ -738,6 +738,11 @@ static void *buffered_file_thread(void *opaque) DPRINTF("transferred %" PRIu64 " time_spent %" PRIu64 " bandwidth %g max_size %" PRId64 "\n", transferred_bytes, time_spent, bandwidth, max_size); + /* if we haven't sent anything, we don't want to recalculate + 10000 is a small enough number for our purposes */ + if (s->dirty_bytes_rate && transferred_bytes > 10000) { + s->expected_downtime = s->dirty_bytes_rate / bandwidth; + } s->bytes_xfer = 0; sleep_time = 0; From 3f58eadeed497445a0ce11468c7394cb3d3f1b65 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 22 Feb 2013 07:28:01 +0100 Subject: [PATCH 1192/1634] ui/gtk: Fix build (missing include for setlocale) At least for Ubuntu Linux locale.h is needed. Signed-off-by: Stefan Weil Message-id: 1361514481-26164-1-git-send-email-sw@weilnetz.de Signed-off-by: Anthony Liguori --- ui/gtk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/gtk.c b/ui/gtk.c index 29156be198..5f91de4d95 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include From 82fb0c8908ccbf775be749be9eb3fc0a5813ceaa Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 22 Feb 2013 12:11:59 +0100 Subject: [PATCH 1193/1634] unbreak hw/usb/redirect.c build Commit 8550a02d1239415342959f6a32d178bc05c557cc added a streams parameter to usb_wakeup and didn't update redirect.c. Fix it. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori --- hw/usb/redirect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 7078403904..c519b9b92a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1897,7 +1897,7 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { - usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f)); + usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0); } /* bufp_alloc also adds the packet to the ep queue */ From 5cbb08283789caf7dbfd0890dcff47124ad766c2 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 22 Feb 2013 08:40:30 -0600 Subject: [PATCH 1194/1634] ui/gtk: require at least GTK 2.18 and VTE 0.26 This gives us the bare amount of features we need. We can add work arounds for older versions and lower the requirement but this should be a good starting point. Suggested-by: Daniel Berrange Signed-off-by: Anthony Liguori --- v1 -> v2 - tremendous simplification suggested by danpb --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 0dadd31a3a..0eb25dd77c 100755 --- a/configure +++ b/configure @@ -1644,8 +1644,8 @@ fi # GTK probe if test "$gtk" != "no"; then - if $pkg_config gtk+-2.0 --modversion >/dev/null 2>/dev/null && \ - $pkg_config vte --modversion >/dev/null 2>/dev/null; then + if $pkg_config --exists 'gtk+-2.0 >= 2.18.0' && \ + $pkg_config --exists 'vte >= 0.26.0'; then gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null` gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null` vte_cflags=`$pkg_config --cflags vte 2>/dev/null` From c6bb9ad198c2caa9c7c8ba360a07630b5c10e4a8 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Mon, 28 Jan 2013 06:59:46 -0500 Subject: [PATCH 1195/1634] qemu-img: find the image end offset during check This patch adds the support for reporting the image end offset (in bytes). This is particularly useful after a conversion (or a rebase) where the destination is a block device in order to find the first unused byte at the end of the image. Signed-off-by: Federico Simoncelli Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 10 ++++++++-- include/block/block.h | 1 + qemu-img.c | 4 ++++ tests/qemu-iotests/026 | 6 +++--- tests/qemu-iotests/036 | 3 ++- tests/qemu-iotests/039 | 2 +- tests/qemu-iotests/044.out | 1 + tests/qemu-iotests/common.rc | 7 ++++--- 8 files changed, 24 insertions(+), 10 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index bc1784c30e..d36cb4dd2f 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1112,7 +1112,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix) { BDRVQcowState *s = bs->opaque; - int64_t size, i; + int64_t size, i, highest_cluster; int nb_clusters, refcount1, refcount2; QCowSnapshot *sn; uint16_t *refcount_table; @@ -1183,7 +1183,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, } /* compare ref counts */ - for(i = 0; i < nb_clusters; i++) { + for (i = 0, highest_cluster = 0; i < nb_clusters; i++) { refcount1 = get_refcount(bs, i); if (refcount1 < 0) { fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n", @@ -1193,6 +1193,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, } refcount2 = refcount_table[i]; + + if (refcount1 > 0 || refcount2 > 0) { + highest_cluster = i; + } + if (refcount1 != refcount2) { /* Check if we're allowed to fix the mismatch */ @@ -1227,6 +1232,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, } } + res->image_end_offset = (highest_cluster + 1) * s->cluster_size; ret = 0; fail: diff --git a/include/block/block.h b/include/block/block.h index 5c3b911c1b..ce61883fc9 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -213,6 +213,7 @@ typedef struct BdrvCheckResult { int check_errors; int corruptions_fixed; int leaks_fixed; + int64_t image_end_offset; BlockFragInfo bfi; } BdrvCheckResult; diff --git a/qemu-img.c b/qemu-img.c index 85d3740b9c..e80c1c55fd 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -475,6 +475,10 @@ static int img_check(int argc, char **argv) result.bfi.fragmented_clusters * 100.0 / result.bfi.allocated_clusters); } + if (result.image_end_offset > 0) { + printf("Image end offset: %" PRId64 "\n", result.image_end_offset); + } + bdrv_delete(bs); if (ret < 0 || result.check_errors) { diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 index 1602ccd2a5..107a3ff2f6 100755 --- a/tests/qemu-iotests/026 +++ b/tests/qemu-iotests/026 @@ -102,7 +102,7 @@ if [ "$event" == "l2_load" ]; then $QEMU_IO -c "read $vmstate 0 128k " $BLKDBG_TEST_IMG | _filter_qemu_io fi -$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0" +_check_test_img 2>&1 | grep -v "refcount=1 reference=0" done done @@ -147,7 +147,7 @@ echo echo "Event: $event; errno: $errno; imm: $imm; once: $once; write $vmstate" $QEMU_IO -c "write $vmstate 0 64M" $BLKDBG_TEST_IMG | _filter_qemu_io -$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0" +_check_test_img 2>&1 | grep -v "refcount=1 reference=0" done done @@ -186,7 +186,7 @@ echo echo "Event: $event; errno: $errno; imm: $imm; once: $once" $QEMU_IO -c "write -b 0 64k" $BLKDBG_TEST_IMG | _filter_qemu_io -$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0" +_check_test_img 2>&1 | grep -v "refcount=1 reference=0" done done diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036 index 329533e9ea..4dbfc5724c 100755 --- a/tests/qemu-iotests/036 +++ b/tests/qemu-iotests/036 @@ -59,7 +59,8 @@ _make_test_img 64M echo echo === Repair image === echo -$QEMU_IMG check -r all $TEST_IMG +_check_test_img -r all + ./qcow2.py $TEST_IMG dump-header # success, all done diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index c5ae806ecb..ae3517575c 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -86,7 +86,7 @@ $QEMU_IO -r -c "read -P 0x5a 0 512" $TEST_IMG | _filter_qemu_io echo echo "== Repairing the image file must succeed ==" -$QEMU_IMG check -r all $TEST_IMG +_check_test_img -r all # The dirty bit must not be set ./qcow2.py $TEST_IMG dump-header | grep incompatible_features diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out index 7a4007137d..9c4867329f 100644 --- a/tests/qemu-iotests/044.out +++ b/tests/qemu-iotests/044.out @@ -1,4 +1,5 @@ No errors were found on the image. +Image end offset: 4296447488 . ---------------------------------------------------------------------- Ran 1 tests diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index aef5f52b4f..5ba960b09f 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -161,9 +161,10 @@ _cleanup_test_img() _check_test_img() { - $QEMU_IMG check -f $IMGFMT $TEST_IMG 2>&1 | \ - grep -v "fragmented$" | \ - sed -e 's/qemu-img\: This image format does not support checks/No errors were found on the image./' + $QEMU_IMG check "$@" -f $IMGFMT $TEST_IMG 2>&1 | \ + sed -e "/fragmented$/d" \ + -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ + -e '/Image end offset: [0-9]\+/d' } _img_info() From 8599ea4c42c098d2657ed632ad569f7a665706a4 Mon Sep 17 00:00:00 2001 From: Federico Simoncelli Date: Mon, 28 Jan 2013 06:59:47 -0500 Subject: [PATCH 1196/1634] qemu-img: add json output option to the check command This option --output=[human|json] makes qemu-img check output a human or JSON representation at the choice of the user. Signed-off-by: Federico Simoncelli Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- qapi-schema.json | 46 +++++++++ qemu-img-cmds.hx | 4 +- qemu-img.c | 244 +++++++++++++++++++++++++++++++++-------------- qemu-img.texi | 5 +- 4 files changed, 226 insertions(+), 73 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index cd7ea25e4c..c20725c7f7 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -244,6 +244,52 @@ '*backing-filename': 'str', '*full-backing-filename': 'str', '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'] } } +## +# @ImageCheck: +# +# Information about a QEMU image file check +# +# @filename: name of the image file checked +# +# @format: format of the image file checked +# +# @check-errors: number of unexpected errors occurred during check +# +# @image-end-offset: #optional offset (in bytes) where the image ends, this +# field is present if the driver for the image format +# supports it +# +# @corruptions: #optional number of corruptions found during the check if any +# +# @leaks: #optional number of leaks found during the check if any +# +# @corruptions-fixed: #optional number of corruptions fixed during the check +# if any +# +# @leaks-fixed: #optional number of leaks fixed during the check if any +# +# @total-clusters: #optional total number of clusters, this field is present +# if the driver for the image format supports it +# +# @allocated-clusters: #optional total number of allocated clusters, this +# field is present if the driver for the image format +# supports it +# +# @fragmented-clusters: #optional total number of fragmented clusters, this +# field is present if the driver for the image format +# supports it +# +# Since: 1.4 +# +## + +{ 'type': 'ImageCheck', + 'data': {'filename': 'str', 'format': 'str', 'check-errors': 'int', + '*image-end-offset': 'int', '*corruptions': 'int', '*leaks': 'int', + '*corruptions-fixed': 'int', '*leaks-fixed': 'int', + '*total-clusters': 'int', '*allocated-clusters': 'int', + '*fragmented-clusters': 'int' } } + ## # @StatusInfo: # diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index a18136302d..259fc142ed 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -10,9 +10,9 @@ STEXI ETEXI DEF("check", img_check, - "check [-f fmt] [-r [leaks | all]] filename") + "check [-f fmt] [--output=ofmt] [-r [leaks | all]] filename") STEXI -@item check [-f @var{fmt}] [-r [leaks | all]] @var{filename} +@item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename} ETEXI DEF("create", img_create, diff --git a/qemu-img.c b/qemu-img.c index e80c1c55fd..34249fee12 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -42,6 +42,16 @@ typedef struct img_cmd_t { int (*handler)(int argc, char **argv); } img_cmd_t; +enum { + OPTION_OUTPUT = 256, + OPTION_BACKING_CHAIN = 257, +}; + +typedef enum OutputFormat { + OFORMAT_JSON, + OFORMAT_HUMAN, +} OutputFormat; + /* Default to cache=writeback as data integrity is not important for qemu-tcg. */ #define BDRV_O_FLAGS BDRV_O_CACHE_WB #define BDRV_DEFAULT_CACHE "writeback" @@ -375,6 +385,96 @@ static int img_create(int argc, char **argv) return 0; } +static void dump_json_image_check(ImageCheck *check) +{ + Error *errp = NULL; + QString *str; + QmpOutputVisitor *ov = qmp_output_visitor_new(); + QObject *obj; + visit_type_ImageCheck(qmp_output_get_visitor(ov), + &check, NULL, &errp); + obj = qmp_output_get_qobject(ov); + str = qobject_to_json_pretty(obj); + assert(str != NULL); + printf("%s\n", qstring_get_str(str)); + qobject_decref(obj); + qmp_output_visitor_cleanup(ov); + QDECREF(str); +} + +static void dump_human_image_check(ImageCheck *check) +{ + if (!(check->corruptions || check->leaks || check->check_errors)) { + printf("No errors were found on the image.\n"); + } else { + if (check->corruptions) { + printf("\n%" PRId64 " errors were found on the image.\n" + "Data may be corrupted, or further writes to the image " + "may corrupt it.\n", + check->corruptions); + } + + if (check->leaks) { + printf("\n%" PRId64 " leaked clusters were found on the image.\n" + "This means waste of disk space, but no harm to data.\n", + check->leaks); + } + + if (check->check_errors) { + printf("\n%" PRId64 " internal errors have occurred during the check.\n", + check->check_errors); + } + } + + if (check->total_clusters != 0 && check->allocated_clusters != 0) { + printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n", + check->allocated_clusters, check->total_clusters, + check->allocated_clusters * 100.0 / check->total_clusters, + check->fragmented_clusters * 100.0 / check->allocated_clusters); + } + + if (check->image_end_offset) { + printf("Image end offset: %" PRId64 "\n", check->image_end_offset); + } +} + +static int collect_image_check(BlockDriverState *bs, + ImageCheck *check, + const char *filename, + const char *fmt, + int fix) +{ + int ret; + BdrvCheckResult result; + + ret = bdrv_check(bs, &result, fix); + if (ret < 0) { + return ret; + } + + check->filename = g_strdup(filename); + check->format = g_strdup(bdrv_get_format_name(bs)); + check->check_errors = result.check_errors; + check->corruptions = result.corruptions; + check->has_corruptions = result.corruptions != 0; + check->leaks = result.leaks; + check->has_leaks = result.leaks != 0; + check->corruptions_fixed = result.corruptions_fixed; + check->has_corruptions_fixed = result.corruptions != 0; + check->leaks_fixed = result.leaks_fixed; + check->has_leaks_fixed = result.leaks != 0; + check->image_end_offset = result.image_end_offset; + check->has_image_end_offset = result.image_end_offset != 0; + check->total_clusters = result.bfi.total_clusters; + check->has_total_clusters = result.bfi.total_clusters != 0; + check->allocated_clusters = result.bfi.allocated_clusters; + check->has_allocated_clusters = result.bfi.allocated_clusters != 0; + check->fragmented_clusters = result.bfi.fragmented_clusters; + check->has_fragmented_clusters = result.bfi.fragmented_clusters != 0; + + return 0; +} + /* * Checks an image for consistency. Exit codes: * @@ -386,15 +486,26 @@ static int img_create(int argc, char **argv) static int img_check(int argc, char **argv) { int c, ret; - const char *filename, *fmt; + OutputFormat output_format = OFORMAT_HUMAN; + const char *filename, *fmt, *output; BlockDriverState *bs; - BdrvCheckResult result; int fix = 0; int flags = BDRV_O_FLAGS | BDRV_O_CHECK; + ImageCheck *check; fmt = NULL; + output = NULL; for(;;) { - c = getopt(argc, argv, "f:hr:"); + int option_index = 0; + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"format", required_argument, 0, 'f'}, + {"repair", no_argument, 0, 'r'}, + {"output", required_argument, 0, OPTION_OUTPUT}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "f:hr:", + long_options, &option_index); if (c == -1) { break; } @@ -417,6 +528,9 @@ static int img_check(int argc, char **argv) help(); } break; + case OPTION_OUTPUT: + output = optarg; + break; } } if (optind >= argc) { @@ -424,77 +538,79 @@ static int img_check(int argc, char **argv) } filename = argv[optind++]; + if (output && !strcmp(output, "json")) { + output_format = OFORMAT_JSON; + } else if (output && !strcmp(output, "human")) { + output_format = OFORMAT_HUMAN; + } else if (output) { + error_report("--output must be used with human or json as argument."); + return 1; + } + bs = bdrv_new_open(filename, fmt, flags, true); if (!bs) { return 1; } - ret = bdrv_check(bs, &result, fix); + + check = g_new0(ImageCheck, 1); + ret = collect_image_check(bs, check, filename, fmt, fix); if (ret == -ENOTSUP) { - error_report("This image format does not support checks"); - bdrv_delete(bs); - return 1; + if (output_format == OFORMAT_HUMAN) { + error_report("This image format does not support checks"); + } + ret = 1; + goto fail; } - if (result.corruptions_fixed || result.leaks_fixed) { - printf("The following inconsistencies were found and repaired:\n\n" - " %d leaked clusters\n" - " %d corruptions\n\n" - "Double checking the fixed image now...\n", - result.leaks_fixed, - result.corruptions_fixed); - ret = bdrv_check(bs, &result, 0); + if (check->corruptions_fixed || check->leaks_fixed) { + int corruptions_fixed, leaks_fixed; + + leaks_fixed = check->leaks_fixed; + corruptions_fixed = check->corruptions_fixed; + + if (output_format == OFORMAT_HUMAN) { + printf("The following inconsistencies were found and repaired:\n\n" + " %" PRId64 " leaked clusters\n" + " %" PRId64 " corruptions\n\n" + "Double checking the fixed image now...\n", + check->leaks_fixed, + check->corruptions_fixed); + } + + ret = collect_image_check(bs, check, filename, fmt, 0); + + check->leaks_fixed = leaks_fixed; + check->corruptions_fixed = corruptions_fixed; } - if (!(result.corruptions || result.leaks || result.check_errors)) { - printf("No errors were found on the image.\n"); + switch (output_format) { + case OFORMAT_HUMAN: + dump_human_image_check(check); + break; + case OFORMAT_JSON: + dump_json_image_check(check); + break; + } + + if (ret || check->check_errors) { + ret = 1; + goto fail; + } + + if (check->corruptions) { + ret = 2; + } else if (check->leaks) { + ret = 3; } else { - if (result.corruptions) { - printf("\n%d errors were found on the image.\n" - "Data may be corrupted, or further writes to the image " - "may corrupt it.\n", - result.corruptions); - } - - if (result.leaks) { - printf("\n%d leaked clusters were found on the image.\n" - "This means waste of disk space, but no harm to data.\n", - result.leaks); - } - - if (result.check_errors) { - printf("\n%d internal errors have occurred during the check.\n", - result.check_errors); - } - } - - if (result.bfi.total_clusters != 0 && result.bfi.allocated_clusters != 0) { - printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n", - result.bfi.allocated_clusters, result.bfi.total_clusters, - result.bfi.allocated_clusters * 100.0 / result.bfi.total_clusters, - result.bfi.fragmented_clusters * 100.0 / result.bfi.allocated_clusters); - } - - if (result.image_end_offset > 0) { - printf("Image end offset: %" PRId64 "\n", result.image_end_offset); + ret = 0; } +fail: + qapi_free_ImageCheck(check); bdrv_delete(bs); - if (ret < 0 || result.check_errors) { - printf("\nAn error has occurred during the check: %s\n" - "The check is not complete and may have missed error.\n", - strerror(-ret)); - return 1; - } - - if (result.corruptions) { - return 2; - } else if (result.leaks) { - return 3; - } else { - return 0; - } + return ret; } static int img_commit(int argc, char **argv) @@ -1396,16 +1512,6 @@ err: return NULL; } -enum { - OPTION_OUTPUT = 256, - OPTION_BACKING_CHAIN = 257, -}; - -typedef enum OutputFormat { - OFORMAT_JSON, - OFORMAT_HUMAN, -} OutputFormat; - static int img_info(int argc, char **argv) { int c; diff --git a/qemu-img.texi b/qemu-img.texi index 00fca8da86..1a6c9e36f1 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -84,9 +84,10 @@ lists all snapshots in the given image Command description: @table @option -@item check [-f @var{fmt}] [-r [leaks | all]] @var{filename} +@item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename} -Perform a consistency check on the disk image @var{filename}. +Perform a consistency check on the disk image @var{filename}. The command can +output in the format @var{ofmt} which is either @code{human} or @code{json}. If @code{-r} is specified, qemu-img tries to repair any inconsistencies found during the check. @code{-r leaks} repairs only cluster leaks, whereas From 801f70445293ec8ed2d78fd92313c2f71fa48ac9 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Feb 2013 17:15:01 +0100 Subject: [PATCH 1197/1634] qcow2: introduce check_refcounts_l1/l2() flags The check_refcounts_l1/l2() functions have a check_copied argument to check that the QCOW_O_COPIED flag is consistent with refcount == 1. This should be a bool, not an int. However, the next patch introduces qcow2 fragmentation statistics and also needs to pass an option to check_refcounts_l1/l2(). This is a good opportunity to use an int flags field. Signed-off-by: Stefan Hajnoczi --- block/qcow2-refcount.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index d36cb4dd2f..4eec4b1228 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -914,6 +914,11 @@ static void inc_refcounts(BlockDriverState *bs, } } +/* Flags for check_refcounts_l1() and check_refcounts_l2() */ +enum { + CHECK_OFLAG_COPIED = 0x1, /* check QCOW_OFLAG_COPIED matches refcount */ +}; + /* * Increases the refcount in the given refcount table for the all clusters * referenced in the L2 table. While doing so, performs some checks on L2 @@ -924,7 +929,7 @@ static void inc_refcounts(BlockDriverState *bs, */ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset, - int check_copied) + int flags) { BDRVQcowState *s = bs->opaque; uint64_t *l2_table, l2_entry; @@ -971,7 +976,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ uint64_t offset = l2_entry & L2E_OFFSET_MASK; - if (check_copied) { + if (flags & CHECK_OFLAG_COPIED) { refcount = get_refcount(bs, offset >> s->cluster_bits); if (refcount < 0) { fprintf(stderr, "Can't get refcount for offset %" @@ -1028,7 +1033,7 @@ static int check_refcounts_l1(BlockDriverState *bs, uint16_t *refcount_table, int refcount_table_size, int64_t l1_table_offset, int l1_size, - int check_copied) + int flags) { BDRVQcowState *s = bs->opaque; uint64_t *l1_table, l2_offset, l1_size2; @@ -1057,7 +1062,7 @@ static int check_refcounts_l1(BlockDriverState *bs, l2_offset = l1_table[i]; if (l2_offset) { /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ - if (check_copied) { + if (flags & CHECK_OFLAG_COPIED) { refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits); if (refcount < 0) { @@ -1086,7 +1091,7 @@ static int check_refcounts_l1(BlockDriverState *bs, /* Process and check L2 entries */ ret = check_refcounts_l2(bs, res, refcount_table, - refcount_table_size, l2_offset, check_copied); + refcount_table_size, l2_offset, flags); if (ret < 0) { goto fail; } @@ -1128,7 +1133,8 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, /* current L1 table */ ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters, - s->l1_table_offset, s->l1_size, 1); + s->l1_table_offset, s->l1_size, + CHECK_OFLAG_COPIED); if (ret < 0) { goto fail; } From fba31bae2d776fb4134186a830a252523df7933f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Feb 2013 17:15:02 +0100 Subject: [PATCH 1198/1634] qcow2: record fragmentation statistics during check The qemu-img check command can display fragmentation statistics: * Total number of clusters in virtual disk * Number of allocated clusters * Number of fragmented clusters This patch adds fragmentation statistics support to qcow2. Compressed and normal clusters count as allocated. Zero clusters are not counted as allocated unless their L2 entry has a non-zero offset (e.g. preallocation). Only the current L1 table counts towards the statistics - snapshots are ignored. Signed-off-by: Stefan Hajnoczi --- block/qcow2-refcount.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 4eec4b1228..771b7b2850 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -917,6 +917,7 @@ static void inc_refcounts(BlockDriverState *bs, /* Flags for check_refcounts_l1() and check_refcounts_l2() */ enum { CHECK_OFLAG_COPIED = 0x1, /* check QCOW_OFLAG_COPIED matches refcount */ + CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */ }; /* @@ -933,6 +934,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, { BDRVQcowState *s = bs->opaque; uint64_t *l2_table, l2_entry; + uint64_t next_contiguous_offset = 0; int i, l2_size, nb_csectors, refcount; /* Read L2 table from disk */ @@ -963,6 +965,17 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, l2_entry &= s->cluster_offset_mask; inc_refcounts(bs, res, refcount_table, refcount_table_size, l2_entry & ~511, nb_csectors * 512); + + if (flags & CHECK_FRAG_INFO) { + res->bfi.allocated_clusters++; + + /* Compressed clusters are fragmented by nature. Since they + * take up sub-sector space but we only have sector granularity + * I/O we need to re-read the same sectors even for adjacent + * compressed clusters. + */ + res->bfi.fragmented_clusters++; + } break; case QCOW2_CLUSTER_ZERO: @@ -990,6 +1003,15 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, } } + if (flags & CHECK_FRAG_INFO) { + res->bfi.allocated_clusters++; + if (next_contiguous_offset && + offset != next_contiguous_offset) { + res->bfi.fragmented_clusters++; + } + next_contiguous_offset = offset + s->cluster_size; + } + /* Mark cluster as used */ inc_refcounts(bs, res, refcount_table,refcount_table_size, offset, s->cluster_size); @@ -1125,6 +1147,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, size = bdrv_getlength(bs->file); nb_clusters = size_to_clusters(s, size); + res->bfi.total_clusters = nb_clusters; refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t)); /* header */ @@ -1134,7 +1157,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, /* current L1 table */ ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters, s->l1_table_offset, s->l1_size, - CHECK_OFLAG_COPIED); + CHECK_OFLAG_COPIED | CHECK_FRAG_INFO); if (ret < 0) { goto fail; } From c9fc50839863f05545caca92bb9fbead8b1c91bd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Feb 2013 17:15:03 +0100 Subject: [PATCH 1199/1634] qemu-img: fix missing space in qemu-img check output The qemu-img check fragmentation printf() is missing a space before the '=' sign. The human output is not guaranteed to be stable and we are not aware of screen scrapers, so add the missing space. Also fix the missing indentation of the printf() arguments. Signed-off-by: Stefan Hajnoczi --- qemu-img.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 34249fee12..0e34bf0c90 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -427,10 +427,11 @@ static void dump_human_image_check(ImageCheck *check) } if (check->total_clusters != 0 && check->allocated_clusters != 0) { - printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n", - check->allocated_clusters, check->total_clusters, - check->allocated_clusters * 100.0 / check->total_clusters, - check->fragmented_clusters * 100.0 / check->allocated_clusters); + printf("%" PRId64 "/%" PRId64 " = %0.2f%% allocated, " + "%0.2f%% fragmented\n", + check->allocated_clusters, check->total_clusters, + check->allocated_clusters * 100.0 / check->total_clusters, + check->fragmented_clusters * 100.0 / check->allocated_clusters); } if (check->image_end_offset) { From e6439d783cce2c5cdbe4f8028f0b45162b540f82 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Feb 2013 17:15:04 +0100 Subject: [PATCH 1200/1634] qemu-img: add compressed clusters to BlockFragInfo Show how many clusters are compressed. This can be used to monitor how many compressed clusters remain and whether to recompress the image. Suggested-by: Cole Robinson Signed-off-by: Stefan Hajnoczi --- include/block/block.h | 1 + qapi-schema.json | 6 +++++- qemu-img.c | 7 +++++-- tests/qemu-iotests/044.out | 1 + tests/qemu-iotests/common.rc | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/block/block.h b/include/block/block.h index ce61883fc9..9661f9aa46 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -24,6 +24,7 @@ typedef struct BlockFragInfo { uint64_t allocated_clusters; uint64_t total_clusters; uint64_t fragmented_clusters; + uint64_t compressed_clusters; } BlockFragInfo; typedef struct QEMUSnapshotInfo { diff --git a/qapi-schema.json b/qapi-schema.json index c20725c7f7..28b070f16b 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -279,6 +279,10 @@ # field is present if the driver for the image format # supports it # +# @compressed-clusters: #optional total number of compressed clusters, this +# field is present if the driver for the image format +# supports it +# # Since: 1.4 # ## @@ -288,7 +292,7 @@ '*image-end-offset': 'int', '*corruptions': 'int', '*leaks': 'int', '*corruptions-fixed': 'int', '*leaks-fixed': 'int', '*total-clusters': 'int', '*allocated-clusters': 'int', - '*fragmented-clusters': 'int' } } + '*fragmented-clusters': 'int', '*compressed-clusters': 'int' } } ## # @StatusInfo: diff --git a/qemu-img.c b/qemu-img.c index 0e34bf0c90..fa9b2af79d 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -428,10 +428,11 @@ static void dump_human_image_check(ImageCheck *check) if (check->total_clusters != 0 && check->allocated_clusters != 0) { printf("%" PRId64 "/%" PRId64 " = %0.2f%% allocated, " - "%0.2f%% fragmented\n", + "%0.2f%% fragmented, %0.2f%% compressed clusters\n", check->allocated_clusters, check->total_clusters, check->allocated_clusters * 100.0 / check->total_clusters, - check->fragmented_clusters * 100.0 / check->allocated_clusters); + check->fragmented_clusters * 100.0 / check->allocated_clusters, + check->compressed_clusters * 100.0 / check->allocated_clusters); } if (check->image_end_offset) { @@ -472,6 +473,8 @@ static int collect_image_check(BlockDriverState *bs, check->has_allocated_clusters = result.bfi.allocated_clusters != 0; check->fragmented_clusters = result.bfi.fragmented_clusters; check->has_fragmented_clusters = result.bfi.fragmented_clusters != 0; + check->compressed_clusters = result.bfi.compressed_clusters; + check->has_compressed_clusters = result.bfi.compressed_clusters != 0; return 0; } diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out index 9c4867329f..5eed3f87a3 100644 --- a/tests/qemu-iotests/044.out +++ b/tests/qemu-iotests/044.out @@ -1,4 +1,5 @@ No errors were found on the image. +7292415/8391499= 86.90% allocated, 0.00% fragmented, 0.00% compressed clusters Image end offset: 4296447488 . ---------------------------------------------------------------------- diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 5ba960b09f..e522d617aa 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -162,7 +162,7 @@ _cleanup_test_img() _check_test_img() { $QEMU_IMG check "$@" -f $IMGFMT $TEST_IMG 2>&1 | \ - sed -e "/fragmented$/d" \ + sed -e '/allocated.*fragmented.*compressed clusters/d' \ -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ -e '/Image end offset: [0-9]\+/d' } From 4db35162ea54d84c29074adfcff470ee2687e7b9 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Feb 2013 17:15:05 +0100 Subject: [PATCH 1201/1634] qcow2: support compressed clusters in BlockFragInfo Signed-off-by: Stefan Hajnoczi --- block/qcow2-refcount.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 771b7b2850..55543edf77 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -968,6 +968,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, if (flags & CHECK_FRAG_INFO) { res->bfi.allocated_clusters++; + res->bfi.compressed_clusters++; /* Compressed clusters are fragmented by nature. Since they * take up sub-sector space but we only have sector granularity From c546194f260fb3e391193cb8cc33505618077ecb Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 13 Feb 2013 16:53:42 +0100 Subject: [PATCH 1202/1634] block: use Error in do_check_io_limits() The do_check_io_limits() function returns false when I/O limits are invalid but it doesn't set an Error to indicate why. The two do_check_io_limits() callers duplicate error reporting. Solve this by passing an Error pointer into do_check_io_limits(). Note that the two callers report slightly different errors: drive_init() prints a custom error message while qmp_block_set_io_throttle() does error_set(errp, QERR_INVALID_PARAMETER_COMBINATION). QERR_INVALID_PARAMETER_COMBINATION is a generic error, see include/qapi/qmp/qerror.h: #define QERR_INVALID_PARAMETER_COMBINATION \ ERROR_CLASS_GENERIC_ERROR, "Invalid parameter combination" Since it is generic we are not obliged to keep this error. Switch to the custom error message which contains more information. This patch prepares for adding additional checks with their own error messages to do_check_io_limits(). The next patch adds a new check. Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- blockdev.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/blockdev.c b/blockdev.c index 63e6f1eafa..9b0351343e 100644 --- a/blockdev.c +++ b/blockdev.c @@ -255,7 +255,7 @@ static int parse_block_error_action(const char *buf, bool is_read) } } -static bool do_check_io_limits(BlockIOLimit *io_limits) +static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp) { bool bps_flag; bool iops_flag; @@ -269,6 +269,8 @@ static bool do_check_io_limits(BlockIOLimit *io_limits) && ((io_limits->iops[BLOCK_IO_LIMIT_READ] != 0) || (io_limits->iops[BLOCK_IO_LIMIT_WRITE] != 0)); if (bps_flag || iops_flag) { + error_setg(errp, "bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) " + "cannot be used at the same time"); return false; } @@ -297,6 +299,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) int snapshot = 0; bool copy_on_read; int ret; + Error *error = NULL; translation = BIOS_ATA_TRANSLATION_AUTO; media = MEDIA_DISK; @@ -427,9 +430,9 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) io_limits.iops[BLOCK_IO_LIMIT_WRITE] = qemu_opt_get_number(opts, "iops_wr", 0); - if (!do_check_io_limits(&io_limits)) { - error_report("bps(iops) and bps_rd/bps_wr(iops_rd/iops_wr) " - "cannot be used at the same time"); + if (!do_check_io_limits(&io_limits, &error)) { + error_report("%s", error_get_pretty(error)); + error_free(error); return NULL; } @@ -975,8 +978,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd; io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr; - if (!do_check_io_limits(&io_limits)) { - error_set(errp, QERR_INVALID_PARAMETER_COMBINATION); + if (!do_check_io_limits(&io_limits, errp)) { return; } From 7d81c1413c9c9bdcc966453636e4ca7776b59861 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 13 Feb 2013 16:53:43 +0100 Subject: [PATCH 1203/1634] block: refuse negative iops and bps values Negative I/O throttling iops and bps values do not make sense so reject them with an error message. Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- blockdev.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/blockdev.c b/blockdev.c index 9b0351343e..ba3759c849 100644 --- a/blockdev.c +++ b/blockdev.c @@ -274,6 +274,16 @@ static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp) return false; } + if (io_limits->bps[BLOCK_IO_LIMIT_TOTAL] < 0 || + io_limits->bps[BLOCK_IO_LIMIT_WRITE] < 0 || + io_limits->bps[BLOCK_IO_LIMIT_READ] < 0 || + io_limits->iops[BLOCK_IO_LIMIT_TOTAL] < 0 || + io_limits->iops[BLOCK_IO_LIMIT_WRITE] < 0 || + io_limits->iops[BLOCK_IO_LIMIT_READ] < 0) { + error_setg(errp, "bps and iops values must be 0 or greater"); + return false; + } + return true; } From b35b2bba5b372ff912c5fe7e5ad6c5a9d883464f Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Wed, 13 Feb 2013 09:09:39 +0100 Subject: [PATCH 1204/1634] block: Add synchronous wrapper for bdrv_co_is_allocated_above There's no synchronous wrapper for bdrv_co_is_allocated_above function so it's not possible to check for sector allocation in an image with a backing file. Signed-off-by: Miroslav Rezanina Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block.c | 39 +++++++++++++++++++++++++++++++++++++++ include/block/block.h | 2 ++ 2 files changed, 41 insertions(+) diff --git a/block.c b/block.c index 50dab8e595..08039d2f32 100644 --- a/block.c +++ b/block.c @@ -2681,6 +2681,7 @@ int bdrv_has_zero_init(BlockDriverState *bs) typedef struct BdrvCoIsAllocatedData { BlockDriverState *bs; + BlockDriverState *base; int64_t sector_num; int nb_sectors; int *pnum; @@ -2813,6 +2814,44 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, return 0; } +/* Coroutine wrapper for bdrv_is_allocated_above() */ +static void coroutine_fn bdrv_is_allocated_above_co_entry(void *opaque) +{ + BdrvCoIsAllocatedData *data = opaque; + BlockDriverState *top = data->bs; + BlockDriverState *base = data->base; + + data->ret = bdrv_co_is_allocated_above(top, base, data->sector_num, + data->nb_sectors, data->pnum); + data->done = true; +} + +/* + * Synchronous wrapper around bdrv_co_is_allocated_above(). + * + * See bdrv_co_is_allocated_above() for details. + */ +int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, + int64_t sector_num, int nb_sectors, int *pnum) +{ + Coroutine *co; + BdrvCoIsAllocatedData data = { + .bs = top, + .base = base, + .sector_num = sector_num, + .nb_sectors = nb_sectors, + .pnum = pnum, + .done = false, + }; + + co = qemu_coroutine_create(bdrv_is_allocated_above_co_entry); + qemu_coroutine_enter(co, &data); + while (!data.done) { + qemu_aio_wait(); + } + return data.ret; +} + BlockInfo *bdrv_query_info(BlockDriverState *bs) { BlockInfo *info = g_malloc0(sizeof(*info)); diff --git a/include/block/block.h b/include/block/block.h index 9661f9aa46..94d84b409d 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -280,6 +280,8 @@ int bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors); int bdrv_has_zero_init(BlockDriverState *bs); int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); +int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, + int64_t sector_num, int nb_sectors, int *pnum); void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error, BlockdevOnError on_write_error); From f382d43a9180ed20c671dc058d5452c2df7d3c61 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Wed, 13 Feb 2013 09:09:40 +0100 Subject: [PATCH 1205/1634] qemu-img: Add "Quiet mode" option There can be a need to turn output to stdout off. This patch adds a -q option that enable "Quiet mode". In Quiet mode, only errors are printed out. Signed-off-by: Miroslav Rezanina Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block.c | 12 ++-- blockdev.c | 6 +- include/block/block.h | 3 +- qemu-img-cmds.hx | 28 ++++---- qemu-img.c | 154 +++++++++++++++++++++++++++++------------- qemu-img.texi | 3 + 6 files changed, 135 insertions(+), 71 deletions(-) diff --git a/block.c b/block.c index 08039d2f32..a4d7125eec 100644 --- a/block.c +++ b/block.c @@ -4470,7 +4470,8 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie) void bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, - char *options, uint64_t img_size, int flags, Error **errp) + char *options, uint64_t img_size, int flags, + Error **errp, bool quiet) { QEMUOptionParameter *param = NULL, *create_options = NULL; QEMUOptionParameter *backing_fmt, *backing_file, *size; @@ -4579,10 +4580,11 @@ void bdrv_img_create(const char *filename, const char *fmt, } } - printf("Formatting '%s', fmt=%s ", filename, fmt); - print_option_parameters(param); - puts(""); - + if (!quiet) { + printf("Formatting '%s', fmt=%s ", filename, fmt); + print_option_parameters(param); + puts(""); + } ret = bdrv_create(drv, filename, param); if (ret < 0) { if (ret == -ENOTSUP) { diff --git a/blockdev.c b/blockdev.c index ba3759c849..b307ed9ba9 100644 --- a/blockdev.c +++ b/blockdev.c @@ -804,7 +804,7 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) bdrv_img_create(new_image_file, format, states->old_bs->filename, states->old_bs->drv->format_name, - NULL, -1, flags, &local_err); + NULL, -1, flags, &local_err, false); if (error_is_set(&local_err)) { error_propagate(errp, local_err); goto delete_and_fail; @@ -1296,7 +1296,7 @@ void qmp_drive_mirror(const char *device, const char *target, /* create new image w/o backing file */ assert(format && drv); bdrv_img_create(target, format, - NULL, NULL, NULL, size, flags, &local_err); + NULL, NULL, NULL, size, flags, &local_err, false); } else { switch (mode) { case NEW_IMAGE_MODE_EXISTING: @@ -1307,7 +1307,7 @@ void qmp_drive_mirror(const char *device, const char *target, bdrv_img_create(target, format, source->filename, source->drv->format_name, - NULL, size, flags, &local_err); + NULL, size, flags, &local_err, false); break; default: abort(); diff --git a/include/block/block.h b/include/block/block.h index 94d84b409d..b4a24da3e9 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -353,7 +353,8 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, void bdrv_img_create(const char *filename, const char *fmt, const char *base_filename, const char *base_fmt, - char *options, uint64_t img_size, int flags, Error **errp); + char *options, uint64_t img_size, int flags, + Error **errp, bool quiet); void bdrv_set_buffer_alignment(BlockDriverState *bs, int align); void *qemu_blockalign(BlockDriverState *bs, size_t size); diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 259fc142ed..92837765b9 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -10,27 +10,27 @@ STEXI ETEXI DEF("check", img_check, - "check [-f fmt] [--output=ofmt] [-r [leaks | all]] filename") + "check [-q] [-f fmt] [--output=ofmt] [-r [leaks | all]] filename") STEXI -@item check [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename} +@item check [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] @var{filename} ETEXI DEF("create", img_create, - "create [-f fmt] [-o options] filename [size]") + "create [-q] [-f fmt] [-o options] filename [size]") STEXI -@item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] +@item create [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] ETEXI DEF("commit", img_commit, - "commit [-f fmt] [-t cache] filename") + "commit [-q] [-f fmt] [-t cache] filename") STEXI -@item commit [-f @var{fmt}] [-t @var{cache}] @var{filename} +@item commit [-q] [-f @var{fmt}] [-t @var{cache}] @var{filename} ETEXI DEF("convert", img_convert, - "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename") + "convert [-c] [-p] [-q] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename") STEXI -@item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("info", img_info, @@ -40,20 +40,20 @@ STEXI ETEXI DEF("snapshot", img_snapshot, - "snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename") + "snapshot [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename") STEXI -@item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename} +@item snapshot [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename} ETEXI DEF("rebase", img_rebase, - "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") + "rebase [-q] [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") STEXI -@item rebase [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} +@item rebase [-q] [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} ETEXI DEF("resize", img_resize, - "resize filename [+ | -]size") + "resize [-q] filename [+ | -]size") STEXI -@item resize @var{filename} [+ | -]@var{size} +@item resize [-q] @var{filename} [+ | -]@var{size} @end table ETEXI diff --git a/qemu-img.c b/qemu-img.c index fa9b2af79d..3e2996e3c3 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -32,6 +32,7 @@ #include "block/block_int.h" #include #include +#include #ifdef _WIN32 #include @@ -96,6 +97,7 @@ static void help(void) " rebasing in this case (useful for renaming the backing file)\n" " '-h' with or without a command shows this help and lists the supported formats\n" " '-p' show progress of command (only certain commands)\n" + " '-q' use Quiet mode - do not print any output (except errors)\n" " '-S' indicates the consecutive number of bytes that must contain only zeros\n" " for qemu-img to create a sparse image during conversion\n" " '--output' takes the format in which the output must be done (human or json)\n" @@ -119,6 +121,18 @@ static void help(void) exit(1); } +static int qprintf(bool quiet, const char *fmt, ...) +{ + int ret = 0; + if (!quiet) { + va_list args; + va_start(args, fmt); + ret = vprintf(fmt, args); + va_end(args); + } + return ret; +} + #if defined(WIN32) /* XXX: put correct support for win32 */ static int read_password(char *buf, int buf_size) @@ -237,7 +251,8 @@ static int print_block_option_help(const char *filename, const char *fmt) static BlockDriverState *bdrv_new_open(const char *filename, const char *fmt, int flags, - bool require_io) + bool require_io, + bool quiet) { BlockDriverState *bs; BlockDriver *drv; @@ -263,7 +278,7 @@ static BlockDriverState *bdrv_new_open(const char *filename, } if (bdrv_is_encrypted(bs) && require_io) { - printf("Disk image '%s' is encrypted.\n", filename); + qprintf(quiet, "Disk image '%s' is encrypted.\n", filename); if (read_password(password, sizeof(password)) < 0) { error_report("No password given"); goto fail; @@ -312,9 +327,10 @@ static int img_create(int argc, char **argv) const char *base_filename = NULL; char *options = NULL; Error *local_err = NULL; + bool quiet = false; for(;;) { - c = getopt(argc, argv, "F:b:f:he6o:"); + c = getopt(argc, argv, "F:b:f:he6o:q"); if (c == -1) { break; } @@ -343,6 +359,9 @@ static int img_create(int argc, char **argv) case 'o': options = optarg; break; + case 'q': + quiet = true; + break; } } @@ -375,7 +394,7 @@ static int img_create(int argc, char **argv) } bdrv_img_create(filename, fmt, base_filename, base_fmt, - options, img_size, BDRV_O_FLAGS, &local_err); + options, img_size, BDRV_O_FLAGS, &local_err, quiet); if (error_is_set(&local_err)) { error_report("%s", error_get_pretty(local_err)); error_free(local_err); @@ -385,7 +404,7 @@ static int img_create(int argc, char **argv) return 0; } -static void dump_json_image_check(ImageCheck *check) +static void dump_json_image_check(ImageCheck *check, bool quiet) { Error *errp = NULL; QString *str; @@ -396,47 +415,52 @@ static void dump_json_image_check(ImageCheck *check) obj = qmp_output_get_qobject(ov); str = qobject_to_json_pretty(obj); assert(str != NULL); - printf("%s\n", qstring_get_str(str)); + qprintf(quiet, "%s\n", qstring_get_str(str)); qobject_decref(obj); qmp_output_visitor_cleanup(ov); QDECREF(str); } -static void dump_human_image_check(ImageCheck *check) +static void dump_human_image_check(ImageCheck *check, bool quiet) { if (!(check->corruptions || check->leaks || check->check_errors)) { - printf("No errors were found on the image.\n"); + qprintf(quiet, "No errors were found on the image.\n"); } else { if (check->corruptions) { - printf("\n%" PRId64 " errors were found on the image.\n" - "Data may be corrupted, or further writes to the image " - "may corrupt it.\n", - check->corruptions); + qprintf(quiet, "\n%" PRId64 " errors were found on the image.\n" + "Data may be corrupted, or further writes to the image " + "may corrupt it.\n", + check->corruptions); } if (check->leaks) { - printf("\n%" PRId64 " leaked clusters were found on the image.\n" - "This means waste of disk space, but no harm to data.\n", - check->leaks); + qprintf(quiet, + "\n%" PRId64 " leaked clusters were found on the image.\n" + "This means waste of disk space, but no harm to data.\n", + check->leaks); } if (check->check_errors) { - printf("\n%" PRId64 " internal errors have occurred during the check.\n", - check->check_errors); + qprintf(quiet, + "\n%" PRId64 + " internal errors have occurred during the check.\n", + check->check_errors); } } if (check->total_clusters != 0 && check->allocated_clusters != 0) { - printf("%" PRId64 "/%" PRId64 " = %0.2f%% allocated, " - "%0.2f%% fragmented, %0.2f%% compressed clusters\n", - check->allocated_clusters, check->total_clusters, - check->allocated_clusters * 100.0 / check->total_clusters, - check->fragmented_clusters * 100.0 / check->allocated_clusters, - check->compressed_clusters * 100.0 / check->allocated_clusters); + qprintf(quiet, "%" PRId64 "/%" PRId64 " = %0.2f%% allocated, " + "%0.2f%% fragmented, %0.2f%% compressed clusters\n", + check->allocated_clusters, check->total_clusters, + check->allocated_clusters * 100.0 / check->total_clusters, + check->fragmented_clusters * 100.0 / check->allocated_clusters, + check->compressed_clusters * 100.0 / + check->allocated_clusters); } if (check->image_end_offset) { - printf("Image end offset: %" PRId64 "\n", check->image_end_offset); + qprintf(quiet, + "Image end offset: %" PRId64 "\n", check->image_end_offset); } } @@ -496,6 +520,7 @@ static int img_check(int argc, char **argv) int fix = 0; int flags = BDRV_O_FLAGS | BDRV_O_CHECK; ImageCheck *check; + bool quiet = false; fmt = NULL; output = NULL; @@ -508,7 +533,7 @@ static int img_check(int argc, char **argv) {"output", required_argument, 0, OPTION_OUTPUT}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "f:hr:", + c = getopt_long(argc, argv, "f:hr:q", long_options, &option_index); if (c == -1) { break; @@ -535,6 +560,9 @@ static int img_check(int argc, char **argv) case OPTION_OUTPUT: output = optarg; break; + case 'q': + quiet = true; + break; } } if (optind >= argc) { @@ -551,7 +579,7 @@ static int img_check(int argc, char **argv) return 1; } - bs = bdrv_new_open(filename, fmt, flags, true); + bs = bdrv_new_open(filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -574,12 +602,13 @@ static int img_check(int argc, char **argv) corruptions_fixed = check->corruptions_fixed; if (output_format == OFORMAT_HUMAN) { - printf("The following inconsistencies were found and repaired:\n\n" - " %" PRId64 " leaked clusters\n" - " %" PRId64 " corruptions\n\n" - "Double checking the fixed image now...\n", - check->leaks_fixed, - check->corruptions_fixed); + qprintf(quiet, + "The following inconsistencies were found and repaired:\n\n" + " %" PRId64 " leaked clusters\n" + " %" PRId64 " corruptions\n\n" + "Double checking the fixed image now...\n", + check->leaks_fixed, + check->corruptions_fixed); } ret = collect_image_check(bs, check, filename, fmt, 0); @@ -590,10 +619,10 @@ static int img_check(int argc, char **argv) switch (output_format) { case OFORMAT_HUMAN: - dump_human_image_check(check); + dump_human_image_check(check, quiet); break; case OFORMAT_JSON: - dump_json_image_check(check); + dump_json_image_check(check, quiet); break; } @@ -622,11 +651,12 @@ static int img_commit(int argc, char **argv) int c, ret, flags; const char *filename, *fmt, *cache; BlockDriverState *bs; + bool quiet = false; fmt = NULL; cache = BDRV_DEFAULT_CACHE; for(;;) { - c = getopt(argc, argv, "f:ht:"); + c = getopt(argc, argv, "f:ht:q"); if (c == -1) { break; } @@ -641,6 +671,9 @@ static int img_commit(int argc, char **argv) case 't': cache = optarg; break; + case 'q': + quiet = true; + break; } } if (optind >= argc) { @@ -655,14 +688,14 @@ static int img_commit(int argc, char **argv) return -1; } - bs = bdrv_new_open(filename, fmt, flags, true); + bs = bdrv_new_open(filename, fmt, flags, true, quiet); if (!bs) { return 1; } ret = bdrv_commit(bs); switch(ret) { case 0: - printf("Image committed.\n"); + qprintf(quiet, "Image committed.\n"); break; case -ENOENT: error_report("No disk inserted"); @@ -805,6 +838,7 @@ static int img_convert(int argc, char **argv) const char *snapshot_name = NULL; float local_progress = 0; int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */ + bool quiet = false; fmt = NULL; out_fmt = "raw"; @@ -812,7 +846,7 @@ static int img_convert(int argc, char **argv) out_baseimg = NULL; compress = 0; for(;;) { - c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:"); + c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:q"); if (c == -1) { break; } @@ -866,9 +900,16 @@ static int img_convert(int argc, char **argv) case 't': cache = optarg; break; + case 'q': + quiet = true; + break; } } + if (quiet) { + progress = 0; + } + bs_n = argc - optind - 1; if (bs_n < 1) { help(); @@ -897,7 +938,8 @@ static int img_convert(int argc, char **argv) total_sectors = 0; for (bs_i = 0; bs_i < bs_n; bs_i++) { - bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true); + bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true, + quiet); if (!bs[bs_i]) { error_report("Could not open '%s'", argv[optind + bs_i]); ret = -1; @@ -1016,7 +1058,7 @@ static int img_convert(int argc, char **argv) return -1; } - out_bs = bdrv_new_open(out_filename, out_fmt, flags, true); + out_bs = bdrv_new_open(out_filename, out_fmt, flags, true, quiet); if (!out_bs) { ret = -1; goto out; @@ -1479,7 +1521,7 @@ static ImageInfoList *collect_image_info_list(const char *filename, g_hash_table_insert(filenames, (gpointer)filename, NULL); bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, - false); + false, false); if (!bs) { goto err; } @@ -1605,11 +1647,12 @@ static int img_snapshot(int argc, char **argv) int c, ret = 0, bdrv_oflags; int action = 0; qemu_timeval tv; + bool quiet = false; bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR; /* Parse commandline parameters */ for(;;) { - c = getopt(argc, argv, "la:c:d:h"); + c = getopt(argc, argv, "la:c:d:hq"); if (c == -1) { break; } @@ -1650,6 +1693,9 @@ static int img_snapshot(int argc, char **argv) action = SNAPSHOT_DELETE; snapshot_name = optarg; break; + case 'q': + quiet = true; + break; } } @@ -1659,7 +1705,7 @@ static int img_snapshot(int argc, char **argv) filename = argv[optind++]; /* Open the image */ - bs = bdrv_new_open(filename, NULL, bdrv_oflags, true); + bs = bdrv_new_open(filename, NULL, bdrv_oflags, true, quiet); if (!bs) { return 1; } @@ -1719,6 +1765,7 @@ static int img_rebase(int argc, char **argv) int c, flags, ret; int unsafe = 0; int progress = 0; + bool quiet = false; /* Parse commandline parameters */ fmt = NULL; @@ -1726,7 +1773,7 @@ static int img_rebase(int argc, char **argv) out_baseimg = NULL; out_basefmt = NULL; for(;;) { - c = getopt(argc, argv, "uhf:F:b:pt:"); + c = getopt(argc, argv, "uhf:F:b:pt:q"); if (c == -1) { break; } @@ -1753,9 +1800,16 @@ static int img_rebase(int argc, char **argv) case 't': cache = optarg; break; + case 'q': + quiet = true; + break; } } + if (quiet) { + progress = 0; + } + if ((optind >= argc) || (!unsafe && !out_baseimg)) { help(); } @@ -1777,7 +1831,7 @@ static int img_rebase(int argc, char **argv) * Ignore the old backing file for unsafe rebase in case we want to correct * the reference to a renamed or moved backing file. */ - bs = bdrv_new_open(filename, fmt, flags, true); + bs = bdrv_new_open(filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -1989,6 +2043,7 @@ static int img_resize(int argc, char **argv) int c, ret, relative; const char *filename, *fmt, *size; int64_t n, total_size; + bool quiet = false; BlockDriverState *bs = NULL; QemuOpts *param; static QemuOptsList resize_options = { @@ -2017,7 +2072,7 @@ static int img_resize(int argc, char **argv) /* Parse getopt arguments */ fmt = NULL; for(;;) { - c = getopt(argc, argv, "f:h"); + c = getopt(argc, argv, "f:hq"); if (c == -1) { break; } @@ -2029,6 +2084,9 @@ static int img_resize(int argc, char **argv) case 'f': fmt = optarg; break; + case 'q': + quiet = true; + break; } } if (optind >= argc) { @@ -2062,7 +2120,7 @@ static int img_resize(int argc, char **argv) n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); qemu_opts_del(param); - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true); + bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); if (!bs) { ret = -1; goto out; @@ -2082,7 +2140,7 @@ static int img_resize(int argc, char **argv) ret = bdrv_truncate(bs, total_size); switch (ret) { case 0: - printf("Image resized.\n"); + qprintf(quiet, "Image resized.\n"); break; case -ENOTSUP: error_report("This image does not support resize"); diff --git a/qemu-img.texi b/qemu-img.texi index 1a6c9e36f1..43430fbea1 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -54,6 +54,9 @@ indicates that target image must be compressed (qcow format only) with or without a command shows help and lists the supported formats @item -p display progress bar (convert and rebase commands only) +@item -q +Quiet mode - do not print any output (except errors). There's no progress bar +in case both @var{-q} and @var{-p} options are used. @item -S @var{size} indicates the consecutive number of bytes that must contain only zeros for qemu-img to create a sparse image during conversion. This value is rounded From d14ed18c8d10a936e6f8b55f56afb4b75c305e10 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Wed, 13 Feb 2013 09:09:41 +0100 Subject: [PATCH 1206/1634] qemu-img: Add compare subcommand This patch adds new qemu-img subcommand that compares content of two disk images. Signed-off-by: Miroslav Rezanina Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- qemu-img-cmds.hx | 6 + qemu-img.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++- qemu-img.texi | 53 +++++++++ 3 files changed, 348 insertions(+), 1 deletion(-) diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 92837765b9..4ca7e95655 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -27,6 +27,12 @@ STEXI @item commit [-q] [-f @var{fmt}] [-t @var{cache}] @var{filename} ETEXI +DEF("compare", img_compare, + "compare [-f fmt] [-F fmt] [-p] [-q] [-s] filename1 filename2") +STEXI +@item compare [-f @var{fmt}] [-F @var{fmt}] [-p] [-q] [-s] @var{filename1} @var{filename2} +ETEXI + DEF("convert", img_convert, "convert [-c] [-p] [-q] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] [-S sparse_size] filename [filename2 [...]] output_filename") STEXI diff --git a/qemu-img.c b/qemu-img.c index 3e2996e3c3..471de7d646 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -113,7 +113,12 @@ static void help(void) " '-a' applies a snapshot (revert disk to saved state)\n" " '-c' creates a snapshot\n" " '-d' deletes a snapshot\n" - " '-l' lists all snapshots in the given image\n"; + " '-l' lists all snapshots in the given image\n" + "\n" + "Parameters to compare subcommand:\n" + " '-f' first image format\n" + " '-F' second image format\n" + " '-s' run in Strict mode - fail on different image size or sector allocation\n"; printf("%s\nSupported formats:", help_msg); bdrv_iterate_format(format_print, NULL); @@ -820,6 +825,289 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n, #define IO_BUF_SIZE (2 * 1024 * 1024) +static int64_t sectors_to_bytes(int64_t sectors) +{ + return sectors << BDRV_SECTOR_BITS; +} + +static int64_t sectors_to_process(int64_t total, int64_t from) +{ + return MIN(total - from, IO_BUF_SIZE >> BDRV_SECTOR_BITS); +} + +/* + * Check if passed sectors are empty (not allocated or contain only 0 bytes) + * + * Returns 0 in case sectors are filled with 0, 1 if sectors contain non-zero + * data and negative value on error. + * + * @param bs: Driver used for accessing file + * @param sect_num: Number of first sector to check + * @param sect_count: Number of sectors to check + * @param filename: Name of disk file we are checking (logging purpose) + * @param buffer: Allocated buffer for storing read data + * @param quiet: Flag for quiet mode + */ +static int check_empty_sectors(BlockDriverState *bs, int64_t sect_num, + int sect_count, const char *filename, + uint8_t *buffer, bool quiet) +{ + int pnum, ret = 0; + ret = bdrv_read(bs, sect_num, buffer, sect_count); + if (ret < 0) { + error_report("Error while reading offset %" PRId64 " of %s: %s", + sectors_to_bytes(sect_num), filename, strerror(-ret)); + return ret; + } + ret = is_allocated_sectors(buffer, sect_count, &pnum); + if (ret || pnum != sect_count) { + qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n", + sectors_to_bytes(ret ? sect_num : sect_num + pnum)); + return 1; + } + + return 0; +} + +/* + * Compares two images. Exit codes: + * + * 0 - Images are identical + * 1 - Images differ + * >1 - Error occurred + */ +static int img_compare(int argc, char **argv) +{ + const char *fmt1 = NULL, *fmt2 = NULL, *filename1, *filename2; + BlockDriverState *bs1, *bs2; + int64_t total_sectors1, total_sectors2; + uint8_t *buf1 = NULL, *buf2 = NULL; + int pnum1, pnum2; + int allocated1, allocated2; + int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */ + bool progress = false, quiet = false, strict = false; + int64_t total_sectors; + int64_t sector_num = 0; + int64_t nb_sectors; + int c, pnum; + uint64_t bs_sectors; + uint64_t progress_base; + + for (;;) { + c = getopt(argc, argv, "hpf:F:sq"); + if (c == -1) { + break; + } + switch (c) { + case '?': + case 'h': + help(); + break; + case 'f': + fmt1 = optarg; + break; + case 'F': + fmt2 = optarg; + break; + case 'p': + progress = true; + break; + case 'q': + quiet = true; + break; + case 's': + strict = true; + break; + } + } + + /* Progress is not shown in Quiet mode */ + if (quiet) { + progress = false; + } + + + if (optind > argc - 2) { + help(); + } + filename1 = argv[optind++]; + filename2 = argv[optind++]; + + /* Initialize before goto out */ + qemu_progress_init(progress, 2.0); + + bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true, quiet); + if (!bs1) { + error_report("Can't open file %s", filename1); + ret = 2; + goto out3; + } + + bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true, quiet); + if (!bs2) { + error_report("Can't open file %s", filename2); + ret = 2; + goto out2; + } + + buf1 = qemu_blockalign(bs1, IO_BUF_SIZE); + buf2 = qemu_blockalign(bs2, IO_BUF_SIZE); + bdrv_get_geometry(bs1, &bs_sectors); + total_sectors1 = bs_sectors; + bdrv_get_geometry(bs2, &bs_sectors); + total_sectors2 = bs_sectors; + total_sectors = MIN(total_sectors1, total_sectors2); + progress_base = MAX(total_sectors1, total_sectors2); + + qemu_progress_print(0, 100); + + if (strict && total_sectors1 != total_sectors2) { + ret = 1; + qprintf(quiet, "Strict mode: Image size mismatch!\n"); + goto out; + } + + for (;;) { + nb_sectors = sectors_to_process(total_sectors, sector_num); + if (nb_sectors <= 0) { + break; + } + allocated1 = bdrv_is_allocated_above(bs1, NULL, sector_num, nb_sectors, + &pnum1); + if (allocated1 < 0) { + ret = 3; + error_report("Sector allocation test failed for %s", filename1); + goto out; + } + + allocated2 = bdrv_is_allocated_above(bs2, NULL, sector_num, nb_sectors, + &pnum2); + if (allocated2 < 0) { + ret = 3; + error_report("Sector allocation test failed for %s", filename2); + goto out; + } + nb_sectors = MIN(pnum1, pnum2); + + if (allocated1 == allocated2) { + if (allocated1) { + ret = bdrv_read(bs1, sector_num, buf1, nb_sectors); + if (ret < 0) { + error_report("Error while reading offset %" PRId64 " of %s:" + " %s", sectors_to_bytes(sector_num), filename1, + strerror(-ret)); + ret = 4; + goto out; + } + ret = bdrv_read(bs2, sector_num, buf2, nb_sectors); + if (ret < 0) { + error_report("Error while reading offset %" PRId64 + " of %s: %s", sectors_to_bytes(sector_num), + filename2, strerror(-ret)); + ret = 4; + goto out; + } + ret = compare_sectors(buf1, buf2, nb_sectors, &pnum); + if (ret || pnum != nb_sectors) { + ret = 1; + qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n", + sectors_to_bytes( + ret ? sector_num : sector_num + pnum)); + goto out; + } + } + } else { + if (strict) { + ret = 1; + qprintf(quiet, "Strict mode: Offset %" PRId64 + " allocation mismatch!\n", + sectors_to_bytes(sector_num)); + goto out; + } + + if (allocated1) { + ret = check_empty_sectors(bs1, sector_num, nb_sectors, + filename1, buf1, quiet); + } else { + ret = check_empty_sectors(bs2, sector_num, nb_sectors, + filename2, buf1, quiet); + } + if (ret) { + if (ret < 0) { + ret = 4; + error_report("Error while reading offset %" PRId64 ": %s", + sectors_to_bytes(sector_num), strerror(-ret)); + } + goto out; + } + } + sector_num += nb_sectors; + qemu_progress_print(((float) nb_sectors / progress_base)*100, 100); + } + + if (total_sectors1 != total_sectors2) { + BlockDriverState *bs_over; + int64_t total_sectors_over; + const char *filename_over; + + qprintf(quiet, "Warning: Image size mismatch!\n"); + if (total_sectors1 > total_sectors2) { + total_sectors_over = total_sectors1; + bs_over = bs1; + filename_over = filename1; + } else { + total_sectors_over = total_sectors2; + bs_over = bs2; + filename_over = filename2; + } + + for (;;) { + nb_sectors = sectors_to_process(total_sectors_over, sector_num); + if (nb_sectors <= 0) { + break; + } + ret = bdrv_is_allocated_above(bs_over, NULL, sector_num, + nb_sectors, &pnum); + if (ret < 0) { + ret = 3; + error_report("Sector allocation test failed for %s", + filename_over); + goto out; + + } + nb_sectors = pnum; + if (ret) { + ret = check_empty_sectors(bs_over, sector_num, nb_sectors, + filename_over, buf1, quiet); + if (ret) { + if (ret < 0) { + ret = 4; + error_report("Error while reading offset %" PRId64 + " of %s: %s", sectors_to_bytes(sector_num), + filename_over, strerror(-ret)); + } + goto out; + } + } + sector_num += nb_sectors; + qemu_progress_print(((float) nb_sectors / progress_base)*100, 100); + } + } + + qprintf(quiet, "Images are identical.\n"); + ret = 0; + +out: + bdrv_delete(bs2); + qemu_vfree(buf1); + qemu_vfree(buf2); +out2: + bdrv_delete(bs1); +out3: + qemu_progress_end(); + return ret; +} + static int img_convert(int argc, char **argv) { int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors; diff --git a/qemu-img.texi b/qemu-img.texi index 43430fbea1..69f1bda6ae 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -84,6 +84,18 @@ deletes a snapshot lists all snapshots in the given image @end table +Parameters to compare subcommand: + +@table @option + +@item -f +First image format +@item -F +Second image format +@item -s +Strict mode - fail on on different image size or sector allocation +@end table + Command description: @table @option @@ -118,6 +130,47 @@ it doesn't need to be specified separately in this case. Commit the changes recorded in @var{filename} in its base image. +@item compare [-f @var{fmt}] [-F @var{fmt}] [-p] [-s] [-q] @var{filename1} @var{filename2} + +Check if two images have the same content. You can compare images with +different format or settings. + +The format is probed unless you specify it by @var{-f} (used for +@var{filename1}) and/or @var{-F} (used for @var{filename2}) option. + +By default, images with different size are considered identical if the larger +image contains only unallocated and/or zeroed sectors in the area after the end +of the other image. In addition, if any sector is not allocated in one image +and contains only zero bytes in the second one, it is evaluated as equal. You +can use Strict mode by specifying the @var{-s} option. When compare runs in +Strict mode, it fails in case image size differs or a sector is allocated in +one image and is not allocated in the second one. + +By default, compare prints out a result message. This message displays +information that both images are same or the position of the first different +byte. In addition, result message can report different image size in case +Strict mode is used. + +Compare exits with @code{0} in case the images are equal and with @code{1} +in case the images differ. Other exit codes mean an error occurred during +execution and standard error output should contain an error message. +The following table sumarizes all exit codes of the compare subcommand: + +@table @option + +@item 0 +Images are identical +@item 1 +Images differ +@item 2 +Error on opening an image +@item 3 +Error on checking a sector allocation +@item 4 +Error on reading data + +@end table + @item convert [-c] [-p] [-f @var{fmt}] [-t @var{cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} Convert the disk image @var{filename} or a snapshot @var{snapshot_name} to disk image @var{output_filename} From e930d201bc8066a314b9e115e4a2afca50f9c504 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Wed, 13 Feb 2013 09:09:42 +0100 Subject: [PATCH 1207/1634] qemu-iotests: Add qemu-img compare test Simple test for qemu-img compare to check it's working correctly. Signed-off-by: Miroslav Rezanina Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/048 | 78 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/048.out | 31 +++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 110 insertions(+) create mode 100755 tests/qemu-iotests/048 create mode 100644 tests/qemu-iotests/048.out diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048 new file mode 100755 index 0000000000..7cce049d2d --- /dev/null +++ b/tests/qemu-iotests/048 @@ -0,0 +1,78 @@ +#!/bin/bash +## +## qemu-img compare test +## +## +## Copyright (C) 2013 Red Hat, Inc. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program 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 General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . +## +# +# creator +owner=mrezanin@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + echo "Cleanup" + _cleanup_test_img + rm ${TEST_IMG2} +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_compare() +{ + $QEMU_IMG compare "$@" $TEST_IMG ${TEST_IMG2} + echo $? +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.pattern + +_supported_fmt raw qcow qcow2 qed +_supported_proto file +_supported_os Linux + +# Setup test basic parameters +TEST_IMG2=$TEST_IMG.2 +CLUSTER_SIZE=4096 +size=1024M + +_make_test_img $size +io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45 + +# Compare identical images +cp $TEST_IMG ${TEST_IMG2} +_compare +_compare -q + +# Compare images with different size +$QEMU_IMG resize $TEST_IMG +512M +_compare +_compare -s + +# Compare images with different content +io_pattern write 1228800 $CLUSTER_SIZE 0 1 67 +_compare +io_pattern write 0 $CLUSTER_SIZE 0 1 123 +_compare + +# Cleanup +status=0 diff --git a/tests/qemu-iotests/048.out b/tests/qemu-iotests/048.out new file mode 100644 index 0000000000..68f65d5e19 --- /dev/null +++ b/tests/qemu-iotests/048.out @@ -0,0 +1,31 @@ +QA output created by 048 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +=== IO: pattern 45 +qemu-io> wrote 4096/4096 bytes at offset 524288 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> wrote 4096/4096 bytes at offset 528384 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> wrote 4096/4096 bytes at offset 532480 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> wrote 4096/4096 bytes at offset 536576 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> Images are identical. +0 +0 +Image resized. +Warning: Image size mismatch! +Images are identical. +0 +Strict mode: Image size mismatch! +1 +=== IO: pattern 67 +qemu-io> wrote 4096/4096 bytes at offset 1228800 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> Content mismatch at offset 1228800! +1 +=== IO: pattern 123 +qemu-io> wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-io> Content mismatch at offset 0! +1 +Cleanup diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 1bbd2bf929..1c0dfefd32 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -54,3 +54,4 @@ 045 rw auto 046 rw auto aio 047 rw auto +048 img auto quick From 4dc9f9d67dbf5d062d8db188b81cef435f291dd8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 29 Jan 2013 10:46:52 +0100 Subject: [PATCH 1208/1634] qemu-iotests: Test qcow2 image creation options Just create lots of images and try out each of the creation options that qcow2 provides (except backing_file/fmt for now) I'm not totally happy with the behaviour of qemu-img in each of the cases, but let's be explicit and update the test when we do change things later. Signed-off-by: Kevin Wolf --- tests/qemu-iotests/049 | 123 +++++++++++++++++++++ tests/qemu-iotests/049.out | 212 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 336 insertions(+) create mode 100755 tests/qemu-iotests/049 create mode 100644 tests/qemu-iotests/049.out diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049 new file mode 100755 index 0000000000..6c6017e2d2 --- /dev/null +++ b/tests/qemu-iotests/049 @@ -0,0 +1,123 @@ +#!/bin/bash +# +# Check qemu-img option parsing +# +# Copyright (C) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +function filter_test_dir() +{ + sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ + -e "s#$TEST_DIR#TEST_DIR#g" +} + +function test_qemu_img() +{ + echo qemu-img "$@" | filter_test_dir + $QEMU_IMG "$@" 2>&1 | filter_test_dir + echo +} + +echo "=== Check correct interpretation of suffixes for image size ===" +echo +sizes="1024 1024b 1k 1K 1M 1G 1T " +sizes+="1024.0 1024.0b 1.5k 1.5K 1.5M 1.5G 1.5T" + +echo "== 1. Traditional size parameter ==" +echo +for s in $sizes; do + test_qemu_img create -f $IMGFMT $TEST_IMG $s +done + +echo "== 2. Specifying size via -o ==" +echo +for s in $sizes; do + test_qemu_img create -f $IMGFMT -o size=$s $TEST_IMG +done + +echo "== 3. Invalid sizes ==" +echo +sizes="-1024 -1k 1kilobyte foobar" + +for s in $sizes; do + test_qemu_img create -f $IMGFMT $TEST_IMG -- $s + test_qemu_img create -f $IMGFMT -o size=$s $TEST_IMG +done + +echo "== Check correct interpretation of suffixes for cluster size ==" +echo +sizes="1024 1024b 1k 1K 1M " +sizes+="1024.0 1024.0b 0.5k 0.5K 0.5M" + +for s in $sizes; do + test_qemu_img create -f $IMGFMT -o cluster_size=$s $TEST_IMG 64M +done + +echo "== Check compat level option ==" +echo +test_qemu_img create -f $IMGFMT -o compat=0.10 $TEST_IMG 64M +test_qemu_img create -f $IMGFMT -o compat=1.1 $TEST_IMG 64M + +test_qemu_img create -f $IMGFMT -o compat=0.42 $TEST_IMG 64M +test_qemu_img create -f $IMGFMT -o compat=foobar $TEST_IMG 64M + +echo "== Check preallocation option ==" +echo +test_qemu_img create -f $IMGFMT -o preallocation=off $TEST_IMG 64M +test_qemu_img create -f $IMGFMT -o preallocation=metadata $TEST_IMG 64M +test_qemu_img create -f $IMGFMT -o preallocation=1234 $TEST_IMG 64M + +echo "== Check encryption option ==" +echo +test_qemu_img create -f $IMGFMT -o encryption=off $TEST_IMG 64M +test_qemu_img create -f $IMGFMT -o encryption=on $TEST_IMG 64M + +echo "== Check lazy_refcounts option (only with v3) ==" +echo +test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=off $TEST_IMG 64M +test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=on $TEST_IMG 64M + +test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=off $TEST_IMG 64M +test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=on $TEST_IMG 64M + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out new file mode 100644 index 0000000000..72db13f8d2 --- /dev/null +++ b/tests/qemu-iotests/049.out @@ -0,0 +1,212 @@ +QA output created by 049 +=== Check correct interpretation of suffixes for image size === + +== 1. Traditional size parameter == + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off + +== 2. Specifying size via -o == + +qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off + +== 3. Invalid sizes == + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1024 +qemu-img: Image size must be less than 8 EiB! + +qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2 +qemu-img: qcow2 doesn't support shrinking images yet +qemu-img: Formatting or formatting option not supported for file format 'qcow2' +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k +qemu-img: Image size must be less than 8 EiB! + +qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2 +qemu-img: qcow2 doesn't support shrinking images yet +qemu-img: Formatting or formatting option not supported for file format 'qcow2' +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte +qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for +qemu-img: kilobytes, megabytes, gigabytes and terabytes. + +qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2 +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar +qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for +qemu-img: kilobytes, megabytes, gigabytes and terabytes. + +qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2 +qemu-img: Parameter 'size' expects a size +qemu-img: Invalid options for file format 'qcow2'. + +== Check correct interpretation of suffixes for cluster size == + +qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off + +qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off + +== Check compat level option == + +qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M +Invalid compatibility level: '0.42' +qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.42' encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M +Invalid compatibility level: 'foobar' +qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='foobar' encryption=off cluster_size=65536 lazy_refcounts=off + +== Check preallocation option == + +qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='off' lazy_refcounts=off + +qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off + +qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M +Invalid preallocation mode: '1234' +qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='1234' lazy_refcounts=off + +== Check encryption option == + +qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off + +== Check lazy_refcounts option (only with v3) == + +qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=on + +qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off + +qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M +Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) +qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument +Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=on + +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 1c0dfefd32..fcf57e0510 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -55,3 +55,4 @@ 046 rw auto aio 047 rw auto 048 img auto quick +049 rw auto From 402397843e20e35d6cb7c80837c7cfdb19ede591 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 19 Feb 2013 11:59:09 +0100 Subject: [PATCH 1209/1634] coroutine: move pooling to common code The coroutine pool code is duplicated between the ucontext and sigaltstack backends, and absent from the win32 backend. But the code can be shared easily by moving it to qemu-coroutine.c. Signed-off-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- coroutine-sigaltstack.c | 43 +-------------------------------------- coroutine-ucontext.c | 43 +-------------------------------------- qemu-coroutine.c | 45 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 86 deletions(-) diff --git a/coroutine-sigaltstack.c b/coroutine-sigaltstack.c index e37ebac9c4..b4d176200c 100644 --- a/coroutine-sigaltstack.c +++ b/coroutine-sigaltstack.c @@ -33,15 +33,6 @@ #include "qemu-common.h" #include "block/coroutine_int.h" -enum { - /* Maximum free pool size prevents holding too many freed coroutines */ - POOL_MAX_SIZE = 64, -}; - -/** Free list to speed up creation */ -static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool); -static unsigned int pool_size; - typedef struct { Coroutine base; void *stack; @@ -85,17 +76,6 @@ static void qemu_coroutine_thread_cleanup(void *opaque) g_free(s); } -static void __attribute__((destructor)) coroutine_cleanup(void) -{ - Coroutine *co; - Coroutine *tmp; - - QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) { - g_free(DO_UPCAST(CoroutineUContext, base, co)->stack); - g_free(co); - } -} - static void __attribute__((constructor)) coroutine_init(void) { int ret; @@ -164,7 +144,7 @@ static void coroutine_trampoline(int signal) coroutine_bootstrap(self, co); } -static Coroutine *coroutine_new(void) +Coroutine *qemu_coroutine_new(void) { const size_t stack_size = 1 << 20; CoroutineUContext *co; @@ -272,31 +252,10 @@ static Coroutine *coroutine_new(void) return &co->base; } -Coroutine *qemu_coroutine_new(void) -{ - Coroutine *co; - - co = QSLIST_FIRST(&pool); - if (co) { - QSLIST_REMOVE_HEAD(&pool, pool_next); - pool_size--; - } else { - co = coroutine_new(); - } - return co; -} - void qemu_coroutine_delete(Coroutine *co_) { CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); - if (pool_size < POOL_MAX_SIZE) { - QSLIST_INSERT_HEAD(&pool, &co->base, pool_next); - co->base.caller = NULL; - pool_size++; - return; - } - g_free(co->stack); g_free(co); } diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index a9c30e9df4..6f8ffa85e3 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -34,15 +34,6 @@ #include #endif -enum { - /* Maximum free pool size prevents holding too many freed coroutines */ - POOL_MAX_SIZE = 64, -}; - -/** Free list to speed up creation */ -static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool); -static unsigned int pool_size; - typedef struct { Coroutine base; void *stack; @@ -96,17 +87,6 @@ static void qemu_coroutine_thread_cleanup(void *opaque) g_free(s); } -static void __attribute__((destructor)) coroutine_cleanup(void) -{ - Coroutine *co; - Coroutine *tmp; - - QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) { - g_free(DO_UPCAST(CoroutineUContext, base, co)->stack); - g_free(co); - } -} - static void __attribute__((constructor)) coroutine_init(void) { int ret; @@ -140,7 +120,7 @@ static void coroutine_trampoline(int i0, int i1) } } -static Coroutine *coroutine_new(void) +Coroutine *qemu_coroutine_new(void) { const size_t stack_size = 1 << 20; CoroutineUContext *co; @@ -185,20 +165,6 @@ static Coroutine *coroutine_new(void) return &co->base; } -Coroutine *qemu_coroutine_new(void) -{ - Coroutine *co; - - co = QSLIST_FIRST(&pool); - if (co) { - QSLIST_REMOVE_HEAD(&pool, pool_next); - pool_size--; - } else { - co = coroutine_new(); - } - return co; -} - #ifdef CONFIG_VALGRIND_H #ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE /* Work around an unused variable in the valgrind.h macro... */ @@ -217,13 +183,6 @@ void qemu_coroutine_delete(Coroutine *co_) { CoroutineUContext *co = DO_UPCAST(CoroutineUContext, base, co_); - if (pool_size < POOL_MAX_SIZE) { - QSLIST_INSERT_HEAD(&pool, &co->base, pool_next); - co->base.caller = NULL; - pool_size++; - return; - } - #ifdef CONFIG_VALGRIND_H valgrind_stack_deregister(co); #endif diff --git a/qemu-coroutine.c b/qemu-coroutine.c index 0f6e268574..25a14c605d 100644 --- a/qemu-coroutine.c +++ b/qemu-coroutine.c @@ -17,13 +17,54 @@ #include "block/coroutine.h" #include "block/coroutine_int.h" +enum { + /* Maximum free pool size prevents holding too many freed coroutines */ + POOL_MAX_SIZE = 64, +}; + +/** Free list to speed up creation */ +static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool); +static unsigned int pool_size; + Coroutine *qemu_coroutine_create(CoroutineEntry *entry) { - Coroutine *co = qemu_coroutine_new(); + Coroutine *co; + + co = QSLIST_FIRST(&pool); + if (co) { + QSLIST_REMOVE_HEAD(&pool, pool_next); + pool_size--; + } else { + co = qemu_coroutine_new(); + } + co->entry = entry; return co; } +static void coroutine_delete(Coroutine *co) +{ + if (pool_size < POOL_MAX_SIZE) { + QSLIST_INSERT_HEAD(&pool, co, pool_next); + co->caller = NULL; + pool_size++; + return; + } + + qemu_coroutine_delete(co); +} + +static void __attribute__((destructor)) coroutine_cleanup(void) +{ + Coroutine *co; + Coroutine *tmp; + + QSLIST_FOREACH_SAFE(co, &pool, pool_next, tmp) { + QSLIST_REMOVE_HEAD(&pool, pool_next); + qemu_coroutine_delete(co); + } +} + static void coroutine_swap(Coroutine *from, Coroutine *to) { CoroutineAction ret; @@ -35,7 +76,7 @@ static void coroutine_swap(Coroutine *from, Coroutine *to) return; case COROUTINE_TERMINATE: trace_qemu_coroutine_terminate(to); - qemu_coroutine_delete(to); + coroutine_delete(to); return; default: abort(); From 027003152f4cf21952f9282b4487daf3fdd372ba Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 19 Feb 2013 11:59:10 +0100 Subject: [PATCH 1210/1634] coroutine: trim down nesting level in perf_nesting test 20000 nested coroutines require 20 GB of virtual address space. Only nest 1000 of them so that the test (only enabled with "-m perf" on the command line) runs on 32-bit machines too. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- tests/test-coroutine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c index 4c6cc81fb9..39be046ec7 100644 --- a/tests/test-coroutine.c +++ b/tests/test-coroutine.c @@ -183,7 +183,7 @@ static void perf_nesting(void) double duration; maxcycles = 100000000; - maxnesting = 20000; + maxnesting = 1000; Coroutine *root; NestData nd = { .n_enter = 0, From 9a665b2b8640e464f0a778216fc2dca8d02acf33 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Mon, 18 Feb 2013 13:48:31 +0100 Subject: [PATCH 1211/1634] block: complete all IOs before .bdrv_truncate bdrv_truncate() invalidates the bdrv_check_request() result for in-flight requests, so there should better be none. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Lieven Reported-by: Kevin Wolf Reviewed-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block.c b/block.c index a4d7125eec..f184b376da 100644 --- a/block.c +++ b/block.c @@ -2427,6 +2427,10 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) return -EACCES; if (bdrv_in_use(bs)) return -EBUSY; + + /* There better not be any in-flight IOs when we truncate the device. */ + bdrv_drain_all(); + ret = drv->bdrv_truncate(bs, offset); if (ret == 0) { ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); From 9e8f1835ea3ab3be83634f34c1bb8b69cd871766 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 8 Feb 2013 14:06:11 +0100 Subject: [PATCH 1212/1634] block: implement BDRV_O_UNMAP It is better to present homogeneous hardware independent of the storage technology that is chosen on the host, hence we make discard a host parameter; the user can choose whether to pass it down to the image format and protocol, or to ignore it. Using DISCARD with filesystems can cause very severe fragmentation, so it is left default-off for now. This can change later when we implement the "anchor" operation for efficient management of preallocated files. There is still one choice to make: whether DISCARD has an effect on the dirty bitmap or not. I chose yes, though there is a disadvantage: if the guest is buggy and issues discards for data that is in use, there will be no way to migrate storage for that guest without downgrading the machine type to an older one. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- block.c | 25 +++++++++++++++++++++++++ include/block/block.h | 2 ++ qemu-io.c | 11 +++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index f184b376da..4582961965 100644 --- a/block.c +++ b/block.c @@ -580,6 +580,26 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint) return 0; } +/** + * Set open flags for a given discard mode + * + * Return 0 on success, -1 if the discard mode was invalid. + */ +int bdrv_parse_discard_flags(const char *mode, int *flags) +{ + *flags &= ~BDRV_O_UNMAP; + + if (!strcmp(mode, "off") || !strcmp(mode, "ignore")) { + /* do nothing */ + } else if (!strcmp(mode, "on") || !strcmp(mode, "unmap")) { + *flags |= BDRV_O_UNMAP; + } else { + return -1; + } + + return 0; +} + /** * Set open flags for a given cache mode * @@ -4191,6 +4211,11 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num, bdrv_reset_dirty(bs, sector_num, nb_sectors); } + /* Do nothing if disabled. */ + if (!(bs->open_flags & BDRV_O_UNMAP)) { + return 0; + } + if (bs->drv->bdrv_co_discard) { return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors); } else if (bs->drv->bdrv_aio_discard) { diff --git a/include/block/block.h b/include/block/block.h index b4a24da3e9..0f750d7da3 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -84,6 +84,7 @@ typedef struct BlockDevOps { #define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */ #define BDRV_O_CHECK 0x1000 /* open solely for consistency check */ #define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */ +#define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */ #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH) @@ -133,6 +134,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); void bdrv_delete(BlockDriverState *bs); int bdrv_parse_cache_flags(const char *mode, int *flags); +int bdrv_parse_discard_flags(const char *mode, int *flags); int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); int bdrv_open_backing_file(BlockDriverState *bs); int bdrv_open(BlockDriverState *bs, const char *filename, int flags, diff --git a/qemu-io.c b/qemu-io.c index 61880932b3..7b3de42773 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -1899,7 +1899,7 @@ int main(int argc, char **argv) { int readonly = 0; int growable = 0; - const char *sopt = "hVc:rsnmgkt:T:"; + const char *sopt = "hVc:d:rsnmgkt:T:"; const struct option lopt[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, @@ -1911,13 +1911,14 @@ int main(int argc, char **argv) { "misalign", 0, NULL, 'm' }, { "growable", 0, NULL, 'g' }, { "native-aio", 0, NULL, 'k' }, + { "discard", 1, NULL, 'd' }, { "cache", 1, NULL, 't' }, { "trace", 1, NULL, 'T' }, { NULL, 0, NULL, 0 } }; int c; int opt_index = 0; - int flags = 0; + int flags = BDRV_O_UNMAP; progname = basename(argv[0]); @@ -1929,6 +1930,12 @@ int main(int argc, char **argv) case 'n': flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB; break; + case 'd': + if (bdrv_parse_discard_flags(optarg, &flags) < 0) { + error_report("Invalid discard option: %s", optarg); + exit(1); + } + break; case 'c': add_user_command(optarg); break; From a9384aff5315e7568b6ebc171f4a482e01f06526 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 8 Feb 2013 14:06:12 +0100 Subject: [PATCH 1213/1634] blockdev: add discard suboption to -drive Add support for BDRV_O_UNMAP from the QEMU command-line. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- blockdev.c | 11 +++++++++++ qemu-options.hx | 2 ++ 2 files changed, 13 insertions(+) diff --git a/blockdev.c b/blockdev.c index b307ed9ba9..0e67d06330 100644 --- a/blockdev.c +++ b/blockdev.c @@ -391,6 +391,13 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) } } + if ((buf = qemu_opt_get(opts, "discard")) != NULL) { + if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) { + error_report("invalid discard option"); + return NULL; + } + } + bdrv_flags |= BDRV_O_CACHE_WB; if ((buf = qemu_opt_get(opts, "cache")) != NULL) { if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) { @@ -1500,6 +1507,10 @@ QemuOptsList qemu_drive_opts = { .name = "file", .type = QEMU_OPT_STRING, .help = "disk image", + },{ + .name = "discard", + .type = QEMU_OPT_STRING, + .help = "discard operation (ignore/off, unmap/on)", },{ .name = "cache", .type = QEMU_OPT_STRING, diff --git a/qemu-options.hx b/qemu-options.hx index 2832d82148..51ff726490 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -440,6 +440,8 @@ These options have the same definition as they have in @option{-hdachs}. @var{cache} is "none", "writeback", "unsafe", "directsync" or "writethrough" and controls how the host cache is used to access block data. @item aio=@var{aio} @var{aio} is "threads", or "native" and selects between pthread based disk I/O and native Linux AIO. +@item discard=@var{discard} +@var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap}) requests are ignored or passed to the filesystem. Some machine types may not support discard requests. @item format=@var{format} Specify which disk @var{format} will be used rather than detecting the format. Can be used to specifiy format=raw to avoid interpreting From ded9d2d5e247dc4d141c01bc8dc99d6ec832f9e8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 8 Feb 2013 14:06:13 +0100 Subject: [PATCH 1214/1634] qemu-nbd: add --discard option Similar to --cache and --aio, this option mimics the discard suboption of "-drive". Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- qemu-nbd.c | 18 +++++++++++++++--- qemu-nbd.texi | 4 ++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index 0a6091b6a8..e7268d0a9f 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -33,9 +33,10 @@ #include #include -#define SOCKET_PATH "/var/lock/qemu-nbd-%s" -#define QEMU_NBD_OPT_CACHE 1 -#define QEMU_NBD_OPT_AIO 2 +#define SOCKET_PATH "/var/lock/qemu-nbd-%s" +#define QEMU_NBD_OPT_CACHE 1 +#define QEMU_NBD_OPT_AIO 2 +#define QEMU_NBD_OPT_DISCARD 3 static NBDExport *exp; static int verbose; @@ -330,6 +331,7 @@ int main(int argc, char **argv) #ifdef CONFIG_LINUX_AIO { "aio", 1, NULL, QEMU_NBD_OPT_AIO }, #endif + { "discard", 1, NULL, QEMU_NBD_OPT_DISCARD }, { "shared", 1, NULL, 'e' }, { "persistent", 0, NULL, 't' }, { "verbose", 0, NULL, 'v' }, @@ -344,6 +346,7 @@ int main(int argc, char **argv) int ret; int fd; bool seen_cache = false; + bool seen_discard = false; #ifdef CONFIG_LINUX_AIO bool seen_aio = false; #endif @@ -389,6 +392,15 @@ int main(int argc, char **argv) } break; #endif + case QEMU_NBD_OPT_DISCARD: + if (seen_discard) { + errx(EXIT_FAILURE, "--discard can only be specified once"); + } + seen_discard = true; + if (bdrv_parse_discard_flags(optarg, &flags) == -1) { + errx(EXIT_FAILURE, "Invalid discard mode `%s'", optarg); + } + break; case 'b': bindto = optarg; break; diff --git a/qemu-nbd.texi b/qemu-nbd.texi index 3e57200e76..5f3f3e3276 100644 --- a/qemu-nbd.texi +++ b/qemu-nbd.texi @@ -35,6 +35,10 @@ Export QEMU disk image using NBD protocol. @item --aio=@var{aio} choose asynchronous I/O mode between @samp{threads} (the default) and @samp{native} (Linux only). +@item --discard=@var{discard} + toggles whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap}) + requests are ignored or passed to the filesystem. The default is no + (@samp{--discard=ignore}). @item -c, --connect=@var{dev} connect @var{filename} to NBD device @var{dev} @item -d, --disconnect From 215e47b9ea2cd7926333b7dc683024aa00e0c386 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 8 Feb 2013 14:06:14 +0100 Subject: [PATCH 1215/1634] blockdev: enable discard by default Because discard is now a host parameter, we can always fake it as enabled in the guest. This is an extension of the current choice to ignore "not supported" errors from the host when discard_granularity is set to nonzero. The default granularity is set to the logical block size or 4k, whichever is largest, because cluster sizes below 4k are rarely used and 4K is a typical block size for files. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- hw/block-common.h | 2 +- hw/ide/qdev.c | 5 ++++- hw/scsi-disk.c | 13 ++++++++++--- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/hw/block-common.h b/hw/block-common.h index bb808f7f56..dd115320c9 100644 --- a/hw/block-common.h +++ b/hw/block-common.h @@ -50,7 +50,7 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \ DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \ DEFINE_PROP_UINT32("discard_granularity", _state, \ - _conf.discard_granularity, 0) + _conf.discard_granularity, -1) #define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf) \ DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0), \ diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index c436b38bcb..fd06da7003 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -143,7 +143,10 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind) IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus); IDEState *s = bus->ifs + dev->unit; - if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) { + if (dev->conf.discard_granularity == -1) { + dev->conf.discard_granularity = 512; + } else if (dev->conf.discard_granularity && + dev->conf.discard_granularity != 512) { error_report("discard_granularity must be 512 for ide"); return -1; } diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 28e75bbf5b..d41158693e 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -41,9 +41,11 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include #endif -#define SCSI_DMA_BUF_SIZE 131072 -#define SCSI_MAX_INQUIRY_LEN 256 -#define SCSI_MAX_MODE_LEN 256 +#define SCSI_DMA_BUF_SIZE 131072 +#define SCSI_MAX_INQUIRY_LEN 256 +#define SCSI_MAX_MODE_LEN 256 + +#define DEFAULT_DISCARD_GRANULARITY 4096 typedef struct SCSIDiskState SCSIDiskState; @@ -2059,6 +2061,11 @@ static int scsi_initfn(SCSIDevice *dev) return -1; } + if (s->qdev.conf.discard_granularity == -1) { + s->qdev.conf.discard_granularity = + MAX(s->qdev.conf.logical_block_size, DEFAULT_DISCARD_GRANULARITY); + } + if (!s->version) { s->version = g_strdup(qemu_get_version()); } From bf3caa3dc17552b323cec6831301a22cfc98ecd5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 8 Feb 2013 14:06:15 +0100 Subject: [PATCH 1216/1634] pc: add compatibility machine types for 1.4 Adds both pc-i440fx-1.4 and pc-q35-1.4. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- hw/pc.h | 31 +++++++++++++++++++++++++++++++ hw/pc_piix.c | 18 ++++++++++++++++-- hw/pc_q35.c | 19 ++++++++++++++++--- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/hw/pc.h b/hw/pc.h index fbcf43d717..da1b102ef1 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -187,4 +187,35 @@ void pc_system_firmware_init(MemoryRegion *rom_memory); int e820_add_entry(uint64_t, uint64_t, uint32_t); +#define PC_COMPAT_1_4 \ + {\ + .driver = "scsi-hd",\ + .property = "discard_granularity",\ + .value = stringify(0),\ + },{\ + .driver = "scsi-cd",\ + .property = "discard_granularity",\ + .value = stringify(0),\ + },{\ + .driver = "scsi-disk",\ + .property = "discard_granularity",\ + .value = stringify(0),\ + },{\ + .driver = "ide-hd",\ + .property = "discard_granularity",\ + .value = stringify(0),\ + },{\ + .driver = "ide-cd",\ + .property = "discard_granularity",\ + .value = stringify(0),\ + },{\ + .driver = "ide-drive",\ + .property = "discard_granularity",\ + .value = stringify(0),\ + },{\ + .driver = "virtio-blk-pci",\ + .property = "discard_granularity",\ + .value = stringify(0),\ + } + #endif diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 0af436cfaf..aa9cc81a2d 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -294,8 +294,8 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) } #endif -static QEMUMachine pc_i440fx_machine_v1_4 = { - .name = "pc-i440fx-1.4", +static QEMUMachine pc_i440fx_machine_v1_5 = { + .name = "pc-i440fx-1.5", .alias = "pc", .desc = "Standard PC (i440FX + PIIX, 1996)", .init = pc_init_pci, @@ -304,7 +304,20 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { DEFAULT_MACHINE_OPTIONS, }; +static QEMUMachine pc_i440fx_machine_v1_4 = { + .name = "pc-i440fx-1.4", + .desc = "Standard PC (i440FX + PIIX, 1996)", + .init = pc_init_pci, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_4, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + #define PC_COMPAT_1_3 \ + PC_COMPAT_1_4, \ {\ .driver = "usb-tablet",\ .property = "usb_version",\ @@ -679,6 +692,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_i440fx_machine_v1_5); qemu_register_machine(&pc_i440fx_machine_v1_4); qemu_register_machine(&pc_machine_v1_3); qemu_register_machine(&pc_machine_v1_2); diff --git a/hw/pc_q35.c b/hw/pc_q35.c index 6f5ff8dcae..e22fb9891d 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -209,8 +209,8 @@ static void pc_q35_init(QEMUMachineInitArgs *args) } } -static QEMUMachine pc_q35_machine = { - .name = "pc-q35-1.4", +static QEMUMachine pc_q35_machine_v1_5 = { + .name = "pc-q35-1.5", .alias = "q35", .desc = "Standard PC (Q35 + ICH9, 2009)", .init = pc_q35_init, @@ -218,9 +218,22 @@ static QEMUMachine pc_q35_machine = { DEFAULT_MACHINE_OPTIONS, }; +static QEMUMachine pc_q35_machine_v1_4 = { + .name = "pc-q35-1.4", + .desc = "Standard PC (Q35 + ICH9, 2009)", + .init = pc_q35_init, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_4, + { /* end of list */ } + }, + DEFAULT_MACHINE_OPTIONS, +}; + static void pc_q35_machine_init(void) { - qemu_register_machine(&pc_q35_machine); + qemu_register_machine(&pc_q35_machine_v1_5); + qemu_register_machine(&pc_q35_machine_v1_4); } machine_init(pc_q35_machine_init); From c95e3080a44946ac5739542b549f5a10ee4ec377 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 22 Feb 2013 21:08:51 +0100 Subject: [PATCH 1217/1634] Reenable -Wstrict-prototypes One part of this patch reverts commit 22bc9a46, which disabled the warning. The rest of it deals with the warning by adding a #pragma for newer gcc and by disabling -Werror for compilers that can't deal with the #pragma. Signed-off-by: Kevin Wolf Message-id: 1361563731-13307-1-git-send-email-kwolf@redhat.com Signed-off-by: Anthony Liguori --- configure | 19 +++++++++++++------ ui/gtk.c | 12 +++++++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 0eb25dd77c..544c3f612c 100755 --- a/configure +++ b/configure @@ -284,7 +284,7 @@ sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}" # default flags for all hosts QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS" QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS" -QEMU_CFLAGS="-Wredundant-decls $QEMU_CFLAGS" +QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS" QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS" QEMU_INCLUDES="-I. -I\$(SRC_PATH) -I\$(SRC_PATH)/include" if test "$debug_info" = "yes"; then @@ -3115,20 +3115,27 @@ if compile_prog "" "" ; then fi ######################################## -# check whether we can disable the -Wunused-but-set-variable -# option with a pragma (this is needed to silence a warning in -# some versions of the valgrind VALGRIND_STACK_DEREGISTER macro.) -# This test has to be compiled with -Werror as otherwise an -# unknown pragma is only a warning. +# check whether we can disable warning option with a pragma (this is needed +# to silence warnings in the headers of some versions of external libraries). +# This test has to be compiled with -Werror as otherwise an unknown pragma is +# only a warning. +# +# If we can't selectively disable warning in the code, disable -Werror so that +# the build doesn't fail anyway. + pragma_disable_unused_but_set=no cat > $TMPC << EOF #pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" + int main(void) { return 0; } EOF if compile_prog "-Werror" "" ; then pragma_diagnostic_available=yes +else + werror=no fi ######################################## diff --git a/ui/gtk.c b/ui/gtk.c index 5f91de4d95..008a6f8aef 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -34,7 +34,18 @@ #define GETTEXT_PACKAGE "qemu" #define LOCALEDIR "po" +#include "qemu-common.h" + +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +/* Work around an -Wstrict-prototypes warning in GTK headers */ +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif #include +#ifdef CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE +#pragma GCC diagnostic error "-Wstrict-prototypes" +#endif + + #include #include #include @@ -46,7 +57,6 @@ #include #include -#include "qemu-common.h" #include "ui/console.h" #include "sysemu/sysemu.h" #include "qmp-commands.h" From 28d2e5b27d538d94d2489d657b563c58b4d69bc4 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 22 Feb 2013 20:09:59 +0100 Subject: [PATCH 1218/1634] ui/gtk: Support versions of VTE before 0.26 This is needed for current Debian stable (Squeeze). VTE versions before 0.26 did not support VtePty. Lower the version requirement and use alternate code which works for Debian. Signed-off-by: Stefan Weil Message-id: 1361560199-28906-1-git-send-email-sw@weilnetz.de Signed-off-by: Anthony Liguori --- configure | 2 +- ui/gtk.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 544c3f612c..dcaa67c6d3 100755 --- a/configure +++ b/configure @@ -1645,7 +1645,7 @@ fi if test "$gtk" != "no"; then if $pkg_config --exists 'gtk+-2.0 >= 2.18.0' && \ - $pkg_config --exists 'vte >= 0.26.0'; then + $pkg_config --exists 'vte >= 0.24.0'; then gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null` gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null` vte_cflags=`$pkg_config --cflags vte 2>/dev/null` diff --git a/ui/gtk.c b/ui/gtk.c index 008a6f8aef..bc8bdfd6b2 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -868,7 +868,9 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL const char *label; char buffer[32]; char path[32]; +#if VTE_CHECK_VERSION(0, 26, 0) VtePty *pty; +#endif GIOChannel *chan; GtkWidget *scrolled_window; GtkAdjustment *vadjustment; @@ -901,9 +903,12 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL cfmakeraw(&tty); tcsetattr(slave_fd, TCSAFLUSH, &tty); +#if VTE_CHECK_VERSION(0, 26, 0) pty = vte_pty_new_foreign(master_fd, NULL); - vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty); +#else + vte_terminal_set_pty(VTE_TERMINAL(vc->terminal), master_fd); +#endif vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1); From 104092825ac3274d16ffc35b7ef9ac8c636e1c48 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 22 Feb 2013 20:33:34 +0100 Subject: [PATCH 1219/1634] ui/gtk: Use menu item from stock for full screen This reduces the required translations and gives a nicer menu with an icon. The full screen menu item is no longer a check menu item. A checked item is not visible in full screen mode, so it is not needed for this special menu item. Signed-off-by: Stefan Weil Message-id: 1361561614-11180-1-git-send-email-sw@weilnetz.de Signed-off-by: Anthony Liguori --- po/de_DE.po | 4 ---- po/it.po | 4 ---- po/messages.po | 4 ---- ui/gtk.c | 5 +++-- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/po/de_DE.po b/po/de_DE.po index cb74d7cfec..875578349d 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -24,10 +24,6 @@ msgstr "_Datei" msgid "_View" msgstr "_Ansicht" -#: ../ui/gtk.c:1002 -msgid "_Full Screen" -msgstr "Voll_bild" - #: ../ui/gtk.c:1029 msgid "Zoom To _Fit" msgstr "Auf _Fenstergröße skalieren" diff --git a/po/it.po b/po/it.po index 2b23491aba..7d77fff2d3 100644 --- a/po/it.po +++ b/po/it.po @@ -24,10 +24,6 @@ msgstr "_File" msgid "_View" msgstr "_Visualizza" -#: ../ui/gtk.c:1002 -msgid "_Full Screen" -msgstr "_Schermo intero" - #: ../ui/gtk.c:1029 msgid "Zoom To _Fit" msgstr "Adatta alla _finestra" diff --git a/po/messages.po b/po/messages.po index a90cd6ff9b..191e81cc7c 100644 --- a/po/messages.po +++ b/po/messages.po @@ -24,10 +24,6 @@ msgstr "" msgid "_View" msgstr "" -#: ../ui/gtk.c:1002 -msgid "_Full Screen" -msgstr "" - #: ../ui/gtk.c:1029 msgid "Zoom To _Fit" msgstr "" diff --git a/ui/gtk.c b/ui/gtk.c index bc8bdfd6b2..0384f26988 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -633,7 +633,7 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque) { GtkDisplayState *s = opaque; - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->full_screen_item))) { + if (!s->full_screen) { gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE); gtk_widget_set_size_request(s->menu_bar, 0, 0); gtk_widget_set_size_request(s->drawing_area, -1, -1); @@ -1015,7 +1015,8 @@ static void gd_create_menus(GtkDisplayState *s) gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); s->view_menu_item = gtk_menu_item_new_with_mnemonic(_("_View")); - s->full_screen_item = gtk_check_menu_item_new_with_mnemonic(_("_Full Screen")); + s->full_screen_item = + gtk_image_menu_item_new_from_stock(GTK_STOCK_FULLSCREEN, NULL); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item), "/View/Full Screen"); gtk_accel_map_add_entry("/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK); From 30e8f22b7bc6694b9abea43f45db6fd5be4df429 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 22 Feb 2013 20:53:33 +0100 Subject: [PATCH 1220/1634] gtk: Rename File to Machine menu and add pause, reset and power down items This adds basic guest control commands to the "Machine" menu - a nice added-value for the GTK UI. We use "pause" as the term for stopping the machine here. So reword also the related caption tag. Signed-off-by: Jan Kiszka Signed-off-by: Anthony Liguori --- ui/gtk.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 0384f26988..dcce36d243 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -91,8 +91,11 @@ typedef struct GtkDisplayState GtkAccelGroup *accel_group; - GtkWidget *file_menu_item; - GtkWidget *file_menu; + GtkWidget *machine_menu_item; + GtkWidget *machine_menu; + GtkWidget *pause_item; + GtkWidget *reset_item; + GtkWidget *powerdown_item; GtkWidget *quit_item; GtkWidget *view_menu_item; @@ -128,6 +131,8 @@ typedef struct GtkDisplayState GdkCursor *null_cursor; Notifier mouse_mode_notifier; gboolean free_scale; + + bool external_pause_update; } GtkDisplayState; static GtkDisplayState *global_state; @@ -171,14 +176,19 @@ static void gd_update_caption(GtkDisplayState *s) const char *status = ""; gchar *title; const char *grab = ""; + bool is_paused = !runstate_is_running(); if (gd_is_grab_active(s)) { grab = " - Press Ctrl+Alt+G to release grab"; } - if (!runstate_is_running()) { - status = " [Stopped]"; + if (is_paused) { + status = " [Paused]"; } + s->external_pause_update = true; + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->pause_item), + is_paused); + s->external_pause_update = false; if (qemu_name) { title = g_strdup_printf("QEMU (%s)%s%s", qemu_name, status, grab); @@ -595,6 +605,30 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) /** Window Menu Actions **/ +static void gd_menu_pause(GtkMenuItem *item, void *opaque) +{ + GtkDisplayState *s = opaque; + + if (s->external_pause_update) { + return; + } + if (runstate_is_running()) { + qmp_stop(NULL); + } else { + qmp_cont(NULL); + } +} + +static void gd_menu_reset(GtkMenuItem *item, void *opaque) +{ + qmp_system_reset(NULL); +} + +static void gd_menu_powerdown(GtkMenuItem *item, void *opaque) +{ + qmp_system_powerdown(NULL); +} + static void gd_menu_quit(GtkMenuItem *item, void *opaque) { qmp_quit(NULL); @@ -968,6 +1002,12 @@ static void gd_connect_signals(GtkDisplayState *s) g_signal_connect(s->drawing_area, "key-release-event", G_CALLBACK(gd_key_event), s); + g_signal_connect(s->pause_item, "activate", + G_CALLBACK(gd_menu_pause), s); + g_signal_connect(s->reset_item, "activate", + G_CALLBACK(gd_menu_reset), s); + g_signal_connect(s->powerdown_item, "activate", + G_CALLBACK(gd_menu_powerdown), s); g_signal_connect(s->quit_item, "activate", G_CALLBACK(gd_menu_quit), s); g_signal_connect(s->full_screen_item, "activate", @@ -1001,15 +1041,31 @@ static void gd_create_menus(GtkDisplayState *s) int i; accel_group = gtk_accel_group_new(); - s->file_menu = gtk_menu_new(); - gtk_menu_set_accel_group(GTK_MENU(s->file_menu), accel_group); - s->file_menu_item = gtk_menu_item_new_with_mnemonic(_("_File")); + s->machine_menu = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(s->machine_menu), accel_group); + s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine")); + + s->pause_item = gtk_check_menu_item_new_with_mnemonic(_("_Pause")); + gtk_menu_append(GTK_MENU(s->machine_menu), s->pause_item); + + separator = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(s->machine_menu), separator); + + s->reset_item = gtk_image_menu_item_new_with_mnemonic(_("_Reset")); + gtk_menu_append(GTK_MENU(s->machine_menu), s->reset_item); + + s->powerdown_item = gtk_image_menu_item_new_with_mnemonic(_("Power _Down")); + gtk_menu_append(GTK_MENU(s->machine_menu), s->powerdown_item); + + separator = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(s->machine_menu), separator); s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); gtk_stock_lookup(GTK_STOCK_QUIT, &item); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item), - "/File/Quit"); - gtk_accel_map_add_entry("/File/Quit", item.keyval, item.modifier); + "/Machine/Quit"); + gtk_accel_map_add_entry("/Machine/Quit", item.keyval, item.modifier); + gtk_menu_append(GTK_MENU(s->machine_menu), s->quit_item); s->view_menu = gtk_menu_new(); gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); @@ -1085,9 +1141,9 @@ static void gd_create_menus(GtkDisplayState *s) gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group); s->accel_group = accel_group; - gtk_menu_append(GTK_MENU(s->file_menu), s->quit_item); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->file_menu_item), s->file_menu); - gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->file_menu_item); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item), + s->machine_menu); + gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->machine_menu_item); gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->view_menu_item), s->view_menu); gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item); From 685cbd2f63a48bd111bd2c3c4a2228029595ba12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Thu, 21 Feb 2013 22:58:08 +0100 Subject: [PATCH 1221/1634] xhci: fix bad print specifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following compilation error: hw/usb/hcd-xhci.c:1156:17: error: format ‘%llx’ expects argument of type ‘long long unsigned int’, but argument 4 has type ‘unsigned int’ Signed-off-by: Hervé Poussineau Reviewed-by: Stefan Weil Acked-by: Gerd Hoffmann Signed-off-by: Blue Swirl --- hw/usb/hcd-xhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 5796102f3a..07afdeef5b 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1152,8 +1152,8 @@ static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx, if (sctx->sct == -1) { xhci_dma_read_u32s(epctx->xhci, sctx->pctx, ctx, sizeof(ctx)); - fprintf(stderr, "%s: init sctx #%d @ %lx: %08x %08x\n", __func__, - streamid, sctx->pctx, ctx[0], ctx[1]); + fprintf(stderr, "%s: init sctx #%d @ " DMA_ADDR_FMT ": %08x %08x\n", + __func__, streamid, sctx->pctx, ctx[0], ctx[1]); sct = (ctx[0] >> 1) & 0x07; if (epctx->lsa && sct != 1) { *cc_error = CC_INVALID_STREAM_TYPE_ERROR; From 632314c49ce20ee9c974f07544d9125fbbbfbe1b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Feb 2013 16:13:27 +0000 Subject: [PATCH 1222/1634] qemu-log: Remove qemu_log_try_set_file() and its users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the function qemu_log_try_set_file() and its users (which are all in TCG code generation functions for various targets). This function was added to abstract out code which was originally written as "if (!logfile) logfile = stderr;" in order that BUG: case code which did an unguarded "fprintf(logfile, ...)" would not crash if debug logging was not enabled. Since those direct uses of logfile have also been abstracted away into qemu_log() calls which check for a NULL logfile, there is no need for the target-* files to mess with the user's chosen logging settings. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Acked-by: Michael Walle Signed-off-by: Blue Swirl --- include/qemu/log.h | 8 -------- target-cris/translate.c | 2 -- target-lm32/translate.c | 2 -- target-microblaze/translate.c | 2 -- target-openrisc/translate.c | 2 -- 5 files changed, 16 deletions(-) diff --git a/include/qemu/log.h b/include/qemu/log.h index 5a46555112..452700329e 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -126,14 +126,6 @@ static inline void qemu_log_set_file(FILE *f) qemu_logfile = f; } -/* Set up a new log file, only if none is set */ -static inline void qemu_log_try_set_file(FILE *f) -{ - if (!qemu_logfile) { - qemu_logfile = f; - } -} - /* define log items */ typedef struct QEMULogItem { int mask; diff --git a/target-cris/translate.c b/target-cris/translate.c index 04a5379775..2cf01a52e7 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3215,8 +3215,6 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, int num_insns; int max_insns; - qemu_log_try_set_file(stderr); - if (env->pregs[PR_VR] == 32) { dc->decoder = crisv32_decoder; dc->clear_locked_irq = 0; diff --git a/target-lm32/translate.c b/target-lm32/translate.c index 6b87340174..ccaf838afa 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -1012,8 +1012,6 @@ static void gen_intermediate_code_internal(CPULM32State *env, int num_insns; int max_insns; - qemu_log_try_set_file(stderr); - pc_start = tb->pc; dc->env = env; dc->tb = tb; diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 12ea820522..687b7d1433 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1734,8 +1734,6 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, int num_insns; int max_insns; - qemu_log_try_set_file(stderr); - pc_start = tb->pc; dc->env = env; dc->tb = tb; diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index 1e1b30cdcb..23e853e488 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -1670,8 +1670,6 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, int num_insns; int max_insns; - qemu_log_try_set_file(stderr); - pc_start = tb->pc; dc->tb = tb; From af18078d8057203b1ed26ac5534d233aabb36886 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 2 Feb 2013 17:17:54 +0000 Subject: [PATCH 1223/1634] disas/i386.c: Add explicit braces round empty for-loop body Add explicit braces round an empty for-loop body; this fits QEMU style and is easier to read than an inconspicuous semicolon at the end of the line. It also silences a clang warning: disas/i386.c:4723:49: warning: for loop has empty body [-Wempty-body] for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); ^ disas/i386.c:4723:49: note: put the semicolon on a separate line to silence this warning [-Wempty-body] Signed-off-by: Peter Maydell Signed-off-by: Blue Swirl --- disas/i386.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/disas/i386.c b/disas/i386.c index 3b006b13e0..dbecf1ffb5 100644 --- a/disas/i386.c +++ b/disas/i386.c @@ -4720,7 +4720,8 @@ print_operand_value (char *buf, size_t bufsize, int hex, bfd_vma disp) buf[0] = '0'; buf[1] = 'x'; snprintf_vma (tmp, sizeof(tmp), disp); - for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++); + for (i = 0; tmp[i] == '0' && tmp[i + 1]; i++) { + } pstrcpy (buf + 2, bufsize - 2, tmp + i); } else From 8eda222831d31e6562bf1ce50d22fa29e1b6d958 Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Tue, 19 Feb 2013 17:22:10 +0100 Subject: [PATCH 1224/1634] Typo: replace gptimer by apbuart Signed-off-by: Fabien Chouteau Signed-off-by: Blue Swirl --- hw/grlib_apbuart.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index 760bed0b72..3a61788a72 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -242,30 +242,30 @@ static int grlib_apbuart_init(SysBusDevice *dev) return 0; } -static Property grlib_gptimer_properties[] = { +static Property grlib_apbuart_properties[] = { DEFINE_PROP_CHR("chrdev", UART, chr), DEFINE_PROP_END_OF_LIST(), }; -static void grlib_gptimer_class_init(ObjectClass *klass, void *data) +static void grlib_apbuart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = grlib_apbuart_init; - dc->props = grlib_gptimer_properties; + dc->props = grlib_apbuart_properties; } -static const TypeInfo grlib_gptimer_info = { +static const TypeInfo grlib_apbuart_info = { .name = "grlib,apbuart", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(UART), - .class_init = grlib_gptimer_class_init, + .class_init = grlib_apbuart_class_init, }; -static void grlib_gptimer_register_types(void) +static void grlib_apbuart_register_types(void) { - type_register_static(&grlib_gptimer_info); + type_register_static(&grlib_apbuart_info); } -type_init(grlib_gptimer_register_types) +type_init(grlib_apbuart_register_types) From 99e448006d9267d71c2e3a629b6e5d29ed67bb30 Mon Sep 17 00:00:00 2001 From: Ronald Hecht Date: Tue, 19 Feb 2013 17:22:11 +0100 Subject: [PATCH 1225/1634] grlib-apbuart: Add support of various flags - enable/disable Rx and Tx - Rx and Tx interrupt - Tx FIFO empty and Tx SHIFT empty Signed-off-by: Fabien Chouteau Signed-off-by: Blue Swirl --- hw/grlib_apbuart.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index 3a61788a72..ba1685afd1 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -75,7 +75,6 @@ typedef struct UART { CharDriverState *chr; /* registers */ - uint32_t receive; uint32_t status; uint32_t control; @@ -136,12 +135,14 @@ static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size) { UART *uart = opaque; - uart_add_to_fifo(uart, buf, size); + if (uart->control & UART_RECEIVE_ENABLE) { + uart_add_to_fifo(uart, buf, size); - uart->status |= UART_DATA_READY; + uart->status |= UART_DATA_READY; - if (uart->control & UART_RECEIVE_INTERRUPT) { - qemu_irq_pulse(uart->irq); + if (uart->control & UART_RECEIVE_INTERRUPT) { + qemu_irq_pulse(uart->irq); + } } } @@ -193,8 +194,15 @@ static void grlib_apbuart_write(void *opaque, hwaddr addr, switch (addr) { case DATA_OFFSET: case DATA_OFFSET + 3: /* When only one byte write */ - c = value & 0xFF; - qemu_chr_fe_write(uart->chr, &c, 1); + /* Transmit when character device available and transmitter enabled */ + if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) { + c = value & 0xFF; + qemu_chr_fe_write(uart->chr, &c, 1); + /* Generate interrupt */ + if (uart->control & UART_TRANSMIT_INTERRUPT) { + qemu_irq_pulse(uart->irq); + } + } return; case STATUS_OFFSET: @@ -242,6 +250,19 @@ static int grlib_apbuart_init(SysBusDevice *dev) return 0; } +static void grlib_apbuart_reset(DeviceState *d) +{ + UART *uart = container_of(d, UART, busdev.qdev); + + /* Transmitter FIFO and shift registers are always empty in QEMU */ + uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY; + /* Everything is off */ + uart->control = 0; + /* Flush receive FIFO */ + uart->len = 0; + uart->current = 0; +} + static Property grlib_apbuart_properties[] = { DEFINE_PROP_CHR("chrdev", UART, chr), DEFINE_PROP_END_OF_LIST(), @@ -253,6 +274,7 @@ static void grlib_apbuart_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = grlib_apbuart_init; + dc->reset = grlib_apbuart_reset; dc->props = grlib_apbuart_properties; } From 7a0a9c2c64be242d5953d5ce6172976b05f6c14f Mon Sep 17 00:00:00 2001 From: Ronald Hecht Date: Tue, 19 Feb 2013 12:45:06 +0100 Subject: [PATCH 1226/1634] Added LEON MMU ASI mappings and corrected LEON3 MMU masks. This patch adds SPARC ASI mappings that are used by the LEON processor.It also corrects the MMU context register and context table pointer mask of the LEON3. Signed-off-by: Ronald Hecht Signed-off-by: Fabien Chouteau Signed-off-by: Blue Swirl --- target-sparc/cpu.c | 4 ++-- target-sparc/ldst_helper.c | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index ef52df6d74..cc1453e55f 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -580,8 +580,8 @@ static const sparc_def_t sparc_defs[] = { .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */ .mmu_version = 0xf3000000, .mmu_bm = 0x00000000, - .mmu_ctpr_mask = 0x007ffff0, - .mmu_cxr_mask = 0x0000003f, + .mmu_ctpr_mask = 0xfffffffc, + .mmu_cxr_mask = 0x000000ff, .mmu_sfsr_mask = 0xffffffff, .mmu_trcr_mask = 0xffffffff, .nwindows = 8, diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 7decd66d0b..6d767fb45a 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -514,6 +514,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, #endif break; case 3: /* MMU probe */ + case 0x18: /* LEON3 MMU probe */ { int mmulev; @@ -528,6 +529,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, } break; case 4: /* read MMU regs */ + case 0x19: /* LEON3 read MMU regs */ { int reg = (addr >> 8) & 0x1f; @@ -603,6 +605,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, case 0xf: /* D-cache data */ break; case 0x20: /* MMU passthrough */ + case 0x1c: /* LEON MMU passthrough */ switch (size) { case 1: ret = ldub_phys(addr); @@ -844,6 +847,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi, #endif break; case 3: /* MMU flush */ + case 0x18: /* LEON3 MMU flush */ { int mmulev; @@ -868,6 +872,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi, } break; case 4: /* write MMU regs */ + case 0x19: /* LEON3 write MMU regs */ { int reg = (addr >> 8) & 0x1f; uint32_t oldreg; @@ -996,6 +1001,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi, } break; case 0x20: /* MMU passthrough */ + case 0x1c: /* LEON MMU passthrough */ { switch (size) { case 1: From d1c36ba707637173b818652e51181370d51b6c58 Mon Sep 17 00:00:00 2001 From: Ronald Hecht Date: Tue, 19 Feb 2013 12:45:07 +0100 Subject: [PATCH 1227/1634] SPARC LEON power-down support added Signed-off-by: Ronald Hecht Signed-off-by: Fabien Chouteau Signed-off-by: Blue Swirl --- target-sparc/cpu.c | 2 +- target-sparc/cpu.h | 1 + target-sparc/helper.c | 11 +++++++++++ target-sparc/helper.h | 1 + target-sparc/translate.c | 5 +++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index cc1453e55f..50def61848 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -586,7 +586,7 @@ static const sparc_def_t sparc_defs[] = { .mmu_trcr_mask = 0xffffffff, .nwindows = 8, .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN | - CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL, + CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN, }, #endif }; diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 7389b03514..a2f2cc8989 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -270,6 +270,7 @@ typedef struct sparc_def_t { #define CPU_FEATURE_TA0_SHUTDOWN (1 << 14) /* Shutdown on "ta 0x0" */ #define CPU_FEATURE_ASR17 (1 << 15) #define CPU_FEATURE_CACHE_CTRL (1 << 16) +#define CPU_FEATURE_POWERDOWN (1 << 17) #ifndef TARGET_SPARC64 #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | \ diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 91ecfc7aa8..58e7efe567 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -225,3 +225,14 @@ target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1, cpu_restore_state(env, GETPC()); helper_raise_exception(env, TT_TOVF); } + +#ifndef TARGET_SPARC64 +void helper_power_down(CPUSPARCState *env) +{ + env->halted = 1; + env->exception_index = EXCP_HLT; + env->pc = env->npc; + env->npc = env->pc + 4; + cpu_loop_exit(env); +} +#endif diff --git a/target-sparc/helper.h b/target-sparc/helper.h index cfcdab1ea4..15f73283fa 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -4,6 +4,7 @@ DEF_HELPER_1(rett, void, env) DEF_HELPER_2(wrpsr, void, env, tl) DEF_HELPER_1(rdpsr, tl, env) +DEF_HELPER_1(power_down, void, env) #else DEF_HELPER_2(wrpil, void, env, tl) DEF_HELPER_2(wrpstate, void, env, tl) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index ca75e1aa48..26c2056b93 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -3642,6 +3642,11 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn) in the SPARCv8 manual, nop on the microSPARC II */ + if ((rd == 0x13) && (dc->def->features & + CPU_FEATURE_POWERDOWN)) { + /* LEON3 power-down */ + gen_helper_power_down(cpu_env); + } break; #else case 0x2: /* V9 wrccr */ From 6ab7e5465a4d6188e29398fb43a30dbab1015b75 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 20 Feb 2013 15:21:09 +0000 Subject: [PATCH 1228/1634] Replace all setjmp()/longjmp() with sigsetjmp()/siglongjmp() The setjmp() function doesn't specify whether signal masks are saved and restored; on Linux they are not, but on BSD (including MacOSX) they are. We want to have consistent behaviour across platforms, so we should always use "don't save/restore signal mask" (this is also generally going to be faster). This also works around a bug in MacOSX where the signal-restoration on longjmp() affects the signal mask for a completely different thread, not just the mask for the thread which did the longjmp. The most visible effect of this was that ctrl-C was ignored on MacOSX because the CPU thread did a longjmp which resulted in its signal mask being applied to every thread, so that all threads had SIGINT and SIGTERM blocked. The POSIX-sanctioned portable way to do a jump without affecting signal masks is to siglongjmp() to a sigjmp_buf which was created by calling sigsetjmp() with a zero savemask parameter, so change all uses of setjmp()/longjmp() accordingly. [Technically POSIX allows sigsetjmp(buf, 0) to save the signal mask; however the following siglongjmp() must not restore the signal mask, so the pair can be effectively considered as "sigjmp/longjmp which don't touch the mask".] For Windows we provide a trivial sigsetjmp/siglongjmp in terms of setjmp/longjmp -- this is OK because no user will ever pass a non-zero savemask. The setjmp() uses in tests/tcg/test-i386.c and tests/tcg/linux-test.c are left untouched because these are self-contained singlethreaded test programs intended to be run under QEMU's Linux emulation, so they have neither the portability nor the multithreading issues to deal with. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Tested-by: Stefan Weil Reviewed-by: Laszlo Ersek Signed-off-by: Blue Swirl --- coroutine-sigaltstack.c | 26 +++++++++++++------------- coroutine-ucontext.c | 27 ++++++++++++++------------- cpu-exec.c | 6 +++--- disas/i386.c | 6 +++--- disas/m68k.c | 11 ++++++----- include/exec/cpu-defs.h | 2 +- include/sysemu/os-win32.h | 8 ++++++++ monitor.c | 6 +++--- user-exec.c | 2 +- 9 files changed, 52 insertions(+), 42 deletions(-) diff --git a/coroutine-sigaltstack.c b/coroutine-sigaltstack.c index e37ebac9c4..1fb41c9f14 100644 --- a/coroutine-sigaltstack.c +++ b/coroutine-sigaltstack.c @@ -45,7 +45,7 @@ static unsigned int pool_size; typedef struct { Coroutine base; void *stack; - jmp_buf env; + sigjmp_buf env; } CoroutineUContext; /** @@ -59,7 +59,7 @@ typedef struct { CoroutineUContext leader; /** Information for the signal handler (trampoline) */ - jmp_buf tr_reenter; + sigjmp_buf tr_reenter; volatile sig_atomic_t tr_called; void *tr_handler; } CoroutineThreadState; @@ -115,8 +115,8 @@ static void __attribute__((constructor)) coroutine_init(void) static void coroutine_bootstrap(CoroutineUContext *self, Coroutine *co) { /* Initialize longjmp environment and switch back the caller */ - if (!setjmp(self->env)) { - longjmp(*(jmp_buf *)co->entry_arg, 1); + if (!sigsetjmp(self->env, 0)) { + siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } while (true) { @@ -145,14 +145,14 @@ static void coroutine_trampoline(int signal) /* * Here we have to do a bit of a ping pong between the caller, given that * this is a signal handler and we have to do a return "soon". Then the - * caller can reestablish everything and do a longjmp here again. + * caller can reestablish everything and do a siglongjmp here again. */ - if (!setjmp(coTS->tr_reenter)) { + if (!sigsetjmp(coTS->tr_reenter, 0)) { return; } /* - * Ok, the caller has longjmp'ed back to us, so now prepare + * Ok, the caller has siglongjmp'ed back to us, so now prepare * us for the real machine state switching. We have to jump * into another function here to get a new stack context for * the auto variables (which have to be auto-variables @@ -179,7 +179,7 @@ static Coroutine *coroutine_new(void) /* The way to manipulate stack is with the sigaltstack function. We * prepare a stack, with it delivering a signal to ourselves and then - * put setjmp/longjmp where needed. + * put sigsetjmp/siglongjmp where needed. * This has been done keeping coroutine-ucontext as a model and with the * pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics * of the coroutines and see pth_mctx.c (from the pth project) for the @@ -220,7 +220,7 @@ static Coroutine *coroutine_new(void) /* * Now transfer control onto the signal stack and set it up. - * It will return immediately via "return" after the setjmp() + * It will return immediately via "return" after the sigsetjmp() * was performed. Be careful here with race conditions. The * signal can be delivered the first time sigsuspend() is * called. @@ -261,8 +261,8 @@ static Coroutine *coroutine_new(void) * type-conversion warnings related to the `volatile' qualifier and * the fact that `jmp_buf' usually is an array type. */ - if (!setjmp(old_env)) { - longjmp(coTS->tr_reenter, 1); + if (!sigsetjmp(old_env, 0)) { + siglongjmp(coTS->tr_reenter, 1); } /* @@ -311,9 +311,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, s->current = to_; - ret = setjmp(from->env); + ret = sigsetjmp(from->env, 0); if (ret == 0) { - longjmp(to->env, action); + siglongjmp(to->env, action); } return ret; } diff --git a/coroutine-ucontext.c b/coroutine-ucontext.c index a9c30e9df4..bd20e384b7 100644 --- a/coroutine-ucontext.c +++ b/coroutine-ucontext.c @@ -46,7 +46,7 @@ static unsigned int pool_size; typedef struct { Coroutine base; void *stack; - jmp_buf env; + sigjmp_buf env; #ifdef CONFIG_VALGRIND_H unsigned int valgrind_stack_id; @@ -130,8 +130,8 @@ static void coroutine_trampoline(int i0, int i1) co = &self->base; /* Initialize longjmp environment and switch back the caller */ - if (!setjmp(self->env)) { - longjmp(*(jmp_buf *)co->entry_arg, 1); + if (!sigsetjmp(self->env, 0)) { + siglongjmp(*(sigjmp_buf *)co->entry_arg, 1); } while (true) { @@ -145,14 +145,15 @@ static Coroutine *coroutine_new(void) const size_t stack_size = 1 << 20; CoroutineUContext *co; ucontext_t old_uc, uc; - jmp_buf old_env; + sigjmp_buf old_env; union cc_arg arg = {0}; - /* The ucontext functions preserve signal masks which incurs a system call - * overhead. setjmp()/longjmp() does not preserve signal masks but only - * works on the current stack. Since we need a way to create and switch to - * a new stack, use the ucontext functions for that but setjmp()/longjmp() - * for everything else. + /* The ucontext functions preserve signal masks which incurs a + * system call overhead. sigsetjmp(buf, 0)/siglongjmp() does not + * preserve signal masks but only works on the current stack. + * Since we need a way to create and switch to a new stack, use + * the ucontext functions for that but sigsetjmp()/siglongjmp() for + * everything else. */ if (getcontext(&uc) == -1) { @@ -178,8 +179,8 @@ static Coroutine *coroutine_new(void) makecontext(&uc, (void (*)(void))coroutine_trampoline, 2, arg.i[0], arg.i[1]); - /* swapcontext() in, longjmp() back out */ - if (!setjmp(old_env)) { + /* swapcontext() in, siglongjmp() back out */ + if (!sigsetjmp(old_env, 0)) { swapcontext(&old_uc, &uc); } return &co->base; @@ -242,9 +243,9 @@ CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_, s->current = to_; - ret = setjmp(from->env); + ret = sigsetjmp(from->env, 0); if (ret == 0) { - longjmp(to->env, action); + siglongjmp(to->env, action); } return ret; } diff --git a/cpu-exec.c b/cpu-exec.c index 9fcfe9e0db..afbe4977ab 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -35,7 +35,7 @@ void cpu_loop_exit(CPUArchState *env) CPUState *cpu = ENV_GET_CPU(env); cpu->current_tb = NULL; - longjmp(env->jmp_env, 1); + siglongjmp(env->jmp_env, 1); } /* exit the current TB from a signal handler. The host registers are @@ -47,7 +47,7 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc) /* XXX: restore cpu registers saved in host registers */ env->exception_index = -1; - longjmp(env->jmp_env, 1); + siglongjmp(env->jmp_env, 1); } #endif @@ -234,7 +234,7 @@ int cpu_exec(CPUArchState *env) /* prepare setjmp context for exception handling */ for(;;) { - if (setjmp(env->jmp_env) == 0) { + if (sigsetjmp(env->jmp_env, 0) == 0) { /* if an exception is pending, we execute it here */ if (env->exception_index >= 0) { if (env->exception_index >= EXCP_INTERRUPT) { diff --git a/disas/i386.c b/disas/i386.c index dbecf1ffb5..73cc06f1c3 100644 --- a/disas/i386.c +++ b/disas/i386.c @@ -226,7 +226,7 @@ struct dis_private { bfd_byte the_buffer[MAX_MNEM_SIZE]; bfd_vma insn_start; int orig_sizeflag; - jmp_buf bailout; + sigjmp_buf bailout; }; enum address_mode @@ -303,7 +303,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr) STATUS. */ if (priv->max_fetched == priv->the_buffer) (*info->memory_error_func) (status, start, info); - longjmp (priv->bailout, 1); + siglongjmp(priv->bailout, 1); } else priv->max_fetched = addr; @@ -3661,7 +3661,7 @@ print_insn (bfd_vma pc, disassemble_info *info) start_codep = priv.the_buffer; codep = priv.the_buffer; - if (setjmp (priv.bailout) != 0) + if (sigsetjmp(priv.bailout, 0) != 0) { const char *name; diff --git a/disas/m68k.c b/disas/m68k.c index c950241f79..cc0db96cae 100644 --- a/disas/m68k.c +++ b/disas/m68k.c @@ -624,7 +624,7 @@ struct private bfd_byte *max_fetched; bfd_byte the_buffer[MAXLEN]; bfd_vma insn_start; - jmp_buf bailout; + sigjmp_buf bailout; }; /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) @@ -644,7 +644,7 @@ fetch_data2(struct disassemble_info *info, bfd_byte *addr) if (status != 0) { (*info->memory_error_func) (status, start, info); - longjmp (priv->bailout, 1); + siglongjmp(priv->bailout, 1); } else priv->max_fetched = addr; @@ -1912,9 +1912,10 @@ print_insn_m68k (bfd_vma memaddr, disassemble_info *info) priv.max_fetched = priv.the_buffer; priv.insn_start = memaddr; - if (setjmp (priv.bailout) != 0) - /* Error return. */ - return -1; + if (sigsetjmp(priv.bailout, 0) != 0) { + /* Error return. */ + return -1; + } switch (info->mach) { diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index ae64590cdf..3dc96568ac 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -184,7 +184,7 @@ typedef struct CPUWatchpoint { struct GDBRegisterState *gdb_regs; \ \ /* Core interrupt code */ \ - jmp_buf jmp_env; \ + sigjmp_buf jmp_env; \ int exception_index; \ \ CPUArchState *next_cpu; /* next CPU sharing TB cache */ \ diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index bf9edeb9ab..71f5fa0a91 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -63,6 +63,14 @@ # undef setjmp # define setjmp(env) _setjmp(env, NULL) #endif +/* QEMU uses sigsetjmp()/siglongjmp() as the portable way to specify + * "longjmp and don't touch the signal masks". Since we know that the + * savemask parameter will always be zero we can safely define these + * in terms of setjmp/longjmp on Win32. + */ +#define sigjmp_buf jmp_buf +#define sigsetjmp(env, savemask) setjmp(env) +#define siglongjmp(env, val) longjmp(env, val) /* Declaration of ffs() is missing in MinGW's strings.h. */ int ffs(int i); diff --git a/monitor.c b/monitor.c index 6a0f2573f5..32a6e74fd9 100644 --- a/monitor.c +++ b/monitor.c @@ -2740,7 +2740,7 @@ static const mon_cmd_t qmp_cmds[] = { /*******************************************************************/ static const char *pch; -static jmp_buf expr_env; +static sigjmp_buf expr_env; #define MD_TLONG 0 #define MD_I32 1 @@ -3135,7 +3135,7 @@ static const MonitorDef monitor_defs[] = { static void expr_error(Monitor *mon, const char *msg) { monitor_printf(mon, "%s\n", msg); - longjmp(expr_env, 1); + siglongjmp(expr_env, 1); } /* return 0 if OK, -1 if not found */ @@ -3345,7 +3345,7 @@ static int64_t expr_sum(Monitor *mon) static int get_expr(Monitor *mon, int64_t *pval, const char **pp) { pch = *pp; - if (setjmp(expr_env)) { + if (sigsetjmp(expr_env, 0)) { *pp = pch; return -1; } diff --git a/user-exec.c b/user-exec.c index c71acbc503..71bd6c531c 100644 --- a/user-exec.c +++ b/user-exec.c @@ -70,7 +70,7 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc) #endif } env1->exception_index = -1; - longjmp(env1->jmp_env, 1); + siglongjmp(env1->jmp_env, 1); } /* 'pc' is the host PC at which the exception was raised. 'address' is From e6a72734549bd05d06d19957518811c24a6cbee4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:49 -0800 Subject: [PATCH 1229/1634] tcg: Make 32-bit multiword operations optional for 64-bit hosts Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/i386/tcg-target.h | 4 ++++ tcg/ia64/tcg-target.h | 3 +++ tcg/ppc64/tcg-target.h | 3 +++ tcg/s390/tcg-target.h | 3 +++ tcg/sparc/tcg-target.h | 4 ++++ tcg/tcg-opc.h | 6 +++--- tcg/tcg.h | 6 +++++- tcg/tci/tcg-target.h | 4 ++++ 8 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index e63db9cfe9..43ad2c4354 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -114,6 +114,10 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 + +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 #endif #define TCG_TARGET_deposit_i32_valid(ofs, len) \ diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index 7f3401ecdd..b4ff7c361b 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -136,6 +136,9 @@ typedef enum { #define TCG_TARGET_HAS_movcond_i64 1 #define TCG_TARGET_HAS_deposit_i32 1 #define TCG_TARGET_HAS_deposit_i64 1 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16) #define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16) diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h index 9b8e9a07b8..ea976adfb0 100644 --- a/tcg/ppc64/tcg-target.h +++ b/tcg/ppc64/tcg-target.h @@ -85,6 +85,9 @@ typedef enum { #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 #define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rot_i64 0 diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index c87b4138b5..7772c35d65 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -65,6 +65,9 @@ typedef enum TCGReg { #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 #define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index 256f973c6d..6c62e4594b 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -124,6 +124,10 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 + +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 #endif #define TCG_AREG0 TCG_REG_I0 diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index 9651063414..1d9a9a22ab 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -83,10 +83,10 @@ DEF(deposit_i32, 1, 2, 2, IMPL(TCG_TARGET_HAS_deposit_i32)) DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END) -DEF(add2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32)) -DEF(sub2_i32, 2, 4, 0, IMPL(TCG_TARGET_REG_BITS == 32)) +DEF(add2_i32, 2, 4, 0, IMPL(TCG_TARGET_HAS_add2_i32)) +DEF(sub2_i32, 2, 4, 0, IMPL(TCG_TARGET_HAS_sub2_i32)) +DEF(mulu2_i32, 2, 2, 0, IMPL(TCG_TARGET_HAS_mulu2_i32)) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | IMPL(TCG_TARGET_REG_BITS == 32)) -DEF(mulu2_i32, 2, 2, 0, IMPL(TCG_TARGET_REG_BITS == 32)) DEF(setcond2_i32, 1, 4, 1, IMPL(TCG_TARGET_REG_BITS == 32)) DEF(ext8s_i32, 1, 1, 0, IMPL(TCG_TARGET_HAS_ext8s_i32)) diff --git a/tcg/tcg.h b/tcg/tcg.h index 51c8176550..e5c7ce4aeb 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -57,8 +57,8 @@ typedef uint64_t TCGRegSet; #error unsupported #endif -/* Turn some undef macros into false macros. */ #if TCG_TARGET_REG_BITS == 32 +/* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_div_i64 0 #define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 0 @@ -80,6 +80,10 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 #define TCG_TARGET_HAS_movcond_i64 0 +/* Turn some undef macros into true macros. */ +#define TCG_TARGET_HAS_add2_i32 1 +#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_mulu2_i32 1 #endif #ifndef TCG_TARGET_deposit_i32_valid diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index a832f5cf52..3e235bd973 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -100,6 +100,10 @@ #define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_movcond_i64 0 + +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_mulu2_i32 0 #endif /* TCG_TARGET_REG_BITS == 64 */ /* Number of registers available. From bbc863bfecfb3e3a3e21ce569e25046e24c0487c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:50 -0800 Subject: [PATCH 1230/1634] tcg-i386: Always implement 32-bit multiword ops Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/i386/tcg-target.c | 18 ++++++++++-------- tcg/i386/tcg-target.h | 7 +++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 7aec3043e3..f6455294e2 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -1922,13 +1922,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_qemu_st(s, args, 3); break; -#if TCG_TARGET_REG_BITS == 32 - case INDEX_op_brcond2_i32: - tcg_out_brcond2(s, args, const_args, 0); - break; - case INDEX_op_setcond2_i32: - tcg_out_setcond2(s, args, const_args); - break; case INDEX_op_mulu2_i32: tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]); break; @@ -1956,6 +1949,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tgen_arithr(s, ARITH_SBB, args[1], args[5]); } break; + +#if TCG_TARGET_REG_BITS == 32 + case INDEX_op_brcond2_i32: + tcg_out_brcond2(s, args, const_args, 0); + break; + case INDEX_op_setcond2_i32: + tcg_out_setcond2(s, args, const_args); + break; #else /* TCG_TARGET_REG_BITS == 64 */ case INDEX_op_movi_i64: tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]); @@ -2078,10 +2079,11 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_movcond_i32, { "r", "r", "ri", "r", "0" } }, #endif -#if TCG_TARGET_REG_BITS == 32 { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } }, { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } }, + +#if TCG_TARGET_REG_BITS == 32 { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } }, { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } }, #else diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 43ad2c4354..487dc238d6 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -92,6 +92,9 @@ typedef enum { #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_add2_i32 1 +#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_mulu2_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 @@ -114,10 +117,6 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 - -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 -#define TCG_TARGET_HAS_mulu2_i32 0 #endif #define TCG_TARGET_deposit_i32_valid(ofs, len) \ From 803d805bcef4ea7b7d6ef0b4929263e1160d6b3c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:51 -0800 Subject: [PATCH 1231/1634] tcg-sparc: Always implement 32-bit multiword ops Cc: Blue Swirl Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/sparc/tcg-target.c | 6 ++++-- tcg/sparc/tcg-target.h | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 03db514a1d..6d489fcc52 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -1327,6 +1327,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, args[3], const_args[3], args[4], const_args[4]); break; +#endif + case INDEX_op_add2_i32: tcg_out_addsub2(s, args[0], args[1], args[2], args[3], args[4], const_args[4], args[5], const_args[5], @@ -1342,7 +1344,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, ARITH_UMUL); tcg_out_rdy(s, args[1]); break; -#endif case INDEX_op_qemu_ld8u: tcg_out_qemu_ld(s, args, 0); @@ -1511,10 +1512,11 @@ static const TCGTargetOpDef sparc_op_defs[] = { #if TCG_TARGET_REG_BITS == 32 { INDEX_op_brcond2_i32, { "rZ", "rZ", "rJ", "rJ" } }, { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rJ", "rJ" } }, +#endif + { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } }, { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } }, { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rJ" } }, -#endif #if TCG_TARGET_REG_BITS == 64 { INDEX_op_mov_i64, { "r", "r" } }, diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index 6c62e4594b..8446721d5b 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -102,6 +102,9 @@ typedef enum { #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_add2_i32 1 +#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_mulu2_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div_i64 1 @@ -124,10 +127,6 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 - -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 -#define TCG_TARGET_HAS_mulu2_i32 0 #endif #define TCG_AREG0 TCG_REG_I0 From d7156f7ce4581c874df4a27409e7d99873faa413 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:52 -0800 Subject: [PATCH 1232/1634] tcg: Add 64-bit multiword arithmetic operations Matching the 32-bit multiword arithmetic that we already have. Signed-off-by: Blue Swirl --- tcg/README | 26 ++++++++++++++------------ tcg/i386/tcg-target.h | 3 +++ tcg/ia64/tcg-target.h | 3 +++ tcg/optimize.c | 4 ++-- tcg/ppc64/tcg-target.h | 3 +++ tcg/s390/tcg-target.h | 3 +++ tcg/sparc/tcg-target.h | 3 +++ tcg/tcg-opc.h | 4 ++++ tcg/tcg.h | 3 +++ tcg/tci/tcg-target.h | 3 +++ 10 files changed, 41 insertions(+), 14 deletions(-) diff --git a/tcg/README b/tcg/README index ec1ac79375..89f0cdd369 100644 --- a/tcg/README +++ b/tcg/README @@ -361,6 +361,20 @@ Write 8, 16, 32 or 64 bits to host memory. All this opcodes assume that the pointed host memory doesn't correspond to a global. In the latter case the behaviour is unpredictable. +********* Multiword arithmetic support + +* add2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high +* sub2_i32/i64 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high + +Similar to add/sub, except that the double-word inputs T1 and T2 are +formed from two single-word arguments, and the double-word output T0 +is returned in two single-word outputs. + +* mulu2_i32/i64 t0_low, t0_high, t1, t2 + +Similar to mul, except two unsigned inputs T1 and T2 yielding the full +double-word product T0. The later is returned in two single-word outputs. + ********* 64-bit target on 32-bit host support The following opcodes are internal to TCG. Thus they are to be implemented by @@ -372,18 +386,6 @@ They are emitted as needed by inline functions within "tcg-op.h". Similar to brcond, except that the 64-bit values T0 and T1 are formed from two 32-bit arguments. -* add2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high -* sub2_i32 t0_low, t0_high, t1_low, t1_high, t2_low, t2_high - -Similar to add/sub, except that the 64-bit inputs T1 and T2 are -formed from two 32-bit arguments, and the 64-bit output T0 -is returned in two 32-bit outputs. - -* mulu2_i32 t0_low, t0_high, t1, t2 - -Similar to mul, except two 32-bit (unsigned) inputs T1 and T2 yielding -the full 64-bit product T0. The later is returned in two 32-bit outputs. - * setcond2_i32 dest, t1_low, t1_high, t2_low, t2_high, cond Similar to setcond, except that the 64-bit values T1 and T2 are diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 487dc238d6..4f0017101a 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -117,6 +117,9 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 #endif #define TCG_TARGET_deposit_i32_valid(ofs, len) \ diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index b4ff7c361b..40f442ebe4 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -137,8 +137,11 @@ typedef enum { #define TCG_TARGET_HAS_deposit_i32 1 #define TCG_TARGET_HAS_deposit_i64 1 #define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i32 0 +#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i32 0 +#define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16) #define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16) diff --git a/tcg/optimize.c b/tcg/optimize.c index 973d2d679f..027b3a53e6 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -554,11 +554,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, args[5] = tcg_invert_cond(args[5]); } break; - case INDEX_op_add2_i32: + CASE_OP_32_64(add2): swap_commutative(args[0], &args[2], &args[4]); swap_commutative(args[1], &args[3], &args[5]); break; - case INDEX_op_mulu2_i32: + CASE_OP_32_64(mulu2): swap_commutative(args[0], &args[2], &args[3]); break; case INDEX_op_brcond2_i32: diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h index ea976adfb0..86929c18ce 100644 --- a/tcg/ppc64/tcg-target.h +++ b/tcg/ppc64/tcg-target.h @@ -109,6 +109,9 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 #define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_AREG0 TCG_REG_R27 diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index 7772c35d65..ee31c37bdb 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -90,6 +90,9 @@ typedef enum TCGReg { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 #define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 #endif /* used for function call generation */ diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index 8446721d5b..e440ad2190 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -127,6 +127,9 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 #define TCG_TARGET_HAS_movcond_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 #endif #define TCG_AREG0 TCG_REG_I0 diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index 1d9a9a22ab..e93698e3d0 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -158,6 +158,10 @@ DEF(eqv_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_eqv_i64)) DEF(nand_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nand_i64)) DEF(nor_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nor_i64)) +DEF(add2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_add2_i64)) +DEF(sub2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_sub2_i64)) +DEF(mulu2_i64, 2, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_mulu2_i64)) + /* QEMU specific */ #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS DEF(debug_insn_start, 0, 0, 2, 0) diff --git a/tcg/tcg.h b/tcg/tcg.h index e5c7ce4aeb..255cbdb473 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -80,6 +80,9 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 0 #define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 /* Turn some undef macros into true macros. */ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 3e235bd973..5986da26aa 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -104,6 +104,9 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_mulu2_i32 0 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 +#define TCG_TARGET_HAS_mulu2_i64 0 #endif /* TCG_TARGET_REG_BITS == 64 */ /* Number of registers available. From 4d3203fd0b5d17e39f631f2534e7cbb37d04ce3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:53 -0800 Subject: [PATCH 1233/1634] tcg: Add signed multiword multiplication operations Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/README | 4 ++++ tcg/arm/tcg-target.h | 1 + tcg/hppa/tcg-target.h | 1 + tcg/i386/tcg-target.h | 2 ++ tcg/ia64/tcg-target.h | 2 ++ tcg/mips/tcg-target.h | 1 + tcg/optimize.c | 1 + tcg/ppc/tcg-target.h | 1 + tcg/ppc64/tcg-target.h | 2 ++ tcg/s390/tcg-target.h | 2 ++ tcg/sparc/tcg-target.h | 2 ++ tcg/tcg-opc.h | 2 ++ tcg/tcg.h | 1 + tcg/tci/tcg-target.h | 2 ++ 14 files changed, 24 insertions(+) diff --git a/tcg/README b/tcg/README index 89f0cdd369..934e7afc96 100644 --- a/tcg/README +++ b/tcg/README @@ -375,6 +375,10 @@ is returned in two single-word outputs. Similar to mul, except two unsigned inputs T1 and T2 yielding the full double-word product T0. The later is returned in two single-word outputs. +* muls2_i32/i64 t0_low, t0_high, t1, t2 + +Similar to mulu2, except the two inputs T1 and T2 are signed. + ********* 64-bit target on 32-bit host support The following opcodes are internal to TCG. Thus they are to be implemented by diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index 7083f3a700..f9599bd687 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -75,6 +75,7 @@ typedef enum { #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_muls2_i32 0 enum { TCG_AREG0 = TCG_REG_R6, diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h index e2754fe970..ebd53d9e36 100644 --- a/tcg/hppa/tcg-target.h +++ b/tcg/hppa/tcg-target.h @@ -98,6 +98,7 @@ typedef enum { #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_muls2_i32 0 /* optional instructions automatically implemented */ #define TCG_TARGET_HAS_neg_i32 0 /* sub rd, 0, rs */ diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 4f0017101a..2b08ef79bb 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -95,6 +95,7 @@ typedef enum { #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 +#define TCG_TARGET_HAS_muls2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 @@ -120,6 +121,7 @@ typedef enum { #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 #endif #define TCG_TARGET_deposit_i32_valid(ofs, len) \ diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h index 40f442ebe4..e3d72ea52f 100644 --- a/tcg/ia64/tcg-target.h +++ b/tcg/ia64/tcg-target.h @@ -142,6 +142,8 @@ typedef enum { #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i32 0 +#define TCG_TARGET_HAS_muls2_i64 0 #define TCG_TARGET_deposit_i32_valid(ofs, len) ((len) <= 16) #define TCG_TARGET_deposit_i64_valid(ofs, len) ((len) <= 16) diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 78af664cca..0384bd384f 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -87,6 +87,7 @@ typedef enum { #define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 +#define TCG_TARGET_HAS_muls2_i32 0 /* optional instructions only implemented on MIPS4, MIPS32 and Loongson 2 */ #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \ diff --git a/tcg/optimize.c b/tcg/optimize.c index 027b3a53e6..bc6e5c16a9 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -559,6 +559,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, swap_commutative(args[1], &args[3], &args[5]); break; CASE_OP_32_64(mulu2): + CASE_OP_32_64(muls2): swap_commutative(args[0], &args[2], &args[3]); break; case INDEX_op_brcond2_i32: diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 0fdad04ee4..17a6bb367a 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -94,6 +94,7 @@ typedef enum { #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_deposit_i32 1 #define TCG_TARGET_HAS_movcond_i32 1 +#define TCG_TARGET_HAS_muls2_i32 0 #define TCG_AREG0 TCG_REG_R27 diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h index 86929c18ce..aa6a0f0306 100644 --- a/tcg/ppc64/tcg-target.h +++ b/tcg/ppc64/tcg-target.h @@ -88,6 +88,7 @@ typedef enum { #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_mulu2_i32 0 +#define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rot_i64 0 @@ -112,6 +113,7 @@ typedef enum { #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 #define TCG_AREG0 TCG_REG_R27 diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index ee31c37bdb..40211e68f1 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -68,6 +68,7 @@ typedef enum TCGReg { #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_mulu2_i32 0 +#define TCG_TARGET_HAS_muls2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 @@ -93,6 +94,7 @@ typedef enum TCGReg { #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 #endif /* used for function call generation */ diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h index e440ad2190..b5217bef25 100644 --- a/tcg/sparc/tcg-target.h +++ b/tcg/sparc/tcg-target.h @@ -105,6 +105,7 @@ typedef enum { #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 +#define TCG_TARGET_HAS_muls2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div_i64 1 @@ -130,6 +131,7 @@ typedef enum { #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 #endif #define TCG_AREG0 TCG_REG_I0 diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h index e93698e3d0..4246e9c1fa 100644 --- a/tcg/tcg-opc.h +++ b/tcg/tcg-opc.h @@ -86,6 +86,7 @@ DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END) DEF(add2_i32, 2, 4, 0, IMPL(TCG_TARGET_HAS_add2_i32)) DEF(sub2_i32, 2, 4, 0, IMPL(TCG_TARGET_HAS_sub2_i32)) DEF(mulu2_i32, 2, 2, 0, IMPL(TCG_TARGET_HAS_mulu2_i32)) +DEF(muls2_i32, 2, 2, 0, IMPL(TCG_TARGET_HAS_muls2_i32)) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | IMPL(TCG_TARGET_REG_BITS == 32)) DEF(setcond2_i32, 1, 4, 1, IMPL(TCG_TARGET_REG_BITS == 32)) @@ -161,6 +162,7 @@ DEF(nor_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_nor_i64)) DEF(add2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_add2_i64)) DEF(sub2_i64, 2, 4, 0, IMPL64 | IMPL(TCG_TARGET_HAS_sub2_i64)) DEF(mulu2_i64, 2, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_mulu2_i64)) +DEF(muls2_i64, 2, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_muls2_i64)) /* QEMU specific */ #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS diff --git a/tcg/tcg.h b/tcg/tcg.h index 255cbdb473..b195396b0f 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -83,6 +83,7 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 /* Turn some undef macros into true macros. */ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index 5986da26aa..1f17576f54 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -76,6 +76,7 @@ #define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_movcond_i32 0 +#define TCG_TARGET_HAS_muls2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_bswap16_i64 1 @@ -100,6 +101,7 @@ #define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_movcond_i64 0 +#define TCG_TARGET_HAS_muls2_i64 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 From 3c51a98507f9ff64fc2a3841c0e5b8a0c9e3c2b7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:54 -0800 Subject: [PATCH 1234/1634] tcg: Implement a 64-bit to 32-bit extraction helper We're going to have use for this shortly in implementing other helpers. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg-op.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 91c9d80dd5..4ded249fad 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2246,6 +2246,26 @@ static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low, tcg_gen_deposit_i64(dest, low, high, 32, 32); } +static inline void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg) +{ +#if TCG_TARGET_REG_BITS == 32 + tcg_gen_mov_i32(lo, TCGV_LOW(arg)); + tcg_gen_mov_i32(hi, TCGV_HIGH(arg)); +#else + TCGv_i64 t0 = tcg_temp_new_i64(); + tcg_gen_trunc_i64_i32(lo, arg); + tcg_gen_shri_i64(t0, arg, 32); + tcg_gen_trunc_i64_i32(hi, t0); + tcg_temp_free_i64(t0); +#endif +} + +static inline void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg) +{ + tcg_gen_ext32u_i64(lo, arg); + tcg_gen_shri_i64(hi, arg, 32); +} + static inline void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, TCGv_i32 c2, TCGv_i32 v1, TCGv_i32 v2) @@ -2625,6 +2645,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_gen_bswap32_tl tcg_gen_bswap32_i64 #define tcg_gen_bswap64_tl tcg_gen_bswap64_i64 #define tcg_gen_concat_tl_i64 tcg_gen_concat32_i64 +#define tcg_gen_extr_i64_tl tcg_gen_extr32_i64 #define tcg_gen_andc_tl tcg_gen_andc_i64 #define tcg_gen_eqv_tl tcg_gen_eqv_i64 #define tcg_gen_nand_tl tcg_gen_nand_i64 @@ -2697,6 +2718,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_gen_bswap16_tl tcg_gen_bswap16_i32 #define tcg_gen_bswap32_tl tcg_gen_bswap32_i32 #define tcg_gen_concat_tl_i64 tcg_gen_concat_i32_i64 +#define tcg_gen_extr_tl_i64 tcg_gen_extr_i32_i64 #define tcg_gen_andc_tl tcg_gen_andc_i32 #define tcg_gen_eqv_tl tcg_gen_eqv_i32 #define tcg_gen_nand_tl tcg_gen_nand_i32 From 696a8be6a077a5760bbf9822209999c908cdf0b1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:55 -0800 Subject: [PATCH 1235/1634] tcg: Implement multiword multiply helpers Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg-runtime.c | 16 ++++++++- tcg/tcg-op.h | 84 +++++++++++++++++++++++++++++++++++++++++++++++ tcg/tcg-runtime.h | 2 ++ 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/tcg-runtime.c b/tcg-runtime.c index abfc36498f..4b66e51ce7 100644 --- a/tcg-runtime.c +++ b/tcg-runtime.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include - +#include "qemu/host-utils.h" #include "tcg/tcg-runtime.h" /* 32-bit helpers */ @@ -83,3 +83,17 @@ uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2) { return arg1 % arg2; } + +uint64_t tcg_helper_muluh_i64(uint64_t arg1, uint64_t arg2) +{ + uint64_t l, h; + mulu64(&l, &h, arg1, arg2); + return h; +} + +int64_t tcg_helper_mulsh_i64(int64_t arg1, int64_t arg2) +{ + uint64_t l, h; + muls64(&l, &h, arg1, arg2); + return h; +} diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 4ded249fad..97e0795b95 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2332,6 +2332,86 @@ static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, #endif } +static inline void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, + TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCG_TARGET_HAS_mulu2_i32) { + tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); + /* Allow the optimizer room to replace mulu2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t0, arg1); + tcg_gen_extu_i32_i64(t1, arg2); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_extr_i64_i32(rl, rh, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } +} + +static inline void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, + TCGv_i32 arg1, TCGv_i32 arg2) +{ + if (TCG_TARGET_HAS_muls2_i32) { + tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); + /* Allow the optimizer room to replace muls2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(t0, arg1); + tcg_gen_ext_i32_i64(t1, arg2); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_extr_i64_i32(rl, rh, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } +} + +static inline void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCG_TARGET_HAS_mulu2_i64) { + tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); + /* Allow the optimizer room to replace mulu2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + int sizemask = 0; + /* Return value and both arguments are 64-bit and unsigned. */ + sizemask |= tcg_gen_sizemask(0, 1, 0); + sizemask |= tcg_gen_sizemask(1, 1, 0); + sizemask |= tcg_gen_sizemask(2, 1, 0); + tcg_gen_mul_i64(t0, arg1, arg2); + tcg_gen_helper64(tcg_helper_muluh_i64, sizemask, rh, arg1, arg2); + tcg_gen_mov_i64(rl, t0); + tcg_temp_free_i64(t0); + } +} + +static inline void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, + TCGv_i64 arg1, TCGv_i64 arg2) +{ + if (TCG_TARGET_HAS_muls2_i64) { + tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); + /* Allow the optimizer room to replace muls2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + int sizemask = 0; + /* Return value and both arguments are 64-bit and signed. */ + sizemask |= tcg_gen_sizemask(0, 1, 1); + sizemask |= tcg_gen_sizemask(1, 1, 1); + sizemask |= tcg_gen_sizemask(2, 1, 1); + tcg_gen_mul_i64(t0, arg1, arg2); + tcg_gen_helper64(tcg_helper_mulsh_i64, sizemask, rh, arg1, arg2); + tcg_gen_mov_i64(rl, t0); + tcg_temp_free_i64(t0); + } +} + /***************************************/ /* QEMU specific operations. Their type depend on the QEMU CPU type. */ @@ -2659,6 +2739,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_const_tl tcg_const_i64 #define tcg_const_local_tl tcg_const_local_i64 #define tcg_gen_movcond_tl tcg_gen_movcond_i64 +#define tcg_gen_mulu2_tl tcg_gen_mulu2_i64 +#define tcg_gen_muls2_tl tcg_gen_muls2_i64 #else #define tcg_gen_movi_tl tcg_gen_movi_i32 #define tcg_gen_mov_tl tcg_gen_mov_i32 @@ -2732,6 +2814,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_const_tl tcg_const_i32 #define tcg_const_local_tl tcg_const_local_i32 #define tcg_gen_movcond_tl tcg_gen_movcond_i32 +#define tcg_gen_mulu2_tl tcg_gen_mulu2_i32 +#define tcg_gen_muls2_tl tcg_gen_muls2_i32 #endif #if TCG_TARGET_REG_BITS == 32 diff --git a/tcg/tcg-runtime.h b/tcg/tcg-runtime.h index 5615b133e0..a1ebef9f9c 100644 --- a/tcg/tcg-runtime.h +++ b/tcg/tcg-runtime.h @@ -12,7 +12,9 @@ int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2); int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2); int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2); int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2); +int64_t tcg_helper_mulsh_i64(int64_t arg1, int64_t arg2); uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2); uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2); +uint64_t tcg_helper_muluh_i64(uint64_t arg1, uint64_t arg2); #endif From f6953a739972353f2cc5e3d5994127ca8c8236ce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:56 -0800 Subject: [PATCH 1236/1634] tcg: Implement multiword addition helpers Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg-op.h | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 97e0795b95..dac3b4ed9f 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2332,6 +2332,44 @@ static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, #endif } +static inline void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, + TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) +{ + if (TCG_TARGET_HAS_add2_i32) { + tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh); + /* Allow the optimizer room to replace add2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(t0, al, ah); + tcg_gen_concat_i32_i64(t1, bl, bh); + tcg_gen_add_i64(t0, t0, t1); + tcg_gen_extr_i64_i32(rl, rh, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } +} + +static inline void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, + TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) +{ + if (TCG_TARGET_HAS_sub2_i32) { + tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh); + /* Allow the optimizer room to replace sub2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(t0, al, ah); + tcg_gen_concat_i32_i64(t1, bl, bh); + tcg_gen_sub_i64(t0, t0, t1); + tcg_gen_extr_i64_i32(rl, rh, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } +} + static inline void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { @@ -2370,6 +2408,46 @@ static inline void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, } } +static inline void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, + TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) +{ + if (TCG_TARGET_HAS_add2_i64) { + tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh); + /* Allow the optimizer room to replace add2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_add_i64(t0, al, bl); + tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, al); + tcg_gen_add_i64(rh, ah, bh); + tcg_gen_add_i64(rh, rh, t1); + tcg_gen_mov_i64(rl, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } +} + +static inline void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, + TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) +{ + if (TCG_TARGET_HAS_sub2_i64) { + tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh); + /* Allow the optimizer room to replace sub2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + } else { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + tcg_gen_sub_i64(t0, al, bl); + tcg_gen_setcond_i64(TCG_COND_LTU, t1, al, bl); + tcg_gen_sub_i64(rh, ah, bh); + tcg_gen_sub_i64(rh, rh, t1); + tcg_gen_mov_i64(rl, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } +} + static inline void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { @@ -2739,6 +2817,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_const_tl tcg_const_i64 #define tcg_const_local_tl tcg_const_local_i64 #define tcg_gen_movcond_tl tcg_gen_movcond_i64 +#define tcg_gen_add2_tl tcg_gen_add2_i64 +#define tcg_gen_sub2_tl tcg_gen_sub2_i64 #define tcg_gen_mulu2_tl tcg_gen_mulu2_i64 #define tcg_gen_muls2_tl tcg_gen_muls2_i64 #else @@ -2814,6 +2894,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) #define tcg_const_tl tcg_const_i32 #define tcg_const_local_tl tcg_const_local_i32 #define tcg_gen_movcond_tl tcg_gen_movcond_i32 +#define tcg_gen_add2_tl tcg_gen_add2_i32 +#define tcg_gen_sub2_tl tcg_gen_sub2_i32 #define tcg_gen_mulu2_tl tcg_gen_mulu2_i32 #define tcg_gen_muls2_tl tcg_gen_muls2_i32 #endif From 624988a53b4db34ee2a2b96dc2bccdf52e133a0a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:57 -0800 Subject: [PATCH 1237/1634] tcg-i386: Implement multiword arithmetic ops Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/i386/tcg-target.c | 33 +++++++++++++++++++++------------ tcg/i386/tcg-target.h | 10 +++++----- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index f6455294e2..9eec06c8a4 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -1922,31 +1922,34 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, tcg_out_qemu_st(s, args, 3); break; - case INDEX_op_mulu2_i32: - tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]); + OP_32_64(mulu2): + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, args[3]); break; - case INDEX_op_add2_i32: + OP_32_64(muls2): + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IMUL, args[3]); + break; + OP_32_64(add2): if (const_args[4]) { - tgen_arithi(s, ARITH_ADD, args[0], args[4], 1); + tgen_arithi(s, ARITH_ADD + rexw, args[0], args[4], 1); } else { - tgen_arithr(s, ARITH_ADD, args[0], args[4]); + tgen_arithr(s, ARITH_ADD + rexw, args[0], args[4]); } if (const_args[5]) { - tgen_arithi(s, ARITH_ADC, args[1], args[5], 1); + tgen_arithi(s, ARITH_ADC + rexw, args[1], args[5], 1); } else { - tgen_arithr(s, ARITH_ADC, args[1], args[5]); + tgen_arithr(s, ARITH_ADC + rexw, args[1], args[5]); } break; - case INDEX_op_sub2_i32: + OP_32_64(sub2): if (const_args[4]) { - tgen_arithi(s, ARITH_SUB, args[0], args[4], 1); + tgen_arithi(s, ARITH_SUB + rexw, args[0], args[4], 1); } else { - tgen_arithr(s, ARITH_SUB, args[0], args[4]); + tgen_arithr(s, ARITH_SUB + rexw, args[0], args[4]); } if (const_args[5]) { - tgen_arithi(s, ARITH_SBB, args[1], args[5], 1); + tgen_arithi(s, ARITH_SBB + rexw, args[1], args[5], 1); } else { - tgen_arithr(s, ARITH_SBB, args[1], args[5]); + tgen_arithr(s, ARITH_SBB + rexw, args[1], args[5]); } break; @@ -2080,6 +2083,7 @@ static const TCGTargetOpDef x86_op_defs[] = { #endif { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, + { INDEX_op_muls2_i32, { "a", "d", "a", "r" } }, { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } }, { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } }, @@ -2134,6 +2138,11 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_deposit_i64, { "Q", "0", "Q" } }, { INDEX_op_movcond_i64, { "r", "r", "re", "r", "0" } }, + + { INDEX_op_mulu2_i64, { "a", "d", "a", "r" } }, + { INDEX_op_muls2_i64, { "a", "d", "a", "r" } }, + { INDEX_op_add2_i64, { "r", "r", "0", "1", "re", "re" } }, + { INDEX_op_sub2_i64, { "r", "r", "0", "1", "re", "re" } }, #endif #if TCG_TARGET_REG_BITS == 64 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 2b08ef79bb..e3f6bb965f 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -95,7 +95,7 @@ typedef enum { #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 -#define TCG_TARGET_HAS_muls2_i32 0 +#define TCG_TARGET_HAS_muls2_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 @@ -118,10 +118,10 @@ typedef enum { #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_deposit_i64 1 #define TCG_TARGET_HAS_movcond_i64 1 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 -#define TCG_TARGET_HAS_mulu2_i64 0 -#define TCG_TARGET_HAS_muls2_i64 0 +#define TCG_TARGET_HAS_add2_i64 1 +#define TCG_TARGET_HAS_sub2_i64 1 +#define TCG_TARGET_HAS_mulu2_i64 1 +#define TCG_TARGET_HAS_muls2_i64 1 #endif #define TCG_TARGET_deposit_i32_valid(ofs, len) \ From d693e14733509f9a2124b03a912058790411140a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:51:58 -0800 Subject: [PATCH 1238/1634] tcg-arm: Implement muls2_i32 We even had the encoding of smull already handy... Cc: Andrzej Zaborowski Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/arm/tcg-target.c | 4 ++++ tcg/arm/tcg-target.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index d9c33d850f..94c6ca43aa 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1647,6 +1647,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_mulu2_i32: tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; + case INDEX_op_muls2_i32: + tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); + break; /* XXX: Perhaps args[2] & 0x1f is wrong */ case INDEX_op_shl_i32: c = const_args[2] ? @@ -1798,6 +1801,7 @@ static const TCGTargetOpDef arm_op_defs[] = { { INDEX_op_sub_i32, { "r", "r", "rI" } }, { INDEX_op_mul_i32, { "r", "r", "r" } }, { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, + { INDEX_op_muls2_i32, { "r", "r", "r", "r" } }, { INDEX_op_and_i32, { "r", "r", "rI" } }, { INDEX_op_andc_i32, { "r", "r", "rI" } }, { INDEX_op_or_i32, { "r", "r", "rI" } }, diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index f9599bd687..b6eed1f3f4 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -75,7 +75,7 @@ typedef enum { #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_deposit_i32 0 #define TCG_TARGET_HAS_movcond_i32 1 -#define TCG_TARGET_HAS_muls2_i32 0 +#define TCG_TARGET_HAS_muls2_i32 1 enum { TCG_AREG0 = TCG_REG_R6, From 76f131332310d8317880ef73a2bc90725d857ed3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:00 -0800 Subject: [PATCH 1239/1634] target-i386: Use add2 to implement the ADX extension Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-i386/translate.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 439d19efe0..605cd88bd2 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4182,7 +4182,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_ADX)) { goto illegal_op; } else { - TCGv carry_in, carry_out; + TCGv carry_in, carry_out, zero; int end_op; ot = (s->dflag == 2 ? OT_QUAD : OT_LONG); @@ -4242,18 +4242,16 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, #endif default: /* Otherwise compute the carry-out in two steps. */ - tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_regs[reg]); - tcg_gen_setcond_tl(TCG_COND_LTU, cpu_tmp4, - cpu_T[0], cpu_regs[reg]); - tcg_gen_add_tl(cpu_regs[reg], cpu_T[0], carry_in); - tcg_gen_setcond_tl(TCG_COND_LTU, carry_out, - cpu_regs[reg], cpu_T[0]); - tcg_gen_or_tl(carry_out, carry_out, cpu_tmp4); + zero = tcg_const_tl(0); + tcg_gen_add2_tl(cpu_T[0], carry_out, + cpu_T[0], zero, + carry_in, zero); + tcg_gen_add2_tl(cpu_regs[reg], carry_out, + cpu_regs[reg], carry_out, + cpu_T[0], zero); + tcg_temp_free(zero); break; } - /* We began with all flags computed to CC_SRC, and we - have now placed the carry-out in CC_DST. All that - is left is to record the CC_OP. */ set_cc_op(s, end_op); } break; From f402f38f439f17d4361b28248f948a6170d30133 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:01 -0800 Subject: [PATCH 1240/1634] tcg: Implement muls2 with mulu2 Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg-op.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index dac3b4ed9f..d70b2eba33 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2396,6 +2396,26 @@ static inline void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); /* Allow the optimizer room to replace muls2 with two moves. */ tcg_gen_op0(INDEX_op_nop); + } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_mulu2_i32) { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_op4_i32(INDEX_op_mulu2_i32, t0, t1, arg1, arg2); + /* Allow the optimizer room to replace mulu2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + /* Adjust for negative inputs. */ + tcg_gen_sari_i32(t2, arg1, 31); + tcg_gen_sari_i32(t3, arg2, 31); + tcg_gen_and_i32(t2, t2, arg2); + tcg_gen_and_i32(t3, t3, arg1); + tcg_gen_sub_i32(rh, t1, t2); + tcg_gen_sub_i32(rh, rh, t3); + tcg_gen_mov_i32(rl, t0); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); } else { TCGv_i64 t0 = tcg_temp_new_i64(); TCGv_i64 t1 = tcg_temp_new_i64(); @@ -2455,6 +2475,26 @@ static inline void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); /* Allow the optimizer room to replace mulu2 with two moves. */ tcg_gen_op0(INDEX_op_nop); + } else if (TCG_TARGET_HAS_mulu2_i64) { + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + tcg_gen_op4_i64(INDEX_op_mulu2_i64, t0, t1, arg1, arg2); + /* Allow the optimizer room to replace mulu2 with two moves. */ + tcg_gen_op0(INDEX_op_nop); + /* Adjust for negative inputs. */ + tcg_gen_sari_i64(t2, arg1, 63); + tcg_gen_sari_i64(t3, arg2, 63); + tcg_gen_and_i64(t2, t2, arg2); + tcg_gen_and_i64(t3, t3, arg1); + tcg_gen_sub_i64(rh, t1, t2); + tcg_gen_sub_i64(rh, rh, t3); + tcg_gen_mov_i64(rl, t0); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + tcg_temp_free_i64(t3); } else { TCGv_i64 t0 = tcg_temp_new_i64(); int sizemask = 0; From f1fae40c61fd4558c7d10992c98b4bb47f99e0ed Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:02 -0800 Subject: [PATCH 1241/1634] tcg: Apply life analysis to 64-bit multiword arithmetic ops Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- tcg/tcg.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index c8a843ed09..1d8265e72e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1217,7 +1217,7 @@ static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, static void tcg_liveness_analysis(TCGContext *s) { int i, op_index, nb_args, nb_iargs, nb_oargs, arg, nb_ops; - TCGOpcode op; + TCGOpcode op, op_new; TCGArg *args; const TCGOpDef *def; uint8_t *dead_temps, *mem_temps; @@ -1324,7 +1324,17 @@ static void tcg_liveness_analysis(TCGContext *s) break; case INDEX_op_add2_i32: + op_new = INDEX_op_add_i32; + goto do_addsub2; case INDEX_op_sub2_i32: + op_new = INDEX_op_sub_i32; + goto do_addsub2; + case INDEX_op_add2_i64: + op_new = INDEX_op_add_i64; + goto do_addsub2; + case INDEX_op_sub2_i64: + op_new = INDEX_op_sub_i64; + do_addsub2: args -= 6; nb_iargs = 4; nb_oargs = 2; @@ -1337,12 +1347,7 @@ static void tcg_liveness_analysis(TCGContext *s) goto do_remove; } /* Create the single operation plus nop. */ - if (op == INDEX_op_add2_i32) { - op = INDEX_op_add_i32; - } else { - op = INDEX_op_sub_i32; - } - s->gen_opc_buf[op_index] = op; + s->gen_opc_buf[op_index] = op = op_new; args[1] = args[2]; args[2] = args[4]; assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); @@ -1354,6 +1359,13 @@ static void tcg_liveness_analysis(TCGContext *s) goto do_not_remove; case INDEX_op_mulu2_i32: + case INDEX_op_muls2_i32: + op_new = INDEX_op_mul_i32; + goto do_mul2; + case INDEX_op_mulu2_i64: + case INDEX_op_muls2_i64: + op_new = INDEX_op_mul_i64; + do_mul2: args -= 4; nb_iargs = 2; nb_oargs = 2; @@ -1362,7 +1374,7 @@ static void tcg_liveness_analysis(TCGContext *s) if (dead_temps[args[0]] && !mem_temps[args[0]]) { goto do_remove; } - s->gen_opc_buf[op_index] = op = INDEX_op_mul_i32; + s->gen_opc_buf[op_index] = op = op_new; args[1] = args[2]; args[2] = args[3]; assert(s->gen_opc_buf[op_index + 1] == INDEX_op_nop); From 962415fcd5f8223a6fbc6f7bb8c5fdf2500f2f84 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:03 -0800 Subject: [PATCH 1242/1634] target-alpha: Use mulu2 for umulh insn Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-alpha/helper.h | 1 - target-alpha/int_helper.c | 7 ------- target-alpha/translate.c | 20 ++++++++++++++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/target-alpha/helper.h b/target-alpha/helper.h index eac3041b87..3321fde916 100644 --- a/target-alpha/helper.h +++ b/target-alpha/helper.h @@ -9,7 +9,6 @@ DEF_HELPER_FLAGS_3(subqv, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(sublv, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(mullv, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(mulqv, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_1(ctpop, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(ctlz, TCG_CALL_NO_RWG_SE, i64, i64) diff --git a/target-alpha/int_helper.c b/target-alpha/int_helper.c index c9b42b6ed4..51ccd41bd2 100644 --- a/target-alpha/int_helper.c +++ b/target-alpha/int_helper.c @@ -22,13 +22,6 @@ #include "qemu/host-utils.h" -uint64_t helper_umulh(uint64_t op1, uint64_t op2) -{ - uint64_t tl, th; - mulu64(&tl, &th, op1, op2); - return th; -} - uint64_t helper_ctpop(uint64_t arg) { return ctpop64(arg); diff --git a/target-alpha/translate.c b/target-alpha/translate.c index f687b95c63..f8f76957a9 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1390,7 +1390,6 @@ static inline void glue(gen_, name)(int ra, int rb, int rc, int islit,\ tcg_temp_free(tmp1); \ } \ } -ARITH3(umulh) ARITH3(cmpbge) ARITH3(minub8) ARITH3(minsb8) @@ -2426,7 +2425,24 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) break; case 0x30: /* UMULH */ - gen_umulh(ra, rb, rc, islit, lit); + { + TCGv low; + if (unlikely(rc == 31)){ + break; + } + if (ra == 31) { + tcg_gen_movi_i64(cpu_ir[rc], 0); + break; + } + low = tcg_temp_new(); + if (islit) { + tcg_gen_movi_tl(low, lit); + tcg_gen_mulu2_i64(low, cpu_ir[rc], cpu_ir[ra], low); + } else { + tcg_gen_mulu2_i64(low, cpu_ir[rc], cpu_ir[ra], cpu_ir[rb]); + } + tcg_temp_free(low); + } break; case 0x40: /* MULL/V */ From dc46d1c68aa107b8e3c95f66e87cd9d02e6452a9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:04 -0800 Subject: [PATCH 1243/1634] target-s390x: Use mulu2 for mlgr insn Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-s390x/helper.h | 1 - target-s390x/int_helper.c | 8 -------- target-s390x/translate.c | 3 +-- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index dd90d93bee..0d80aa046f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -8,7 +8,6 @@ DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) -DEF_HELPER_FLAGS_3(mul128, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64) DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index 685830124f..af16b21baa 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -29,14 +29,6 @@ #define HELPER_LOG(x...) #endif -/* 64/64 -> 128 unsigned multiplication */ -uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) -{ - uint64_t reth; - mulu64(&env->retxl, &reth, v1, v2); - return reth; -} - /* 64/32 -> 32 signed division */ int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index a57296c64f..bdf69a3c7c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2566,8 +2566,7 @@ static ExitStatus op_mul(DisasContext *s, DisasOps *o) static ExitStatus op_mul128(DisasContext *s, DisasOps *o) { - gen_helper_mul128(o->out, cpu_env, o->in1, o->in2); - return_low128(o->out2); + tcg_gen_mulu2_i64(o->out2, o->out, o->in1, o->in2); return NO_EXIT; } From 831d7fe800774db0d7142fdf2a8f8758c8bf9c92 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:05 -0800 Subject: [PATCH 1244/1634] target-arm: Use mul[us]2 in gen_mul[us]_i64_i32 Cc: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-arm/translate.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index a8893f767f..129f6744cb 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -305,35 +305,41 @@ static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv b) return a; } -/* FIXME: Most targets have native widening multiplication. - It would be good to use that instead of a full wide multiply. */ /* 32x32->64 multiply. Marks inputs as dead. */ static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b) { - TCGv_i64 tmp1 = tcg_temp_new_i64(); - TCGv_i64 tmp2 = tcg_temp_new_i64(); + TCGv lo = tcg_temp_new_i32(); + TCGv hi = tcg_temp_new_i32(); + TCGv_i64 ret; - tcg_gen_extu_i32_i64(tmp1, a); + tcg_gen_mulu2_i32(lo, hi, a, b); tcg_temp_free_i32(a); - tcg_gen_extu_i32_i64(tmp2, b); tcg_temp_free_i32(b); - tcg_gen_mul_i64(tmp1, tmp1, tmp2); - tcg_temp_free_i64(tmp2); - return tmp1; + + ret = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(ret, lo, hi); + tcg_temp_free(lo); + tcg_temp_free(hi); + + return ret; } static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b) { - TCGv_i64 tmp1 = tcg_temp_new_i64(); - TCGv_i64 tmp2 = tcg_temp_new_i64(); + TCGv lo = tcg_temp_new_i32(); + TCGv hi = tcg_temp_new_i32(); + TCGv_i64 ret; - tcg_gen_ext_i32_i64(tmp1, a); + tcg_gen_muls2_i32(lo, hi, a, b); tcg_temp_free_i32(a); - tcg_gen_ext_i32_i64(tmp2, b); tcg_temp_free_i32(b); - tcg_gen_mul_i64(tmp1, tmp1, tmp2); - tcg_temp_free_i64(tmp2); - return tmp1; + + ret = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(ret, lo, hi); + tcg_temp_free(lo); + tcg_temp_free(hi); + + return ret; } /* Swap low and high halfwords. */ From c9f10124a2704b6bab21b31e79735b18d414a654 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:06 -0800 Subject: [PATCH 1245/1634] target-arm: Use mul[us]2 and add2 in umlal et al Cc: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-arm/helper.c | 5 ----- target-arm/helper.h | 2 -- target-arm/translate.c | 26 ++++++++++++++------------ 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index e63da57a51..e97e1a59c7 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2893,11 +2893,6 @@ uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) return (a & mask) | (b & ~mask); } -uint32_t HELPER(logicq_cc)(uint64_t val) -{ - return (val >> 32) | (val != 0); -} - /* VFP support. We follow the convention used for VFP instructions: Single precision routines have a "s" suffix, double precision a "d" suffix. */ diff --git a/target-arm/helper.h b/target-arm/helper.h index 8544f82a94..bca5a5b0d8 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -46,8 +46,6 @@ DEF_HELPER_3(usat16, i32, env, i32, i32) DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32) -DEF_HELPER_1(logicq_cc, i32, i64) - DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_2(exception, void, env, i32) diff --git a/target-arm/translate.c b/target-arm/translate.c index 129f6744cb..efe76d04cb 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6433,13 +6433,11 @@ static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh) tcg_temp_free_i64(tmp); } -/* Set N and Z flags from a 64-bit value. */ -static void gen_logicq_cc(TCGv_i64 val) +/* Set N and Z flags from hi|lo. */ +static void gen_logicq_cc(TCGv lo, TCGv hi) { - TCGv tmp = tcg_temp_new_i32(); - gen_helper_logicq_cc(tmp, val); - gen_logic_CC(tmp); - tcg_temp_free_i32(tmp); + tcg_gen_mov_i32(cpu_NF, hi); + tcg_gen_or_i32(cpu_ZF, lo, hi); } /* Load/Store exclusive instructions are implemented by remembering @@ -7219,18 +7217,22 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) tmp = load_reg(s, rs); tmp2 = load_reg(s, rm); if (insn & (1 << 22)) { - tmp64 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2); } else { - tmp64 = gen_mulu_i64_i32(tmp, tmp2); + tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2); } if (insn & (1 << 21)) { /* mult accumulate */ - gen_addq(s, tmp64, rn, rd); + TCGv al = load_reg(s, rn); + TCGv ah = load_reg(s, rd); + tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah); + tcg_temp_free(al); + tcg_temp_free(ah); } if (insn & (1 << 20)) { - gen_logicq_cc(tmp64); + gen_logicq_cc(tmp, tmp2); } - gen_storeq_reg(s, rn, rd, tmp64); - tcg_temp_free_i64(tmp64); + store_reg(s, rn, tmp); + store_reg(s, rd, tmp2); break; default: goto illegal_op; From e3482cb8063575f9fe0f39b701a4b6dc5a55c9cd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:07 -0800 Subject: [PATCH 1246/1634] target-arm: Use add2 in gen_add_CC Cc: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-arm/translate.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index efe76d04cb..ca6f0af874 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -410,12 +410,11 @@ static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) /* dest = T0 + T1. Compute C, N, V and Z flags */ static void gen_add_CC(TCGv dest, TCGv t0, TCGv t1) { - TCGv tmp; - tcg_gen_add_i32(cpu_NF, t0, t1); + TCGv tmp = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp, 0); + tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, t1, tmp); tcg_gen_mov_i32(cpu_ZF, cpu_NF); - tcg_gen_setcond_i32(TCG_COND_LTU, cpu_CF, cpu_NF, t0); tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); - tmp = tcg_temp_new_i32(); tcg_gen_xor_i32(tmp, t0, t1); tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp); tcg_temp_free_i32(tmp); From 49b4c31efcce45ab714f286f14fa5d5173f9069d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:08 -0800 Subject: [PATCH 1247/1634] target-arm: Implement adc_cc inline Use add2 if available, otherwise use 64-bit arithmetic. Cc: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-arm/helper.h | 1 - target-arm/op_helper.c | 15 --------------- target-arm/translate.c | 39 ++++++++++++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/target-arm/helper.h b/target-arm/helper.h index bca5a5b0d8..507bb9cf2b 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -140,7 +140,6 @@ DEF_HELPER_2(recpe_u32, i32, i32, env) DEF_HELPER_2(rsqrte_u32, i32, i32, env) DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32) -DEF_HELPER_3(adc_cc, i32, env, i32, i32) DEF_HELPER_3(sbc_cc, i32, env, i32, i32) DEF_HELPER_3(shl_cc, i32, env, i32, i32) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 99610d7734..49fc036cc9 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -315,21 +315,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) The only way to do that in TCG is a conditional branch, which clobbers all our temporaries. For now implement these as helper functions. */ -uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b) -{ - uint32_t result; - if (!env->CF) { - result = a + b; - env->CF = result < a; - } else { - result = a + b + 1; - env->CF = result <= a; - } - env->VF = (a ^ b ^ -1) & (a ^ result); - env->NF = env->ZF = result; - return result; -} - uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) { uint32_t result; diff --git a/target-arm/translate.c b/target-arm/translate.c index ca6f0af874..493448a637 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -421,6 +421,34 @@ static void gen_add_CC(TCGv dest, TCGv t0, TCGv t1) tcg_gen_mov_i32(dest, cpu_NF); } +/* dest = T0 + T1 + CF. Compute C, N, V and Z flags */ +static void gen_adc_CC(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp = tcg_temp_new_i32(); + if (TCG_TARGET_HAS_add2_i32) { + tcg_gen_movi_i32(tmp, 0); + tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp); + tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, cpu_CF, t1, tmp); + } else { + TCGv_i64 q0 = tcg_temp_new_i64(); + TCGv_i64 q1 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(q0, t0); + tcg_gen_extu_i32_i64(q1, t1); + tcg_gen_add_i64(q0, q0, q1); + tcg_gen_extu_i32_i64(q1, cpu_CF); + tcg_gen_add_i64(q0, q0, q1); + tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0); + tcg_temp_free_i64(q0); + tcg_temp_free_i64(q1); + } + tcg_gen_mov_i32(cpu_ZF, cpu_NF); + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp); + tcg_temp_free_i32(tmp); + tcg_gen_mov_i32(dest, cpu_NF); +} + /* dest = T0 - T1. Compute C, N, V and Z flags */ static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1) { @@ -7073,7 +7101,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x05: if (set_cc) { - gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2); + gen_adc_CC(tmp, tmp, tmp2); } else { gen_add_carry(tmp, tmp, tmp2); } @@ -7914,7 +7942,7 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG break; case 10: /* adc */ if (conds) - gen_helper_adc_cc(t0, cpu_env, t0, t1); + gen_adc_CC(t0, t0, t1); else gen_adc(t0, t1); break; @@ -9232,10 +9260,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) } break; case 0x5: /* adc */ - if (s->condexec_mask) + if (s->condexec_mask) { gen_adc(tmp, tmp2); - else - gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2); + } else { + gen_adc_CC(tmp, tmp, tmp2); + } break; case 0x6: /* sbc */ if (s->condexec_mask) From 2de68a4900ef6eb67380b0c128abfe1976bc66e8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:09 -0800 Subject: [PATCH 1248/1634] target-arm: Implement sbc_cc inline Use sub2 if available, otherwise use 64-bit arithmetic. Cc: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-arm/helper.h | 2 -- target-arm/op_helper.c | 15 -------------- target-arm/translate.c | 47 +++++++++++++++++++++++++++++++++++------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/target-arm/helper.h b/target-arm/helper.h index 507bb9cf2b..63ae13acff 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -140,8 +140,6 @@ DEF_HELPER_2(recpe_u32, i32, i32, env) DEF_HELPER_2(rsqrte_u32, i32, i32, env) DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32) -DEF_HELPER_3(sbc_cc, i32, env, i32, i32) - DEF_HELPER_3(shl_cc, i32, env, i32, i32) DEF_HELPER_3(shr_cc, i32, env, i32, i32) DEF_HELPER_3(sar_cc, i32, env, i32, i32) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 49fc036cc9..a52231346c 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -315,21 +315,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) The only way to do that in TCG is a conditional branch, which clobbers all our temporaries. For now implement these as helper functions. */ -uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) -{ - uint32_t result; - if (!env->CF) { - result = a - b - 1; - env->CF = a > b; - } else { - result = a - b; - env->CF = a >= b; - } - env->VF = (a ^ b) & (a ^ result); - env->NF = env->ZF = result; - return result; -} - /* Similarly for variable shift instructions. */ uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i) diff --git a/target-arm/translate.c b/target-arm/translate.c index 493448a637..9993aea93e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -464,6 +464,35 @@ static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1) tcg_gen_mov_i32(dest, cpu_NF); } +/* dest = T0 + ~T1 + CF = T0 - T1 + CF - 1. Compute C, N, V and Z flags */ +static void gen_sbc_CC(TCGv dest, TCGv t0, TCGv t1) +{ + TCGv tmp = tcg_temp_new_i32(); + tcg_gen_subi_i32(cpu_CF, cpu_CF, 1); + if (TCG_TARGET_HAS_add2_i32) { + tcg_gen_movi_i32(tmp, 0); + tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp); + tcg_gen_sub2_i32(cpu_NF, cpu_CF, t0, cpu_CF, t1, tmp); + } else { + TCGv_i64 q0 = tcg_temp_new_i64(); + TCGv_i64 q1 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(q0, t0); + tcg_gen_extu_i32_i64(q1, t1); + tcg_gen_sub_i64(q0, q0, q1); + tcg_gen_extu_i32_i64(q1, cpu_CF); + tcg_gen_add_i64(q0, q0, q1); + tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0); + tcg_temp_free_i64(q0); + tcg_temp_free_i64(q1); + } + tcg_gen_mov_i32(cpu_ZF, cpu_NF); + tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); + tcg_gen_xor_i32(tmp, t0, t1); + tcg_gen_and_i32(cpu_VF, cpu_VF, tmp); + tcg_temp_free_i32(tmp); + tcg_gen_mov_i32(dest, cpu_NF); +} + #define GEN_SHIFT(name) \ static void gen_##name(TCGv dest, TCGv t0, TCGv t1) \ { \ @@ -7109,7 +7138,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x06: if (set_cc) { - gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2); + gen_sbc_CC(tmp, tmp, tmp2); } else { gen_sub_carry(tmp, tmp, tmp2); } @@ -7117,7 +7146,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) break; case 0x07: if (set_cc) { - gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp); + gen_sbc_CC(tmp, tmp2, tmp); } else { gen_sub_carry(tmp, tmp2, tmp); } @@ -7947,10 +7976,11 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG gen_adc(t0, t1); break; case 11: /* sbc */ - if (conds) - gen_helper_sbc_cc(t0, cpu_env, t0, t1); - else + if (conds) { + gen_sbc_CC(t0, t0, t1); + } else { gen_sub_carry(t0, t0, t1); + } break; case 13: /* sub */ if (conds) @@ -9267,10 +9297,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) } break; case 0x6: /* sbc */ - if (s->condexec_mask) + if (s->condexec_mask) { gen_sub_carry(tmp, tmp, tmp2); - else - gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2); + } else { + gen_sbc_CC(tmp, tmp, tmp2); + } break; case 0x7: /* ror */ if (s->condexec_mask) { From ce1dd5d1bbb0a3769566cb6967714c8c8c97a815 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:10 -0800 Subject: [PATCH 1249/1634] target-mips: Use mul[us]2 in [D]MULT[U] insns Cc: Aurelien Jarno Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-mips/helper.h | 2 -- target-mips/op_helper.c | 12 ----------- target-mips/translate.c | 48 +++++++++++++++++------------------------ 3 files changed, 20 insertions(+), 42 deletions(-) diff --git a/target-mips/helper.h b/target-mips/helper.h index cd48738ff9..ed75e2c9f2 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -24,8 +24,6 @@ DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl) #ifdef TARGET_MIPS64 DEF_HELPER_FLAGS_1(dclo, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(dclz, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_3(dmult, void, env, tl, tl) -DEF_HELPER_3(dmultu, void, env, tl, tl) #endif DEF_HELPER_3(muls, tl, env, tl, tl) diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 526f84f136..45cbb2f1c2 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -267,18 +267,6 @@ target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1, (uint64_t)(uint32_t)arg2); } -#ifdef TARGET_MIPS64 -void helper_dmult(CPUMIPSState *env, target_ulong arg1, target_ulong arg2) -{ - muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); -} - -void helper_dmultu(CPUMIPSState *env, target_ulong arg1, target_ulong arg2) -{ - mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); -} -#endif - #ifndef CONFIG_USER_ONLY static inline hwaddr do_translate_address(CPUMIPSState *env, diff --git a/target-mips/translate.c b/target-mips/translate.c index 4ee9615fda..f10a533e80 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2715,47 +2715,39 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, break; case OPC_MULT: { - TCGv_i64 t2 = tcg_temp_new_i64(); - TCGv_i64 t3 = tcg_temp_new_i64(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); acc = ((ctx->opcode) >> 11) & 0x03; if (acc != 0) { check_dsp(ctx); } - tcg_gen_ext_tl_i64(t2, t0); - tcg_gen_ext_tl_i64(t3, t1); - tcg_gen_mul_i64(t2, t2, t3); - tcg_temp_free_i64(t3); - tcg_gen_trunc_i64_tl(t0, t2); - tcg_gen_shri_i64(t2, t2, 32); - tcg_gen_trunc_i64_tl(t1, t2); - tcg_temp_free_i64(t2); - tcg_gen_ext32s_tl(cpu_LO[acc], t0); - tcg_gen_ext32s_tl(cpu_HI[acc], t1); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_muls2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); } opn = "mult"; break; case OPC_MULTU: { - TCGv_i64 t2 = tcg_temp_new_i64(); - TCGv_i64 t3 = tcg_temp_new_i64(); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); acc = ((ctx->opcode) >> 11) & 0x03; if (acc != 0) { check_dsp(ctx); } - tcg_gen_ext32u_tl(t0, t0); - tcg_gen_ext32u_tl(t1, t1); - tcg_gen_extu_tl_i64(t2, t0); - tcg_gen_extu_tl_i64(t3, t1); - tcg_gen_mul_i64(t2, t2, t3); - tcg_temp_free_i64(t3); - tcg_gen_trunc_i64_tl(t0, t2); - tcg_gen_shri_i64(t2, t2, 32); - tcg_gen_trunc_i64_tl(t1, t2); - tcg_temp_free_i64(t2); - tcg_gen_ext32s_tl(cpu_LO[acc], t0); - tcg_gen_ext32s_tl(cpu_HI[acc], t1); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mulu2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); } opn = "multu"; break; @@ -2791,11 +2783,11 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, opn = "ddivu"; break; case OPC_DMULT: - gen_helper_dmult(cpu_env, t0, t1); + tcg_gen_muls2_i64(cpu_LO[0], cpu_HI[0], t0, t1); opn = "dmult"; break; case OPC_DMULTU: - gen_helper_dmultu(cpu_env, t0, t1); + tcg_gen_mulu2_i64(cpu_LO[0], cpu_HI[0], t0, t1); opn = "dmultu"; break; #endif From bf45f97133b7f81d27711971a9e28d60528d90c8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:11 -0800 Subject: [PATCH 1250/1634] target-cris: Use mul*2 in mul* insns Cc: Edgar E. Iglesias Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-cris/translate.c | 44 ++--------------------------------------- 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/target-cris/translate.c b/target-cris/translate.c index 2cf01a52e7..14c167fb0b 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -340,46 +340,6 @@ static void t_gen_asr(TCGv d, TCGv a, TCGv b) tcg_temp_free(t_31); } -/* 64-bit signed mul, lower result in d and upper in d2. */ -static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b) -{ - TCGv_i64 t0, t1; - - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - - tcg_gen_ext_i32_i64(t0, a); - tcg_gen_ext_i32_i64(t1, b); - tcg_gen_mul_i64(t0, t0, t1); - - tcg_gen_trunc_i64_i32(d, t0); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(d2, t0); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); -} - -/* 64-bit unsigned muls, lower result in d and upper in d2. */ -static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b) -{ - TCGv_i64 t0, t1; - - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - - tcg_gen_extu_i32_i64(t0, a); - tcg_gen_extu_i32_i64(t1, b); - tcg_gen_mul_i64(t0, t0, t1); - - tcg_gen_trunc_i64_i32(d, t0); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(d2, t0); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); -} - static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b) { int l1; @@ -832,10 +792,10 @@ static void cris_alu_op_exec(DisasContext *dc, int op, gen_helper_lz(dst, b); break; case CC_OP_MULS: - t_gen_muls(dst, cpu_PR[PR_MOF], a, b); + tcg_gen_muls2_tl(dst, cpu_PR[PR_MOF], a, b); break; case CC_OP_MULU: - t_gen_mulu(dst, cpu_PR[PR_MOF], a, b); + tcg_gen_mulu2_tl(dst, cpu_PR[PR_MOF], a, b); break; case CC_OP_DSTEP: t_gen_cris_dstep(dst, a, b); From 23ad1d5d3c00cd07ab7aedc128565c6029802c30 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:12 -0800 Subject: [PATCH 1251/1634] target-ppc: Use mul*2 in mulh* insns Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/helper.h | 2 - target-ppc/int_helper.c | 18 --------- target-ppc/translate.c | 82 +++++++++++++++++++---------------------- 3 files changed, 38 insertions(+), 64 deletions(-) diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 18e039452f..fcf372ab45 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -30,8 +30,6 @@ DEF_HELPER_2(icbi, void, env, tl) DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) #if defined(TARGET_PPC64) -DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_NO_RWG_SE, i64, i64, i64) -DEF_HELPER_FLAGS_2(mulhdu, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_3(mulldo, i64, env, i64, i64) #endif diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 783079d995..86531517fc 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -25,24 +25,6 @@ /* Fixed point operations helpers */ #if defined(TARGET_PPC64) -/* multiply high word */ -uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2) -{ - uint64_t tl, th; - - muls64(&tl, &th, arg1, arg2); - return th; -} - -/* multiply high word unsigned */ -uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2) -{ - uint64_t tl, th; - - mulu64(&tl, &th, arg1, arg2); - return th; -} - uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2) { int64_t th; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2ac5794add..2673a895de 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1061,24 +1061,15 @@ GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1); /* mulhw mulhw. */ static void gen_mulhw(DisasContext *ctx) { - TCGv_i64 t0, t1; + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); -#if defined(TARGET_PPC64) - tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32); -#else - tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0); -#endif - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_muls2_i32(t0, t1, t0, t1); + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } @@ -1086,24 +1077,15 @@ static void gen_mulhw(DisasContext *ctx) /* mulhwu mulhwu. */ static void gen_mulhwu(DisasContext *ctx) { - TCGv_i64 t0, t1; + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); -#if defined(TARGET_PPC64) - tcg_gen_ext32u_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext32u_i64(t1, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32); -#else - tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0); -#endif - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mulu2_i32(t0, t1, t0, t1); + tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } @@ -1159,19 +1141,31 @@ static void gen_mulli(DisasContext *ctx) tcg_gen_muli_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode)); } + #if defined(TARGET_PPC64) -#define GEN_INT_ARITH_MUL_HELPER(name, opc3) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - gen_helper_##name (cpu_gpr[rD(ctx->opcode)], \ - cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \ - if (unlikely(Rc(ctx->opcode) != 0)) \ - gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); \ -} /* mulhd mulhd. */ -GEN_INT_ARITH_MUL_HELPER(mulhdu, 0x00); +static void gen_mulhd(DisasContext *ctx) +{ + TCGv lo = tcg_temp_new(); + tcg_gen_muls2_tl(lo, cpu_gpr[rD(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_temp_free(lo); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } +} + /* mulhdu mulhdu. */ -GEN_INT_ARITH_MUL_HELPER(mulhd, 0x02); +static void gen_mulhdu(DisasContext *ctx) +{ + TCGv lo = tcg_temp_new(); + tcg_gen_mulu2_tl(lo, cpu_gpr[rD(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_temp_free(lo); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); + } +} /* mulld mulld. */ static void gen_mulld(DisasContext *ctx) From da91a00f191fc70ea7d81d7476ef933c562e6fcd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:13 -0800 Subject: [PATCH 1252/1634] target-ppc: Split out SO, OV, CA fields from XER In preparation for more efficient setting of these fields. Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/cpu.h | 24 ++++- target-ppc/int_helper.c | 38 +++----- target-ppc/kvm.c | 4 +- target-ppc/machine.c | 8 +- target-ppc/translate.c | 188 ++++++++++++++++++++++-------------- target-ppc/translate_init.c | 4 +- 6 files changed, 160 insertions(+), 106 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8c081dbec5..20f4565a1a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -941,8 +941,11 @@ struct CPUPPCState { /* CFAR */ target_ulong cfar; #endif - /* XER */ + /* XER (with SO, OV, CA split out) */ target_ulong xer; + target_ulong so; + target_ulong ov; + target_ulong ca; /* Reservation address */ target_ulong reserve_addr; /* Reservation value */ @@ -1268,9 +1271,9 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) #define XER_CA 29 #define XER_CMP 8 #define XER_BC 0 -#define xer_so ((env->xer >> XER_SO) & 1) -#define xer_ov ((env->xer >> XER_OV) & 1) -#define xer_ca ((env->xer >> XER_CA) & 1) +#define xer_so (env->so) +#define xer_ov (env->ov) +#define xer_ca (env->ca) #define xer_cmp ((env->xer >> XER_CMP) & 0xFF) #define xer_bc ((env->xer >> XER_BC) & 0x7F) @@ -2087,6 +2090,19 @@ enum { /*****************************************************************************/ +static inline target_ulong cpu_read_xer(CPUPPCState *env) +{ + return env->xer | (env->so << XER_SO) | (env->ov << XER_OV) | (env->ca << XER_CA); +} + +static inline void cpu_write_xer(CPUPPCState *env, target_ulong xer) +{ + env->so = (xer >> XER_SO) & 1; + env->ov = (xer >> XER_OV) & 1; + env->ca = (xer >> XER_CA) & 1; + env->xer = xer & ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA)); +} + static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index 86531517fc..54eca9bbee 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -33,9 +33,9 @@ uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2) muls64(&tl, (uint64_t *)&th, arg1, arg2); /* If th != 0 && th != -1, then we had an overflow */ if (likely((uint64_t)(th + 1) <= 1)) { - env->xer &= ~(1 << XER_OV); + env->ov = 0; } else { - env->xer |= (1 << XER_OV) | (1 << XER_SO); + env->so = env->ov = 1; } return (int64_t)tl; } @@ -64,21 +64,17 @@ target_ulong helper_sraw(CPUPPCState *env, target_ulong value, shift &= 0x1f; ret = (int32_t)value >> shift; if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { - env->xer &= ~(1 << XER_CA); + env->ca = 0; } else { - env->xer |= (1 << XER_CA); + env->ca = 1; } } else { ret = (int32_t)value; - env->xer &= ~(1 << XER_CA); + env->ca = 0; } } else { ret = (int32_t)value >> 31; - if (ret) { - env->xer |= (1 << XER_CA); - } else { - env->xer &= ~(1 << XER_CA); - } + env->ca = (ret != 0); } return (target_long)ret; } @@ -94,21 +90,17 @@ target_ulong helper_srad(CPUPPCState *env, target_ulong value, shift &= 0x3f; ret = (int64_t)value >> shift; if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) { - env->xer &= ~(1 << XER_CA); + env->ca = 0; } else { - env->xer |= (1 << XER_CA); + env->ca = 1; } } else { ret = (int64_t)value; - env->xer &= ~(1 << XER_CA); + env->ca = 0; } } else { ret = (int64_t)value >> 63; - if (ret) { - env->xer |= (1 << XER_CA); - } else { - env->xer &= ~(1 << XER_CA); - } + env->ca = (ret != 0); } return ret; } @@ -188,16 +180,16 @@ target_ulong helper_divo(CPUPPCState *env, target_ulong arg1, if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || (int32_t)arg2 == 0) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); + env->so = env->ov = 1; env->spr[SPR_MQ] = 0; return INT32_MIN; } else { env->spr[SPR_MQ] = tmp % arg2; tmp /= (int32_t)arg2; if ((int32_t)tmp != tmp) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); + env->so = env->ov = 1; } else { - env->xer &= ~(1 << XER_OV); + env->ov = 0; } return tmp; } @@ -221,11 +213,11 @@ target_ulong helper_divso(CPUPPCState *env, target_ulong arg1, { if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || (int32_t)arg2 == 0) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); + env->so = env->ov = 1; env->spr[SPR_MQ] = 0; return INT32_MIN; } else { - env->xer &= ~(1 << XER_OV); + env->ov = 0; env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2; return (int32_t)arg1 / (int32_t)arg2; } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 2c64c634f1..8e6441614e 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -464,7 +464,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) regs.ctr = env->ctr; regs.lr = env->lr; - regs.xer = env->xer; + regs.xer = cpu_read_xer(env); regs.msr = env->msr; regs.pc = env->nip; @@ -566,7 +566,7 @@ int kvm_arch_get_registers(CPUState *cs) env->ctr = regs.ctr; env->lr = regs.lr; - env->xer = regs.xer; + cpu_write_xer(env, regs.xer); env->msr = regs.msr; env->nip = regs.pc; diff --git a/target-ppc/machine.c b/target-ppc/machine.c index e014c0c1af..708a840da7 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -7,6 +7,7 @@ void cpu_save(QEMUFile *f, void *opaque) CPUPPCState *env = (CPUPPCState *)opaque; unsigned int i, j; uint32_t fpscr; + target_ulong xer; for (i = 0; i < 32; i++) qemu_put_betls(f, &env->gpr[i]); @@ -18,7 +19,8 @@ void cpu_save(QEMUFile *f, void *opaque) qemu_put_betls(f, &env->ctr); for (i = 0; i < 8; i++) qemu_put_be32s(f, &env->crf[i]); - qemu_put_betls(f, &env->xer); + xer = cpu_read_xer(env); + qemu_put_betls(f, &xer); qemu_put_betls(f, &env->reserve_addr); qemu_put_betls(f, &env->msr); for (i = 0; i < 4; i++) @@ -93,6 +95,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) unsigned int i, j; target_ulong sdr1; uint32_t fpscr; + target_ulong xer; for (i = 0; i < 32; i++) qemu_get_betls(f, &env->gpr[i]); @@ -104,7 +107,8 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_betls(f, &env->ctr); for (i = 0; i < 8; i++) qemu_get_be32s(f, &env->crf[i]); - qemu_get_betls(f, &env->xer); + qemu_get_betls(f, &xer); + cpu_write_xer(env, xer); qemu_get_betls(f, &env->reserve_addr); qemu_get_betls(f, &env->msr); for (i = 0; i < 4; i++) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2673a895de..0ac072c9e6 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -66,7 +66,7 @@ static TCGv cpu_lr; #if defined(TARGET_PPC64) static TCGv cpu_cfar; #endif -static TCGv cpu_xer; +static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca; static TCGv cpu_reserve; static TCGv cpu_fpscr; static TCGv_i32 cpu_access_type; @@ -158,6 +158,12 @@ void ppc_translate_init(void) cpu_xer = tcg_global_mem_new(TCG_AREG0, offsetof(CPUPPCState, xer), "xer"); + cpu_so = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUPPCState, so), "SO"); + cpu_ov = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUPPCState, ov), "OV"); + cpu_ca = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUPPCState, ca), "CA"); cpu_reserve = tcg_global_mem_new(TCG_AREG0, offsetof(CPUPPCState, reserve_addr), @@ -592,9 +598,7 @@ static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf) { int l1, l2, l3; - tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer); - tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO); - tcg_gen_andi_i32(cpu_crf[crf], cpu_crf[crf], 1); + tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_so); l1 = gen_new_label(); l2 = gen_new_label(); @@ -747,7 +751,7 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, l1 = gen_new_label(); /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); t0 = tcg_temp_local_new(); tcg_gen_xor_tl(t0, arg0, arg1); #if defined(TARGET_PPC64) @@ -767,7 +771,8 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); else tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1); - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); gen_set_label(l1); tcg_temp_free(t0); } @@ -790,7 +795,7 @@ static inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, } else { tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); } - tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + tcg_gen_movi_tl(cpu_ca, 1); gen_set_label(l1); tcg_temp_free(t0); tcg_temp_free(t1); @@ -802,7 +807,7 @@ static inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, } else { tcg_gen_brcond_tl(TCG_COND_GEU, arg1, arg2, l1); } - tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + tcg_gen_movi_tl(cpu_ca, 1); gen_set_label(l1); } } @@ -823,21 +828,18 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, if (add_ca) { t1 = tcg_temp_local_new(); - tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA)); - tcg_gen_shri_tl(t1, t1, XER_CA); + tcg_gen_mov_tl(t1, cpu_ca); } else { TCGV_UNUSED(t1); } - if (compute_ca && compute_ov) { - /* Start with XER CA and OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV))); - } else if (compute_ca) { + if (compute_ca) { /* Start with XER CA disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); - } else if (compute_ov) { + tcg_gen_movi_tl(cpu_ca, 0); + } + if (compute_ov) { /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); } tcg_gen_add_tl(t0, arg1, arg2); @@ -915,8 +917,8 @@ static inline void gen_op_addic(DisasContext *ctx, TCGv ret, TCGv arg1, { target_long simm = SIMM(ctx->opcode); - /* Start with XER CA and OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + /* Start with XER CA disabled, the most likely case */ + tcg_gen_movi_tl(cpu_ca, 0); if (likely(simm != 0)) { TCGv t0 = tcg_temp_local_new(); @@ -976,7 +978,7 @@ static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_gen_divu_i32(t0, t0, t1); } if (compute_ov) { - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); } tcg_gen_br(l2); gen_set_label(l1); @@ -986,7 +988,8 @@ static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_gen_movi_i32(t0, 0); } if (compute_ov) { - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); } gen_set_label(l2); tcg_gen_extu_i32_tl(ret, t0); @@ -1027,7 +1030,7 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_gen_divu_i64(ret, arg1, arg2); } if (compute_ov) { - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); } tcg_gen_br(l2); gen_set_label(l1); @@ -1037,7 +1040,8 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_gen_movi_i64(ret, 0); } if (compute_ov) { - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); } gen_set_label(l2); if (unlikely(Rc(ctx->opcode) != 0)) @@ -1110,7 +1114,7 @@ static void gen_mullwo(DisasContext *ctx) t1 = tcg_temp_new_i64(); l1 = gen_new_label(); /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); #if defined(TARGET_PPC64) tcg_gen_ext32s_i64(t0, cpu_gpr[rA(ctx->opcode)]); tcg_gen_ext32s_i64(t1, cpu_gpr[rB(ctx->opcode)]); @@ -1127,7 +1131,8 @@ static void gen_mullwo(DisasContext *ctx) tcg_gen_ext32s_i64(t1, t0); tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1); #endif - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); gen_set_label(l1); tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); @@ -1206,13 +1211,14 @@ static inline void gen_op_arith_neg(DisasContext *ctx, TCGv ret, TCGv arg1, } tcg_gen_neg_tl(ret, arg1); if (ov_check) { - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); } tcg_gen_br(l2); gen_set_label(l1); tcg_gen_mov_tl(ret, t0); if (ov_check) { - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); } gen_set_label(l2); tcg_temp_free(t0); @@ -1246,21 +1252,18 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, if (add_ca) { t1 = tcg_temp_local_new(); - tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA)); - tcg_gen_shri_tl(t1, t1, XER_CA); + tcg_gen_mov_tl(t1, cpu_ca); } else { TCGV_UNUSED(t1); } - if (compute_ca && compute_ov) { - /* Start with XER CA and OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV))); - } else if (compute_ca) { + if (compute_ca) { /* Start with XER CA disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); - } else if (compute_ov) { + tcg_gen_movi_tl(cpu_ca, 0); + } + if (compute_ov) { /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); } if (add_ca) { @@ -1326,8 +1329,8 @@ GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1) /* subfic */ static void gen_subfic(DisasContext *ctx) { - /* Start with XER CA and OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + /* Start with XER CA disabled, the most likely case */ + tcg_gen_movi_tl(cpu_ca, 0); TCGv t0 = tcg_temp_local_new(); TCGv t1 = tcg_const_local_tl(SIMM(ctx->opcode)); tcg_gen_sub_tl(t0, t1, cpu_gpr[rA(ctx->opcode)]); @@ -1891,17 +1894,17 @@ static void gen_srawi(DisasContext *ctx) tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1); tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); - tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + tcg_gen_movi_tl(cpu_ca, 1); tcg_gen_br(l2); gen_set_label(l1); - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 0); gen_set_label(l2); tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]); tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], t0, sh); tcg_temp_free(t0); } else { tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 0); } if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); @@ -1973,16 +1976,16 @@ static inline void gen_sradi(DisasContext *ctx, int n) tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1); tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1); tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); - tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA); + tcg_gen_movi_tl(cpu_ca, 1); tcg_gen_br(l2); gen_set_label(l1); - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 0); gen_set_label(l2); tcg_temp_free(t0); tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh); } else { tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 0); } if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); @@ -3170,9 +3173,7 @@ static void gen_stwcx_(DisasContext *ctx) { int l1; - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer); - tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO); - tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); l1 = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1); tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ); @@ -3213,9 +3214,7 @@ static void gen_stdcx_(DisasContext *ctx) #else { int l1; - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer); - tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO); - tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); l1 = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1); tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ); @@ -3791,12 +3790,55 @@ static void gen_tdi(DisasContext *ctx) /*** Processor control ***/ +static void gen_read_xer(TCGv dst) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + tcg_gen_mov_tl(dst, cpu_xer); + tcg_gen_shli_tl(t0, cpu_so, XER_SO); + tcg_gen_shli_tl(t1, cpu_ov, XER_OV); + tcg_gen_shli_tl(t2, cpu_ca, XER_CA); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_or_tl(dst, dst, t2); + tcg_gen_or_tl(dst, dst, t0); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); +} + +static void gen_write_xer(TCGv src) +{ + tcg_gen_andi_tl(cpu_xer, src, + ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA))); + tcg_gen_shri_tl(cpu_so, src, XER_SO); + tcg_gen_shri_tl(cpu_ov, src, XER_OV); + tcg_gen_shri_tl(cpu_ca, src, XER_CA); + tcg_gen_andi_tl(cpu_so, cpu_so, 1); + tcg_gen_andi_tl(cpu_ov, cpu_ov, 1); + tcg_gen_andi_tl(cpu_ca, cpu_ca, 1); +} + /* mcrxr */ static void gen_mcrxr(DisasContext *ctx) { - tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], cpu_xer); - tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], XER_CA); - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA)); + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 dst = cpu_crf[crfD(ctx->opcode)]; + + tcg_gen_trunc_tl_i32(t0, cpu_so); + tcg_gen_trunc_tl_i32(t1, cpu_ov); + tcg_gen_trunc_tl_i32(dst, cpu_ca); + tcg_gen_shri_i32(t0, t0, 2); + tcg_gen_shri_i32(t1, t1, 1); + tcg_gen_or_i32(dst, dst, t0); + tcg_gen_or_i32(dst, dst, t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + + tcg_gen_movi_tl(cpu_so, 0); + tcg_gen_movi_tl(cpu_ov, 0); + tcg_gen_movi_tl(cpu_ca, 0); } /* mfcr mfocrf */ @@ -4526,10 +4568,11 @@ static void gen_abso(DisasContext *ctx) int l2 = gen_new_label(); int l3 = gen_new_label(); /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l2); tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rA(ctx->opcode)], 0x80000000, l1); - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); tcg_gen_br(l2); gen_set_label(l1); tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); @@ -4610,7 +4653,7 @@ static void gen_dozo(DisasContext *ctx) TCGv t1 = tcg_temp_new(); TCGv t2 = tcg_temp_new(); /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1); tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); @@ -4618,7 +4661,8 @@ static void gen_dozo(DisasContext *ctx) tcg_gen_andc_tl(t1, t1, t2); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2); - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); tcg_gen_br(l2); gen_set_label(l1); tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0); @@ -4736,7 +4780,7 @@ static void gen_mulo(DisasContext *ctx) TCGv_i64 t1 = tcg_temp_new_i64(); TCGv t2 = tcg_temp_new(); /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); tcg_gen_mul_i64(t0, t0, t1); @@ -4746,7 +4790,8 @@ static void gen_mulo(DisasContext *ctx) tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1); tcg_gen_ext32s_i64(t1, t0); tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1); - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); gen_set_label(l1); tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); @@ -4782,7 +4827,7 @@ static void gen_nabso(DisasContext *ctx) tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); gen_set_label(l2); /* nabs never overflows */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } @@ -4959,10 +5004,10 @@ static void gen_sraiq(DisasContext *ctx) tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh); tcg_gen_or_tl(t0, t0, t1); gen_store_spr(SPR_MQ, t0); - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 0); tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1); - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 1); gen_set_label(l1); tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh); tcg_temp_free(t0); @@ -4993,10 +5038,10 @@ static void gen_sraq(DisasContext *ctx) gen_set_label(l1); tcg_temp_free(t0); tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t1); - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 0); tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2); tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l2); - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA)); + tcg_gen_movi_tl(cpu_ca, 1); gen_set_label(l2); tcg_temp_free(t1); tcg_temp_free(t2); @@ -5565,7 +5610,7 @@ static inline void gen_405_mulladd_insn(DisasContext *ctx, int opc2, int opc3, if (opc3 & 0x10) { /* Start with XER OV disabled, the most likely case */ - tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_movi_tl(cpu_ov, 0); } if (opc3 & 0x01) { /* Signed */ @@ -5588,7 +5633,8 @@ static inline void gen_405_mulladd_insn(DisasContext *ctx, int opc2, int opc3, } if (opc3 & 0x10) { /* Check overflow */ - tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_movi_tl(cpu_ov, 1); + tcg_gen_movi_tl(cpu_so, 1); } gen_set_label(l1); tcg_gen_mov_tl(cpu_gpr[rt], t0); @@ -5976,9 +6022,7 @@ static void gen_tlbsx_40x(DisasContext *ctx) tcg_temp_free(t0); if (Rc(ctx->opcode)) { int l1 = gen_new_label(); - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer); - tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO); - tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1); tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02); gen_set_label(l1); @@ -6059,9 +6103,7 @@ static void gen_tlbsx_440(DisasContext *ctx) tcg_temp_free(t0); if (Rc(ctx->opcode)) { int l1 = gen_new_label(); - tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer); - tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO); - tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1); tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02); gen_set_label(l1); @@ -9410,7 +9452,7 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR " TARGET_FMT_lx " XER " TARGET_FMT_lx "\n", - env->nip, env->lr, env->ctr, env->xer); + env->nip, env->lr, env->ctr, cpu_read_xer(env)); cpu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " TARGET_FMT_lx " idx %d\n", env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5df205757b..f5fc9b18f0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -118,12 +118,12 @@ static void spr_write_clear (void *opaque, int sprn, int gprn) /* XER */ static void spr_read_xer (void *opaque, int gprn, int sprn) { - tcg_gen_mov_tl(cpu_gpr[gprn], cpu_xer); + gen_read_xer(cpu_gpr[gprn]); } static void spr_write_xer (void *opaque, int sprn, int gprn) { - tcg_gen_mov_tl(cpu_xer, cpu_gpr[gprn]); + gen_write_xer(cpu_gpr[gprn]); } /* LR */ From 2fdcb629071cb6206028bc7d6b69f3585fc365ec Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:14 -0800 Subject: [PATCH 1253/1634] target-ppc: Use setcond in gen_op_cmp Which means that callers need not copy data into local tmps. Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/translate.c | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 0ac072c9e6..7aab6ae31c 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -596,33 +596,33 @@ static opc_handler_t invalid_handler = { static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf) { - int l1, l2, l3; + TCGv t0 = tcg_temp_new(); + TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_so); - l1 = gen_new_label(); - l2 = gen_new_label(); - l3 = gen_new_label(); - if (s) { - tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1); - tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2); - } else { - tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1); - tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2); - } - tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_EQ); - tcg_gen_br(l3); - gen_set_label(l1); - tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_LT); - tcg_gen_br(l3); - gen_set_label(l2); - tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_GT); - gen_set_label(l3); + tcg_gen_setcond_tl((s ? TCG_COND_LT: TCG_COND_LTU), t0, arg0, arg1); + tcg_gen_trunc_tl_i32(t1, t0); + tcg_gen_shli_i32(t1, t1, CRF_LT); + tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1); + + tcg_gen_setcond_tl((s ? TCG_COND_GT: TCG_COND_GTU), t0, arg0, arg1); + tcg_gen_trunc_tl_i32(t1, t0); + tcg_gen_shli_i32(t1, t1, CRF_GT); + tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1); + + tcg_gen_setcond_tl(TCG_COND_EQ, t0, arg0, arg1); + tcg_gen_trunc_tl_i32(t1, t0); + tcg_gen_shli_i32(t1, t1, CRF_EQ); + tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1); + + tcg_temp_free(t0); + tcg_temp_free_i32(t1); } static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf) { - TCGv t0 = tcg_const_local_tl(arg1); + TCGv t0 = tcg_const_tl(arg1); gen_op_cmp(arg0, t0, s, crf); tcg_temp_free(t0); } @@ -631,8 +631,8 @@ static inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf) static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf) { TCGv t0, t1; - t0 = tcg_temp_local_new(); - t1 = tcg_temp_local_new(); + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); if (s) { tcg_gen_ext32s_tl(t0, arg0); tcg_gen_ext32s_tl(t1, arg1); @@ -647,7 +647,7 @@ static inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf) static inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf) { - TCGv t0 = tcg_const_local_tl(arg1); + TCGv t0 = tcg_const_tl(arg1); gen_op_cmp32(arg0, t0, s, crf); tcg_temp_free(t0); } From ffe30937c89dd67a53bf3f35b962701cd9d8f70e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:15 -0800 Subject: [PATCH 1254/1634] target-ppc: Compute addition overflow without branches Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/translate.c | 48 ++++++++++++------------------------------ 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 7aab6ae31c..116cf12b3e 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -746,35 +746,23 @@ static void gen_isel(DisasContext *ctx) static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, TCGv arg1, TCGv arg2, int sub) { - int l1; - TCGv t0; + TCGv t0 = tcg_temp_new(); - l1 = gen_new_label(); - /* Start with XER OV disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ov, 0); - t0 = tcg_temp_local_new(); - tcg_gen_xor_tl(t0, arg0, arg1); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) - tcg_gen_ext32s_tl(t0, t0); -#endif - if (sub) - tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1); - else - tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); + tcg_gen_xor_tl(cpu_ov, arg0, arg1); tcg_gen_xor_tl(t0, arg1, arg2); -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) - tcg_gen_ext32s_tl(t0, t0); -#endif - if (sub) - tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); - else - tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1); - tcg_gen_movi_tl(cpu_ov, 1); - tcg_gen_movi_tl(cpu_so, 1); - gen_set_label(l1); + if (sub) { + tcg_gen_and_tl(cpu_ov, cpu_ov, t0); + } else { + tcg_gen_andc_tl(cpu_ov, cpu_ov, t0); + } tcg_temp_free(t0); +#if defined(TARGET_PPC64) + if (!ctx->sf_mode) { + tcg_gen_ext32s_tl(cpu_ov, cpu_ov); + } +#endif + tcg_gen_shri_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1); + tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov); } static inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, @@ -837,10 +825,6 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, /* Start with XER CA disabled, the most likely case */ tcg_gen_movi_tl(cpu_ca, 0); } - if (compute_ov) { - /* Start with XER OV disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ov, 0); - } tcg_gen_add_tl(t0, arg1, arg2); @@ -1261,10 +1245,6 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, /* Start with XER CA disabled, the most likely case */ tcg_gen_movi_tl(cpu_ca, 0); } - if (compute_ov) { - /* Start with XER OV disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ov, 0); - } if (add_ca) { tcg_gen_not_tl(t0, arg1); From 146de60dcade65a401c6665ae4b51c2b15dfaa55 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:16 -0800 Subject: [PATCH 1255/1634] target-ppc: Compute addition carry with setcond Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/translate.c | 44 ++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 116cf12b3e..fce261b2c3 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -768,36 +768,26 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, static inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, TCGv arg2, int sub) { - int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(), t1 = arg1, t2 = arg2; #if defined(TARGET_PPC64) if (!(ctx->sf_mode)) { - TCGv t0, t1; - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - - tcg_gen_ext32u_tl(t0, arg1); - tcg_gen_ext32u_tl(t1, arg2); - if (sub) { - tcg_gen_brcond_tl(TCG_COND_GTU, t0, t1, l1); - } else { - tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); - } - tcg_gen_movi_tl(cpu_ca, 1); - gen_set_label(l1); - tcg_temp_free(t0); - tcg_temp_free(t1); - } else -#endif - { - if (sub) { - tcg_gen_brcond_tl(TCG_COND_GTU, arg1, arg2, l1); - } else { - tcg_gen_brcond_tl(TCG_COND_GEU, arg1, arg2, l1); - } - tcg_gen_movi_tl(cpu_ca, 1); - gen_set_label(l1); + t1 = t0; + tcg_gen_ext32u_tl(t1, arg1); + t2 = tcg_temp_new(); + tcg_gen_ext32u_tl(t2, arg2); } +#endif + + tcg_gen_setcond_tl(sub ? TCG_COND_LEU : TCG_COND_LTU, t0, t1, t2); + tcg_gen_or_tl(cpu_ca, cpu_ca, t0); + + tcg_temp_free(t0); +#if defined(TARGET_PPC64) + if (!(ctx->sf_mode)) { + tcg_temp_free(t2); + } +#endif } /* Common add function */ @@ -811,7 +801,7 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2))) { t0 = ret; } else { - t0 = tcg_temp_local_new(); + t0 = tcg_temp_new(); } if (add_ca) { From b5a73f8d8a57e940f9bbeb399a9e47897522ee9a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:17 -0800 Subject: [PATCH 1256/1634] target-ppc: Use add2 for carry generation Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/translate.c | 196 +++++++++++++++-------------------------- 1 file changed, 70 insertions(+), 126 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index fce261b2c3..abc75e2cf0 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -765,73 +765,40 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov); } -static inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, - TCGv arg2, int sub) -{ - TCGv t0 = tcg_temp_new(), t1 = arg1, t2 = arg2; - -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode)) { - t1 = t0; - tcg_gen_ext32u_tl(t1, arg1); - t2 = tcg_temp_new(); - tcg_gen_ext32u_tl(t2, arg2); - } -#endif - - tcg_gen_setcond_tl(sub ? TCG_COND_LEU : TCG_COND_LTU, t0, t1, t2); - tcg_gen_or_tl(cpu_ca, cpu_ca, t0); - - tcg_temp_free(t0); -#if defined(TARGET_PPC64) - if (!(ctx->sf_mode)) { - tcg_temp_free(t2); - } -#endif -} - /* Common add function */ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, - TCGv arg2, int add_ca, int compute_ca, - int compute_ov) + TCGv arg2, bool add_ca, bool compute_ca, + bool compute_ov, bool compute_rc0) { - TCGv t0, t1; + TCGv t0 = ret; - if ((!compute_ca && !compute_ov) || - (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2))) { - t0 = ret; - } else { + if (((compute_ca && add_ca) || compute_ov) + && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) { t0 = tcg_temp_new(); } - if (add_ca) { - t1 = tcg_temp_local_new(); - tcg_gen_mov_tl(t1, cpu_ca); + if (compute_ca) { + TCGv zero = tcg_const_tl(0); + if (add_ca) { + tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero); + tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero); + } else { + tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero); + } + tcg_temp_free(zero); } else { - TCGV_UNUSED(t1); + tcg_gen_add_tl(t0, arg1, arg2); + if (add_ca) { + tcg_gen_add_tl(t0, t0, cpu_ca); + } } - if (compute_ca) { - /* Start with XER CA disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ca, 0); - } - - tcg_gen_add_tl(t0, arg1, arg2); - - if (compute_ca) { - gen_op_arith_compute_ca(ctx, t0, arg1, 0); - } - if (add_ca) { - tcg_gen_add_tl(t0, t0, t1); - gen_op_arith_compute_ca(ctx, t0, t1, 0); - tcg_temp_free(t1); - } if (compute_ov) { gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 0); } - - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(compute_rc0)) { gen_set_Rc0(ctx, t0); + } if (!TCGV_EQUAL(t0, ret)) { tcg_gen_mov_tl(ret, t0); @@ -840,21 +807,21 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, } /* Add functions with two operands */ #define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ - add_ca, compute_ca, compute_ov); \ + add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \ } /* Add functions with one operand and one immediate */ #define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, \ add_ca, compute_ca, compute_ov) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ - TCGv t0 = tcg_const_local_tl(const_val); \ + TCGv t0 = tcg_const_tl(const_val); \ gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \ cpu_gpr[rA(ctx->opcode)], t0, \ - add_ca, compute_ca, compute_ov); \ + add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \ tcg_temp_free(t0); \ } @@ -882,40 +849,27 @@ static void gen_addi(DisasContext *ctx) /* li case */ tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm); } else { - tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm); + tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], simm); } } /* addic addic.*/ -static inline void gen_op_addic(DisasContext *ctx, TCGv ret, TCGv arg1, - int compute_Rc0) +static inline void gen_op_addic(DisasContext *ctx, bool compute_rc0) { - target_long simm = SIMM(ctx->opcode); - - /* Start with XER CA disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ca, 0); - - if (likely(simm != 0)) { - TCGv t0 = tcg_temp_local_new(); - tcg_gen_addi_tl(t0, arg1, simm); - gen_op_arith_compute_ca(ctx, t0, arg1, 0); - tcg_gen_mov_tl(ret, t0); - tcg_temp_free(t0); - } else { - tcg_gen_mov_tl(ret, arg1); - } - if (compute_Rc0) { - gen_set_Rc0(ctx, ret); - } + TCGv c = tcg_const_tl(SIMM(ctx->opcode)); + gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + c, 0, 1, 0, compute_rc0); + tcg_temp_free(c); } static void gen_addic(DisasContext *ctx) { - gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0); + gen_op_addic(ctx, 0); } static void gen_addic_(DisasContext *ctx) { - gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1); + gen_op_addic(ctx, 1); } /* addis */ @@ -927,7 +881,8 @@ static void gen_addis(DisasContext *ctx) /* lis case */ tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm << 16); } else { - tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm << 16); + tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], + cpu_gpr[rA(ctx->opcode)], simm << 16); } } @@ -1212,49 +1167,43 @@ static void gen_nego(DisasContext *ctx) /* Common subf function */ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, - TCGv arg2, int add_ca, int compute_ca, - int compute_ov) + TCGv arg2, bool add_ca, bool compute_ca, + bool compute_ov, bool compute_rc0) { - TCGv t0, t1; + TCGv t0 = ret; - if ((!compute_ca && !compute_ov) || - (!TCGV_EQUAL(ret, arg1) && !TCGV_EQUAL(ret, arg2))) { - t0 = ret; - } else { - t0 = tcg_temp_local_new(); + if (((add_ca && compute_ca) || compute_ov) + && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) { + t0 = tcg_temp_new(); } if (add_ca) { - t1 = tcg_temp_local_new(); - tcg_gen_mov_tl(t1, cpu_ca); - } else { - TCGV_UNUSED(t1); - } - - if (compute_ca) { - /* Start with XER CA disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ca, 0); - } - - if (add_ca) { - tcg_gen_not_tl(t0, arg1); - tcg_gen_add_tl(t0, t0, arg2); - gen_op_arith_compute_ca(ctx, t0, arg2, 0); - tcg_gen_add_tl(t0, t0, t1); - gen_op_arith_compute_ca(ctx, t0, t1, 0); - tcg_temp_free(t1); - } else { - tcg_gen_sub_tl(t0, arg2, arg1); + /* dest = ~arg1 + arg2 + ca = arg2 - arg1 + ca - 1. */ if (compute_ca) { - gen_op_arith_compute_ca(ctx, t0, arg2, 1); + TCGv zero; + tcg_gen_subi_tl(cpu_ca, cpu_ca, 1); + zero = tcg_const_tl(0); + tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero); + tcg_gen_sub2_tl(t0, cpu_ca, t0, cpu_ca, arg1, zero); + tcg_temp_free(zero); + } else { + tcg_gen_sub_tl(t0, arg2, arg1); + tcg_gen_add_tl(t0, t0, cpu_ca); + tcg_gen_subi_tl(t0, t0, 1); } + } else { + if (compute_ca) { + tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1); + } + tcg_gen_sub_tl(t0, arg2, arg1); } + if (compute_ov) { gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 1); } - - if (unlikely(Rc(ctx->opcode) != 0)) + if (unlikely(compute_rc0)) { gen_set_Rc0(ctx, t0); + } if (!TCGV_EQUAL(t0, ret)) { tcg_gen_mov_tl(ret, t0); @@ -1263,21 +1212,21 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, } /* Sub functions with Two operands functions */ #define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \ - add_ca, compute_ca, compute_ov); \ + add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \ } /* Sub functions with one operand and one immediate */ #define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val, \ add_ca, compute_ca, compute_ov) \ -static void glue(gen_, name)(DisasContext *ctx) \ +static void glue(gen_, name)(DisasContext *ctx) \ { \ - TCGv t0 = tcg_const_local_tl(const_val); \ + TCGv t0 = tcg_const_tl(const_val); \ gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], \ cpu_gpr[rA(ctx->opcode)], t0, \ - add_ca, compute_ca, compute_ov); \ + add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \ tcg_temp_free(t0); \ } /* subf subf. subfo subfo. */ @@ -1299,15 +1248,10 @@ GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1) /* subfic */ static void gen_subfic(DisasContext *ctx) { - /* Start with XER CA disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ca, 0); - TCGv t0 = tcg_temp_local_new(); - TCGv t1 = tcg_const_local_tl(SIMM(ctx->opcode)); - tcg_gen_sub_tl(t0, t1, cpu_gpr[rA(ctx->opcode)]); - gen_op_arith_compute_ca(ctx, t0, t1, 1); - tcg_temp_free(t1); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); + TCGv c = tcg_const_tl(SIMM(ctx->opcode)); + gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + c, 0, 1, 0, 0); + tcg_temp_free(c); } /*** Integer logical ***/ From fd3f0081e5d873b26b9988b48f7118a9914bbd64 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:18 -0800 Subject: [PATCH 1257/1634] target-ppc: Implement neg in terms of subf Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/translate.c | 63 +++++++++++++----------------------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index abc75e2cf0..05f93f6ffa 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1121,50 +1121,6 @@ static void gen_mulldo(DisasContext *ctx) } #endif -/* neg neg. nego nego. */ -static inline void gen_op_arith_neg(DisasContext *ctx, TCGv ret, TCGv arg1, - int ov_check) -{ - int l1 = gen_new_label(); - int l2 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); -#if defined(TARGET_PPC64) - if (ctx->sf_mode) { - tcg_gen_mov_tl(t0, arg1); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT64_MIN, l1); - } else -#endif - { - tcg_gen_ext32s_tl(t0, arg1); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT32_MIN, l1); - } - tcg_gen_neg_tl(ret, arg1); - if (ov_check) { - tcg_gen_movi_tl(cpu_ov, 0); - } - tcg_gen_br(l2); - gen_set_label(l1); - tcg_gen_mov_tl(ret, t0); - if (ov_check) { - tcg_gen_movi_tl(cpu_ov, 1); - tcg_gen_movi_tl(cpu_so, 1); - } - gen_set_label(l2); - tcg_temp_free(t0); - if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, ret); -} - -static void gen_neg(DisasContext *ctx) -{ - gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0); -} - -static void gen_nego(DisasContext *ctx) -{ - gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1); -} - /* Common subf function */ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2, bool add_ca, bool compute_ca, @@ -1254,6 +1210,25 @@ static void gen_subfic(DisasContext *ctx) tcg_temp_free(c); } +/* neg neg. nego nego. */ +static inline void gen_op_arith_neg(DisasContext *ctx, bool compute_ov) +{ + TCGv zero = tcg_const_tl(0); + gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], + zero, 0, 0, compute_ov, Rc(ctx->opcode)); + tcg_temp_free(zero); +} + +static void gen_neg(DisasContext *ctx) +{ + gen_op_arith_neg(ctx, 0); +} + +static void gen_nego(DisasContext *ctx) +{ + gen_op_arith_neg(ctx, 1); +} + /*** Integer logical ***/ #define GEN_LOGICAL2(name, tcg_op, opc, type) \ static void glue(gen_, name)(DisasContext *ctx) \ From ba4af3e422f7ba2de58fd752d6ca89922c259a74 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:19 -0800 Subject: [PATCH 1258/1634] target-ppc: Compute arithmetic shift carry without branches Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/translate.c | 71 ++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 05f93f6ffa..4311119590 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1773,30 +1773,25 @@ static void gen_sraw(DisasContext *ctx) static void gen_srawi(DisasContext *ctx) { int sh = SH(ctx->opcode); - if (sh != 0) { - int l1, l2; - TCGv t0; - l1 = gen_new_label(); - l2 = gen_new_label(); - t0 = tcg_temp_local_new(); - tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]); - tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1); - tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); - tcg_gen_movi_tl(cpu_ca, 1); - tcg_gen_br(l2); - gen_set_label(l1); + TCGv dst = cpu_gpr[rA(ctx->opcode)]; + TCGv src = cpu_gpr[rS(ctx->opcode)]; + if (sh == 0) { + tcg_gen_mov_tl(dst, src); tcg_gen_movi_tl(cpu_ca, 0); - gen_set_label(l2); - tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]); - tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], t0, sh); - tcg_temp_free(t0); } else { - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); - tcg_gen_movi_tl(cpu_ca, 0); + TCGv t0; + tcg_gen_ext32s_tl(dst, src); + tcg_gen_andi_tl(cpu_ca, dst, (1ULL << sh) - 1); + t0 = tcg_temp_new(); + tcg_gen_sari_tl(t0, dst, TARGET_LONG_BITS - 1); + tcg_gen_and_tl(cpu_ca, cpu_ca, t0); + tcg_temp_free(t0); + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_ca, cpu_ca, 0); + tcg_gen_sari_tl(dst, dst, sh); + } + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, dst); } - if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* srw & srw. */ @@ -1856,28 +1851,24 @@ static void gen_srad(DisasContext *ctx) static inline void gen_sradi(DisasContext *ctx, int n) { int sh = SH(ctx->opcode) + (n << 5); - if (sh != 0) { - int l1, l2; - TCGv t0; - l1 = gen_new_label(); - l2 = gen_new_label(); - t0 = tcg_temp_local_new(); - tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1); - tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); - tcg_gen_movi_tl(cpu_ca, 1); - tcg_gen_br(l2); - gen_set_label(l1); + TCGv dst = cpu_gpr[rA(ctx->opcode)]; + TCGv src = cpu_gpr[rS(ctx->opcode)]; + if (sh == 0) { + tcg_gen_mov_tl(dst, src); tcg_gen_movi_tl(cpu_ca, 0); - gen_set_label(l2); - tcg_temp_free(t0); - tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh); } else { - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]); - tcg_gen_movi_tl(cpu_ca, 0); + TCGv t0; + tcg_gen_andi_tl(cpu_ca, src, (1ULL << sh) - 1); + t0 = tcg_temp_new(); + tcg_gen_sari_tl(t0, src, TARGET_LONG_BITS - 1); + tcg_gen_and_tl(cpu_ca, cpu_ca, t0); + tcg_temp_free(t0); + tcg_gen_setcondi_tl(TCG_COND_NE, cpu_ca, cpu_ca, 0); + tcg_gen_sari_tl(dst, src, sh); + } + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_Rc0(ctx, dst); } - if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } static void gen_sradi0(DisasContext *ctx) From e4a2c846248ff8e786e741bc4bc3103b24dfba74 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:20 -0800 Subject: [PATCH 1259/1634] target-ppc: Compute mullwo without branches Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-ppc/translate.c | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4311119590..f88644118b 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1036,35 +1036,21 @@ static void gen_mullw(DisasContext *ctx) /* mullwo mullwo. */ static void gen_mullwo(DisasContext *ctx) { - int l1; - TCGv_i64 t0, t1; + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - l1 = gen_new_label(); - /* Start with XER OV disabled, the most likely case */ - tcg_gen_movi_tl(cpu_ov, 0); -#if defined(TARGET_PPC64) - tcg_gen_ext32s_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext32s_i64(t1, cpu_gpr[rB(ctx->opcode)]); -#else - tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); - tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); -#endif - tcg_gen_mul_i64(t0, t0, t1); -#if defined(TARGET_PPC64) - tcg_gen_ext32s_i64(cpu_gpr[rD(ctx->opcode)], t0); - tcg_gen_brcond_i64(TCG_COND_EQ, t0, cpu_gpr[rD(ctx->opcode)], l1); -#else - tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_gen_ext32s_i64(t1, t0); - tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1); -#endif - tcg_gen_movi_tl(cpu_ov, 1); - tcg_gen_movi_tl(cpu_so, 1); - gen_set_label(l1); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_muls2_i32(t0, t1, t0, t1); + tcg_gen_ext_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); + + tcg_gen_sari_i32(t0, t0, 31); + tcg_gen_setcond_i32(TCG_COND_NE, t0, t0, t1); + tcg_gen_extu_i32_tl(cpu_ov, t0); + tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); if (unlikely(Rc(ctx->opcode) != 0)) gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } From 15fe216fc510c2a0ecf39536bbbc92ba75beb963 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:21 -0800 Subject: [PATCH 1260/1634] target-sparc: Use official add2/sub2 interfaces for addx/subx Cc: Blue Swirl Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 42 +++++++++++++++------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 26c2056b93..a5678b0bec 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -448,19 +448,16 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, case CC_OP_ADD: case CC_OP_TADD: case CC_OP_TADDTV: -#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 - { - /* For 32-bit hosts, we can re-use the host's hardware carry - generation by using an ADD2 opcode. We discard the low - part of the output. Ideally we'd combine this operation - with the add that generated the carry in the first place. */ - TCGv dst_low = tcg_temp_new(); - tcg_gen_op6_i32(INDEX_op_add2_i32, dst_low, dst, - cpu_cc_src, src1, cpu_cc_src2, src2); - tcg_temp_free(dst_low); + if (TARGET_LONG_BITS == 32) { + /* We can re-use the host's hardware carry generation by using + an ADD2 opcode. We discard the low part of the output. + Ideally we'd combine this operation with the add that + generated the carry in the first place. */ + carry = tcg_temp_new(); + tcg_gen_add2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2); + tcg_temp_free(carry); goto add_done; } -#endif carry_32 = gen_add32_carry32(); break; @@ -492,9 +489,7 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1, tcg_temp_free(carry); #endif -#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 add_done: -#endif if (update_cc) { tcg_gen_mov_tl(cpu_cc_src, src1); tcg_gen_mov_tl(cpu_cc_src2, src2); @@ -554,19 +549,16 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, case CC_OP_SUB: case CC_OP_TSUB: case CC_OP_TSUBTV: -#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 - { - /* For 32-bit hosts, we can re-use the host's hardware carry - generation by using a SUB2 opcode. We discard the low - part of the output. Ideally we'd combine this operation - with the add that generated the carry in the first place. */ - TCGv dst_low = tcg_temp_new(); - tcg_gen_op6_i32(INDEX_op_sub2_i32, dst_low, dst, - cpu_cc_src, src1, cpu_cc_src2, src2); - tcg_temp_free(dst_low); + if (TARGET_LONG_BITS == 32) { + /* We can re-use the host's hardware carry generation by using + a SUB2 opcode. We discard the low part of the output. + Ideally we'd combine this operation with the add that + generated the carry in the first place. */ + carry = tcg_temp_new(); + tcg_gen_sub2_tl(carry, dst, cpu_cc_src, src1, cpu_cc_src2, src2); + tcg_temp_free(carry); goto sub_done; } -#endif carry_32 = gen_sub32_carry32(); break; @@ -592,9 +584,7 @@ static void gen_op_subx_int(DisasContext *dc, TCGv dst, TCGv src1, tcg_temp_free(carry); #endif -#if TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 32 sub_done: -#endif if (update_cc) { tcg_gen_mov_tl(cpu_cc_src, src1); tcg_gen_mov_tl(cpu_cc_src2, src2); From 528692a8a4fb6c545d818957e758d6ad70fa255c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:22 -0800 Subject: [PATCH 1261/1634] target-sparc: Use mul*2 for multiply Cc: Blue Swirl Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sparc/translate.c | 45 ++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index a5678b0bec..12276d5608 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -642,39 +642,30 @@ static inline void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) static inline void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext) { - TCGv_i32 r_src1, r_src2; - TCGv_i64 r_temp, r_temp2; - - r_src1 = tcg_temp_new_i32(); - r_src2 = tcg_temp_new_i32(); - - tcg_gen_trunc_tl_i32(r_src1, src1); - tcg_gen_trunc_tl_i32(r_src2, src2); - - r_temp = tcg_temp_new_i64(); - r_temp2 = tcg_temp_new_i64(); +#if TARGET_LONG_BITS == 32 + if (sign_ext) { + tcg_gen_muls2_tl(dst, cpu_y, src1, src2); + } else { + tcg_gen_mulu2_tl(dst, cpu_y, src1, src2); + } +#else + TCGv t0 = tcg_temp_new_i64(); + TCGv t1 = tcg_temp_new_i64(); if (sign_ext) { - tcg_gen_ext_i32_i64(r_temp, r_src2); - tcg_gen_ext_i32_i64(r_temp2, r_src1); + tcg_gen_ext32s_i64(t0, src1); + tcg_gen_ext32s_i64(t1, src2); } else { - tcg_gen_extu_i32_i64(r_temp, r_src2); - tcg_gen_extu_i32_i64(r_temp2, r_src1); + tcg_gen_ext32u_i64(t0, src1); + tcg_gen_ext32u_i64(t1, src2); } - tcg_gen_mul_i64(r_temp2, r_temp, r_temp2); + tcg_gen_mul_i64(dst, t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); - tcg_gen_shri_i64(r_temp, r_temp2, 32); - tcg_gen_trunc_i64_tl(cpu_y, r_temp); - tcg_temp_free_i64(r_temp); - tcg_gen_andi_tl(cpu_y, cpu_y, 0xffffffff); - - tcg_gen_trunc_i64_tl(dst, r_temp2); - - tcg_temp_free_i64(r_temp2); - - tcg_temp_free_i32(r_src1); - tcg_temp_free_i32(r_src2); + tcg_gen_shri_i64(cpu_y, dst, 32); +#endif } static inline void gen_op_umul(TCGv dst, TCGv src1, TCGv src2) From 1d3b708491b9d7dde573261fdee8ca0afc6980fd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:23 -0800 Subject: [PATCH 1262/1634] target-sh4: Use mul*2 for dmul* Cc: Aurelien Jarno Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-sh4/translate.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index c58d79a5cd..d255066e0a 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -833,36 +833,10 @@ static void _decode_opc(DisasContext * ctx) gen_helper_div1(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8)); return; case 0x300d: /* dmuls.l Rm,Rn */ - { - TCGv_i64 tmp1 = tcg_temp_new_i64(); - TCGv_i64 tmp2 = tcg_temp_new_i64(); - - tcg_gen_ext_i32_i64(tmp1, REG(B7_4)); - tcg_gen_ext_i32_i64(tmp2, REG(B11_8)); - tcg_gen_mul_i64(tmp1, tmp1, tmp2); - tcg_gen_trunc_i64_i32(cpu_macl, tmp1); - tcg_gen_shri_i64(tmp1, tmp1, 32); - tcg_gen_trunc_i64_i32(cpu_mach, tmp1); - - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp1); - } + tcg_gen_muls2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8)); return; case 0x3005: /* dmulu.l Rm,Rn */ - { - TCGv_i64 tmp1 = tcg_temp_new_i64(); - TCGv_i64 tmp2 = tcg_temp_new_i64(); - - tcg_gen_extu_i32_i64(tmp1, REG(B7_4)); - tcg_gen_extu_i32_i64(tmp2, REG(B11_8)); - tcg_gen_mul_i64(tmp1, tmp1, tmp2); - tcg_gen_trunc_i64_i32(cpu_macl, tmp1); - tcg_gen_shri_i64(tmp1, tmp1, 32); - tcg_gen_trunc_i64_i32(cpu_mach, tmp1); - - tcg_temp_free_i64(tmp2); - tcg_temp_free_i64(tmp1); - } + tcg_gen_mulu2_i32(cpu_macl, cpu_mach, REG(B7_4), REG(B11_8)); return; case 0x600e: /* exts.b Rm,Rn */ tcg_gen_ext8s_i32(REG(B11_8), REG(B7_4)); From d1f8cd839136337b713a05aaf11a5f189e81532d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:24 -0800 Subject: [PATCH 1263/1634] target-unicore32: Use mul*2 for do_mult Cc: Guan Xuetao Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-unicore32/translate.c | 81 +++++------------------------------- 1 file changed, 10 insertions(+), 71 deletions(-) diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index f4498bcb14..d5039e2093 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -267,37 +267,6 @@ static void gen_exception(int excp) dead_tmp(tmp); } -/* FIXME: Most targets have native widening multiplication. - It would be good to use that instead of a full wide multiply. */ -/* 32x32->64 multiply. Marks inputs as dead. */ -static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b) -{ - TCGv_i64 tmp1 = tcg_temp_new_i64(); - TCGv_i64 tmp2 = tcg_temp_new_i64(); - - tcg_gen_extu_i32_i64(tmp1, a); - dead_tmp(a); - tcg_gen_extu_i32_i64(tmp2, b); - dead_tmp(b); - tcg_gen_mul_i64(tmp1, tmp1, tmp2); - tcg_temp_free_i64(tmp2); - return tmp1; -} - -static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b) -{ - TCGv_i64 tmp1 = tcg_temp_new_i64(); - TCGv_i64 tmp2 = tcg_temp_new_i64(); - - tcg_gen_ext_i32_i64(tmp1, a); - dead_tmp(a); - tcg_gen_ext_i32_i64(tmp2, b); - dead_tmp(b); - tcg_gen_mul_i64(tmp1, tmp1, tmp2); - tcg_temp_free_i64(tmp2); - return tmp1; -} - #define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, CF)) /* Set CF to the top bit of var. */ @@ -1219,38 +1188,6 @@ static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s, } } - -/* Store a 64-bit value to a register pair. Clobbers val. */ -static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val) -{ - TCGv tmp; - tmp = new_tmp(); - tcg_gen_trunc_i64_i32(tmp, val); - store_reg(s, rlow, tmp); - tmp = new_tmp(); - tcg_gen_shri_i64(val, val, 32); - tcg_gen_trunc_i64_i32(tmp, val); - store_reg(s, rhigh, tmp); -} - -/* load and add a 64-bit value from a register pair. */ -static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh) -{ - TCGv_i64 tmp; - TCGv tmpl; - TCGv tmph; - - /* Load 64-bit value rd:rn. */ - tmpl = load_reg(s, rlow); - tmph = load_reg(s, rhigh); - tmp = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(tmp, tmpl, tmph); - dead_tmp(tmpl); - dead_tmp(tmph); - tcg_gen_add_i64(val, val, tmp); - tcg_temp_free_i64(tmp); -} - /* data processing instructions */ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) { @@ -1445,24 +1382,26 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) /* multiply */ static void do_mult(CPUUniCore32State *env, DisasContext *s, uint32_t insn) { - TCGv tmp; - TCGv tmp2; - TCGv_i64 tmp64; + TCGv tmp, tmp2, tmp3, tmp4; if (UCOP_SET(27)) { /* 64 bit mul */ tmp = load_reg(s, UCOP_REG_M); tmp2 = load_reg(s, UCOP_REG_N); if (UCOP_SET(26)) { - tmp64 = gen_muls_i64_i32(tmp, tmp2); + tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2); } else { - tmp64 = gen_mulu_i64_i32(tmp, tmp2); + tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2); } if (UCOP_SET(25)) { /* mult accumulate */ - gen_addq(s, tmp64, UCOP_REG_LO, UCOP_REG_HI); + tmp3 = load_reg(s, UCOP_REG_LO); + tmp4 = load_reg(s, UCOP_REG_HI); + tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, tmp3, tmp4); + dead_tmp(tmp3); + dead_tmp(tmp4); } - gen_storeq_reg(s, UCOP_REG_LO, UCOP_REG_HI, tmp64); - tcg_temp_free_i64(tmp64); + store_reg(s, UCOP_REG_LO, tmp); + store_reg(s, UCOP_REG_HI, tmp2); } else { /* 32 bit mul */ tmp = load_reg(s, UCOP_REG_M); From c9cda20bc55e549d31e791bfa55eabe3642b73a7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:25 -0800 Subject: [PATCH 1264/1634] target-xtensa: Use mul*2 for mul*hi Cc: Max Filippov Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-xtensa/translate.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 7029ac4814..b41d12c540 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -1652,24 +1652,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 11: /*MULSHi*/ HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL_HIGH); { - TCGv_i64 r = tcg_temp_new_i64(); - TCGv_i64 s = tcg_temp_new_i64(); - TCGv_i64 t = tcg_temp_new_i64(); + TCGv lo = tcg_temp_new(); if (OP2 == 10) { - tcg_gen_extu_i32_i64(s, cpu_R[RRR_S]); - tcg_gen_extu_i32_i64(t, cpu_R[RRR_T]); + tcg_gen_mulu2_i32(lo, cpu_R[RRR_R], + cpu_R[RRR_S], cpu_R[RRR_T]); } else { - tcg_gen_ext_i32_i64(s, cpu_R[RRR_S]); - tcg_gen_ext_i32_i64(t, cpu_R[RRR_T]); + tcg_gen_muls2_i32(lo, cpu_R[RRR_R], + cpu_R[RRR_S], cpu_R[RRR_T]); } - tcg_gen_mul_i64(r, s, t); - tcg_gen_shri_i64(r, r, 32); - tcg_gen_trunc_i64_i32(cpu_R[RRR_R], r); - - tcg_temp_free_i64(r); - tcg_temp_free_i64(s); - tcg_temp_free_i64(t); + tcg_temp_free(lo); } break; From d2123a079d983677ec8333940aa4bec803d98cde Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 19 Feb 2013 23:52:26 -0800 Subject: [PATCH 1265/1634] target-xtensa: Use add2/sub2 for mac Cc: Max Filippov Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-xtensa/translate.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index b41d12c540..11e06a34f5 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -2487,27 +2487,24 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) tcg_gen_sari_i32(cpu_SR[ACCHI], cpu_SR[ACCLO], 31); } } else { - TCGv_i32 res = tcg_temp_new_i32(); - TCGv_i64 res64 = tcg_temp_new_i64(); - TCGv_i64 tmp = tcg_temp_new_i64(); + TCGv_i32 lo = tcg_temp_new_i32(); + TCGv_i32 hi = tcg_temp_new_i32(); - tcg_gen_mul_i32(res, m1, m2); - tcg_gen_ext_i32_i64(res64, res); - tcg_gen_concat_i32_i64(tmp, - cpu_SR[ACCLO], cpu_SR[ACCHI]); + tcg_gen_mul_i32(lo, m1, m2); + tcg_gen_sari_i32(hi, lo, 31); if (op == MAC16_MULA) { - tcg_gen_add_i64(tmp, tmp, res64); + tcg_gen_add2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], + cpu_SR[ACCLO], cpu_SR[ACCHI], + lo, hi); } else { - tcg_gen_sub_i64(tmp, tmp, res64); + tcg_gen_sub2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], + cpu_SR[ACCLO], cpu_SR[ACCHI], + lo, hi); } - tcg_gen_trunc_i64_i32(cpu_SR[ACCLO], tmp); - tcg_gen_shri_i64(tmp, tmp, 32); - tcg_gen_trunc_i64_i32(cpu_SR[ACCHI], tmp); tcg_gen_ext8s_i32(cpu_SR[ACCHI], cpu_SR[ACCHI]); - tcg_temp_free(res); - tcg_temp_free_i64(res64); - tcg_temp_free_i64(tmp); + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); } tcg_temp_free(m1); tcg_temp_free(m2); From 9c19eb1e205b29018f6f61c5f43db6abbe7dc0e5 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Wed, 6 Feb 2013 18:05:25 +0100 Subject: [PATCH 1266/1634] target-mips: fix for incorrect multiplication with MULQ_S.PH The change corrects sign-related issue with MULQ_S.PH. It also includes extension to the already existing test which will trigger the issue. Signed-off-by: Petar Jovanovic Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 2 +- tests/tcg/mips/mips32-dspr2/mulq_s_ph.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 96cb0447e2..6781da8214 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -652,7 +652,7 @@ static inline int32_t mipsdsp_sat16_mul_q15_q15(uint16_t a, uint16_t b, temp = 0x7FFF0000; set_DSPControl_overflow_flag(1, 21, env); } else { - temp = ((uint32_t)a * (uint32_t)b); + temp = (int16_t)a * (int16_t)b; temp = temp << 1; } diff --git a/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c b/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c index d0f7674a38..00e015542e 100644 --- a/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c +++ b/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c @@ -6,6 +6,21 @@ int main() int rd, rs, rt, dsp; int result, resultdsp; + rs = 0x80000000; + rt = 0x0ffc0000; + result = 0xF0040000; + resultdsp = 0; + + __asm + ("mulq_s.ph %0, %2, %3\n\t" + "rddsp %1\n\t" + : "=r"(rd), "=r"(dsp) + : "r"(rs), "r"(rt) + ); + dsp = (dsp >> 21) & 0x01; + assert(rd == result); + assert(dsp == resultdsp); + rs = 0x80001234; rt = 0x80004321; result = 0x7FFF098B; From a345481baa2b2fb3d54f8c9ddb58dfcaf75786df Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Thu, 7 Feb 2013 19:36:09 +0100 Subject: [PATCH 1267/1634] target-mips: fix for sign-issue in MULQ_W helper Correct sign-propagation before multiplication in MULQ_W helper. The change also fixes previously incorrect expected values in the tests for MULQ_RS.W and MULQ_S.W. Signed-off-by: Petar Jovanovic Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 2 +- tests/tcg/mips/mips32-dspr2/mulq_rs_w.c | 2 +- tests/tcg/mips/mips32-dspr2/mulq_s_w.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 6781da8214..841f47b91d 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -2689,7 +2689,7 @@ MAQ_SA_W(maq_sa_w_phr, 0); target_ulong helper_##name(target_ulong rs, target_ulong rt, \ CPUMIPSState *env) \ { \ - uint32_t rs_t, rt_t; \ + int32_t rs_t, rt_t; \ int32_t tempI; \ int64_t tempL; \ \ diff --git a/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c b/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c index 669405faf1..7ba633bc17 100644 --- a/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c +++ b/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c @@ -8,7 +8,7 @@ int main() rs = 0x80001234; rt = 0x80004321; - result = 0x80005555; + result = 0x7FFFAAAB; __asm ("mulq_rs.w %0, %1, %2\n\t" diff --git a/tests/tcg/mips/mips32-dspr2/mulq_s_w.c b/tests/tcg/mips/mips32-dspr2/mulq_s_w.c index df148b7ffb..9c2be06cc0 100644 --- a/tests/tcg/mips/mips32-dspr2/mulq_s_w.c +++ b/tests/tcg/mips/mips32-dspr2/mulq_s_w.c @@ -8,7 +8,7 @@ int main() rs = 0x80001234; rt = 0x80004321; - result = 0x80005555; + result = 0x7FFFAAAB; __asm ("mulq_s.w %0, %1, %2\n\t" From 8c3ac601bdaf8d4d81823a79f2a166b586db7dab Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 25 Feb 2013 11:41:38 -0800 Subject: [PATCH 1268/1634] arm/translate.c: Fix adc_CC/sbc_CC implementation commits 49b4c31efcce45ab714f286f14fa5d5173f9069d and 2de68a4900ef6eb67380b0c128abfe1976bc66e8 reworked the implementation of adc_CC and sub_CC. The new implementations (on the TCG_TARGET_HAS_add2_i32 code path) are incorrect. The new logic is: CF:NF = 0:A +/- 0:CF CF:NF = CF:A +/- 0:B The lower 32 bits of the intermediate result stored in NF needs to be passes into the second addition in place of A (s/CF:A/CF:NF): CF:NF = 0:A +/- 0:CF CF:NF = CF:NF +/- 0:B This patch fixes the issue. Cc: Peter Maydell Reviewed-by: Peter Maydell Signed-off-by: Peter Crosthwaite Signed-off-by: Richard Henderson Signed-off-by: Anthony Liguori --- target-arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 9993aea93e..6d91b70aff 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -428,7 +428,7 @@ static void gen_adc_CC(TCGv dest, TCGv t0, TCGv t1) if (TCG_TARGET_HAS_add2_i32) { tcg_gen_movi_i32(tmp, 0); tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp); - tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, cpu_CF, t1, tmp); + tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp); } else { TCGv_i64 q0 = tcg_temp_new_i64(); TCGv_i64 q1 = tcg_temp_new_i64(); @@ -472,7 +472,7 @@ static void gen_sbc_CC(TCGv dest, TCGv t0, TCGv t1) if (TCG_TARGET_HAS_add2_i32) { tcg_gen_movi_i32(tmp, 0); tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp); - tcg_gen_sub2_i32(cpu_NF, cpu_CF, t0, cpu_CF, t1, tmp); + tcg_gen_sub2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp); } else { TCGv_i64 q0 = tcg_temp_new_i64(); TCGv_i64 q1 = tcg_temp_new_i64(); From e77f083292916ba43b940fdacd2fc1001b750d1d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 25 Feb 2013 11:41:39 -0800 Subject: [PATCH 1269/1634] target-arm: Fix sbc_CC carry While T0+~T1+CF = T0-T1+CF-1 is true for the low 32-bits, it does not produce the correct carry-out to bit 33. Do exactly what the manual says. Using the ~T1 makes the add and subtract code paths nearly identical, so have sbc_CC use adc_CC. Cc: Peter Maydell Reported-by: Laurent Desnogues Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Signed-off-by: Anthony Liguori --- target-arm/translate.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 6d91b70aff..f2f649dffd 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -464,33 +464,13 @@ static void gen_sub_CC(TCGv dest, TCGv t0, TCGv t1) tcg_gen_mov_i32(dest, cpu_NF); } -/* dest = T0 + ~T1 + CF = T0 - T1 + CF - 1. Compute C, N, V and Z flags */ +/* dest = T0 + ~T1 + CF. Compute C, N, V and Z flags */ static void gen_sbc_CC(TCGv dest, TCGv t0, TCGv t1) { TCGv tmp = tcg_temp_new_i32(); - tcg_gen_subi_i32(cpu_CF, cpu_CF, 1); - if (TCG_TARGET_HAS_add2_i32) { - tcg_gen_movi_i32(tmp, 0); - tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp); - tcg_gen_sub2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp); - } else { - TCGv_i64 q0 = tcg_temp_new_i64(); - TCGv_i64 q1 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(q0, t0); - tcg_gen_extu_i32_i64(q1, t1); - tcg_gen_sub_i64(q0, q0, q1); - tcg_gen_extu_i32_i64(q1, cpu_CF); - tcg_gen_add_i64(q0, q0, q1); - tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0); - tcg_temp_free_i64(q0); - tcg_temp_free_i64(q1); - } - tcg_gen_mov_i32(cpu_ZF, cpu_NF); - tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); - tcg_gen_xor_i32(tmp, t0, t1); - tcg_gen_and_i32(cpu_VF, cpu_VF, tmp); - tcg_temp_free_i32(tmp); - tcg_gen_mov_i32(dest, cpu_NF); + tcg_gen_not_i32(tmp, t1); + gen_adc_CC(dest, t0, tmp); + tcg_temp_free(tmp); } #define GEN_SHIFT(name) \ From 08f4a0f7ee899c32bac91114e859d2687cbcf1d7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 25 Feb 2013 11:41:40 -0800 Subject: [PATCH 1270/1634] target-ppc: Fix SUBFE carry While ~T0+T1+CF = T1-T0+CF-1 is true for the low 32-bits, it does not produce the correct carry-out to bit 33. Do exactly what the manual says. Cc: Alexander Graf Signed-off-by: Richard Henderson Signed-off-by: Anthony Liguori --- target-ppc/translate.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index f88644118b..80d5366d27 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -1120,14 +1120,15 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, } if (add_ca) { - /* dest = ~arg1 + arg2 + ca = arg2 - arg1 + ca - 1. */ + /* dest = ~arg1 + arg2 + ca. */ if (compute_ca) { - TCGv zero; - tcg_gen_subi_tl(cpu_ca, cpu_ca, 1); + TCGv zero, inv1 = tcg_temp_new(); + tcg_gen_not_tl(inv1, arg1); zero = tcg_const_tl(0); tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero); - tcg_gen_sub2_tl(t0, cpu_ca, t0, cpu_ca, arg1, zero); + tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero); tcg_temp_free(zero); + tcg_temp_free(inv1); } else { tcg_gen_sub_tl(t0, arg2, arg1); tcg_gen_add_tl(t0, t0, cpu_ca); From 7bd43ec2dd3ffaa12e6331af41fc55d4b2b12f13 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 22 Feb 2013 20:47:10 +0100 Subject: [PATCH 1271/1634] slirp: Properly initialize pollfds_idx of new sockets Otherwise we may start processing sockets in slirp_pollfds_poll that were created past slirp_pollfds_fill. Signed-off-by: Jan Kiszka Reviewed-by: Stefan Hajnoczi --- slirp/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/slirp/socket.c b/slirp/socket.c index a7ab933c43..bb639aed9c 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -51,6 +51,7 @@ socreate(Slirp *slirp) so->so_state = SS_NOFDREF; so->s = -1; so->slirp = slirp; + so->pollfds_idx = -1; } return(so); } From f963e4d0ca5b7704aed8048e2bc293597d333dfb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 25 Feb 2013 16:02:30 +0100 Subject: [PATCH 1272/1634] gtk ui: unbreak spice Merge of the gtk ui brought a initialitation order issue for spice: The using_spice variable isn't set yet when checked, leading to the default UI being activated (additionally to spice remote access). Let's set display_remote when we find a -spice switch on the command line, like we do for vnc. Signed-off-by: Gerd Hoffmann Message-id: 1361804550-15858-1-git-send-email-kraxel@redhat.com Signed-off-by: Anthony Liguori --- vl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vl.c b/vl.c index 0da156e8b4..febd2eaa02 100644 --- a/vl.c +++ b/vl.c @@ -3767,6 +3767,7 @@ int main(int argc, char **argv, char **envp) if (!opts) { exit(1); } + display_remote++; break; case QEMU_OPTION_writeconfig: { @@ -4006,9 +4007,6 @@ int main(int argc, char **argv, char **envp) } } - if (using_spice) { - display_remote++; - } if (display_type == DT_DEFAULT && !display_remote) { #if defined(CONFIG_GTK) display_type = DT_GTK; From cba68834c69f2d0fd04127301171fedac63d9b67 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:34 +0000 Subject: [PATCH 1273/1634] Add compat for gdk_drawable_get_size on GTK3 GTK3 lacks the gdk_drawable_get_size method, so we create a stub impl which gets the get_width/get_height mehtods instead Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-2-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index dcce36d243..dfffbb86f2 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -74,6 +74,16 @@ #define MAX_VCS 10 + +/* Compatibility define to let us build on both Gtk2 and Gtk3 */ +#if GTK_CHECK_VERSION(3, 0, 0) +static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh) +{ + *ww = gdk_window_get_width(w); + *wh = gdk_window_get_height(w); +} +#endif + typedef struct VirtualConsole { GtkWidget *menu_item; From 66962f14378d0adf2e7d0fcfac66e2248b09bb4d Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:35 +0000 Subject: [PATCH 1274/1634] Remove use of gdk_drawable_get_{screen, display} The gdk_drawable_get_screen and gdk_drawable_get_display methods don't exist in GDK3. Fortunately, even on GTK2 they are not required - we can call the equivalent gtk_widget_get_screen/gtk_widget_get_display methods which have existed since GTK 2.2 Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-3-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index dfffbb86f2..8ccd95f0e8 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -501,9 +501,8 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, } if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) { - GdkDrawable *drawable = GDK_DRAWABLE(gtk_widget_get_window(s->drawing_area)); - GdkDisplay *display = gdk_drawable_get_display(drawable); - GdkScreen *screen = gdk_drawable_get_screen(drawable); + GdkDisplay *display = gtk_widget_get_display(s->drawing_area); + GdkScreen *screen = gtk_widget_get_screen(s->drawing_area); int x = (int)motion->x_root; int y = (int)motion->y_root; From 655199da197d2c3407d4bc937c9d3d3ac4551764 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:36 +0000 Subject: [PATCH 1275/1634] Conditionalize use of gdk_keyboard_grab / gdk_keyboard_ungrab On GTK3 there is support for multiple keyboard devices, so rather than using gdk_keyboard_grab / gdk_keyboard_ungrab we should iterate over all devices, grabbing each one in turn Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-4-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/ui/gtk.c b/ui/gtk.c index 8ccd95f0e8..3826bea97c 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -758,14 +758,53 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) static void gd_grab_keyboard(GtkDisplayState *s) { - gdk_keyboard_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)), +#if GTK_CHECK_VERSION(3, 0, 0) + GdkDisplay *display = gtk_widget_get_display(s->drawing_area); + GdkDeviceManager *mgr = gdk_display_get_device_manager(display); + GList *devices = gdk_device_manager_list_devices(mgr, + GDK_DEVICE_TYPE_MASTER); + GList *tmp = devices; + while (tmp) { + GdkDevice *dev = tmp->data; + if (gdk_device_get_source(dev) == GDK_SOURCE_KEYBOARD) { + gdk_device_grab(dev, + gtk_widget_get_window(s->drawing_area), + GDK_OWNERSHIP_NONE, + FALSE, + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, + NULL, + GDK_CURRENT_TIME); + } + tmp = tmp->next; + } + g_list_free(devices); +#else + gdk_keyboard_grab(gtk_widget_get_window(s->drawing_area), FALSE, GDK_CURRENT_TIME); +#endif } static void gd_ungrab_keyboard(GtkDisplayState *s) { +#if GTK_CHECK_VERSION(3, 0, 0) + GdkDisplay *display = gtk_widget_get_display(s->drawing_area); + GdkDeviceManager *mgr = gdk_display_get_device_manager(display); + GList *devices = gdk_device_manager_list_devices(mgr, + GDK_DEVICE_TYPE_MASTER); + GList *tmp = devices; + while (tmp) { + GdkDevice *dev = tmp->data; + if (gdk_device_get_source(dev) == GDK_SOURCE_KEYBOARD) { + gdk_device_ungrab(dev, + GDK_CURRENT_TIME); + } + tmp = tmp->next; + } + g_list_free(devices); +#else gdk_keyboard_ungrab(GDK_CURRENT_TIME); +#endif } static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) From 2a05485d72504ed92ce91dffd1f5867974c47ff0 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:37 +0000 Subject: [PATCH 1276/1634] Conditionalize use of gdk_pointer_grab / gdk_pointer_ungrab On GTK3 there is support for multiple pointer devices, so rather than using gdk_pointer_grab / gdk_pointer_ungrab we should iterate over all devices, grabbing each one in turn Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-5-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 3826bea97c..19d554d35b 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -807,25 +807,79 @@ static void gd_ungrab_keyboard(GtkDisplayState *s) #endif } +static void gd_grab_pointer(GtkDisplayState *s) +{ +#if GTK_CHECK_VERSION(3, 0, 0) + GdkDisplay *display = gtk_widget_get_display(s->drawing_area); + GdkDeviceManager *mgr = gdk_display_get_device_manager(display); + GList *devices = gdk_device_manager_list_devices(mgr, + GDK_DEVICE_TYPE_MASTER); + GList *tmp = devices; + while (tmp) { + GdkDevice *dev = tmp->data; + if (gdk_device_get_source(dev) == GDK_SOURCE_MOUSE) { + gdk_device_grab(dev, + gtk_widget_get_window(s->drawing_area), + GDK_OWNERSHIP_NONE, + FALSE, /* All events to come to our + window directly */ + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_SCROLL_MASK, + s->null_cursor, + GDK_CURRENT_TIME); + } + tmp = tmp->next; + } + g_list_free(devices); +#else + gdk_pointer_grab(gtk_widget_get_window(s->drawing_area), + FALSE, /* All events to come to our window directly */ + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_SCROLL_MASK, + NULL, /* Allow cursor to move over entire desktop */ + s->null_cursor, + GDK_CURRENT_TIME); +#endif +} + +static void gd_ungrab_pointer(GtkDisplayState *s) +{ +#if GTK_CHECK_VERSION(3, 0, 0) + GdkDisplay *display = gtk_widget_get_display(s->drawing_area); + GdkDeviceManager *mgr = gdk_display_get_device_manager(display); + GList *devices = gdk_device_manager_list_devices(mgr, + GDK_DEVICE_TYPE_MASTER); + GList *tmp = devices; + while (tmp) { + GdkDevice *dev = tmp->data; + if (gdk_device_get_source(dev) == GDK_SOURCE_MOUSE) { + gdk_device_ungrab(dev, + GDK_CURRENT_TIME); + } + tmp = tmp->next; + } + g_list_free(devices); +#else + gdk_pointer_ungrab(GDK_CURRENT_TIME); +#endif +} + static void gd_menu_grab_input(GtkMenuItem *item, void *opaque) { GtkDisplayState *s = opaque; if (gd_is_grab_active(s)) { gd_grab_keyboard(s); - gdk_pointer_grab(gtk_widget_get_window(GTK_WIDGET(s->drawing_area)), - FALSE, /* All events to come to our window directly */ - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_SCROLL_MASK, - NULL, /* Allow cursor to move over entire desktop */ - s->null_cursor, - GDK_CURRENT_TIME); + gd_grab_pointer(s); } else { gd_ungrab_keyboard(s); - gdk_pointer_ungrab(GDK_CURRENT_TIME); + gd_ungrab_pointer(s); } gd_update_caption(s); From 51572ab087b900ea67cc25f1c49dae4112274221 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:38 +0000 Subject: [PATCH 1277/1634] Remove use of GtkVBox in GTK3 The GtkVBox class is deprecated, in favour of just using the GtkBox class directly. Eventually even GtkBox will be deprecated in favour of GtkGrid, but that is a bigger fix which can wait. Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-6-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index 19d554d35b..4211b7e4d2 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1264,7 +1264,11 @@ void gtk_display_init(DisplayState *ds) s->dcl.dpy_refresh = gd_refresh; s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); +#if GTK_CHECK_VERSION(3, 2, 0) + s->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); +#else s->vbox = gtk_vbox_new(FALSE, 0); +#endif s->notebook = gtk_notebook_new(); s->drawing_area = gtk_drawing_area_new(); s->menu_bar = gtk_menu_bar_new(); From 530daf82c129c2a8a6fa757b3ef5a21f1f50f66a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:39 +0000 Subject: [PATCH 1278/1634] Replace gtk_menu_append with gtk_menu_shell_append The gtk_menu_append method has long been deprecated in favour of the gtk_menu_shell_append method. The former is now entirely gone in GTK3, so switch all code to the latter which works on both GTK2 and GTK3 Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-7-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 4211b7e4d2..182a16cbca 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1066,7 +1066,7 @@ static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSL g_signal_connect(vc->menu_item, "activate", G_CALLBACK(gd_menu_switch_vc), s); - gtk_menu_append(GTK_MENU(s->view_menu), vc->menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), vc->menu_item); qemu_chr_generic_open(vc->chr); if (vc->chr->init) { @@ -1148,26 +1148,26 @@ static void gd_create_menus(GtkDisplayState *s) s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine")); s->pause_item = gtk_check_menu_item_new_with_mnemonic(_("_Pause")); - gtk_menu_append(GTK_MENU(s->machine_menu), s->pause_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->pause_item); separator = gtk_separator_menu_item_new(); - gtk_menu_append(GTK_MENU(s->machine_menu), separator); + gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), separator); s->reset_item = gtk_image_menu_item_new_with_mnemonic(_("_Reset")); - gtk_menu_append(GTK_MENU(s->machine_menu), s->reset_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->reset_item); s->powerdown_item = gtk_image_menu_item_new_with_mnemonic(_("Power _Down")); - gtk_menu_append(GTK_MENU(s->machine_menu), s->powerdown_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->powerdown_item); separator = gtk_separator_menu_item_new(); - gtk_menu_append(GTK_MENU(s->machine_menu), separator); + gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), separator); s->quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); gtk_stock_lookup(GTK_STOCK_QUIT, &item); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->quit_item), "/Machine/Quit"); gtk_accel_map_add_entry("/Machine/Quit", item.keyval, item.modifier); - gtk_menu_append(GTK_MENU(s->machine_menu), s->quit_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->machine_menu), s->quit_item); s->view_menu = gtk_menu_new(); gtk_menu_set_accel_group(GTK_MENU(s->view_menu), accel_group); @@ -1178,53 +1178,53 @@ static void gd_create_menus(GtkDisplayState *s) gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->full_screen_item), "/View/Full Screen"); gtk_accel_map_add_entry("/View/Full Screen", GDK_KEY_f, GDK_CONTROL_MASK | GDK_MOD1_MASK); - gtk_menu_append(GTK_MENU(s->view_menu), s->full_screen_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->full_screen_item); separator = gtk_separator_menu_item_new(); - gtk_menu_append(GTK_MENU(s->view_menu), separator); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator); s->zoom_in_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_IN, NULL); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_in_item), "/View/Zoom In"); gtk_accel_map_add_entry("/View/Zoom In", GDK_KEY_plus, GDK_CONTROL_MASK | GDK_MOD1_MASK); - gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_in_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_in_item); s->zoom_out_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_OUT, NULL); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_out_item), "/View/Zoom Out"); gtk_accel_map_add_entry("/View/Zoom Out", GDK_KEY_minus, GDK_CONTROL_MASK | GDK_MOD1_MASK); - gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_out_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_out_item); s->zoom_fixed_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ZOOM_100, NULL); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->zoom_fixed_item), "/View/Zoom Fixed"); gtk_accel_map_add_entry("/View/Zoom Fixed", GDK_KEY_0, GDK_CONTROL_MASK | GDK_MOD1_MASK); - gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fixed_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_fixed_item); s->zoom_fit_item = gtk_check_menu_item_new_with_mnemonic(_("Zoom To _Fit")); - gtk_menu_append(GTK_MENU(s->view_menu), s->zoom_fit_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->zoom_fit_item); separator = gtk_separator_menu_item_new(); - gtk_menu_append(GTK_MENU(s->view_menu), separator); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator); s->grab_on_hover_item = gtk_check_menu_item_new_with_mnemonic(_("Grab On _Hover")); - gtk_menu_append(GTK_MENU(s->view_menu), s->grab_on_hover_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->grab_on_hover_item); s->grab_item = gtk_check_menu_item_new_with_mnemonic(_("_Grab Input")); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->grab_item), "/View/Grab Input"); gtk_accel_map_add_entry("/View/Grab Input", GDK_KEY_g, GDK_CONTROL_MASK | GDK_MOD1_MASK); - gtk_menu_append(GTK_MENU(s->view_menu), s->grab_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->grab_item); separator = gtk_separator_menu_item_new(); - gtk_menu_append(GTK_MENU(s->view_menu), separator); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator); s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA"); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item)); gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item), "/View/VGA"); gtk_accel_map_add_entry("/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK); - gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->vga_item); for (i = 0; i < nb_vcs; i++) { VirtualConsole *vc = &s->vc[i]; @@ -1234,10 +1234,10 @@ static void gd_create_menus(GtkDisplayState *s) } separator = gtk_separator_menu_item_new(); - gtk_menu_append(GTK_MENU(s->view_menu), separator); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), separator); s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs")); - gtk_menu_append(GTK_MENU(s->view_menu), s->show_tabs_item); + gtk_menu_shell_append(GTK_MENU_SHELL(s->view_menu), s->show_tabs_item); g_object_set_data(G_OBJECT(s->window), "accel_group", accel_group); gtk_window_add_accel_group(GTK_WINDOW(s->window), accel_group); From 8906de769be0978fed31a0341d0a5829a4ef7ecf Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:40 +0000 Subject: [PATCH 1279/1634] Conditionalize use of gdk_display_warp_pointer In GTK3 the gdk_display_warp_pointer method is deprecated. Instead we should use gdk_device_warp on the GdkDevice instead associated with the event being processed. Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-8-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/gtk.c b/ui/gtk.c index 182a16cbca..93c3b43fc4 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -501,7 +501,6 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, } if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) { - GdkDisplay *display = gtk_widget_get_display(s->drawing_area); GdkScreen *screen = gtk_widget_get_screen(s->drawing_area); int x = (int)motion->x_root; int y = (int)motion->y_root; @@ -527,7 +526,13 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, } if (x != (int)motion->x_root || y != (int)motion->y_root) { +#if GTK_CHECK_VERSION(3, 0, 0) + GdkDevice *dev = gdk_event_get_device((GdkEvent *)motion); + gdk_device_warp(dev, screen, x, y); +#else + GdkDisplay *display = gtk_widget_get_display(widget); gdk_display_warp_pointer(display, screen, x, y); +#endif s->last_x = -1; s->last_y = -1; return FALSE; From 1ed76b59c4f8670eb06df48cebe086da06111e1f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:41 +0000 Subject: [PATCH 1280/1634] Conditionalize use of gtk_widget_size_request The gtk_widget_size_request method has been replaced by the gtk_widget_get_preferred_size method in GTK3. Conditionally call the new method in GTK3 Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-9-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index 93c3b43fc4..c89c7c4f8b 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -305,7 +305,11 @@ static void gd_resize(DisplayState *ds) gtk_widget_set_size_request(s->drawing_area, ds_get_width(ds) * s->scale_x, ds_get_height(ds) * s->scale_y); +#if GTK_CHECK_VERSION(3, 0, 0) + gtk_widget_get_preferred_size(s->vbox, NULL, &req); +#else gtk_widget_size_request(s->vbox, &req); +#endif gtk_window_resize(GTK_WINDOW(s->window), req.width * sx, req.height * sy); From fe43bca85b269314b007cd9b2eecc4a52aa73dde Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:42 +0000 Subject: [PATCH 1281/1634] Replace expose-event handler with draw handler in GTK3 In GTK3 the 'expose-event' signal has been replaced by a new 'draw' signal. The only difference is that the latter will pre-create the cairo drawing context & set the clip mask. Since the drawing code is already structured in a nice way, we can just wire up the 'gd_draw_event' method to the 'draw' signal in GTK3 Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-10-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index c89c7c4f8b..fa4c3b0d12 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -433,6 +433,7 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) return TRUE; } +#if !GTK_CHECK_VERSION(3, 0, 0) static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose, void *opaque) { @@ -453,6 +454,7 @@ static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose, return ret; } +#endif static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, void *opaque) @@ -1100,8 +1102,13 @@ static void gd_connect_signals(GtkDisplayState *s) g_signal_connect(s->window, "delete-event", G_CALLBACK(gd_window_close), s); +#if GTK_CHECK_VERSION(3, 0, 0) + g_signal_connect(s->drawing_area, "draw", + G_CALLBACK(gd_draw_event), s); +#else g_signal_connect(s->drawing_area, "expose-event", G_CALLBACK(gd_expose_event), s); +#endif g_signal_connect(s->drawing_area, "motion-notify-event", G_CALLBACK(gd_motion_event), s); g_signal_connect(s->drawing_area, "button-press-event", From 0d20664018a401120af28ff80ac8d22fbc887956 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:43 +0000 Subject: [PATCH 1282/1634] Ensure x_keymap.o is built when GTK is enabled The x_keymap.o file is required by both GTK and SDL builds, so it must be explicitly listed as a GTK dep to ensure the linker works when SDL is disabled Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-11-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/Makefile.objs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 85c50cd89b..6ddc0def6d 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -13,7 +13,7 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o common-obj-$(CONFIG_COCOA) += cocoa.o common-obj-$(CONFIG_CURSES) += curses.o common-obj-$(CONFIG_VNC) += $(vnc-obj-y) -common-obj-$(CONFIG_GTK) += gtk.o +common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o $(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS) From 528de90ab7133e22df7c1da4632a6dcd525e88f0 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:44 +0000 Subject: [PATCH 1283/1634] Add support for enabling build with GTK3 Add a arg to configure to switch from GTK2 (default) to GTK3 (optional) build for QEMU. ./configure --with-gtkabi=3.0 will choose GTK3, while ./configure --with-gtkabi=2.0 will choose GTK2 (and remains the current default) Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-12-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- configure | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/configure b/configure index dcaa67c6d3..8b6309f53e 100755 --- a/configure +++ b/configure @@ -227,6 +227,7 @@ seccomp="" glusterfs="" virtio_blk_data_plane="" gtk="" +gtkabi="2.0" # parse CC options first for opt do @@ -902,6 +903,8 @@ for opt do ;; --enable-gtk) gtk="yes" ;; + --with-gtkabi=*) gtkabi="$optarg" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -1644,12 +1647,22 @@ fi # GTK probe if test "$gtk" != "no"; then - if $pkg_config --exists 'gtk+-2.0 >= 2.18.0' && \ - $pkg_config --exists 'vte >= 0.24.0'; then - gtk_cflags=`$pkg_config --cflags gtk+-2.0 2>/dev/null` - gtk_libs=`$pkg_config --libs gtk+-2.0 2>/dev/null` - vte_cflags=`$pkg_config --cflags vte 2>/dev/null` - vte_libs=`$pkg_config --libs vte 2>/dev/null` + gtkpackage="gtk+-$gtkabi" + if test "$gtkabi" = "3.0" ; then + gtkversion="3.0.0" + vtepackage="vte-2.90" + vteversion="0.32.0" + else + gtkversion="2.18.0" + vtepackage="vte" + vteversion="0.24.0" + fi + if $pkg_config --exists "$gtkpackage >= $gtkversion" && \ + $pkg_config --exists "$vtepackage >= $vteversion"; then + gtk_cflags=`$pkg_config --cflags $gtkpackage 2>/dev/null` + gtk_libs=`$pkg_config --libs $gtkpackage 2>/dev/null` + vte_cflags=`$pkg_config --cflags $vtepackage 2>/dev/null` + vte_libs=`$pkg_config --libs $vtepackage 2>/dev/null` libs_softmmu="$gtk_libs $vte_libs $libs_softmmu" gtk="yes" else From ef6413a2a833abe24aae072bd59c7434969fc59d Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:45 +0000 Subject: [PATCH 1284/1634] Add compat macro for gtk_widget_get_realized The gtk_widget_get_realized method only arrived in GTK 2.20, so defined a compat macro for earlier GTK Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-13-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index fa4c3b0d12..82f0bb2081 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -84,6 +84,11 @@ static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh) } #endif +#if !GTK_CHECK_VERSION(2, 20, 0) +#define gtk_widget_get_realized(widget) GTK_WIDGET_REALIZED(widget) +#endif + + typedef struct VirtualConsole { GtkWidget *menu_item; From bc0477c7d6445730b22e733ad4a65f0cc23fa405 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 25 Feb 2013 15:20:46 +0000 Subject: [PATCH 1285/1634] Add compat for GDK_KEY_XXX symbols The GDK_KEY_XXX symbols are new in GTK3 and only the most recent GTK2 releases. Most versions of GTK2 have simply used GDK_XXX Signed-off-by: Daniel P. Berrange Message-id: 1361805646-6425-14-git-send-email-berrange@redhat.com Signed-off-by: Anthony Liguori --- ui/gtk.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index 82f0bb2081..544593e90d 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -88,6 +88,15 @@ static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh) #define gtk_widget_get_realized(widget) GTK_WIDGET_REALIZED(widget) #endif +#ifndef GDK_KEY_0 +#define GDK_KEY_0 GDK_0 +#define GDK_KEY_1 GDK_1 +#define GDK_KEY_2 GDK_2 +#define GDK_KEY_f GDK_f +#define GDK_KEY_g GDK_g +#define GDK_KEY_plus GDK_plus +#define GDK_KEY_minus GDK_minus +#endif typedef struct VirtualConsole { From ab4004495cb1cf38ab2e35f84ee54e669e2ad08a Mon Sep 17 00:00:00 2001 From: Hu Tao Date: Mon, 25 Feb 2013 10:27:48 +0800 Subject: [PATCH 1286/1634] show --disable-gtk and --enable-gtk in the help message Signed-off-by: Hu Tao Message-id: 1361759268-16314-1-git-send-email-hutao@cn.fujitsu.com Signed-off-by: Anthony Liguori --- configure | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure b/configure index 8b6309f53e..19738ac968 100755 --- a/configure +++ b/configure @@ -1055,6 +1055,8 @@ echo " --disable-strip disable stripping binaries" echo " --disable-werror disable compilation abort on warning" echo " --disable-sdl disable SDL" echo " --enable-sdl enable SDL" +echo " --disable-gtk disable gtk UI" +echo " --enable-gtk enable gtk UI" echo " --disable-virtfs disable VirtFS" echo " --enable-virtfs enable VirtFS" echo " --disable-vnc disable VNC" From 989b697ddd46769b0999e8cd16b5ecd393204734 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 26 Feb 2013 17:52:40 +0000 Subject: [PATCH 1287/1634] qemu-log: default to stderr for logging output Switch the default for qemu_log logging output from "/tmp/qemu.log" to stderr. This is an incompatible change in some sense, but logging is mostly used for debugging purposes so it shouldn't affect production use. The previous behaviour can be obtained by adding "-D /tmp/qemu.log" to the command line. This change requires us to: * update all the documentation/help text (we take the opportunity to smooth out minor inconsistencies between the phrasing in linux-user/bsd-user/system help messages) * make linux-user and bsd-user defer to qemu-log for the default logging destination rather than overriding it themselves * ensure that all logfile closing is done via qemu_log_close() and that that function doesn't close stderr as well as the obvious change to the behaviour of do_qemu_set_log() when no logfile name has been specified. Signed-off-by: Peter Maydell Reviewed-by: Stefan Hajnoczi Reviewed-by: Markus Armbruster Message-id: 1361901160-28729-1-git-send-email-peter.maydell@linaro.org Signed-off-by: Anthony Liguori --- bsd-user/main.c | 18 ++++++++---------- hmp-commands.hx | 4 ++-- include/qemu/log.h | 8 ++++++-- linux-user/main.c | 16 +++++----------- qemu-doc.texi | 8 ++++---- qemu-log.c | 29 +++++++++++------------------ qemu-options.hx | 10 +++++----- tcg/tci/README | 2 +- 8 files changed, 42 insertions(+), 53 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 097fbfe432..cc8498187a 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -34,8 +34,6 @@ #include "qemu/timer.h" #include "qemu/envlist.h" -#define DEBUG_LOGFILE "/tmp/qemu.log" - int singlestep; #if defined(CONFIG_USE_GUEST_BASE) unsigned long mmap_min_addr; @@ -691,11 +689,12 @@ static void usage(void) "-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n" "\n" "Debug options:\n" - "-d options activate log (default logfile=%s)\n" - "-D logfile override default logfile location\n" - "-p pagesize set the host page size to 'pagesize'\n" - "-singlestep always run in singlestep mode\n" - "-strace log system calls\n" + "-d item1[,...] enable logging of specified items\n" + " (use '-d help' for a list of log items)\n" + "-D logfile write logs to 'logfile' (default stderr)\n" + "-p pagesize set the host page size to 'pagesize'\n" + "-singlestep always run in singlestep mode\n" + "-strace log system calls\n" "\n" "Environment variables:\n" "QEMU_STRACE Print system calls and arguments similar to the\n" @@ -709,8 +708,7 @@ static void usage(void) , TARGET_ARCH, interp_prefix, - x86_stack_size, - DEBUG_LOGFILE); + x86_stack_size); exit(1); } @@ -733,7 +731,7 @@ int main(int argc, char **argv) { const char *filename; const char *cpu_model; - const char *log_file = DEBUG_LOGFILE; + const char *log_file = NULL; const char *log_mask = NULL; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; diff --git a/hmp-commands.hx b/hmp-commands.hx index 64008a92d1..cef7708e3a 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -295,14 +295,14 @@ ETEXI .name = "log", .args_type = "items:s", .params = "item1[,...]", - .help = "activate logging of the specified items to '/tmp/qemu.log'", + .help = "activate logging of the specified items", .mhandler.cmd = do_log, }, STEXI @item log @var{item1}[,...] @findex log -Activate logging of the specified items to @file{/tmp/qemu.log}. +Activate logging of the specified items. ETEXI { diff --git a/include/qemu/log.h b/include/qemu/log.h index 452700329e..6b0db02efc 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -116,8 +116,12 @@ static inline void qemu_log_flush(void) /* Close the log file */ static inline void qemu_log_close(void) { - fclose(qemu_logfile); - qemu_logfile = NULL; + if (qemu_logfile) { + if (qemu_logfile != stderr) { + fclose(qemu_logfile); + } + qemu_logfile = NULL; + } } /* Set up a new log file */ diff --git a/linux-user/main.c b/linux-user/main.c index e51568430f..29845f9c81 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -35,8 +35,6 @@ #include "qemu/envlist.h" #include "elf.h" -#define DEBUG_LOGFILE "/tmp/qemu.log" - char *exec_path; int singlestep; @@ -3296,9 +3294,10 @@ static const struct qemu_argument arg_table[] = { "size", "reserve 'size' bytes for guest virtual address space"}, #endif {"d", "QEMU_LOG", true, handle_arg_log, - "options", "activate log"}, + "item[,...]", "enable logging of specified items " + "(use '-d help' for a list of items)"}, {"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename, - "logfile", "override default logfile location"}, + "logfile", "write logs to 'logfile' (default stderr)"}, {"p", "QEMU_PAGESIZE", true, handle_arg_pagesize, "pagesize", "set the host page size to 'pagesize'"}, {"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep, @@ -3351,11 +3350,9 @@ static void usage(void) printf("\n" "Defaults:\n" "QEMU_LD_PREFIX = %s\n" - "QEMU_STACK_SIZE = %ld byte\n" - "QEMU_LOG = %s\n", + "QEMU_STACK_SIZE = %ld byte\n", interp_prefix, - guest_stack_size, - DEBUG_LOGFILE); + guest_stack_size); printf("\n" "You can use -E and -U options or the QEMU_SET_ENV and\n" @@ -3439,7 +3436,6 @@ static int parse_args(int argc, char **argv) int main(int argc, char **argv, char **envp) { - const char *log_file = DEBUG_LOGFILE; struct target_pt_regs regs1, *regs = ®s1; struct image_info info1, *info = &info1; struct linux_binprm bprm; @@ -3482,8 +3478,6 @@ int main(int argc, char **argv, char **envp) cpudef_setup(); /* parse cpu definitions in target config file (TBD) */ #endif - /* init debug */ - qemu_set_log_filename(log_file); optind = parse_args(argc, argv); /* Zero out regs */ diff --git a/qemu-doc.texi b/qemu-doc.texi index 6d7f50d832..747e052fcb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2642,8 +2642,8 @@ Pre-allocate a guest virtual address space of the given size (in bytes). Debug options: @table @option -@item -d -Activate log (logfile=/tmp/qemu.log) +@item -d item1,... +Activate logging of the specified items (use '-d help' for a list of log items) @item -p pagesize Act as if the host page size was 'pagesize' bytes @item -g port @@ -2781,8 +2781,8 @@ FreeBSD, NetBSD and OpenBSD (default). Debug options: @table @option -@item -d -Activate log (logfile=/tmp/qemu.log) +@item -d item1,... +Activate logging of the specified items (use '-d help' for a list of log items) @item -p pagesize Act as if the host page size was 'pagesize' bytes @item -singlestep diff --git a/qemu-log.c b/qemu-log.c index 2f47aafd24..797f2af983 100644 --- a/qemu-log.c +++ b/qemu-log.c @@ -20,12 +20,6 @@ #include "qemu-common.h" #include "qemu/log.h" -#ifdef WIN32 -#define DEFAULT_LOGFILENAME "qemu.log" -#else -#define DEFAULT_LOGFILENAME "/tmp/qemu.log" -#endif - static char *logfilename; FILE *qemu_logfile; int qemu_loglevel; @@ -56,14 +50,17 @@ void qemu_log_mask(int mask, const char *fmt, ...) /* enable or disable low levels log */ void do_qemu_set_log(int log_flags, bool use_own_buffers) { - const char *fname = logfilename ?: DEFAULT_LOGFILENAME; - qemu_loglevel = log_flags; if (qemu_loglevel && !qemu_logfile) { - qemu_logfile = fopen(fname, log_append ? "a" : "w"); - if (!qemu_logfile) { - perror(fname); - _exit(1); + if (logfilename) { + qemu_logfile = fopen(logfilename, log_append ? "a" : "w"); + if (!qemu_logfile) { + perror(logfilename); + _exit(1); + } + } else { + /* Default to stderr if no log file specified */ + qemu_logfile = stderr; } /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ if (use_own_buffers) { @@ -81,8 +78,7 @@ void do_qemu_set_log(int log_flags, bool use_own_buffers) } } if (!qemu_loglevel && qemu_logfile) { - fclose(qemu_logfile); - qemu_logfile = NULL; + qemu_log_close(); } } @@ -90,10 +86,7 @@ void qemu_set_log_filename(const char *filename) { g_free(logfilename); logfilename = g_strdup(filename); - if (qemu_logfile) { - fclose(qemu_logfile); - qemu_logfile = NULL; - } + qemu_log_close(); qemu_set_log(qemu_loglevel); } diff --git a/qemu-options.hx b/qemu-options.hx index 51ff726490..797d992804 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2517,21 +2517,21 @@ Shorthand for -gdb tcp::1234, i.e. open a gdbserver on TCP port 1234 ETEXI DEF("d", HAS_ARG, QEMU_OPTION_d, \ - "-d item1,... output log to /tmp/qemu.log (use '-d help' for a list of log items)\n", + "-d item1,... enable logging of specified items (use '-d help' for a list of log items)\n", QEMU_ARCH_ALL) STEXI -@item -d +@item -d @var{item1}[,...] @findex -d -Output log in /tmp/qemu.log +Enable logging of specified items. Use '-d help' for a list of log items. ETEXI DEF("D", HAS_ARG, QEMU_OPTION_D, \ - "-D logfile output log to logfile (instead of the default /tmp/qemu.log)\n", + "-D logfile output log to logfile (default stderr)\n", QEMU_ARCH_ALL) STEXI @item -D @var{logfile} @findex -D -Output log in @var{logfile} instead of /tmp/qemu.log +Output log in @var{logfile} instead of to stderr ETEXI DEF("L", HAS_ARG, QEMU_OPTION_L, \ diff --git a/tcg/tci/README b/tcg/tci/README index 6ac1ac99d6..dc57f076b5 100644 --- a/tcg/tci/README +++ b/tcg/tci/README @@ -52,7 +52,7 @@ The only difference from running QEMU with TCI to running without TCI should be speed. Especially during development of TCI, it was very useful to compare runs with and without TCI. Create /tmp/qemu.log by - qemu-system-i386 -d in_asm,op_opt,cpu -singlestep + qemu-system-i386 -d in_asm,op_opt,cpu -D /tmp/qemu.log -singlestep once with interpreter and once without interpreter and compare the resulting qemu.log files. This is also useful to see the effects of additional From 31e76f65a98e1502cbfd362eed5768c48e264c23 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 26 Feb 2013 00:46:10 +0100 Subject: [PATCH 1288/1634] glib: Add compat wrapper for g_poll on old glib Older glib doesn't implement g_poll(). Most notably the glib version in use on SLE11 is on 2.18 which is hit by this. We do want to use g_poll() in the source however. So on older systems, just wrap it with functions that do exist on older versions. Signed-off-by: Anthony Liguori Signed-off-by: Alexander Graf Message-id: 1361835970-2889-1-git-send-email-agraf@suse.de Signed-off-by: Anthony Liguori --- include/qemu-common.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/qemu-common.h b/include/qemu-common.h index 80016adae3..5e137084b5 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -142,6 +142,18 @@ int qemu_main(int argc, char **argv, char **envp); void qemu_get_timedate(struct tm *tm, int offset); int qemu_timedate_diff(struct tm *tm); +#if !GLIB_CHECK_VERSION(2, 20, 0) +/* + * Glib before 2.20.0 doesn't implement g_poll, so wrap it to compile properly + * on older systems. + */ +static inline gint g_poll(GPollFD *fds, guint nfds, gint timeout) +{ + GMainContext *ctx = g_main_context_default(); + return g_main_context_get_poll_func(ctx)(fds, nfds, timeout); +} +#endif + /** * is_help_option: * @s: string to test From 6b37a23df98faa26391a93373930bfb15b943e00 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 21 Feb 2013 13:16:06 +0200 Subject: [PATCH 1289/1634] vhost: memory sync fixes This fixes two bugs related to memory sync during migration: - ram address calculation was missing the chunk address, so the wrong page was dirtied - one after last was used instead of the end address of a region, which might overflow to 0 and cause us to skip the region when the region ends at ~0x0ull. Signed-off-by: Michael S. Tsirkin Tested-by: Jason Wang --- hw/vhost.c | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/hw/vhost.c b/hw/vhost.c index 8d41fdb53f..37777c267e 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -53,10 +53,14 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, log = __sync_fetch_and_and(from, 0); while ((bit = sizeof(log) > sizeof(int) ? ffsll(log) : ffs(log))) { - ram_addr_t ram_addr; + hwaddr page_addr; + hwaddr section_offset; + hwaddr mr_offset; bit -= 1; - ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE; - memory_region_set_dirty(section->mr, ram_addr, VHOST_LOG_PAGE); + page_addr = addr + bit * VHOST_LOG_PAGE; + section_offset = page_addr - section->offset_within_address_space; + mr_offset = section_offset + section->offset_within_region; + memory_region_set_dirty(section->mr, mr_offset, VHOST_LOG_PAGE); log &= ~(0x1ull << bit); } addr += VHOST_LOG_CHUNK; @@ -65,14 +69,21 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, static int vhost_sync_dirty_bitmap(struct vhost_dev *dev, MemoryRegionSection *section, - hwaddr start_addr, - hwaddr end_addr) + hwaddr first, + hwaddr last) { int i; + hwaddr start_addr; + hwaddr end_addr; if (!dev->log_enabled || !dev->started) { return 0; } + start_addr = section->offset_within_address_space; + end_addr = range_get_last(start_addr, section->size); + start_addr = MAX(first, start_addr); + end_addr = MIN(last, end_addr); + for (i = 0; i < dev->mem->nregions; ++i) { struct vhost_memory_region *reg = dev->mem->regions + i; vhost_dev_sync_region(dev, section, start_addr, end_addr, @@ -93,10 +104,18 @@ static void vhost_log_sync(MemoryListener *listener, { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); - hwaddr start_addr = section->offset_within_address_space; - hwaddr end_addr = start_addr + section->size; + vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL); +} - vhost_sync_dirty_bitmap(dev, section, start_addr, end_addr); +static void vhost_log_sync_range(struct vhost_dev *dev, + hwaddr first, hwaddr last) +{ + int i; + /* FIXME: this is N^2 in number of sections */ + for (i = 0; i < dev->n_mem_sections; ++i) { + MemoryRegionSection *section = &dev->mem_sections[i]; + vhost_sync_dirty_bitmap(dev, section, first, last); + } } /* Assign/unassign. Keep an unsorted array of non-overlapping @@ -268,16 +287,15 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) { vhost_log_chunk_t *log; uint64_t log_base; - int r, i; + int r; log = g_malloc0(size * sizeof *log); log_base = (uint64_t)(unsigned long)log; r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base); assert(r >= 0); - for (i = 0; i < dev->n_mem_sections; ++i) { - /* Sync only the range covered by the old log */ - vhost_sync_dirty_bitmap(dev, &dev->mem_sections[i], 0, - dev->log_size * VHOST_LOG_CHUNK - 1); + /* Sync only the range covered by the old log */ + if (dev->log_size) { + vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1); } if (dev->log) { g_free(dev->log); @@ -1014,10 +1032,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->vqs + i, hdev->vq_index + i); } - for (i = 0; i < hdev->n_mem_sections; ++i) { - vhost_sync_dirty_bitmap(hdev, &hdev->mem_sections[i], - 0, (hwaddr)~0x0ull); - } + vhost_log_sync_range(hdev, 0, ~0x0ull); hdev->started = false; g_free(hdev->log); From 199ee608f0d08510b5c6c37f31a7fbff211d63c4 Mon Sep 17 00:00:00 2001 From: Luigi Rizzo Date: Tue, 5 Feb 2013 17:53:31 +0100 Subject: [PATCH 1290/1634] net: fix qemu_flush_queued_packets() in presence of a hub When frontend and backend are connected through a hub as below (showing only one direction), and the frontend (or in general, all output ports of the hub) cannot accept more traffic, the backend queues packets in queue-A. When the frontend (or in general, one output port) becomes ready again, quemu tries to flush packets from queue-B, which is unfortunately empty. e1000.0 <--[queue B]-- hub0port0(hub)hub0port1 <--[queue A]-- tap.0 To fix this i propose to introduce a new function net_hub_flush() which is called when trying to flush a queue connected to a hub. Signed-off-by: Luigi Rizzo Signed-off-by: Stefan Hajnoczi --- net/hub.c | 14 ++++++++++++++ net/hub.h | 1 + net/net.c | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/net/hub.c b/net/hub.c index a24c9d17f7..df32074de0 100644 --- a/net/hub.c +++ b/net/hub.c @@ -338,3 +338,17 @@ void net_hub_check_clients(void) } } } + +bool net_hub_flush(NetClientState *nc) +{ + NetHubPort *port; + NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc); + int ret = 0; + + QLIST_FOREACH(port, &source_port->hub->ports, next) { + if (port != source_port) { + ret += qemu_net_queue_flush(port->nc.send_queue); + } + } + return ret ? true : false; +} diff --git a/net/hub.h b/net/hub.h index 583ada89d8..a625effe00 100644 --- a/net/hub.h +++ b/net/hub.h @@ -21,5 +21,6 @@ NetClientState *net_hub_add_port(int hub_id, const char *name); NetClientState *net_hub_find_client_by_name(int hub_id, const char *name); void net_hub_info(Monitor *mon); void net_hub_check_clients(void); +bool net_hub_flush(NetClientState *nc); #endif /* NET_HUB_H */ diff --git a/net/net.c b/net/net.c index be03a8dd14..a66aa02472 100644 --- a/net/net.c +++ b/net/net.c @@ -441,6 +441,12 @@ void qemu_flush_queued_packets(NetClientState *nc) { nc->receive_disabled = 0; + if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { + if (net_hub_flush(nc->peer)) { + qemu_notify_event(); + } + return; + } if (qemu_net_queue_flush(nc->send_queue)) { /* We emptied the queue successfully, signal to the IO thread to repoll * the file descriptor (for tap, for example). From 7d91ddd25e3a4e5008a2ac16127d51a34fd56bf1 Mon Sep 17 00:00:00 2001 From: Luigi Rizzo Date: Tue, 5 Feb 2013 18:29:09 +0100 Subject: [PATCH 1291/1634] net: fix unbounded NetQueue In the current implementation of qemu, running without a network backend will cause the queue to grow unbounded when the guest is transmitting traffic. This patch fixes the problem by implementing bounded size NetQueue, used with an arbitrary limit of 10000 packets, and dropping packets when the queue is full _and_ the sender does not pass a callback. The second condition makes sure that we never drop packets that contains a callback (which would be tricky, because the producer expects the callback to be run when all previous packets have been consumed; so we cannot run it when the packet is dropped). If documentation is correct, producers that submit a callback should stop sending when their packet is queued, so there is no real risk that the queue exceeds the max size by large values. Signed-off-by: Luigi Rizzo Signed-off-by: Stefan Hajnoczi --- net/queue.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/net/queue.c b/net/queue.c index 6eaf5b63c0..859d02a136 100644 --- a/net/queue.c +++ b/net/queue.c @@ -50,6 +50,8 @@ struct NetPacket { struct NetQueue { void *opaque; + uint32_t nq_maxlen; + uint32_t nq_count; QTAILQ_HEAD(packets, NetPacket) packets; @@ -63,6 +65,8 @@ NetQueue *qemu_new_net_queue(void *opaque) queue = g_malloc0(sizeof(NetQueue)); queue->opaque = opaque; + queue->nq_maxlen = 10000; + queue->nq_count = 0; QTAILQ_INIT(&queue->packets); @@ -92,6 +96,9 @@ static void qemu_net_queue_append(NetQueue *queue, { NetPacket *packet; + if (queue->nq_count >= queue->nq_maxlen && !sent_cb) { + return; /* drop if queue full and no callback */ + } packet = g_malloc(sizeof(NetPacket) + size); packet->sender = sender; packet->flags = flags; @@ -99,6 +106,7 @@ static void qemu_net_queue_append(NetQueue *queue, packet->sent_cb = sent_cb; memcpy(packet->data, buf, size); + queue->nq_count++; QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); } @@ -113,6 +121,9 @@ static void qemu_net_queue_append_iov(NetQueue *queue, size_t max_len = 0; int i; + if (queue->nq_count >= queue->nq_maxlen && !sent_cb) { + return; /* drop if queue full and no callback */ + } for (i = 0; i < iovcnt; i++) { max_len += iov[i].iov_len; } @@ -130,6 +141,7 @@ static void qemu_net_queue_append_iov(NetQueue *queue, packet->size += len; } + queue->nq_count++; QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); } @@ -220,6 +232,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { if (packet->sender == from) { QTAILQ_REMOVE(&queue->packets, packet, entry); + queue->nq_count--; g_free(packet); } } @@ -233,6 +246,7 @@ bool qemu_net_queue_flush(NetQueue *queue) packet = QTAILQ_FIRST(&queue->packets); QTAILQ_REMOVE(&queue->packets, packet, entry); + queue->nq_count--; ret = qemu_net_queue_deliver(queue, packet->sender, @@ -240,6 +254,7 @@ bool qemu_net_queue_flush(NetQueue *queue) packet->data, packet->size); if (ret == 0) { + queue->nq_count++; QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); return false; } From ce675a7579fea498397c5d2da3c5367671e9f02a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 21 Feb 2013 11:05:56 +0800 Subject: [PATCH 1292/1634] tap: forbid creating multiqueue tap when hub is used Obviously, hub does not support multiqueue tap. So this patch forbids creating multiple queue tap when hub is used to prevent the crash when command line such as "-net tap,queues=2" is used. Cc: qemu-stable@nongnu.org Signed-off-by: Jason Wang Signed-off-by: Stefan Hajnoczi --- net/tap.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/tap.c b/net/tap.c index 48c254ed85..daab350efc 100644 --- a/net/tap.c +++ b/net/tap.c @@ -693,6 +693,13 @@ int net_init_tap(const NetClientOptions *opts, const char *name, queues = tap->has_queues ? tap->queues : 1; vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL; + /* QEMU vlans does not support multiqueue tap, in this case peer is set. + * For -netdev, peer is always NULL. */ + if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) { + error_report("Multiqueue tap cannnot be used with QEMU vlans"); + return -1; + } + if (tap->has_fd) { if (tap->has_ifname || tap->has_script || tap->has_downscript || tap->has_vnet_hdr || tap->has_helper || tap->has_queues || From d26e445c80fddcc7483b83f3115e5067fef28fe6 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Mon, 25 Feb 2013 10:17:08 +0100 Subject: [PATCH 1293/1634] tap: set IFF_ONE_QUEUE per default historically the kernel queues packets two times. once at the device and second in qdisc. this is believed to cause interface stalls if one of these queues overruns. setting IFF_ONE_QUEUE is the default in kernels >= 3.8. the flag is ignored since then. see kernel commit 5d097109257c03a71845729f8db6b5770c4bbedc Signed-off-by: Peter Lieven Acked-by: Michael S. Tsirkin Signed-off-by: Stefan Hajnoczi --- net/tap-linux.c | 10 ++++++---- net/tap-linux.h | 9 +++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/net/tap-linux.c b/net/tap-linux.c index a9531892a6..36c09e24d8 100644 --- a/net/tap-linux.c +++ b/net/tap-linux.c @@ -42,6 +42,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, struct ifreq ifr; int fd, ret; int len = sizeof(struct virtio_net_hdr); + unsigned int features; TFR(fd = open(PATH_NET_TUN, O_RDWR)); if (fd < 0) { @@ -51,9 +52,12 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (*vnet_hdr) { - unsigned int features; + if (ioctl(fd, TUNGETFEATURES, &features) == 0 && + features & IFF_ONE_QUEUE) { + ifr.ifr_flags |= IFF_ONE_QUEUE; + } + if (*vnet_hdr) { if (ioctl(fd, TUNGETFEATURES, &features) == 0 && features & IFF_VNET_HDR) { *vnet_hdr = 1; @@ -78,8 +82,6 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, } if (mq_required) { - unsigned int features; - if ((ioctl(fd, TUNGETFEATURES, &features) != 0) || !(features & IFF_MULTI_QUEUE)) { error_report("multiqueue required, but no kernel " diff --git a/net/tap-linux.h b/net/tap-linux.h index 65087e1419..1cf35d41bd 100644 --- a/net/tap-linux.h +++ b/net/tap-linux.h @@ -34,10 +34,11 @@ #endif /* TUNSETIFF ifr flags */ -#define IFF_TAP 0x0002 -#define IFF_NO_PI 0x1000 -#define IFF_VNET_HDR 0x4000 -#define IFF_MULTI_QUEUE 0x0100 +#define IFF_TAP 0x0002 +#define IFF_NO_PI 0x1000 +#define IFF_ONE_QUEUE 0x2000 +#define IFF_VNET_HDR 0x4000 +#define IFF_MULTI_QUEUE 0x0100 #define IFF_ATTACH_QUEUE 0x0200 #define IFF_DETACH_QUEUE 0x0400 From f6b26cf257232e5854c0e5c98a8685c625bf986e Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 22 Feb 2013 23:15:06 +0800 Subject: [PATCH 1294/1634] net: reduce the unnecessary memory allocation of multiqueue Edivaldo reports a problem that the array of NetClientState in NICState is too large - MAX_QUEUE_NUM(1024) which will wastes memory even if multiqueue is not used. Instead of static arrays, solving this issue by allocating the queues on demand for both the NetClientState array in NICState and VirtIONetQueue array in VirtIONet. Tested by myself, with single virtio-net-pci device. The memory allocation is almost the same as when multiqueue is not merged. Cc: Edivaldo de Araujo Pereira Cc: qemu-stable@nongnu.org Signed-off-by: Jason Wang Signed-off-by: Stefan Hajnoczi --- hw/virtio-net.c | 6 ++++-- include/net/net.h | 2 +- net/net.c | 19 +++++++++---------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 573c669d15..bb2c26c483 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -44,7 +44,7 @@ typedef struct VirtIONet VirtIODevice vdev; uint8_t mac[ETH_ALEN]; uint16_t status; - VirtIONetQueue vqs[MAX_QUEUE_NUM]; + VirtIONetQueue *vqs; VirtQueue *ctrl_vq; NICState *nic; uint32_t tx_timeout; @@ -1326,8 +1326,9 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->vdev.set_status = virtio_net_set_status; n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask; n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending; + n->max_queues = MAX(conf->queues, 1); + n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues); n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); - n->max_queues = conf->queues; n->curr_queues = 1; n->vqs[0].n = n; n->tx_timeout = net->txtimer; @@ -1412,6 +1413,7 @@ void virtio_net_exit(VirtIODevice *vdev) } } + g_free(n->vqs); qemu_del_nic(n->nic); virtio_cleanup(&n->vdev); } diff --git a/include/net/net.h b/include/net/net.h index 43a045e052..cb049a16a3 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -72,7 +72,7 @@ struct NetClientState { }; typedef struct NICState { - NetClientState ncs[MAX_QUEUE_NUM]; + NetClientState *ncs; NICConf *conf; void *opaque; bool peer_deleted; diff --git a/net/net.c b/net/net.c index a66aa02472..f3d67f8322 100644 --- a/net/net.c +++ b/net/net.c @@ -235,23 +235,20 @@ NICState *qemu_new_nic(NetClientInfo *info, const char *name, void *opaque) { - NetClientState *nc; NetClientState **peers = conf->peers.ncs; NICState *nic; - int i; + int i, queues = MAX(1, conf->queues); assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC); assert(info->size >= sizeof(NICState)); - nc = qemu_new_net_client(info, peers[0], model, name); - nc->queue_index = 0; - - nic = qemu_get_nic(nc); + nic = g_malloc0(info->size + sizeof(NetClientState) * queues); + nic->ncs = (void *)nic + info->size; nic->conf = conf; nic->opaque = opaque; - for (i = 1; i < conf->queues; i++) { - qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, nc->name, + for (i = 0; i < queues; i++) { + qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, NULL); nic->ncs[i].queue_index = i; } @@ -261,7 +258,7 @@ NICState *qemu_new_nic(NetClientInfo *info, NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) { - return &nic->ncs[queue_index]; + return nic->ncs + queue_index; } NetClientState *qemu_get_queue(NICState *nic) @@ -273,7 +270,7 @@ NICState *qemu_get_nic(NetClientState *nc) { NetClientState *nc0 = nc - nc->queue_index; - return DO_UPCAST(NICState, ncs[0], nc0); + return (NICState *)((void *)nc0 - nc->info->size); } void *qemu_get_nic_opaque(NetClientState *nc) @@ -368,6 +365,8 @@ void qemu_del_nic(NICState *nic) qemu_cleanup_net_client(nc); qemu_free_net_client(nc); } + + g_free(nic); } void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) From 40e8c26d7b7e260cc3566c6b68cee969e816970e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 26 Feb 2013 11:07:16 +0100 Subject: [PATCH 1295/1634] doc: document -netdev hubport Reviewed-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- hmp-commands.hx | 2 +- qemu-options.hx | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index cef7708e3a..69c707d332 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1169,7 +1169,7 @@ ETEXI { .name = "netdev_add", .args_type = "netdev:O", - .params = "[user|tap|socket],id=str[,prop=value][,...]", + .params = "[user|tap|socket|hubport],id=str[,prop=value][,...]", .help = "add host network device", .mhandler.cmd = hmp_netdev_add, }, diff --git a/qemu-options.hx b/qemu-options.hx index 797d992804..863069f293 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1408,7 +1408,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, #ifdef CONFIG_VDE "vde|" #endif - "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL) + "socket|" + "hubport],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL) STEXI @item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}] @findex -net @@ -1730,6 +1731,14 @@ vde_switch -F -sock /tmp/myswitch qemu-system-i386 linux.img -net nic -net vde,sock=/tmp/myswitch @end example +@item -netdev hubport,id=@var{id},hubid=@var{hubid} + +Create a hub port on QEMU "vlan" @var{hubid}. + +The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single +netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the +required hub automatically. + @item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}] Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default). At most @var{len} bytes (64k by default) per packet are stored. The file format is From af347aa5a521555f5342e67993eb717d4f542ba8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 22 Feb 2013 18:31:51 +0100 Subject: [PATCH 1296/1634] qmp: netdev_add is like -netdev, not -net, fix documentation Cc: qemu-stable@nongnu.org Signed-off-by: Markus Armbruster Reviewed-by: Laszlo Ersek Signed-off-by: Stefan Hajnoczi --- qmp-commands.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmp-commands.hx b/qmp-commands.hx index 799adea1b7..95022e259f 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -822,7 +822,7 @@ Example: -> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } } <- { "return": {} } -Note: The supported device options are the same ones supported by the '-net' +Note: The supported device options are the same ones supported by the '-netdev' command-line argument, which are listed in the '-help' output or QEMU's manual From 2af234e61d59f39ae16ba882271e7c4fef2c41c1 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 14 Feb 2013 19:11:27 +0200 Subject: [PATCH 1297/1634] e1000: unbreak the guest network migration to 1.3 QEMU 1.3 does not emulate the link auto negotiation, so if migrate to a 1.3 machine during link auto negotiation, the guest link will be set to down. Fix this by just disabling auto negotiation for 1.3 and older. Signed-off-by: Michael S. Tsirkin --- hw/e1000.c | 25 +++++++++++++++++++++++++ hw/pc_piix.c | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/hw/e1000.c b/hw/e1000.c index d6fe815eda..45cc3300cf 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -131,6 +131,11 @@ typedef struct E1000State_st { } eecd_state; QEMUTimer *autoneg_timer; + +/* Compatibility flags for migration to/from qemu 1.3.0 and older */ +#define E1000_FLAG_AUTONEG_BIT 0 +#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT) + uint32_t compat_flags; } E1000State; #define defreg(x) x = (E1000_##x>>2) @@ -165,6 +170,14 @@ e1000_link_up(E1000State *s) static void set_phy_ctrl(E1000State *s, int index, uint16_t val) { + /* + * QEMU 1.3 does not support link auto-negotiation emulation, so if we + * migrate during auto negotiation, after migration the link will be + * down. + */ + if (!(s->compat_flags & E1000_FLAG_AUTONEG)) { + return; + } if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { e1000_link_down(s); s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; @@ -1120,6 +1133,11 @@ static void e1000_pre_save(void *opaque) { E1000State *s = opaque; NetClientState *nc = qemu_get_queue(s->nic); + + if (!(s->compat_flags & E1000_FLAG_AUTONEG)) { + return; + } + /* * If link is down and auto-negotiation is ongoing, complete * auto-negotiation immediately. This allows is to look at @@ -1141,6 +1159,11 @@ static int e1000_post_load(void *opaque, int version_id) * to link status bit in mac_reg[STATUS]. * Alternatively, restart link negotiation if it was in progress. */ nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0; + + if (!(s->compat_flags & E1000_FLAG_AUTONEG)) { + return 0; + } + if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN && s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG && !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) { @@ -1343,6 +1366,8 @@ static void qdev_e1000_reset(DeviceState *dev) static Property e1000_properties[] = { DEFINE_NIC_PROPERTIES(E1000State, conf), + DEFINE_PROP_BIT("autonegotiation", E1000State, + compat_flags, E1000_FLAG_AUTONEG_BIT, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/pc_piix.c b/hw/pc_piix.c index aa9cc81a2d..a305e1fb77 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -330,6 +330,10 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { .driver = "virtio-net-pci", \ .property = "mq", \ .value = "off", \ + }, {\ + .driver = "e1000",\ + .property = "autonegotiation",\ + .value = "off",\ } static QEMUMachine pc_machine_v1_3 = { From 7feb640cf32d86f91f5a624136345eb6a63eab42 Mon Sep 17 00:00:00 2001 From: Alexey Korolev Date: Fri, 22 Feb 2013 16:58:44 +1300 Subject: [PATCH 1298/1634] Fix guest OS hang when 64bit PCI bar present This patch addresses the issue fully described here: http://lists.nongnu.org/archive/html/qemu-devel/2013-02/msg01804.html Linux kernels prior to 2.6.36 do not disable the PCI device during enumeration process. Since lower and higher parts of a 64bit BAR are programmed separately this leads to qemu receiving a request to occupy a completely wrong address region for a short period of time. We have found that the boot process screws up completely if kvm-apic range is overlapped even for a short period of time (it is fine for other regions though). This patch raises the priority of the kvm-apic memory region, so it is never pushed out by PCI devices. The patch is quite safe as it does not touch memory manager. Signed-off-by: Alexey Korolev Signed-off-by: Michael S. Tsirkin --- hw/sysbus.c | 27 +++++++++++++++++++++++---- hw/sysbus.h | 2 ++ target-i386/cpu.c | 3 ++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/hw/sysbus.c b/hw/sysbus.c index 6d9d1df419..50c7232799 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -48,7 +48,8 @@ void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) } } -void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) +static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr, + bool may_overlap, unsigned priority) { assert(n >= 0 && n < dev->num_mmio); @@ -61,11 +62,29 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory); } dev->mmio[n].addr = addr; - memory_region_add_subregion(get_system_memory(), - addr, - dev->mmio[n].memory); + if (may_overlap) { + memory_region_add_subregion_overlap(get_system_memory(), + addr, + dev->mmio[n].memory, + priority); + } + else { + memory_region_add_subregion(get_system_memory(), + addr, + dev->mmio[n].memory); + } } +void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr) +{ + sysbus_mmio_map_common(dev, n, addr, false, 0); +} + +void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr, + unsigned priority) +{ + sysbus_mmio_map_common(dev, n, addr, true, priority); +} /* Request an IRQ source. The actual IRQ object may be populated later. */ void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p) diff --git a/hw/sysbus.h b/hw/sysbus.h index a7fcded6e7..2100bd7d07 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -56,6 +56,8 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size); void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq); void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr); +void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr, + unsigned priority); void sysbus_add_memory(SysBusDevice *dev, hwaddr addr, MemoryRegion *mem); void sysbus_add_memory_overlap(SysBusDevice *dev, hwaddr addr, diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 5582e5f4e6..8fb736a5b4 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2088,7 +2088,8 @@ static void x86_cpu_apic_init(X86CPU *cpu, Error **errp) /* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ /* XXX: what if the base changes? */ - sysbus_mmio_map(SYS_BUS_DEVICE(env->apic_state), 0, MSI_ADDR_BASE); + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(env->apic_state), 0, + MSI_ADDR_BASE, 0x1000); apic_mapped = 1; } } From 0e98b436eceb9d31caad898f4983a369c76524e0 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 20 Feb 2013 02:51:24 +0100 Subject: [PATCH 1299/1634] ICH9 LPC: Reset Control Register, basic implementation This commit does the same for the ICH9 LPC as commit 1ec4ba74 for the PIIX3. For the present we're ignoring the Full Reset (FULL_RST) and System Reset (SYS_RST) bits; the guest can read them back but that's it. Signed-off-by: Laszlo Ersek Signed-off-by: Michael S. Tsirkin --- hw/ich9.h | 11 ++++++++++ hw/lpc_ich9.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/hw/ich9.h b/hw/ich9.h index d4509bb606..dbc44957b4 100644 --- a/hw/ich9.h +++ b/hw/ich9.h @@ -49,6 +49,15 @@ typedef struct ICH9LPCState { /* 10.1 Chipset Configuration registers(Memory Space) which is pointed by RCBA */ uint8_t chip_config[ICH9_CC_SIZE]; + + /* + * 13.7.5 RST_CNT---Reset Control Register (LPC I/F---D31:F0) + * + * register contents and IO memory region + */ + uint8_t rst_cnt; + MemoryRegion rst_cnt_mem; + /* isa bus */ ISABus *isa_bus; MemoryRegion rbca_mem; @@ -103,6 +112,8 @@ typedef struct ICH9LPCState { #define ICH9_D2P_A2_REVISION 0x92 +/* D31:F0 LPC Processor Interface */ +#define ICH9_RST_CNT_IOPORT 0xCF9 /* D31:F1 LPC controller */ #define ICH9_A2_LPC "ICH9 A2 LPC" diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index e25689bf87..eceb052420 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -466,6 +466,7 @@ static void ich9_lpc_reset(DeviceState *qdev) ich9_lpc_rcba_update(lpc, rbca_old); lpc->sci_level = 0; + lpc->rst_cnt = 0; } static const MemoryRegionOps rbca_mmio_ops = { @@ -498,6 +499,32 @@ static void ich9_lpc_machine_ready(Notifier *n, void *opaque) } } +/* reset control */ +static void ich9_rst_cnt_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) +{ + ICH9LPCState *lpc = opaque; + + if (val & 4) { + qemu_system_reset_request(); + return; + } + lpc->rst_cnt = val & 0xA; /* keep FULL_RST (bit 3) and SYS_RST (bit 1) */ +} + +static uint64_t ich9_rst_cnt_read(void *opaque, hwaddr addr, unsigned len) +{ + ICH9LPCState *lpc = opaque; + + return lpc->rst_cnt; +} + +static const MemoryRegionOps ich9_rst_cnt_ops = { + .read = ich9_rst_cnt_read, + .write = ich9_rst_cnt_write, + .endianness = DEVICE_LITTLE_ENDIAN +}; + static int ich9_lpc_initfn(PCIDevice *d) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); @@ -519,9 +546,32 @@ static int ich9_lpc_initfn(PCIDevice *d) lpc->machine_ready.notify = ich9_lpc_machine_ready; qemu_add_machine_init_done_notifier(&lpc->machine_ready); + memory_region_init_io(&lpc->rst_cnt_mem, &ich9_rst_cnt_ops, lpc, + "lpc-reset-control", 1); + memory_region_add_subregion_overlap(pci_address_space_io(d), + ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem, + 1); + return 0; } +static bool ich9_rst_cnt_needed(void *opaque) +{ + ICH9LPCState *lpc = opaque; + + return (lpc->rst_cnt != 0); +} + +static const VMStateDescription vmstate_ich9_rst_cnt = { + .name = "ICH9LPC/rst_cnt", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(rst_cnt, ICH9LPCState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_ich9_lpc = { .name = "ICH9LPC", .version_id = 1, @@ -535,6 +585,13 @@ static const VMStateDescription vmstate_ich9_lpc = { VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE), VMSTATE_UINT32(sci_level, ICH9LPCState), VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection[]) { + { + .vmsd = &vmstate_ich9_rst_cnt, + .needed = ich9_rst_cnt_needed + }, + { 0 } } }; From 554f1997f0328bc259454239db64b20b3376d9a6 Mon Sep 17 00:00:00 2001 From: Gal Hammer Date: Wed, 27 Feb 2013 15:15:31 +0200 Subject: [PATCH 1300/1634] Set virtio-serial device to have a default of 2 MSI vectors. The virtio-serial device is expected to use 2 MSI vectors, one for control queue and a second shared for all queues. Signed-off-by: Gal Hammer Signed-off-by: Michael S. Tsirkin --- hw/pc.h | 5 +++++ hw/virtio-pci.c | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/pc.h b/hw/pc.h index da1b102ef1..f2c1b1c2a4 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -216,6 +216,11 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); .driver = "virtio-blk-pci",\ .property = "discard_granularity",\ .value = stringify(0),\ + },{\ + .driver = "virtio-serial-pci",\ + .property = "vectors",\ + /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\ + .value = stringify(0xFFFFFFFF),\ } #endif diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index a869f535de..ba56ab2d77 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -975,6 +975,9 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev) if (!vdev) { return -1; } + + /* backwards-compatibility with machines that were created with + DEV_NVECTORS_UNSPECIFIED */ vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED ? proxy->serial.max_virtserial_ports + 1 : proxy->nvectors; @@ -1155,7 +1158,7 @@ static const TypeInfo virtio_net_info = { static Property virtio_serial_properties[] = { DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31), From a4bcea3d67949c6be45992bd5092a19f163bcd4e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 26 Feb 2013 12:06:23 -0800 Subject: [PATCH 1301/1634] target-i386: Use mulu2 and muls2 These correspond very closely to the insns that we're emulating. Signed-off-by: Richard Henderson Signed-off-by: Blue Swirl --- target-i386/helper.h | 4 - target-i386/int_helper.c | 40 ---------- target-i386/translate.c | 167 +++++++++++++-------------------------- 3 files changed, 56 insertions(+), 155 deletions(-) diff --git a/target-i386/helper.h b/target-i386/helper.h index 26a0cc80a4..d6974dfd6b 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -14,12 +14,8 @@ DEF_HELPER_2(idivw_AX, void, env, tl) DEF_HELPER_2(divl_EAX, void, env, tl) DEF_HELPER_2(idivl_EAX, void, env, tl) #ifdef TARGET_X86_64 -DEF_HELPER_2(mulq_EAX_T0, void, env, tl) -DEF_HELPER_2(imulq_EAX_T0, void, env, tl) -DEF_HELPER_3(imulq_T0_T1, tl, env, tl, tl) DEF_HELPER_2(divq_EAX, void, env, tl) DEF_HELPER_2(idivq_EAX, void, env, tl) -DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, tl, tl, tl) #endif DEF_HELPER_2(aam, void, env, int) diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c index 3b56075a9d..74c7c36124 100644 --- a/target-i386/int_helper.c +++ b/target-i386/int_helper.c @@ -374,46 +374,6 @@ static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) return 0; } -void helper_mulq_EAX_T0(CPUX86State *env, target_ulong t0) -{ - uint64_t r0, r1; - - mulu64(&r0, &r1, EAX, t0); - EAX = r0; - EDX = r1; - CC_DST = r0; - CC_SRC = r1; -} - -target_ulong helper_umulh(target_ulong t0, target_ulong t1) -{ - uint64_t h, l; - mulu64(&l, &h, t0, t1); - return h; -} - -void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0) -{ - uint64_t r0, r1; - - muls64(&r0, &r1, EAX, t0); - EAX = r0; - EDX = r1; - CC_DST = r0; - CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); -} - -target_ulong helper_imulq_T0_T1(CPUX86State *env, target_ulong t0, - target_ulong t1) -{ - uint64_t r0, r1; - - muls64(&r0, &r1, t0, t1); - CC_DST = r0; - CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); - return r0; -} - void helper_divq_EAX(CPUX86State *env, target_ulong t0) { uint64_t r0, r1; diff --git a/target-i386/translate.c b/target-i386/translate.c index 605cd88bd2..3b92f3b227 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4111,31 +4111,18 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, ot = s->dflag == 2 ? OT_QUAD : OT_LONG; gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); switch (ot) { - TCGv_i64 t0, t1; default: - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); -#ifdef TARGET_X86_64 - tcg_gen_ext32u_i64(t0, cpu_T[0]); - tcg_gen_ext32u_i64(t1, cpu_regs[R_EDX]); -#else - tcg_gen_extu_i32_i64(t0, cpu_T[0]); - tcg_gen_extu_i32_i64(t0, cpu_regs[R_EDX]); -#endif - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_trunc_i64_tl(cpu_T[0], t0); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_tl(cpu_T[1], t0); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - gen_op_mov_reg_T0(OT_LONG, s->vex_v); - gen_op_mov_reg_T1(OT_LONG, reg); + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_regs[R_EDX]); + tcg_gen_mulu2_i32(cpu_tmp2_i32, cpu_tmp3_i32, + cpu_tmp2_i32, cpu_tmp3_i32); + tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_regs[reg], cpu_tmp3_i32); break; #ifdef TARGET_X86_64 case OT_QUAD: - tcg_gen_mov_tl(cpu_T[1], cpu_regs[R_EDX]); - tcg_gen_mul_tl(cpu_regs[s->vex_v], cpu_T[0], cpu_T[1]); - gen_helper_umulh(cpu_regs[reg], cpu_T[0], cpu_T[1]); + tcg_gen_mulu2_i64(cpu_regs[s->vex_v], cpu_regs[reg], + cpu_T[0], cpu_regs[R_EDX]); break; #endif } @@ -5032,39 +5019,22 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, break; default: case OT_LONG: -#ifdef TARGET_X86_64 - gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); - tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]); - tcg_gen_ext32u_tl(cpu_T[1], cpu_T[1]); - tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); - gen_op_mov_reg_T0(OT_LONG, R_EAX); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32); - gen_op_mov_reg_T0(OT_LONG, R_EDX); - tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); -#else - { - TCGv_i64 t0, t1; - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); - tcg_gen_extu_i32_i64(t0, cpu_T[0]); - tcg_gen_extu_i32_i64(t1, cpu_T[1]); - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_trunc_i64_i32(cpu_T[0], t0); - gen_op_mov_reg_T0(OT_LONG, R_EAX); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(cpu_T[0], t0); - gen_op_mov_reg_T0(OT_LONG, R_EDX); - tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]); - } -#endif + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_regs[R_EAX]); + tcg_gen_mulu2_i32(cpu_tmp2_i32, cpu_tmp3_i32, + cpu_tmp2_i32, cpu_tmp3_i32); + tcg_gen_extu_i32_tl(cpu_regs[R_EAX], cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_regs[R_EDX], cpu_tmp3_i32); + tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]); + tcg_gen_mov_tl(cpu_cc_src, cpu_regs[R_EDX]); set_cc_op(s, CC_OP_MULL); break; #ifdef TARGET_X86_64 case OT_QUAD: - gen_helper_mulq_EAX_T0(cpu_env, cpu_T[0]); + tcg_gen_mulu2_i64(cpu_regs[R_EAX], cpu_regs[R_EDX], + cpu_T[0], cpu_regs[R_EAX]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]); + tcg_gen_mov_tl(cpu_cc_src, cpu_regs[R_EDX]); set_cc_op(s, CC_OP_MULQ); break; #endif @@ -5100,41 +5070,25 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, break; default: case OT_LONG: -#ifdef TARGET_X86_64 - gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); - tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); - tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]); - tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); - gen_op_mov_reg_T0(OT_LONG, R_EAX); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]); - tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); - tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32); - gen_op_mov_reg_T0(OT_LONG, R_EDX); -#else - { - TCGv_i64 t0, t1; - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - gen_op_mov_TN_reg(OT_LONG, 1, R_EAX); - tcg_gen_ext_i32_i64(t0, cpu_T[0]); - tcg_gen_ext_i32_i64(t1, cpu_T[1]); - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_trunc_i64_i32(cpu_T[0], t0); - gen_op_mov_reg_T0(OT_LONG, R_EAX); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(cpu_T[0], t0); - gen_op_mov_reg_T0(OT_LONG, R_EDX); - tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); - } -#endif + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_regs[R_EAX]); + tcg_gen_muls2_i32(cpu_tmp2_i32, cpu_tmp3_i32, + cpu_tmp2_i32, cpu_tmp3_i32); + tcg_gen_extu_i32_tl(cpu_regs[R_EAX], cpu_tmp2_i32); + tcg_gen_extu_i32_tl(cpu_regs[R_EDX], cpu_tmp3_i32); + tcg_gen_sari_i32(cpu_tmp2_i32, cpu_tmp2_i32, 31); + tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]); + tcg_gen_sub_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32); + tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32); set_cc_op(s, CC_OP_MULL); break; #ifdef TARGET_X86_64 case OT_QUAD: - gen_helper_imulq_EAX_T0(cpu_env, cpu_T[0]); + tcg_gen_muls2_i64(cpu_regs[R_EAX], cpu_regs[R_EDX], + cpu_T[0], cpu_regs[R_EAX]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]); + tcg_gen_sari_tl(cpu_cc_src, cpu_regs[R_EAX], 63); + tcg_gen_sub_tl(cpu_cc_src, cpu_cc_src, cpu_regs[R_EDX]); set_cc_op(s, CC_OP_MULQ); break; #endif @@ -5389,37 +5343,27 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, } else { gen_op_mov_TN_reg(ot, 1, reg); } - + switch (ot) { #ifdef TARGET_X86_64 - if (ot == OT_QUAD) { - gen_helper_imulq_T0_T1(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); - } else + case OT_QUAD: + tcg_gen_muls2_i64(cpu_regs[reg], cpu_T[1], cpu_T[0], cpu_T[1]); + tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[reg]); + tcg_gen_sari_tl(cpu_cc_src, cpu_cc_dst, 63); + tcg_gen_sub_tl(cpu_cc_src, cpu_cc_src, cpu_T[1]); + break; #endif - if (ot == OT_LONG) { -#ifdef TARGET_X86_64 - tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]); - tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]); - tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]); - tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); -#else - { - TCGv_i64 t0, t1; - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(t0, cpu_T[0]); - tcg_gen_ext_i32_i64(t1, cpu_T[1]); - tcg_gen_mul_i64(t0, t0, t1); - tcg_gen_trunc_i64_i32(cpu_T[0], t0); - tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); - tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31); - tcg_gen_shri_i64(t0, t0, 32); - tcg_gen_trunc_i64_i32(cpu_T[1], t0); - tcg_gen_sub_tl(cpu_cc_src, cpu_T[1], cpu_tmp0); - } -#endif - } else { + case OT_LONG: + tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); + tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]); + tcg_gen_muls2_i32(cpu_tmp2_i32, cpu_tmp3_i32, + cpu_tmp2_i32, cpu_tmp3_i32); + tcg_gen_extu_i32_tl(cpu_regs[reg], cpu_tmp2_i32); + tcg_gen_sari_i32(cpu_tmp2_i32, cpu_tmp2_i32, 31); + tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[reg]); + tcg_gen_sub_i32(cpu_tmp2_i32, cpu_tmp2_i32, cpu_tmp3_i32); + tcg_gen_extu_i32_tl(cpu_cc_src, cpu_tmp2_i32); + break; + default: tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]); tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]); /* XXX: use 32 bit mul which could be faster */ @@ -5427,8 +5371,9 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]); tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]); tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0); + gen_op_mov_reg_T0(ot, reg); + break; } - gen_op_mov_reg_T0(ot, reg); set_cc_op(s, CC_OP_MULB + ot); break; case 0x1c0: From 5c75fb10029c5fd1e705a6ef5d698fbea06c7a33 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Feb 2013 09:18:56 +0100 Subject: [PATCH 1302/1634] update seabios to 1.7.2.1 Alex Williamson (3): seabios q35: Enable all PIRQn IRQs at startup seabios q35: Add new PCI slot to irq routing function seabios: Add a dummy PCI slot to irq mapping function Avik Sil (1): USB-EHCI: Fix null pointer assignment Kevin O'Connor (4): Update tools/acpi_extract.py to handle iasl 20130117 release. Fix Makefile - don't reference "out/" directly, instead use "$(OUT)". build: Don't require $(OUT) to be a sub-directory of the main directory. Verify CC is valid during build tests. Signed-off-by: Gerd Hoffmann --- pc-bios/bios.bin | Bin 131072 -> 131072 bytes roms/seabios | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin index ab5dd9db6addf9d6a6f67697231ef604bab02fc8..ec9eeb12c62a511f2e45bfc6fe3af90cc6da0d65 100644 GIT binary patch delta 27073 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%0AnXIG#S6j| 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 diff --git a/roms/seabios b/roms/seabios index 4bd8aebf35..88cb66ea54 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit 4bd8aebf3534e10d9aa21e820903f2cf9120708c +Subproject commit 88cb66ea542906ffff8a80ef397b9e3adbb33116 From 5c78d6a84b504e831adc8f1917cde0c79061dff0 Mon Sep 17 00:00:00 2001 From: Antoine Mathys Date: Thu, 28 Feb 2013 18:23:12 +0000 Subject: [PATCH 1303/1634] hw/ds1338: Fix conversion between 12 hours and 24 hours modes. The proper mapping between 24 hours and 12 hours modes is: 0 12 AM 1-11 1-11 AM 12 12 PM 13-23 1-11 PM Fix code accordingly. Signed-off-by: Antoine Mathys Signed-off-by: Peter Maydell --- hw/ds1338.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ds1338.c b/hw/ds1338.c index 6f70538eb3..1da0f96fdc 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -59,8 +59,8 @@ static void capture_current_time(DS1338State *s) s->nvram[1] = to_bcd(now.tm_min); if (s->nvram[2] & HOURS_12) { int tmp = now.tm_hour; - if (tmp == 0) { - tmp = 24; + if (tmp % 12 == 0) { + tmp += 12; } if (tmp <= 12) { s->nvram[2] = HOURS_12 | to_bcd(tmp); @@ -145,8 +145,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data) if (data & HOURS_PM) { tmp += 12; } - if (tmp == 24) { - tmp = 0; + if (tmp % 12 == 0) { + tmp -= 12; } now.tm_hour = tmp; } else { From 6e392787c85809671033ec419d8e8ecf684d55da Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Feb 2013 18:23:12 +0000 Subject: [PATCH 1304/1634] hw/pflash_cfi01: Make read after byte-write or erase return status The Intel flash command set requires that a read operation after doing a 'single byte write' command returns the status register; add this case to pflash_read() so we return the correct information. Similarly, the case for the 0x28 flavour of block erase was missing. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Tested-by: Peter Crosthwaite Message-id: 1358777318-7579-2-git-send-email-peter.maydell@linaro.org --- hw/pflash_cfi01.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 9e6ff52336..c79e5995c2 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -162,7 +162,10 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, } break; + case 0x10: /* Single byte program */ case 0x20: /* Block erase */ + case 0x28: /* Block erase */ + case 0x40: /* single byte program */ case 0x50: /* Clear status register */ case 0x60: /* Block /un)lock */ case 0x70: /* Status Register */ From 1be97bf22447088adebf23b1ca508d4bb00f853c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Feb 2013 18:23:12 +0000 Subject: [PATCH 1305/1634] hw/pflash_cfi01: Treat read in unknown command state as read The code for handling the default "unknown command state" case in pflash_read in pflash_cfi01.c comments "reset state & treat it as a read". However the code doesn't actually do this. Moving the default case to the top of the switch so it can fall through into the read case brings this file into line with pflash_cfi02 and makes the code behave as the comments suggest. The pflash_cfi01 code has always had this bug -- it was presumably introduced when the original author copied the cfi02 code and rearranged the order of the switch statement without noticing that the default case relied on the fall-through. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Tested-by: Peter Crosthwaite Message-id: 1358777318-7579-3-git-send-email-peter.maydell@linaro.org --- hw/pflash_cfi01.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index c79e5995c2..123b00653a 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -122,6 +122,12 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, __func__, offset, pfl->cmd, width); #endif switch (pfl->cmd) { + default: + /* This should never happen : reset state & treat it as a read */ + DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); + pfl->wcycle = 0; + pfl->cmd = 0; + /* fall through to read code */ case 0x00: /* Flash area read */ p = pfl->storage; @@ -197,11 +203,6 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, else ret = pfl->cfi_table[boff]; break; - default: - /* This should never happen : reset state & treat it as a read */ - DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); - pfl->wcycle = 0; - pfl->cmd = 0; } return ret; } From c6205ddf6cff202ac0ce6621987cd3de8b57adee Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:13 +0000 Subject: [PATCH 1306/1634] arm: mptimer: CamelCased type names Trivial find replace on type names "timerblock" and "arm_mptimer_state" to conform with QEMU coding style. Signed-off-by: Peter Crosthwaite Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm_mptimer.c | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 32817d3814..de0ef3658e 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -38,16 +38,16 @@ typedef struct { QEMUTimer *timer; qemu_irq irq; MemoryRegion iomem; -} timerblock; +} TimerBlock; typedef struct { SysBusDevice busdev; uint32_t num_cpu; - timerblock timerblock[MAX_CPUS * 2]; + TimerBlock timerblock[MAX_CPUS * 2]; MemoryRegion iomem[2]; -} arm_mptimer_state; +} ARMMPTimerState; -static inline int get_current_cpu(arm_mptimer_state *s) +static inline int get_current_cpu(ARMMPTimerState *s) { CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env); @@ -58,18 +58,18 @@ static inline int get_current_cpu(arm_mptimer_state *s) return cpu_single_cpu->cpu_index; } -static inline void timerblock_update_irq(timerblock *tb) +static inline void timerblock_update_irq(TimerBlock *tb) { qemu_set_irq(tb->irq, tb->status); } /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */ -static inline uint32_t timerblock_scale(timerblock *tb) +static inline uint32_t timerblock_scale(TimerBlock *tb) { return (((tb->control >> 8) & 0xff) + 1) * 10; } -static void timerblock_reload(timerblock *tb, int restart) +static void timerblock_reload(TimerBlock *tb, int restart) { if (tb->count == 0) { return; @@ -83,7 +83,7 @@ static void timerblock_reload(timerblock *tb, int restart) static void timerblock_tick(void *opaque) { - timerblock *tb = (timerblock *)opaque; + TimerBlock *tb = (TimerBlock *)opaque; tb->status = 1; if (tb->control & 2) { tb->count = tb->load; @@ -97,7 +97,7 @@ static void timerblock_tick(void *opaque) static uint64_t timerblock_read(void *opaque, hwaddr addr, unsigned size) { - timerblock *tb = (timerblock *)opaque; + TimerBlock *tb = (TimerBlock *)opaque; int64_t val; switch (addr) { case 0: /* Load */ @@ -125,7 +125,7 @@ static uint64_t timerblock_read(void *opaque, hwaddr addr, static void timerblock_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - timerblock *tb = (timerblock *)opaque; + TimerBlock *tb = (TimerBlock *)opaque; int64_t old; switch (addr) { case 0: /* Load */ @@ -164,7 +164,7 @@ static void timerblock_write(void *opaque, hwaddr addr, static uint64_t arm_thistimer_read(void *opaque, hwaddr addr, unsigned size) { - arm_mptimer_state *s = (arm_mptimer_state *)opaque; + ARMMPTimerState *s = (ARMMPTimerState *)opaque; int id = get_current_cpu(s); return timerblock_read(&s->timerblock[id * 2], addr, size); } @@ -172,7 +172,7 @@ static uint64_t arm_thistimer_read(void *opaque, hwaddr addr, static void arm_thistimer_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - arm_mptimer_state *s = (arm_mptimer_state *)opaque; + ARMMPTimerState *s = (ARMMPTimerState *)opaque; int id = get_current_cpu(s); timerblock_write(&s->timerblock[id * 2], addr, value, size); } @@ -180,7 +180,7 @@ static void arm_thistimer_write(void *opaque, hwaddr addr, static uint64_t arm_thiswdog_read(void *opaque, hwaddr addr, unsigned size) { - arm_mptimer_state *s = (arm_mptimer_state *)opaque; + ARMMPTimerState *s = (ARMMPTimerState *)opaque; int id = get_current_cpu(s); return timerblock_read(&s->timerblock[id * 2 + 1], addr, size); } @@ -188,7 +188,7 @@ static uint64_t arm_thiswdog_read(void *opaque, hwaddr addr, static void arm_thiswdog_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - arm_mptimer_state *s = (arm_mptimer_state *)opaque; + ARMMPTimerState *s = (ARMMPTimerState *)opaque; int id = get_current_cpu(s); timerblock_write(&s->timerblock[id * 2 + 1], addr, value, size); } @@ -223,7 +223,7 @@ static const MemoryRegionOps timerblock_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void timerblock_reset(timerblock *tb) +static void timerblock_reset(TimerBlock *tb) { tb->count = 0; tb->load = 0; @@ -237,8 +237,8 @@ static void timerblock_reset(timerblock *tb) static void arm_mptimer_reset(DeviceState *dev) { - arm_mptimer_state *s = - FROM_SYSBUS(arm_mptimer_state, SYS_BUS_DEVICE(dev)); + ARMMPTimerState *s = + FROM_SYSBUS(ARMMPTimerState, SYS_BUS_DEVICE(dev)); int i; /* We reset every timer in the array, not just the ones we're using, * because vmsave will look at every array element. @@ -250,7 +250,7 @@ static void arm_mptimer_reset(DeviceState *dev) static int arm_mptimer_init(SysBusDevice *dev) { - arm_mptimer_state *s = FROM_SYSBUS(arm_mptimer_state, dev); + ARMMPTimerState *s = FROM_SYSBUS(ARMMPTimerState, dev); int i; if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) { hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS); @@ -278,7 +278,7 @@ static int arm_mptimer_init(SysBusDevice *dev) "arm_mptimer_wdog", 0x20); sysbus_init_mmio(dev, &s->iomem[1]); for (i = 0; i < (s->num_cpu * 2); i++) { - timerblock *tb = &s->timerblock[i]; + TimerBlock *tb = &s->timerblock[i]; tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb); sysbus_init_irq(dev, &tb->irq); memory_region_init_io(&tb->iomem, &timerblock_ops, tb, @@ -294,11 +294,11 @@ static const VMStateDescription vmstate_timerblock = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(count, timerblock), - VMSTATE_UINT32(load, timerblock), - VMSTATE_UINT32(control, timerblock), - VMSTATE_UINT32(status, timerblock), - VMSTATE_INT64(tick, timerblock), + VMSTATE_UINT32(count, TimerBlock), + VMSTATE_UINT32(load, TimerBlock), + VMSTATE_UINT32(control, TimerBlock), + VMSTATE_UINT32(status, TimerBlock), + VMSTATE_INT64(tick, TimerBlock), VMSTATE_END_OF_LIST() } }; @@ -308,14 +308,14 @@ static const VMStateDescription vmstate_arm_mptimer = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(timerblock, arm_mptimer_state, (MAX_CPUS * 2), - 1, vmstate_timerblock, timerblock), + VMSTATE_STRUCT_ARRAY(timerblock, ARMMPTimerState, (MAX_CPUS * 2), + 1, vmstate_timerblock, TimerBlock), VMSTATE_END_OF_LIST() } }; static Property arm_mptimer_properties[] = { - DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0), + DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0), DEFINE_PROP_END_OF_LIST() }; @@ -334,7 +334,7 @@ static void arm_mptimer_class_init(ObjectClass *klass, void *data) static const TypeInfo arm_mptimer_info = { .name = "arm_mptimer", .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(arm_mptimer_state), + .instance_size = sizeof(ARMMPTimerState), .class_init = arm_mptimer_class_init, }; From 845769fc6319d308a39a78734c6dc03fa93ff2c5 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:13 +0000 Subject: [PATCH 1307/1634] arm: arm11mpcore, a9mpcore: CamelCased type names To conform with QEMU coding style. Signed-off-by: Peter Crosthwaite Signed-off-by: Peter Maydell --- hw/a9mpcore.c | 26 +++++++++++++------------- hw/arm11mpcore.c | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 673bbd8c42..33b9e07f46 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -12,7 +12,7 @@ /* A9MP private memory region. */ -typedef struct a9mp_priv_state { +typedef struct A9MPPrivState { SysBusDevice busdev; uint32_t scu_control; uint32_t scu_status; @@ -23,12 +23,12 @@ typedef struct a9mp_priv_state { DeviceState *mptimer; DeviceState *gic; uint32_t num_irq; -} a9mp_priv_state; +} A9MPPrivState; static uint64_t a9_scu_read(void *opaque, hwaddr offset, unsigned size) { - a9mp_priv_state *s = (a9mp_priv_state *)opaque; + A9MPPrivState *s = (A9MPPrivState *)opaque; switch (offset) { case 0x00: /* Control */ return s->scu_control; @@ -59,7 +59,7 @@ static uint64_t a9_scu_read(void *opaque, hwaddr offset, static void a9_scu_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - a9mp_priv_state *s = (a9mp_priv_state *)opaque; + A9MPPrivState *s = (A9MPPrivState *)opaque; uint32_t mask; uint32_t shift; switch (size) { @@ -112,7 +112,7 @@ static const MemoryRegionOps a9_scu_ops = { static void a9mp_priv_reset(DeviceState *dev) { - a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, SYS_BUS_DEVICE(dev)); + A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, SYS_BUS_DEVICE(dev)); int i; s->scu_control = 0; for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) { @@ -122,13 +122,13 @@ static void a9mp_priv_reset(DeviceState *dev) static void a9mp_priv_set_irq(void *opaque, int irq, int level) { - a9mp_priv_state *s = (a9mp_priv_state *)opaque; + A9MPPrivState *s = (A9MPPrivState *)opaque; qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } static int a9mp_priv_init(SysBusDevice *dev) { - a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, dev); + A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev); SysBusDevice *busdev, *gicbusdev; int i; @@ -196,22 +196,22 @@ static const VMStateDescription vmstate_a9mp_priv = { .version_id = 2, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32(scu_control, a9mp_priv_state), - VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8), - VMSTATE_UINT32_V(scu_status, a9mp_priv_state, 2), + VMSTATE_UINT32(scu_control, A9MPPrivState), + VMSTATE_UINT32_ARRAY(old_timer_status, A9MPPrivState, 8), + VMSTATE_UINT32_V(scu_status, A9MPPrivState, 2), VMSTATE_END_OF_LIST() } }; static Property a9mp_priv_properties[] = { - DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1), + DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1), /* The Cortex-A9MP may have anything from 0 to 224 external interrupt * IRQ lines (with another 32 internal). We default to 64+32, which * is the number provided by the Cortex-A9MP test chip in the * Realview PBX-A9 and Versatile Express A9 development boards. * Other boards may differ and should set this property appropriately. */ - DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96), + DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 96), DEFINE_PROP_END_OF_LIST(), }; @@ -229,7 +229,7 @@ static void a9mp_priv_class_init(ObjectClass *klass, void *data) static const TypeInfo a9mp_priv_info = { .name = "a9mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(a9mp_priv_state), + .instance_size = sizeof(A9MPPrivState), .class_init = a9mp_priv_class_init, }; diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index 324e503dd9..b900b35d01 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -12,7 +12,7 @@ /* MPCore private memory region. */ -typedef struct mpcore_priv_state { +typedef struct ARM11MPCorePriveState { SysBusDevice busdev; uint32_t scu_control; int iomemtype; @@ -23,14 +23,14 @@ typedef struct mpcore_priv_state { DeviceState *mptimer; DeviceState *gic; uint32_t num_irq; -} mpcore_priv_state; +} ARM11MPCorePriveState; /* Per-CPU private memory mapped IO. */ static uint64_t mpcore_scu_read(void *opaque, hwaddr offset, unsigned size) { - mpcore_priv_state *s = (mpcore_priv_state *)opaque; + ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque; int id; /* SCU */ switch (offset) { @@ -53,7 +53,7 @@ static uint64_t mpcore_scu_read(void *opaque, hwaddr offset, static void mpcore_scu_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - mpcore_priv_state *s = (mpcore_priv_state *)opaque; + ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque; /* SCU */ switch (offset) { case 0: /* Control register. */ @@ -76,11 +76,11 @@ static const MemoryRegionOps mpcore_scu_ops = { static void mpcore_priv_set_irq(void *opaque, int irq, int level) { - mpcore_priv_state *s = (mpcore_priv_state *)opaque; + ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque; qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } -static void mpcore_priv_map_setup(mpcore_priv_state *s) +static void mpcore_priv_map_setup(ARM11MPCorePriveState *s) { int i; SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic); @@ -121,7 +121,7 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s) static int mpcore_priv_init(SysBusDevice *dev) { - mpcore_priv_state *s = FROM_SYSBUS(mpcore_priv_state, dev); + ARM11MPCorePriveState *s = FROM_SYSBUS(ARM11MPCorePriveState, dev); s->gic = qdev_create(NULL, "arm_gic"); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); @@ -230,7 +230,7 @@ static const TypeInfo mpcore_rirq_info = { }; static Property mpcore_priv_properties[] = { - DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), + DEFINE_PROP_UINT32("num-cpu", ARM11MPCorePriveState, num_cpu, 1), /* The ARM11 MPCORE TRM says the on-chip controller may have * anything from 0 to 224 external interrupt IRQ lines (with another * 32 internal). We default to 32+32, which is the number provided by @@ -239,7 +239,7 @@ static Property mpcore_priv_properties[] = { * appropriately. Some Linux kernels may not boot if the hardware * has more IRQ lines than the kernel expects. */ - DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64), + DEFINE_PROP_UINT32("num-irq", ARM11MPCorePriveState, num_irq, 64), DEFINE_PROP_END_OF_LIST(), }; @@ -255,7 +255,7 @@ static void mpcore_priv_class_init(ObjectClass *klass, void *data) static const TypeInfo mpcore_priv_info = { .name = "arm11mpcore_priv", .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mpcore_priv_state), + .instance_size = sizeof(ARM11MPCorePriveState), .class_init = mpcore_priv_class_init, }; From cde4577f11cd557cfd48d752b7a0929d19eac9e9 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:13 +0000 Subject: [PATCH 1308/1634] arm: mptimer: Remove WDT distinction In QEMU emulation, there is no functional difference between the ARM mpcore private timers and watchdogs. Removed all the distinction between the two from arm_mptimer.c and converted it to be just the mptimer. a9mpcore and arm11mpcore just instantiate the same mptimer object twice to get both timer and WDT. If in the future we want to make the WDT functionally different then we can use either QOM hierarchy to derive WDT from from mptimer, or we can add a property "is-wdt" or some such. Signed-off-by: Peter Crosthwaite Signed-off-by: Peter Maydell --- hw/a9mpcore.c | 18 ++++++++----- hw/arm11mpcore.c | 21 ++++++++++----- hw/arm_mptimer.c | 66 ++++++++++-------------------------------------- 3 files changed, 41 insertions(+), 64 deletions(-) diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 33b9e07f46..0032f53c04 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -21,6 +21,7 @@ typedef struct A9MPPrivState { MemoryRegion scu_iomem; MemoryRegion container; DeviceState *mptimer; + DeviceState *wdt; DeviceState *gic; uint32_t num_irq; } A9MPPrivState; @@ -129,7 +130,7 @@ static void a9mp_priv_set_irq(void *opaque, int irq, int level) static int a9mp_priv_init(SysBusDevice *dev) { A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev); - SysBusDevice *busdev, *gicbusdev; + SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev; int i; s->gic = qdev_create(NULL, "arm_gic"); @@ -147,7 +148,12 @@ static int a9mp_priv_init(SysBusDevice *dev) s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); qdev_init_nofail(s->mptimer); - busdev = SYS_BUS_DEVICE(s->mptimer); + timerbusdev = SYS_BUS_DEVICE(s->mptimer); + + s->wdt = qdev_create(NULL, "arm_mptimer"); + qdev_prop_set_uint32(s->wdt, "num-cpu", s->num_cpu); + qdev_init_nofail(s->wdt); + wdtbusdev = SYS_BUS_DEVICE(s->wdt); /* Memory map (addresses are offsets from PERIPHBASE): * 0x0000-0x00ff -- Snoop Control Unit @@ -170,9 +176,9 @@ static int a9mp_priv_init(SysBusDevice *dev) * memory region, not the "timer/watchdog for core X" ones 11MPcore has. */ memory_region_add_subregion(&s->container, 0x600, - sysbus_mmio_get_region(busdev, 0)); + sysbus_mmio_get_region(timerbusdev, 0)); memory_region_add_subregion(&s->container, 0x620, - sysbus_mmio_get_region(busdev, 1)); + sysbus_mmio_get_region(wdtbusdev, 0)); memory_region_add_subregion(&s->container, 0x1000, sysbus_mmio_get_region(gicbusdev, 0)); @@ -183,9 +189,9 @@ static int a9mp_priv_init(SysBusDevice *dev) */ for (i = 0; i < s->num_cpu; i++) { int ppibase = (s->num_irq - 32) + i * 32; - sysbus_connect_irq(busdev, i * 2, + sysbus_connect_irq(timerbusdev, i, qdev_get_gpio_in(s->gic, ppibase + 29)); - sysbus_connect_irq(busdev, i * 2 + 1, + sysbus_connect_irq(wdtbusdev, i, qdev_get_gpio_in(s->gic, ppibase + 30)); } return 0; diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index b900b35d01..ca49948ffc 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -21,6 +21,7 @@ typedef struct ARM11MPCorePriveState { MemoryRegion iomem; MemoryRegion container; DeviceState *mptimer; + DeviceState *wdtimer; DeviceState *gic; uint32_t num_irq; } ARM11MPCorePriveState; @@ -84,7 +85,8 @@ static void mpcore_priv_map_setup(ARM11MPCorePriveState *s) { int i; SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic); - SysBusDevice *busdev = SYS_BUS_DEVICE(s->mptimer); + SysBusDevice *timerbusdev = SYS_BUS_DEVICE(s->mptimer); + SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(s->wdtimer); memory_region_init(&s->container, "mpcode-priv-container", 0x2000); memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100); memory_region_add_subregion(&s->container, 0, &s->iomem); @@ -99,11 +101,13 @@ static void mpcore_priv_map_setup(ARM11MPCorePriveState *s) /* Add the regions for timer and watchdog for "current CPU" and * for each specific CPU. */ - for (i = 0; i < (s->num_cpu + 1) * 2; i++) { + for (i = 0; i < (s->num_cpu + 1); i++) { /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */ - hwaddr offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20; + hwaddr offset = 0x600 + i * 0x100; memory_region_add_subregion(&s->container, offset, - sysbus_mmio_get_region(busdev, i)); + sysbus_mmio_get_region(timerbusdev, i)); + memory_region_add_subregion(&s->container, offset + 0x20, + sysbus_mmio_get_region(wdtbusdev, i)); } memory_region_add_subregion(&s->container, 0x1000, sysbus_mmio_get_region(gicbusdev, 0)); @@ -112,9 +116,9 @@ static void mpcore_priv_map_setup(ARM11MPCorePriveState *s) */ for (i = 0; i < s->num_cpu; i++) { int ppibase = (s->num_irq - 32) + i * 32; - sysbus_connect_irq(busdev, i * 2, + sysbus_connect_irq(timerbusdev, i, qdev_get_gpio_in(s->gic, ppibase + 29)); - sysbus_connect_irq(busdev, i * 2 + 1, + sysbus_connect_irq(wdtbusdev, i, qdev_get_gpio_in(s->gic, ppibase + 30)); } } @@ -139,6 +143,11 @@ static int mpcore_priv_init(SysBusDevice *dev) s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); qdev_init_nofail(s->mptimer); + + s->wdtimer = qdev_create(NULL, "arm_mptimer"); + qdev_prop_set_uint32(s->wdtimer, "num-cpu", s->num_cpu); + qdev_init_nofail(s->wdtimer); + mpcore_priv_map_setup(s); sysbus_init_mmio(dev, &s->container); return 0; diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index de0ef3658e..7b08aa3644 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -43,8 +43,8 @@ typedef struct { typedef struct { SysBusDevice busdev; uint32_t num_cpu; - TimerBlock timerblock[MAX_CPUS * 2]; - MemoryRegion iomem[2]; + TimerBlock timerblock[MAX_CPUS]; + MemoryRegion iomem; } ARMMPTimerState; static inline int get_current_cpu(ARMMPTimerState *s) @@ -166,7 +166,7 @@ static uint64_t arm_thistimer_read(void *opaque, hwaddr addr, { ARMMPTimerState *s = (ARMMPTimerState *)opaque; int id = get_current_cpu(s); - return timerblock_read(&s->timerblock[id * 2], addr, size); + return timerblock_read(&s->timerblock[id], addr, size); } static void arm_thistimer_write(void *opaque, hwaddr addr, @@ -174,23 +174,7 @@ static void arm_thistimer_write(void *opaque, hwaddr addr, { ARMMPTimerState *s = (ARMMPTimerState *)opaque; int id = get_current_cpu(s); - timerblock_write(&s->timerblock[id * 2], addr, value, size); -} - -static uint64_t arm_thiswdog_read(void *opaque, hwaddr addr, - unsigned size) -{ - ARMMPTimerState *s = (ARMMPTimerState *)opaque; - int id = get_current_cpu(s); - return timerblock_read(&s->timerblock[id * 2 + 1], addr, size); -} - -static void arm_thiswdog_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - ARMMPTimerState *s = (ARMMPTimerState *)opaque; - int id = get_current_cpu(s); - timerblock_write(&s->timerblock[id * 2 + 1], addr, value, size); + timerblock_write(&s->timerblock[id], addr, value, size); } static const MemoryRegionOps arm_thistimer_ops = { @@ -203,16 +187,6 @@ static const MemoryRegionOps arm_thistimer_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static const MemoryRegionOps arm_thiswdog_ops = { - .read = arm_thiswdog_read, - .write = arm_thiswdog_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - static const MemoryRegionOps timerblock_ops = { .read = timerblock_read, .write = timerblock_write, @@ -240,9 +214,6 @@ static void arm_mptimer_reset(DeviceState *dev) ARMMPTimerState *s = FROM_SYSBUS(ARMMPTimerState, SYS_BUS_DEVICE(dev)); int i; - /* We reset every timer in the array, not just the ones we're using, - * because vmsave will look at every array element. - */ for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) { timerblock_reset(&s->timerblock[i]); } @@ -255,29 +226,20 @@ static int arm_mptimer_init(SysBusDevice *dev) if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) { hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS); } - /* We implement one timer and one watchdog block per CPU, and - * expose multiple MMIO regions: + /* We implement one timer block per CPU, and expose multiple MMIO regions: * * region 0 is "timer for this core" - * * region 1 is "watchdog for this core" - * * region 2 is "timer for core 0" - * * region 3 is "watchdog for core 0" - * * region 4 is "timer for core 1" - * * region 5 is "watchdog for core 1" + * * region 1 is "timer for core 0" + * * region 2 is "timer for core 1" * and so on. * The outgoing interrupt lines are * * timer for core 0 - * * watchdog for core 0 * * timer for core 1 - * * watchdog for core 1 * and so on. */ - memory_region_init_io(&s->iomem[0], &arm_thistimer_ops, s, + memory_region_init_io(&s->iomem, &arm_thistimer_ops, s, "arm_mptimer_timer", 0x20); - sysbus_init_mmio(dev, &s->iomem[0]); - memory_region_init_io(&s->iomem[1], &arm_thiswdog_ops, s, - "arm_mptimer_wdog", 0x20); - sysbus_init_mmio(dev, &s->iomem[1]); - for (i = 0; i < (s->num_cpu * 2); i++) { + sysbus_init_mmio(dev, &s->iomem); + for (i = 0; i < s->num_cpu; i++) { TimerBlock *tb = &s->timerblock[i]; tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb); sysbus_init_irq(dev, &tb->irq); @@ -305,11 +267,11 @@ static const VMStateDescription vmstate_timerblock = { static const VMStateDescription vmstate_arm_mptimer = { .name = "arm_mptimer", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(timerblock, ARMMPTimerState, (MAX_CPUS * 2), - 1, vmstate_timerblock, TimerBlock), + VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu, + 2, vmstate_timerblock, TimerBlock), VMSTATE_END_OF_LIST() } }; From 9595978292e9a5b5f0ec77a9f6a0e724c10bf3b4 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:13 +0000 Subject: [PATCH 1309/1634] arm: a9mpcore: remove old_timer_status field This field was write only and thus unused. Removed. Signed-off-by: Peter Crosthwaite Signed-off-by: Peter Maydell --- hw/a9mpcore.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 0032f53c04..23630af1fe 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -16,7 +16,6 @@ typedef struct A9MPPrivState { SysBusDevice busdev; uint32_t scu_control; uint32_t scu_status; - uint32_t old_timer_status[8]; uint32_t num_cpu; MemoryRegion scu_iomem; MemoryRegion container; @@ -114,11 +113,8 @@ static const MemoryRegionOps a9_scu_ops = { static void a9mp_priv_reset(DeviceState *dev) { A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, SYS_BUS_DEVICE(dev)); - int i; + s->scu_control = 0; - for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) { - s->old_timer_status[i] = 0; - } } static void a9mp_priv_set_irq(void *opaque, int irq, int level) @@ -199,11 +195,10 @@ static int a9mp_priv_init(SysBusDevice *dev) static const VMStateDescription vmstate_a9mp_priv = { .name = "a9mpcore_priv", - .version_id = 2, - .minimum_version_id = 1, + .version_id = 3, + .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINT32(scu_control, A9MPPrivState), - VMSTATE_UINT32_ARRAY(old_timer_status, A9MPPrivState, 8), VMSTATE_UINT32_V(scu_status, A9MPPrivState, 2), VMSTATE_END_OF_LIST() } From 353575f0959234e1680622f747e20308c94505b7 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:14 +0000 Subject: [PATCH 1310/1634] arm: a9mpcore: Coreify the SCU Split the SCU in a9mpcore out into its own object definition. mpcore is now just a container for the mpcore components. Signed-off-by: Peter Crosthwaite Signed-off-by: Peter Maydell --- hw/a9mpcore.c | 122 +++----------------------------- hw/a9scu.c | 164 +++++++++++++++++++++++++++++++++++++++++++ hw/arm/Makefile.objs | 1 + 3 files changed, 174 insertions(+), 113 deletions(-) create mode 100644 hw/a9scu.c diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 23630af1fe..01aee0264d 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -10,113 +10,17 @@ #include "sysbus.h" -/* A9MP private memory region. */ - typedef struct A9MPPrivState { SysBusDevice busdev; - uint32_t scu_control; - uint32_t scu_status; uint32_t num_cpu; - MemoryRegion scu_iomem; MemoryRegion container; DeviceState *mptimer; DeviceState *wdt; DeviceState *gic; + DeviceState *scu; uint32_t num_irq; } A9MPPrivState; -static uint64_t a9_scu_read(void *opaque, hwaddr offset, - unsigned size) -{ - A9MPPrivState *s = (A9MPPrivState *)opaque; - switch (offset) { - case 0x00: /* Control */ - return s->scu_control; - case 0x04: /* Configuration */ - return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1); - case 0x08: /* CPU Power Status */ - return s->scu_status; - case 0x09: /* CPU status. */ - return s->scu_status >> 8; - case 0x0a: /* CPU status. */ - return s->scu_status >> 16; - case 0x0b: /* CPU status. */ - return s->scu_status >> 24; - case 0x0c: /* Invalidate All Registers In Secure State */ - return 0; - case 0x40: /* Filtering Start Address Register */ - case 0x44: /* Filtering End Address Register */ - /* RAZ/WI, like an implementation with only one AXI master */ - return 0; - case 0x50: /* SCU Access Control Register */ - case 0x54: /* SCU Non-secure Access Control Register */ - /* unimplemented, fall through */ - default: - return 0; - } -} - -static void a9_scu_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - A9MPPrivState *s = (A9MPPrivState *)opaque; - uint32_t mask; - uint32_t shift; - switch (size) { - case 1: - mask = 0xff; - break; - case 2: - mask = 0xffff; - break; - case 4: - mask = 0xffffffff; - break; - default: - fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n", - size, (unsigned)offset); - return; - } - - switch (offset) { - case 0x00: /* Control */ - s->scu_control = value & 1; - break; - case 0x4: /* Configuration: RO */ - break; - case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */ - shift = (offset - 0x8) * 8; - s->scu_status &= ~(mask << shift); - s->scu_status |= ((value & mask) << shift); - break; - case 0x0c: /* Invalidate All Registers In Secure State */ - /* no-op as we do not implement caches */ - break; - case 0x40: /* Filtering Start Address Register */ - case 0x44: /* Filtering End Address Register */ - /* RAZ/WI, like an implementation with only one AXI master */ - break; - case 0x50: /* SCU Access Control Register */ - case 0x54: /* SCU Non-secure Access Control Register */ - /* unimplemented, fall through */ - default: - break; - } -} - -static const MemoryRegionOps a9_scu_ops = { - .read = a9_scu_read, - .write = a9_scu_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void a9mp_priv_reset(DeviceState *dev) -{ - A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, SYS_BUS_DEVICE(dev)); - - s->scu_control = 0; -} - static void a9mp_priv_set_irq(void *opaque, int irq, int level) { A9MPPrivState *s = (A9MPPrivState *)opaque; @@ -126,7 +30,7 @@ static void a9mp_priv_set_irq(void *opaque, int irq, int level) static int a9mp_priv_init(SysBusDevice *dev) { A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev); - SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev; + SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev, *scubusdev; int i; s->gic = qdev_create(NULL, "arm_gic"); @@ -141,6 +45,11 @@ static int a9mp_priv_init(SysBusDevice *dev) /* Pass through inbound GPIO lines to the GIC */ qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32); + s->scu = qdev_create(NULL, "a9-scu"); + qdev_prop_set_uint32(s->scu, "num-cpu", s->num_cpu); + qdev_init_nofail(s->scu); + scubusdev = SYS_BUS_DEVICE(s->scu); + s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); qdev_init_nofail(s->mptimer); @@ -163,8 +72,8 @@ static int a9mp_priv_init(SysBusDevice *dev) * We should implement the global timer but don't currently do so. */ memory_region_init(&s->container, "a9mp-priv-container", 0x2000); - memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100); - memory_region_add_subregion(&s->container, 0, &s->scu_iomem); + memory_region_add_subregion(&s->container, 0, + sysbus_mmio_get_region(scubusdev, 0)); /* GIC CPU interface */ memory_region_add_subregion(&s->container, 0x100, sysbus_mmio_get_region(gicbusdev, 1)); @@ -193,17 +102,6 @@ static int a9mp_priv_init(SysBusDevice *dev) return 0; } -static const VMStateDescription vmstate_a9mp_priv = { - .name = "a9mpcore_priv", - .version_id = 3, - .minimum_version_id = 3, - .fields = (VMStateField[]) { - VMSTATE_UINT32(scu_control, A9MPPrivState), - VMSTATE_UINT32_V(scu_status, A9MPPrivState, 2), - VMSTATE_END_OF_LIST() - } -}; - static Property a9mp_priv_properties[] = { DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, num_cpu, 1), /* The Cortex-A9MP may have anything from 0 to 224 external interrupt @@ -223,8 +121,6 @@ static void a9mp_priv_class_init(ObjectClass *klass, void *data) k->init = a9mp_priv_init; dc->props = a9mp_priv_properties; - dc->vmsd = &vmstate_a9mp_priv; - dc->reset = a9mp_priv_reset; } static const TypeInfo a9mp_priv_info = { diff --git a/hw/a9scu.c b/hw/a9scu.c new file mode 100644 index 0000000000..0e9e54d7fb --- /dev/null +++ b/hw/a9scu.c @@ -0,0 +1,164 @@ +/* + * Cortex-A9MPCore Snoop Control Unit (SCU) emulation. + * + * Copyright (c) 2009 CodeSourcery. + * Copyright (c) 2011 Linaro Limited. + * Written by Paul Brook, Peter Maydell. + * + * This code is licensed under the GPL. + */ + +#include "sysbus.h" + +/* A9MP private memory region. */ + +typedef struct A9SCUState { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t control; + uint32_t status; + uint32_t num_cpu; +} A9SCUState; + +#define TYPE_A9_SCU "a9-scu" +#define A9_SCU(obj) OBJECT_CHECK(A9SCUState, (obj), TYPE_A9_SCU) + +static uint64_t a9_scu_read(void *opaque, hwaddr offset, + unsigned size) +{ + A9SCUState *s = (A9SCUState *)opaque; + switch (offset) { + case 0x00: /* Control */ + return s->control; + case 0x04: /* Configuration */ + return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1); + case 0x08: /* CPU Power Status */ + return s->status; + case 0x09: /* CPU status. */ + return s->status >> 8; + case 0x0a: /* CPU status. */ + return s->status >> 16; + case 0x0b: /* CPU status. */ + return s->status >> 24; + case 0x0c: /* Invalidate All Registers In Secure State */ + return 0; + case 0x40: /* Filtering Start Address Register */ + case 0x44: /* Filtering End Address Register */ + /* RAZ/WI, like an implementation with only one AXI master */ + return 0; + case 0x50: /* SCU Access Control Register */ + case 0x54: /* SCU Non-secure Access Control Register */ + /* unimplemented, fall through */ + default: + return 0; + } +} + +static void a9_scu_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + A9SCUState *s = (A9SCUState *)opaque; + uint32_t mask; + uint32_t shift; + switch (size) { + case 1: + mask = 0xff; + break; + case 2: + mask = 0xffff; + break; + case 4: + mask = 0xffffffff; + break; + default: + fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n", + size, (unsigned)offset); + return; + } + + switch (offset) { + case 0x00: /* Control */ + s->control = value & 1; + break; + case 0x4: /* Configuration: RO */ + break; + case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */ + shift = (offset - 0x8) * 8; + s->status &= ~(mask << shift); + s->status |= ((value & mask) << shift); + break; + case 0x0c: /* Invalidate All Registers In Secure State */ + /* no-op as we do not implement caches */ + break; + case 0x40: /* Filtering Start Address Register */ + case 0x44: /* Filtering End Address Register */ + /* RAZ/WI, like an implementation with only one AXI master */ + break; + case 0x50: /* SCU Access Control Register */ + case 0x54: /* SCU Non-secure Access Control Register */ + /* unimplemented, fall through */ + default: + break; + } +} + +static const MemoryRegionOps a9_scu_ops = { + .read = a9_scu_read, + .write = a9_scu_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void a9_scu_reset(DeviceState *dev) +{ + A9SCUState *s = A9_SCU(dev); + s->control = 0; +} + +static void a9_scu_realize(DeviceState *dev, Error ** errp) +{ + A9SCUState *s = A9_SCU(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, &a9_scu_ops, s, "a9-scu", 0x100); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_a9_scu = { + .name = "a9-scu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(control, A9SCUState), + VMSTATE_UINT32(status, A9SCUState), + VMSTATE_END_OF_LIST() + } +}; + +static Property a9_scu_properties[] = { + DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void a9_scu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = a9_scu_realize; + dc->props = a9_scu_properties; + dc->vmsd = &vmstate_a9_scu; + dc->reset = a9_scu_reset; +} + +static const TypeInfo a9_scu_info = { + .name = TYPE_A9_SCU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(A9SCUState), + .class_init = a9_scu_class_init, +}; + +static void a9mp_register_types(void) +{ + type_register_static(&a9_scu_info); +} + +type_init(a9mp_register_types) diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 6d049e7de6..4c109858fd 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -3,6 +3,7 @@ obj-y += arm_boot.o obj-y += xilinx_zynq.o zynq_slcr.o obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o +obj-y += a9scu.o obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o From d7dfca0807a0f579d3ec985bf1220519420c4dfe Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Thu, 28 Feb 2013 18:23:14 +0000 Subject: [PATCH 1311/1634] hw/sdhci: introduce standard SD host controller Device model for standard SD Host Controller Interface (SDHCI) compliant with version 2.00 of SD association specification. Signed-off-by: Peter Crosthwaite Signed-off-by: Igor Mitsyanko Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- default-configs/arm-softmmu.mak | 2 + hw/Makefile.objs | 1 + hw/sdhci.c | 1300 +++++++++++++++++++++++++++++++ hw/sdhci.h | 312 ++++++++ 4 files changed, 1615 insertions(+) create mode 100644 hw/sdhci.c create mode 100644 hw/sdhci.h diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index b40f7b08e2..68b204547c 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -47,3 +47,5 @@ CONFIG_XGMAC=y CONFIG_VERSATILE_PCI=y CONFIG_VERSATILE_I2C=y + +CONFIG_SDHCI=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index a1f3a808ac..40ebe466ad 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -43,6 +43,7 @@ common-obj-y += ccid-card-passthru.o common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o endif common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o +common-obj-$(CONFIG_SDHCI) += sdhci.o common-obj-y += fifo.o common-obj-y += pam.o diff --git a/hw/sdhci.c b/hw/sdhci.c new file mode 100644 index 0000000000..e535df9671 --- /dev/null +++ b/hw/sdhci.c @@ -0,0 +1,1300 @@ +/* + * SD Association Host Standard Specification v2.0 controller emulation + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Mitsyanko Igor + * Peter A.G. Crosthwaite + * + * Based on MMC controller for Samsung S5PC1xx-based board emulation + * by Alexey Merkulov and Vladimir Monakhov. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw.h" +#include "sysemu/blockdev.h" +#include "sysemu/dma.h" +#include "qemu/timer.h" +#include "block/block_int.h" +#include "qemu/bitops.h" + +#include "sdhci.h" + +/* host controller debug messages */ +#ifndef SDHC_DEBUG +#define SDHC_DEBUG 0 +#endif + +#if SDHC_DEBUG == 0 + #define DPRINT_L1(fmt, args...) do { } while (0) + #define DPRINT_L2(fmt, args...) do { } while (0) + #define ERRPRINT(fmt, args...) do { } while (0) +#elif SDHC_DEBUG == 1 + #define DPRINT_L1(fmt, args...) \ + do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0) + #define DPRINT_L2(fmt, args...) do { } while (0) + #define ERRPRINT(fmt, args...) \ + do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0) +#else + #define DPRINT_L1(fmt, args...) \ + do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0) + #define DPRINT_L2(fmt, args...) \ + do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0) + #define ERRPRINT(fmt, args...) \ + do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0) +#endif + +/* Default SD/MMC host controller features information, which will be + * presented in CAPABILITIES register of generic SD host controller at reset. + * If not stated otherwise: + * 0 - not supported, 1 - supported, other - prohibited. + */ +#define SDHC_CAPAB_64BITBUS 0ul /* 64-bit System Bus Support */ +#define SDHC_CAPAB_18V 1ul /* Voltage support 1.8v */ +#define SDHC_CAPAB_30V 0ul /* Voltage support 3.0v */ +#define SDHC_CAPAB_33V 1ul /* Voltage support 3.3v */ +#define SDHC_CAPAB_SUSPRESUME 0ul /* Suspend/resume support */ +#define SDHC_CAPAB_SDMA 1ul /* SDMA support */ +#define SDHC_CAPAB_HIGHSPEED 1ul /* High speed support */ +#define SDHC_CAPAB_ADMA1 1ul /* ADMA1 support */ +#define SDHC_CAPAB_ADMA2 1ul /* ADMA2 support */ +/* Maximum host controller R/W buffers size + * Possible values: 512, 1024, 2048 bytes */ +#define SDHC_CAPAB_MAXBLOCKLENGTH 512ul +/* Maximum clock frequency for SDclock in MHz + * value in range 10-63 MHz, 0 - not defined */ +#define SDHC_CAPAB_BASECLKFREQ 0ul +#define SDHC_CAPAB_TOUNIT 1ul /* Timeout clock unit 0 - kHz, 1 - MHz */ +/* Timeout clock frequency 1-63, 0 - not defined */ +#define SDHC_CAPAB_TOCLKFREQ 0ul + +/* Now check all parameters and calculate CAPABILITIES REGISTER value */ +#if SDHC_CAPAB_64BITBUS > 1 || SDHC_CAPAB_18V > 1 || SDHC_CAPAB_30V > 1 || \ + SDHC_CAPAB_33V > 1 || SDHC_CAPAB_SUSPRESUME > 1 || SDHC_CAPAB_SDMA > 1 || \ + SDHC_CAPAB_HIGHSPEED > 1 || SDHC_CAPAB_ADMA2 > 1 || SDHC_CAPAB_ADMA1 > 1 ||\ + SDHC_CAPAB_TOUNIT > 1 +#error Capabilities features can have value 0 or 1 only! +#endif + +#if SDHC_CAPAB_MAXBLOCKLENGTH == 512 +#define MAX_BLOCK_LENGTH 0ul +#elif SDHC_CAPAB_MAXBLOCKLENGTH == 1024 +#define MAX_BLOCK_LENGTH 1ul +#elif SDHC_CAPAB_MAXBLOCKLENGTH == 2048 +#define MAX_BLOCK_LENGTH 2ul +#else +#error Max host controller block size can have value 512, 1024 or 2048 only! +#endif + +#if (SDHC_CAPAB_BASECLKFREQ > 0 && SDHC_CAPAB_BASECLKFREQ < 10) || \ + SDHC_CAPAB_BASECLKFREQ > 63 +#error SDclock frequency can have value in range 0, 10-63 only! +#endif + +#if SDHC_CAPAB_TOCLKFREQ > 63 +#error Timeout clock frequency can have value in range 0-63 only! +#endif + +#define SDHC_CAPAB_REG_DEFAULT \ + ((SDHC_CAPAB_64BITBUS << 28) | (SDHC_CAPAB_18V << 26) | \ + (SDHC_CAPAB_30V << 25) | (SDHC_CAPAB_33V << 24) | \ + (SDHC_CAPAB_SUSPRESUME << 23) | (SDHC_CAPAB_SDMA << 22) | \ + (SDHC_CAPAB_HIGHSPEED << 21) | (SDHC_CAPAB_ADMA1 << 20) | \ + (SDHC_CAPAB_ADMA2 << 19) | (MAX_BLOCK_LENGTH << 16) | \ + (SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \ + (SDHC_CAPAB_TOCLKFREQ)) + +#define MASKED_WRITE(reg, mask, val) (reg = (reg & (mask)) | (val)) + +static uint8_t sdhci_slotint(SDHCIState *s) +{ + return (s->norintsts & s->norintsigen) || (s->errintsts & s->errintsigen) || + ((s->norintsts & SDHC_NIS_INSERT) && (s->wakcon & SDHC_WKUP_ON_INS)) || + ((s->norintsts & SDHC_NIS_REMOVE) && (s->wakcon & SDHC_WKUP_ON_RMV)); +} + +static inline void sdhci_update_irq(SDHCIState *s) +{ + qemu_set_irq(s->irq, sdhci_slotint(s)); +} + +static void sdhci_raise_insertion_irq(void *opaque) +{ + SDHCIState *s = (SDHCIState *)opaque; + + if (s->norintsts & SDHC_NIS_REMOVE) { + qemu_mod_timer(s->insert_timer, + qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY); + } else { + s->prnsts = 0x1ff0000; + if (s->norintstsen & SDHC_NISEN_INSERT) { + s->norintsts |= SDHC_NIS_INSERT; + } + sdhci_update_irq(s); + } +} + +static void sdhci_insert_eject_cb(void *opaque, int irq, int level) +{ + SDHCIState *s = (SDHCIState *)opaque; + DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject"); + + if ((s->norintsts & SDHC_NIS_REMOVE) && level) { + /* Give target some time to notice card ejection */ + qemu_mod_timer(s->insert_timer, + qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY); + } else { + if (level) { + s->prnsts = 0x1ff0000; + if (s->norintstsen & SDHC_NISEN_INSERT) { + s->norintsts |= SDHC_NIS_INSERT; + } + } else { + s->prnsts = 0x1fa0000; + s->pwrcon &= ~SDHC_POWER_ON; + s->clkcon &= ~SDHC_CLOCK_SDCLK_EN; + if (s->norintstsen & SDHC_NISEN_REMOVE) { + s->norintsts |= SDHC_NIS_REMOVE; + } + } + sdhci_update_irq(s); + } +} + +static void sdhci_card_readonly_cb(void *opaque, int irq, int level) +{ + SDHCIState *s = (SDHCIState *)opaque; + + if (level) { + s->prnsts &= ~SDHC_WRITE_PROTECT; + } else { + /* Write enabled */ + s->prnsts |= SDHC_WRITE_PROTECT; + } +} + +static void sdhci_reset(SDHCIState *s) +{ + qemu_del_timer(s->insert_timer); + qemu_del_timer(s->transfer_timer); + /* Set all registers to 0. Capabilities registers are not cleared + * and assumed to always preserve their value, given to them during + * initialization */ + memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad); + + sd_set_cb(s->card, s->ro_cb, s->eject_cb); + s->data_count = 0; + s->stopped_state = sdhc_not_stopped; +} + +static void sdhci_do_data_transfer(void *opaque) +{ + SDHCIState *s = (SDHCIState *)opaque; + + SDHCI_GET_CLASS(s)->data_transfer(s); +} + +static void sdhci_send_command(SDHCIState *s) +{ + SDRequest request; + uint8_t response[16]; + int rlen; + + s->errintsts = 0; + s->acmd12errsts = 0; + request.cmd = s->cmdreg >> 8; + request.arg = s->argument; + DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg); + rlen = sd_do_command(s->card, &request, response); + + if (s->cmdreg & SDHC_CMD_RESPONSE) { + if (rlen == 4) { + s->rspreg[0] = (response[0] << 24) | (response[1] << 16) | + (response[2] << 8) | response[3]; + s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0; + DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]); + } else if (rlen == 16) { + s->rspreg[0] = (response[11] << 24) | (response[12] << 16) | + (response[13] << 8) | response[14]; + s->rspreg[1] = (response[7] << 24) | (response[8] << 16) | + (response[9] << 8) | response[10]; + s->rspreg[2] = (response[3] << 24) | (response[4] << 16) | + (response[5] << 8) | response[6]; + s->rspreg[3] = (response[0] << 16) | (response[1] << 8) | + response[2]; + DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.." + "64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n", + s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]); + } else { + ERRPRINT("Timeout waiting for command response\n"); + if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) { + s->errintsts |= SDHC_EIS_CMDTIMEOUT; + s->norintsts |= SDHC_NIS_ERR; + } + } + + if ((s->norintstsen & SDHC_NISEN_TRSCMP) && + (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) { + s->norintsts |= SDHC_NIS_TRSCMP; + } + } else if (rlen != 0 && (s->errintstsen & SDHC_EISEN_CMDIDX)) { + s->errintsts |= SDHC_EIS_CMDIDX; + s->norintsts |= SDHC_NIS_ERR; + } + + if (s->norintstsen & SDHC_NISEN_CMDCMP) { + s->norintsts |= SDHC_NIS_CMDCMP; + } + + sdhci_update_irq(s); + + if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) { + sdhci_do_data_transfer(s); + } +} + +static void sdhci_end_transfer(SDHCIState *s) +{ + /* Automatically send CMD12 to stop transfer if AutoCMD12 enabled */ + if ((s->trnmod & SDHC_TRNS_ACMD12) != 0) { + SDRequest request; + uint8_t response[16]; + + request.cmd = 0x0C; + request.arg = 0; + DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg); + sd_do_command(s->card, &request, response); + /* Auto CMD12 response goes to the upper Response register */ + s->rspreg[3] = (response[0] << 24) | (response[1] << 16) | + (response[2] << 8) | response[3]; + } + + s->prnsts &= ~(SDHC_DOING_READ | SDHC_DOING_WRITE | + SDHC_DAT_LINE_ACTIVE | SDHC_DATA_INHIBIT | + SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE); + + if (s->norintstsen & SDHC_NISEN_TRSCMP) { + s->norintsts |= SDHC_NIS_TRSCMP; + } + + sdhci_update_irq(s); +} + +/* + * Programmed i/o data transfer + */ + +/* Fill host controller's read buffer with BLKSIZE bytes of data from card */ +static void sdhci_read_block_from_card(SDHCIState *s) +{ + int index = 0; + + if ((s->trnmod & SDHC_TRNS_MULTI) && + (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) { + return; + } + + for (index = 0; index < (s->blksize & 0x0fff); index++) { + s->fifo_buffer[index] = sd_read_data(s->card); + } + + /* New data now available for READ through Buffer Port Register */ + s->prnsts |= SDHC_DATA_AVAILABLE; + if (s->norintstsen & SDHC_NISEN_RBUFRDY) { + s->norintsts |= SDHC_NIS_RBUFRDY; + } + + /* Clear DAT line active status if that was the last block */ + if ((s->trnmod & SDHC_TRNS_MULTI) == 0 || + ((s->trnmod & SDHC_TRNS_MULTI) && s->blkcnt == 1)) { + s->prnsts &= ~SDHC_DAT_LINE_ACTIVE; + } + + /* If stop at block gap request was set and it's not the last block of + * data - generate Block Event interrupt */ + if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) && + s->blkcnt != 1) { + s->prnsts &= ~SDHC_DAT_LINE_ACTIVE; + if (s->norintstsen & SDHC_EISEN_BLKGAP) { + s->norintsts |= SDHC_EIS_BLKGAP; + } + } + + sdhci_update_irq(s); +} + +/* Read @size byte of data from host controller @s BUFFER DATA PORT register */ +static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size) +{ + uint32_t value = 0; + int i; + + /* first check that a valid data exists in host controller input buffer */ + if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) { + ERRPRINT("Trying to read from empty buffer\n"); + return 0; + } + + for (i = 0; i < size; i++) { + value |= s->fifo_buffer[s->data_count] << i * 8; + s->data_count++; + /* check if we've read all valid data (blksize bytes) from buffer */ + if ((s->data_count) >= (s->blksize & 0x0fff)) { + DPRINT_L2("All %u bytes of data have been read from input buffer\n", + s->data_count); + s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */ + s->data_count = 0; /* next buff read must start at position [0] */ + + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + s->blkcnt--; + } + + /* if that was the last block of data */ + if ((s->trnmod & SDHC_TRNS_MULTI) == 0 || + ((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) || + /* stop at gap request */ + (s->stopped_state == sdhc_gap_read && + !(s->prnsts & SDHC_DAT_LINE_ACTIVE))) { + SDHCI_GET_CLASS(s)->end_data_transfer(s); + } else { /* if there are more data, read next block from card */ + SDHCI_GET_CLASS(s)->read_block_from_card(s); + } + break; + } + } + + return value; +} + +/* Write data from host controller FIFO to card */ +static void sdhci_write_block_to_card(SDHCIState *s) +{ + int index = 0; + + if (s->prnsts & SDHC_SPACE_AVAILABLE) { + if (s->norintstsen & SDHC_NISEN_WBUFRDY) { + s->norintsts |= SDHC_NIS_WBUFRDY; + } + sdhci_update_irq(s); + return; + } + + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + if (s->blkcnt == 0) { + return; + } else { + s->blkcnt--; + } + } + + for (index = 0; index < (s->blksize & 0x0fff); index++) { + sd_write_data(s->card, s->fifo_buffer[index]); + } + + /* Next data can be written through BUFFER DATORT register */ + s->prnsts |= SDHC_SPACE_AVAILABLE; + if (s->norintstsen & SDHC_NISEN_WBUFRDY) { + s->norintsts |= SDHC_NIS_WBUFRDY; + } + + /* Finish transfer if that was the last block of data */ + if ((s->trnmod & SDHC_TRNS_MULTI) == 0 || + ((s->trnmod & SDHC_TRNS_MULTI) && + (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0))) { + SDHCI_GET_CLASS(s)->end_data_transfer(s); + } + + /* Generate Block Gap Event if requested and if not the last block */ + if (s->stopped_state == sdhc_gap_write && (s->trnmod & SDHC_TRNS_MULTI) && + s->blkcnt > 0) { + s->prnsts &= ~SDHC_DOING_WRITE; + if (s->norintstsen & SDHC_EISEN_BLKGAP) { + s->norintsts |= SDHC_EIS_BLKGAP; + } + SDHCI_GET_CLASS(s)->end_data_transfer(s); + } + + sdhci_update_irq(s); +} + +/* Write @size bytes of @value data to host controller @s Buffer Data Port + * register */ +static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size) +{ + unsigned i; + + /* Check that there is free space left in a buffer */ + if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) { + ERRPRINT("Can't write to data buffer: buffer full\n"); + return; + } + + for (i = 0; i < size; i++) { + s->fifo_buffer[s->data_count] = value & 0xFF; + s->data_count++; + value >>= 8; + if (s->data_count >= (s->blksize & 0x0fff)) { + DPRINT_L2("write buffer filled with %u bytes of data\n", + s->data_count); + s->data_count = 0; + s->prnsts &= ~SDHC_SPACE_AVAILABLE; + if (s->prnsts & SDHC_DOING_WRITE) { + SDHCI_GET_CLASS(s)->write_block_to_card(s); + } + } + } +} + +/* + * Single DMA data transfer + */ + +/* Multi block SDMA transfer */ +static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) +{ + bool page_aligned = false; + unsigned int n, begin; + const uint16_t block_size = s->blksize & 0x0fff; + uint32_t boundary_chk = 1 << (((s->blksize & 0xf000) >> 12) + 12); + uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk); + + /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for + * possible stop at page boundary if initial address is not page aligned, + * allow them to work properly */ + if ((s->sdmasysad % boundary_chk) == 0) { + page_aligned = true; + } + + if (s->trnmod & SDHC_TRNS_READ) { + s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT | + SDHC_DAT_LINE_ACTIVE; + while (s->blkcnt) { + if (s->data_count == 0) { + for (n = 0; n < block_size; n++) { + s->fifo_buffer[n] = sd_read_data(s->card); + } + } + begin = s->data_count; + if (((boundary_count + begin) < block_size) && page_aligned) { + s->data_count = boundary_count + begin; + boundary_count = 0; + } else { + s->data_count = block_size; + boundary_count -= block_size - begin; + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + s->blkcnt--; + } + } + dma_memory_write(&dma_context_memory, s->sdmasysad, + &s->fifo_buffer[begin], s->data_count - begin); + s->sdmasysad += s->data_count - begin; + if (s->data_count == block_size) { + s->data_count = 0; + } + if (page_aligned && boundary_count == 0) { + break; + } + } + } else { + s->prnsts |= SDHC_DOING_WRITE | SDHC_DATA_INHIBIT | + SDHC_DAT_LINE_ACTIVE; + while (s->blkcnt) { + begin = s->data_count; + if (((boundary_count + begin) < block_size) && page_aligned) { + s->data_count = boundary_count + begin; + boundary_count = 0; + } else { + s->data_count = block_size; + boundary_count -= block_size - begin; + } + dma_memory_read(&dma_context_memory, s->sdmasysad, + &s->fifo_buffer[begin], s->data_count); + s->sdmasysad += s->data_count - begin; + if (s->data_count == block_size) { + for (n = 0; n < block_size; n++) { + sd_write_data(s->card, s->fifo_buffer[n]); + } + s->data_count = 0; + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + s->blkcnt--; + } + } + if (page_aligned && boundary_count == 0) { + break; + } + } + } + + if (s->blkcnt == 0) { + SDHCI_GET_CLASS(s)->end_data_transfer(s); + } else { + if (s->norintstsen & SDHC_NISEN_DMA) { + s->norintsts |= SDHC_NIS_DMA; + } + sdhci_update_irq(s); + } +} + +/* single block SDMA transfer */ + +static void sdhci_sdma_transfer_single_block(SDHCIState *s) +{ + int n; + uint32_t datacnt = s->blksize & 0x0fff; + + if (s->trnmod & SDHC_TRNS_READ) { + for (n = 0; n < datacnt; n++) { + s->fifo_buffer[n] = sd_read_data(s->card); + } + dma_memory_write(&dma_context_memory, s->sdmasysad, s->fifo_buffer, + datacnt); + } else { + dma_memory_read(&dma_context_memory, s->sdmasysad, s->fifo_buffer, + datacnt); + for (n = 0; n < datacnt; n++) { + sd_write_data(s->card, s->fifo_buffer[n]); + } + } + + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + s->blkcnt--; + } + + SDHCI_GET_CLASS(s)->end_data_transfer(s); +} + +typedef struct ADMADescr { + hwaddr addr; + uint16_t length; + uint8_t attr; + uint8_t incr; +} ADMADescr; + +static void get_adma_description(SDHCIState *s, ADMADescr *dscr) +{ + uint32_t adma1 = 0; + uint64_t adma2 = 0; + hwaddr entry_addr = (hwaddr)s->admasysaddr; + switch (SDHC_DMA_TYPE(s->hostctl)) { + case SDHC_CTRL_ADMA2_32: + dma_memory_read(&dma_context_memory, entry_addr, (uint8_t *)&adma2, + sizeof(adma2)); + adma2 = le64_to_cpu(adma2); + /* The spec does not specify endianness of descriptor table. + * We currently assume that it is LE. + */ + dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull; + dscr->length = (uint16_t)extract64(adma2, 16, 16); + dscr->attr = (uint8_t)extract64(adma2, 0, 7); + dscr->incr = 8; + break; + case SDHC_CTRL_ADMA1_32: + dma_memory_read(&dma_context_memory, entry_addr, (uint8_t *)&adma1, + sizeof(adma1)); + adma1 = le32_to_cpu(adma1); + dscr->addr = (hwaddr)(adma1 & 0xFFFFF000); + dscr->attr = (uint8_t)extract32(adma1, 0, 7); + dscr->incr = 4; + if ((dscr->attr & SDHC_ADMA_ATTR_ACT_MASK) == SDHC_ADMA_ATTR_SET_LEN) { + dscr->length = (uint16_t)extract32(adma1, 12, 16); + } else { + dscr->length = 4096; + } + break; + case SDHC_CTRL_ADMA2_64: + dma_memory_read(&dma_context_memory, entry_addr, + (uint8_t *)(&dscr->attr), 1); + dma_memory_read(&dma_context_memory, entry_addr + 2, + (uint8_t *)(&dscr->length), 2); + dscr->length = le16_to_cpu(dscr->length); + dma_memory_read(&dma_context_memory, entry_addr + 4, + (uint8_t *)(&dscr->addr), 8); + dscr->attr = le64_to_cpu(dscr->attr); + dscr->attr &= 0xfffffff8; + dscr->incr = 12; + break; + } +} + +/* Advanced DMA data transfer */ + +static void sdhci_do_adma(SDHCIState *s) +{ + unsigned int n, begin, length; + const uint16_t block_size = s->blksize & 0x0fff; + ADMADescr dscr; + int i; + + for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) { + s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH; + + get_adma_description(s, &dscr); + DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n", + dscr.addr, dscr.length, dscr.attr); + + if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) { + /* Indicate that error occurred in ST_FDS state */ + s->admaerr &= ~SDHC_ADMAERR_STATE_MASK; + s->admaerr |= SDHC_ADMAERR_STATE_ST_FDS; + + /* Generate ADMA error interrupt */ + if (s->errintstsen & SDHC_EISEN_ADMAERR) { + s->errintsts |= SDHC_EIS_ADMAERR; + s->norintsts |= SDHC_NIS_ERR; + } + + sdhci_update_irq(s); + return; + } + + length = dscr.length ? dscr.length : 65536; + + switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) { + case SDHC_ADMA_ATTR_ACT_TRAN: /* data transfer */ + + if (s->trnmod & SDHC_TRNS_READ) { + while (length) { + if (s->data_count == 0) { + for (n = 0; n < block_size; n++) { + s->fifo_buffer[n] = sd_read_data(s->card); + } + } + begin = s->data_count; + if ((length + begin) < block_size) { + s->data_count = length + begin; + length = 0; + } else { + s->data_count = block_size; + length -= block_size - begin; + } + dma_memory_write(&dma_context_memory, dscr.addr, + &s->fifo_buffer[begin], + s->data_count - begin); + dscr.addr += s->data_count - begin; + if (s->data_count == block_size) { + s->data_count = 0; + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + s->blkcnt--; + if (s->blkcnt == 0) { + break; + } + } + } + } + } else { + while (length) { + begin = s->data_count; + if ((length + begin) < block_size) { + s->data_count = length + begin; + length = 0; + } else { + s->data_count = block_size; + length -= block_size - begin; + } + dma_memory_read(&dma_context_memory, dscr.addr, + &s->fifo_buffer[begin], s->data_count); + dscr.addr += s->data_count - begin; + if (s->data_count == block_size) { + for (n = 0; n < block_size; n++) { + sd_write_data(s->card, s->fifo_buffer[n]); + } + s->data_count = 0; + if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { + s->blkcnt--; + if (s->blkcnt == 0) { + break; + } + } + } + } + } + s->admasysaddr += dscr.incr; + break; + case SDHC_ADMA_ATTR_ACT_LINK: /* link to next descriptor table */ + s->admasysaddr = dscr.addr; + DPRINT_L1("ADMA link: admasysaddr=0x%lx\n", s->admasysaddr); + break; + default: + s->admasysaddr += dscr.incr; + break; + } + + /* ADMA transfer terminates if blkcnt == 0 or by END attribute */ + if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && + (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) { + DPRINT_L2("ADMA transfer completed\n"); + if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) && + (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && + s->blkcnt != 0)) { + ERRPRINT("SD/MMC host ADMA length mismatch\n"); + s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH | + SDHC_ADMAERR_STATE_ST_TFR; + if (s->errintstsen & SDHC_EISEN_ADMAERR) { + ERRPRINT("Set ADMA error flag\n"); + s->errintsts |= SDHC_EIS_ADMAERR; + s->norintsts |= SDHC_NIS_ERR; + } + + sdhci_update_irq(s); + } + SDHCI_GET_CLASS(s)->end_data_transfer(s); + return; + } + + if (dscr.attr & SDHC_ADMA_ATTR_INT) { + DPRINT_L1("ADMA interrupt: admasysaddr=0x%lx\n", s->admasysaddr); + if (s->norintstsen & SDHC_NISEN_DMA) { + s->norintsts |= SDHC_NIS_DMA; + } + + sdhci_update_irq(s); + return; + } + } + + /* we have unfinished bussiness - reschedule to continue ADMA */ + qemu_mod_timer(s->transfer_timer, + qemu_get_clock_ns(vm_clock) + SDHC_TRANSFER_DELAY); +} + +/* Perform data transfer according to controller configuration */ + +static void sdhci_data_transfer(SDHCIState *s) +{ + SDHCIClass *k = SDHCI_GET_CLASS(s); + s->data_count = 0; + + if (s->trnmod & SDHC_TRNS_DMA) { + switch (SDHC_DMA_TYPE(s->hostctl)) { + case SDHC_CTRL_SDMA: + if ((s->trnmod & SDHC_TRNS_MULTI) && + (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || s->blkcnt == 0)) { + break; + } + + if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) { + k->do_sdma_single(s); + } else { + k->do_sdma_multi(s); + } + + break; + case SDHC_CTRL_ADMA1_32: + if (!(s->capareg & SDHC_CAN_DO_ADMA1)) { + ERRPRINT("ADMA1 not supported\n"); + break; + } + + k->do_adma(s); + break; + case SDHC_CTRL_ADMA2_32: + if (!(s->capareg & SDHC_CAN_DO_ADMA2)) { + ERRPRINT("ADMA2 not supported\n"); + break; + } + + k->do_adma(s); + break; + case SDHC_CTRL_ADMA2_64: + if (!(s->capareg & SDHC_CAN_DO_ADMA2) || + !(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) { + ERRPRINT("64 bit ADMA not supported\n"); + break; + } + + k->do_adma(s); + break; + default: + ERRPRINT("Unsupported DMA type\n"); + break; + } + } else { + if ((s->trnmod & SDHC_TRNS_READ) && sd_data_ready(s->card)) { + s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT | + SDHC_DAT_LINE_ACTIVE; + SDHCI_GET_CLASS(s)->read_block_from_card(s); + } else { + s->prnsts |= SDHC_DOING_WRITE | SDHC_DAT_LINE_ACTIVE | + SDHC_SPACE_AVAILABLE | SDHC_DATA_INHIBIT; + SDHCI_GET_CLASS(s)->write_block_to_card(s); + } + } +} + +static bool sdhci_can_issue_command(SDHCIState *s) +{ + if (!SDHC_CLOCK_IS_ON(s->clkcon) || !(s->pwrcon & SDHC_POWER_ON) || + (((s->prnsts & SDHC_DATA_INHIBIT) || s->stopped_state) && + ((s->cmdreg & SDHC_CMD_DATA_PRESENT) || + ((s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY && + !(SDHC_COMMAND_TYPE(s->cmdreg) == SDHC_CMD_ABORT))))) { + return false; + } + + return true; +} + +/* The Buffer Data Port register must be accessed in sequential and + * continuous manner */ +static inline bool +sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num) +{ + if ((s->data_count & 0x3) != byte_num) { + ERRPRINT("Non-sequential access to Buffer Data Port register" + "is prohibited\n"); + return false; + } + return true; +} + +static uint32_t sdhci_read(SDHCIState *s, unsigned int offset, unsigned size) +{ + uint32_t ret = 0; + + switch (offset & ~0x3) { + case SDHC_SYSAD: + ret = s->sdmasysad; + break; + case SDHC_BLKSIZE: + ret = s->blksize | (s->blkcnt << 16); + break; + case SDHC_ARGUMENT: + ret = s->argument; + break; + case SDHC_TRNMOD: + ret = s->trnmod | (s->cmdreg << 16); + break; + case SDHC_RSPREG0 ... SDHC_RSPREG3: + ret = s->rspreg[((offset & ~0x3) - SDHC_RSPREG0) >> 2]; + break; + case SDHC_BDATA: + if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) { + ret = SDHCI_GET_CLASS(s)->bdata_read(s, size); + DPRINT_L2("read %ub: addr[0x%04x] -> %u\n", size, offset, ret); + return ret; + } + break; + case SDHC_PRNSTS: + ret = s->prnsts; + break; + case SDHC_HOSTCTL: + ret = s->hostctl | (s->pwrcon << 8) | (s->blkgap << 16) | + (s->wakcon << 24); + break; + case SDHC_CLKCON: + ret = s->clkcon | (s->timeoutcon << 16); + break; + case SDHC_NORINTSTS: + ret = s->norintsts | (s->errintsts << 16); + break; + case SDHC_NORINTSTSEN: + ret = s->norintstsen | (s->errintstsen << 16); + break; + case SDHC_NORINTSIGEN: + ret = s->norintsigen | (s->errintsigen << 16); + break; + case SDHC_ACMD12ERRSTS: + ret = s->acmd12errsts; + break; + case SDHC_CAPAREG: + ret = s->capareg; + break; + case SDHC_MAXCURR: + ret = s->maxcurr; + break; + case SDHC_ADMAERR: + ret = s->admaerr; + break; + case SDHC_ADMASYSADDR: + ret = (uint32_t)s->admasysaddr; + break; + case SDHC_ADMASYSADDR + 4: + ret = (uint32_t)(s->admasysaddr >> 32); + break; + case SDHC_SLOT_INT_STATUS: + ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s); + break; + default: + ERRPRINT("bad %ub read: addr[0x%04x]\n", size, offset); + break; + } + + ret >>= (offset & 0x3) * 8; + ret &= (1ULL << (size * 8)) - 1; + DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, offset, ret, ret); + return ret; +} + +static inline void sdhci_blkgap_write(SDHCIState *s, uint8_t value) +{ + if ((value & SDHC_STOP_AT_GAP_REQ) && (s->blkgap & SDHC_STOP_AT_GAP_REQ)) { + return; + } + s->blkgap = value & SDHC_STOP_AT_GAP_REQ; + + if ((value & SDHC_CONTINUE_REQ) && s->stopped_state && + (s->blkgap & SDHC_STOP_AT_GAP_REQ) == 0) { + if (s->stopped_state == sdhc_gap_read) { + s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_READ; + SDHCI_GET_CLASS(s)->read_block_from_card(s); + } else { + s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_WRITE; + SDHCI_GET_CLASS(s)->write_block_to_card(s); + } + s->stopped_state = sdhc_not_stopped; + } else if (!s->stopped_state && (value & SDHC_STOP_AT_GAP_REQ)) { + if (s->prnsts & SDHC_DOING_READ) { + s->stopped_state = sdhc_gap_read; + } else if (s->prnsts & SDHC_DOING_WRITE) { + s->stopped_state = sdhc_gap_write; + } + } +} + +static inline void sdhci_reset_write(SDHCIState *s, uint8_t value) +{ + switch (value) { + case SDHC_RESET_ALL: + DEVICE_GET_CLASS(s)->reset(DEVICE(s)); + break; + case SDHC_RESET_CMD: + s->prnsts &= ~SDHC_CMD_INHIBIT; + s->norintsts &= ~SDHC_NIS_CMDCMP; + break; + case SDHC_RESET_DATA: + s->data_count = 0; + s->prnsts &= ~(SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE | + SDHC_DOING_READ | SDHC_DOING_WRITE | + SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE); + s->blkgap &= ~(SDHC_STOP_AT_GAP_REQ | SDHC_CONTINUE_REQ); + s->stopped_state = sdhc_not_stopped; + s->norintsts &= ~(SDHC_NIS_WBUFRDY | SDHC_NIS_RBUFRDY | + SDHC_NIS_DMA | SDHC_NIS_TRSCMP | SDHC_NIS_BLKGAP); + break; + } +} + +static void +sdhci_write(SDHCIState *s, unsigned int offset, uint32_t value, unsigned size) +{ + unsigned shift = 8 * (offset & 0x3); + uint32_t mask = ~(((1ULL << (size * 8)) - 1) << shift); + value <<= shift; + + switch (offset & ~0x3) { + case SDHC_SYSAD: + s->sdmasysad = (s->sdmasysad & mask) | value; + MASKED_WRITE(s->sdmasysad, mask, value); + /* Writing to last byte of sdmasysad might trigger transfer */ + if (!(mask & 0xFF000000) && TRANSFERRING_DATA(s->prnsts) && s->blkcnt && + s->blksize && SDHC_DMA_TYPE(s->hostctl) == SDHC_CTRL_SDMA) { + SDHCI_GET_CLASS(s)->do_sdma_multi(s); + } + break; + case SDHC_BLKSIZE: + if (!TRANSFERRING_DATA(s->prnsts)) { + MASKED_WRITE(s->blksize, mask, value); + MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16); + } + break; + case SDHC_ARGUMENT: + MASKED_WRITE(s->argument, mask, value); + break; + case SDHC_TRNMOD: + /* DMA can be enabled only if it is supported as indicated by + * capabilities register */ + if (!(s->capareg & SDHC_CAN_DO_DMA)) { + value &= ~SDHC_TRNS_DMA; + } + MASKED_WRITE(s->trnmod, mask, value); + MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16); + + /* Writing to the upper byte of CMDREG triggers SD command generation */ + if ((mask & 0xFF000000) || !SDHCI_GET_CLASS(s)->can_issue_command(s)) { + break; + } + + SDHCI_GET_CLASS(s)->send_command(s); + break; + case SDHC_BDATA: + if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) { + SDHCI_GET_CLASS(s)->bdata_write(s, value >> shift, size); + } + break; + case SDHC_HOSTCTL: + if (!(mask & 0xFF0000)) { + sdhci_blkgap_write(s, value >> 16); + } + MASKED_WRITE(s->hostctl, mask, value); + MASKED_WRITE(s->pwrcon, mask >> 8, value >> 8); + MASKED_WRITE(s->wakcon, mask >> 24, value >> 24); + if (!(s->prnsts & SDHC_CARD_PRESENT) || ((s->pwrcon >> 1) & 0x7) < 5 || + !(s->capareg & (1 << (31 - ((s->pwrcon >> 1) & 0x7))))) { + s->pwrcon &= ~SDHC_POWER_ON; + } + break; + case SDHC_CLKCON: + if (!(mask & 0xFF000000)) { + sdhci_reset_write(s, value >> 24); + } + MASKED_WRITE(s->clkcon, mask, value); + MASKED_WRITE(s->timeoutcon, mask >> 16, value >> 16); + if (s->clkcon & SDHC_CLOCK_INT_EN) { + s->clkcon |= SDHC_CLOCK_INT_STABLE; + } else { + s->clkcon &= ~SDHC_CLOCK_INT_STABLE; + } + break; + case SDHC_NORINTSTS: + if (s->norintstsen & SDHC_NISEN_CARDINT) { + value &= ~SDHC_NIS_CARDINT; + } + s->norintsts &= mask | ~value; + s->errintsts &= (mask >> 16) | ~(value >> 16); + if (s->errintsts) { + s->norintsts |= SDHC_NIS_ERR; + } else { + s->norintsts &= ~SDHC_NIS_ERR; + } + sdhci_update_irq(s); + break; + case SDHC_NORINTSTSEN: + MASKED_WRITE(s->norintstsen, mask, value); + MASKED_WRITE(s->errintstsen, mask >> 16, value >> 16); + s->norintsts &= s->norintstsen; + s->errintsts &= s->errintstsen; + if (s->errintsts) { + s->norintsts |= SDHC_NIS_ERR; + } else { + s->norintsts &= ~SDHC_NIS_ERR; + } + sdhci_update_irq(s); + break; + case SDHC_NORINTSIGEN: + MASKED_WRITE(s->norintsigen, mask, value); + MASKED_WRITE(s->errintsigen, mask >> 16, value >> 16); + sdhci_update_irq(s); + break; + case SDHC_ADMAERR: + MASKED_WRITE(s->admaerr, mask, value); + break; + case SDHC_ADMASYSADDR: + s->admasysaddr = (s->admasysaddr & (0xFFFFFFFF00000000ULL | + (uint64_t)mask)) | (uint64_t)value; + break; + case SDHC_ADMASYSADDR + 4: + s->admasysaddr = (s->admasysaddr & (0x00000000FFFFFFFFULL | + ((uint64_t)mask << 32))) | ((uint64_t)value << 32); + break; + case SDHC_FEAER: + s->acmd12errsts |= value; + s->errintsts |= (value >> 16) & s->errintstsen; + if (s->acmd12errsts) { + s->errintsts |= SDHC_EIS_CMD12ERR; + } + if (s->errintsts) { + s->norintsts |= SDHC_NIS_ERR; + } + sdhci_update_irq(s); + break; + default: + ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n", + size, offset, value >> shift, value >> shift); + break; + } + DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n", + size, offset, value >> shift, value >> shift); +} + +static uint64_t +sdhci_readfn(void *opaque, hwaddr offset, unsigned size) +{ + SDHCIState *s = (SDHCIState *)opaque; + + return SDHCI_GET_CLASS(s)->mem_read(s, offset, size); +} + +static void +sdhci_writefn(void *opaque, hwaddr off, uint64_t val, unsigned sz) +{ + SDHCIState *s = (SDHCIState *)opaque; + + SDHCI_GET_CLASS(s)->mem_write(s, off, val, sz); +} + +static const MemoryRegionOps sdhci_mmio_ops = { + .read = sdhci_readfn, + .write = sdhci_writefn, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + .unaligned = false + }, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static inline unsigned int sdhci_get_fifolen(SDHCIState *s) +{ + switch (SDHC_CAPAB_BLOCKSIZE(s->capareg)) { + case 0: + return 512; + case 1: + return 1024; + case 2: + return 2048; + default: + hw_error("SDHC: unsupported value for maximum block size\n"); + return 0; + } +} + +static void sdhci_initfn(Object *obj) +{ + SDHCIState *s = SDHCI(obj); + DriveInfo *di; + + di = drive_get_next(IF_SD); + s->card = sd_init(di ? di->bdrv : NULL, 0); + s->eject_cb = qemu_allocate_irqs(sdhci_insert_eject_cb, s, 1)[0]; + s->ro_cb = qemu_allocate_irqs(sdhci_card_readonly_cb, s, 1)[0]; + sd_set_cb(s->card, s->ro_cb, s->eject_cb); + + s->insert_timer = qemu_new_timer_ns(vm_clock, sdhci_raise_insertion_irq, s); + s->transfer_timer = qemu_new_timer_ns(vm_clock, sdhci_do_data_transfer, s); +} + +static void sdhci_uninitfn(Object *obj) +{ + SDHCIState *s = SDHCI(obj); + + qemu_del_timer(s->insert_timer); + qemu_free_timer(s->insert_timer); + qemu_del_timer(s->transfer_timer); + qemu_free_timer(s->transfer_timer); + qemu_free_irqs(&s->eject_cb); + qemu_free_irqs(&s->ro_cb); + + if (s->fifo_buffer) { + g_free(s->fifo_buffer); + s->fifo_buffer = NULL; + } +} + +const VMStateDescription sdhci_vmstate = { + .name = "sdhci", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(sdmasysad, SDHCIState), + VMSTATE_UINT16(blksize, SDHCIState), + VMSTATE_UINT16(blkcnt, SDHCIState), + VMSTATE_UINT32(argument, SDHCIState), + VMSTATE_UINT16(trnmod, SDHCIState), + VMSTATE_UINT16(cmdreg, SDHCIState), + VMSTATE_UINT32_ARRAY(rspreg, SDHCIState, 4), + VMSTATE_UINT32(prnsts, SDHCIState), + VMSTATE_UINT8(hostctl, SDHCIState), + VMSTATE_UINT8(pwrcon, SDHCIState), + VMSTATE_UINT8(blkgap, SDHCIState), + VMSTATE_UINT8(wakcon, SDHCIState), + VMSTATE_UINT16(clkcon, SDHCIState), + VMSTATE_UINT8(timeoutcon, SDHCIState), + VMSTATE_UINT8(admaerr, SDHCIState), + VMSTATE_UINT16(norintsts, SDHCIState), + VMSTATE_UINT16(errintsts, SDHCIState), + VMSTATE_UINT16(norintstsen, SDHCIState), + VMSTATE_UINT16(errintstsen, SDHCIState), + VMSTATE_UINT16(norintsigen, SDHCIState), + VMSTATE_UINT16(errintsigen, SDHCIState), + VMSTATE_UINT16(acmd12errsts, SDHCIState), + VMSTATE_UINT16(data_count, SDHCIState), + VMSTATE_UINT64(admasysaddr, SDHCIState), + VMSTATE_UINT8(stopped_state, SDHCIState), + VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz), + VMSTATE_TIMER(insert_timer, SDHCIState), + VMSTATE_TIMER(transfer_timer, SDHCIState), + VMSTATE_END_OF_LIST() + } +}; + +/* Capabilities registers provide information on supported features of this + * specific host controller implementation */ +static Property sdhci_properties[] = { + DEFINE_PROP_HEX32("capareg", SDHCIState, capareg, + SDHC_CAPAB_REG_DEFAULT), + DEFINE_PROP_HEX32("maxcurr", SDHCIState, maxcurr, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sdhci_realize(DeviceState *dev, Error ** errp) +{ + SDHCIState *s = SDHCI(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + s->buf_maxsz = sdhci_get_fifolen(s); + s->fifo_buffer = g_malloc0(s->buf_maxsz); + sysbus_init_irq(sbd, &s->irq); + memory_region_init_io(&s->iomem, &sdhci_mmio_ops, s, "sdhci", + SDHC_REGISTERS_MAP_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void sdhci_generic_reset(DeviceState *ds) +{ + SDHCIState *s = SDHCI(ds); + SDHCI_GET_CLASS(s)->reset(s); +} + +static void sdhci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SDHCIClass *k = SDHCI_CLASS(klass); + + dc->vmsd = &sdhci_vmstate; + dc->props = sdhci_properties; + dc->reset = sdhci_generic_reset; + dc->realize = sdhci_realize; + + k->reset = sdhci_reset; + k->mem_read = sdhci_read; + k->mem_write = sdhci_write; + k->send_command = sdhci_send_command; + k->can_issue_command = sdhci_can_issue_command; + k->data_transfer = sdhci_data_transfer; + k->end_data_transfer = sdhci_end_transfer; + k->do_sdma_single = sdhci_sdma_transfer_single_block; + k->do_sdma_multi = sdhci_sdma_transfer_multi_blocks; + k->do_adma = sdhci_do_adma; + k->read_block_from_card = sdhci_read_block_from_card; + k->write_block_to_card = sdhci_write_block_to_card; + k->bdata_read = sdhci_read_dataport; + k->bdata_write = sdhci_write_dataport; +} + +static const TypeInfo sdhci_type_info = { + .name = TYPE_SDHCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SDHCIState), + .instance_init = sdhci_initfn, + .instance_finalize = sdhci_uninitfn, + .class_init = sdhci_class_init, + .class_size = sizeof(SDHCIClass) +}; + +static void sdhci_register_types(void) +{ + type_register_static(&sdhci_type_info); +} + +type_init(sdhci_register_types) diff --git a/hw/sdhci.h b/hw/sdhci.h new file mode 100644 index 0000000000..931d7406f0 --- /dev/null +++ b/hw/sdhci.h @@ -0,0 +1,312 @@ +/* + * SD Association Host Standard Specification v2.0 controller emulation + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Mitsyanko Igor + * Peter A.G. Crosthwaite + * + * Based on MMC controller for Samsung S5PC1xx-based board emulation + * by Alexey Merkulov and Vladimir Monakhov. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef SDHCI_H +#define SDHCI_H + +#include "qemu-common.h" +#include "sysbus.h" +#include "sd.h" + +/* R/W SDMA System Address register 0x0 */ +#define SDHC_SYSAD 0x00 + +/* R/W Host DMA Buffer Boundary and Transfer Block Size Register 0x0 */ +#define SDHC_BLKSIZE 0x04 + +/* R/W Blocks count for current transfer 0x0 */ +#define SDHC_BLKCNT 0x06 + +/* R/W Command Argument Register 0x0 */ +#define SDHC_ARGUMENT 0x08 + +/* R/W Transfer Mode Setting Register 0x0 */ +#define SDHC_TRNMOD 0x0C +#define SDHC_TRNS_DMA 0x0001 +#define SDHC_TRNS_BLK_CNT_EN 0x0002 +#define SDHC_TRNS_ACMD12 0x0004 +#define SDHC_TRNS_READ 0x0010 +#define SDHC_TRNS_MULTI 0x0020 + +/* R/W Command Register 0x0 */ +#define SDHC_CMDREG 0x0E +#define SDHC_CMD_RSP_WITH_BUSY (3 << 0) +#define SDHC_CMD_DATA_PRESENT (1 << 5) +#define SDHC_CMD_SUSPEND (1 << 6) +#define SDHC_CMD_RESUME (1 << 7) +#define SDHC_CMD_ABORT ((1 << 6)|(1 << 7)) +#define SDHC_CMD_TYPE_MASK ((1 << 6)|(1 << 7)) +#define SDHC_COMMAND_TYPE(x) ((x) & SDHC_CMD_TYPE_MASK) + +/* ROC Response Register 0 0x0 */ +#define SDHC_RSPREG0 0x10 +/* ROC Response Register 1 0x0 */ +#define SDHC_RSPREG1 0x14 +/* ROC Response Register 2 0x0 */ +#define SDHC_RSPREG2 0x18 +/* ROC Response Register 3 0x0 */ +#define SDHC_RSPREG3 0x1C + +/* R/W Buffer Data Register 0x0 */ +#define SDHC_BDATA 0x20 + +/* R/ROC Present State Register 0x000A0000 */ +#define SDHC_PRNSTS 0x24 +#define SDHC_CMD_INHIBIT 0x00000001 +#define SDHC_DATA_INHIBIT 0x00000002 +#define SDHC_DAT_LINE_ACTIVE 0x00000004 +#define SDHC_DOING_WRITE 0x00000100 +#define SDHC_DOING_READ 0x00000200 +#define SDHC_SPACE_AVAILABLE 0x00000400 +#define SDHC_DATA_AVAILABLE 0x00000800 +#define SDHC_CARD_PRESENT 0x00010000 +#define SDHC_CARD_DETECT 0x00040000 +#define SDHC_WRITE_PROTECT 0x00080000 +#define TRANSFERRING_DATA(x) \ + ((x) & (SDHC_DOING_READ | SDHC_DOING_WRITE)) + +/* R/W Host control Register 0x0 */ +#define SDHC_HOSTCTL 0x28 +#define SDHC_CTRL_DMA_CHECK_MASK 0x18 +#define SDHC_CTRL_SDMA 0x00 +#define SDHC_CTRL_ADMA1_32 0x08 +#define SDHC_CTRL_ADMA2_32 0x10 +#define SDHC_CTRL_ADMA2_64 0x18 +#define SDHC_DMA_TYPE(x) ((x) & SDHC_CTRL_DMA_CHECK_MASK) + +/* R/W Power Control Register 0x0 */ +#define SDHC_PWRCON 0x29 +#define SDHC_POWER_ON (1 << 0) + +/* R/W Block Gap Control Register 0x0 */ +#define SDHC_BLKGAP 0x2A +#define SDHC_STOP_AT_GAP_REQ 0x01 +#define SDHC_CONTINUE_REQ 0x02 + +/* R/W WakeUp Control Register 0x0 */ +#define SDHC_WAKCON 0x2B +#define SDHC_WKUP_ON_INS (1 << 1) +#define SDHC_WKUP_ON_RMV (1 << 2) + +/* CLKCON */ +#define SDHC_CLKCON 0x2C +#define SDHC_CLOCK_INT_STABLE 0x0002 +#define SDHC_CLOCK_INT_EN 0x0001 +#define SDHC_CLOCK_SDCLK_EN (1 << 2) +#define SDHC_CLOCK_CHK_MASK 0x0007 +#define SDHC_CLOCK_IS_ON(x) \ + (((x) & SDHC_CLOCK_CHK_MASK) == SDHC_CLOCK_CHK_MASK) + +/* R/W Timeout Control Register 0x0 */ +#define SDHC_TIMEOUTCON 0x2E + +/* R/W Software Reset Register 0x0 */ +#define SDHC_SWRST 0x2F +#define SDHC_RESET_ALL 0x01 +#define SDHC_RESET_CMD 0x02 +#define SDHC_RESET_DATA 0x04 + +/* ROC/RW1C Normal Interrupt Status Register 0x0 */ +#define SDHC_NORINTSTS 0x30 +#define SDHC_NIS_ERR 0x8000 +#define SDHC_NIS_CMDCMP 0x0001 +#define SDHC_NIS_TRSCMP 0x0002 +#define SDHC_NIS_BLKGAP 0x0004 +#define SDHC_NIS_DMA 0x0008 +#define SDHC_NIS_WBUFRDY 0x0010 +#define SDHC_NIS_RBUFRDY 0x0020 +#define SDHC_NIS_INSERT 0x0040 +#define SDHC_NIS_REMOVE 0x0080 +#define SDHC_NIS_CARDINT 0x0100 + +/* ROC/RW1C Error Interrupt Status Register 0x0 */ +#define SDHC_ERRINTSTS 0x32 +#define SDHC_EIS_CMDTIMEOUT 0x0001 +#define SDHC_EIS_BLKGAP 0x0004 +#define SDHC_EIS_CMDIDX 0x0008 +#define SDHC_EIS_CMD12ERR 0x0100 +#define SDHC_EIS_ADMAERR 0x0200 + +/* R/W Normal Interrupt Status Enable Register 0x0 */ +#define SDHC_NORINTSTSEN 0x34 +#define SDHC_NISEN_CMDCMP 0x0001 +#define SDHC_NISEN_TRSCMP 0x0002 +#define SDHC_NISEN_DMA 0x0008 +#define SDHC_NISEN_WBUFRDY 0x0010 +#define SDHC_NISEN_RBUFRDY 0x0020 +#define SDHC_NISEN_INSERT 0x0040 +#define SDHC_NISEN_REMOVE 0x0080 +#define SDHC_NISEN_CARDINT 0x0100 + +/* R/W Error Interrupt Status Enable Register 0x0 */ +#define SDHC_ERRINTSTSEN 0x36 +#define SDHC_EISEN_CMDTIMEOUT 0x0001 +#define SDHC_EISEN_BLKGAP 0x0004 +#define SDHC_EISEN_CMDIDX 0x0008 +#define SDHC_EISEN_ADMAERR 0x0200 + +/* R/W Normal Interrupt Signal Enable Register 0x0 */ +#define SDHC_NORINTSIGEN 0x38 +#define SDHC_NORINTSIG_INSERT (1 << 6) +#define SDHC_NORINTSIG_REMOVE (1 << 7) + +/* R/W Error Interrupt Signal Enable Register 0x0 */ +#define SDHC_ERRINTSIGEN 0x3A + +/* ROC Auto CMD12 error status register 0x0 */ +#define SDHC_ACMD12ERRSTS 0x3C + +/* HWInit Capabilities Register 0x05E80080 */ +#define SDHC_CAPAREG 0x40 +#define SDHC_CAN_DO_DMA 0x00400000 +#define SDHC_CAN_DO_ADMA2 0x00080000 +#define SDHC_CAN_DO_ADMA1 0x00100000 +#define SDHC_64_BIT_BUS_SUPPORT (1 << 28) +#define SDHC_CAPAB_BLOCKSIZE(x) (((x) >> 16) & 0x3) + +/* HWInit Maximum Current Capabilities Register 0x0 */ +#define SDHC_MAXCURR 0x48 + +/* W Force Event Auto CMD12 Error Interrupt Register 0x0000 */ +#define SDHC_FEAER 0x50 +/* W Force Event Error Interrupt Register Error Interrupt 0x0000 */ +#define SDHC_FEERR 0x52 + +/* R/W ADMA Error Status Register 0x00 */ +#define SDHC_ADMAERR 0x54 +#define SDHC_ADMAERR_LENGTH_MISMATCH (1 << 2) +#define SDHC_ADMAERR_STATE_ST_STOP (0 << 0) +#define SDHC_ADMAERR_STATE_ST_FDS (1 << 0) +#define SDHC_ADMAERR_STATE_ST_TFR (3 << 0) +#define SDHC_ADMAERR_STATE_MASK (3 << 0) + +/* R/W ADMA System Address Register 0x00 */ +#define SDHC_ADMASYSADDR 0x58 +#define SDHC_ADMA_ATTR_SET_LEN (1 << 4) +#define SDHC_ADMA_ATTR_ACT_TRAN (1 << 5) +#define SDHC_ADMA_ATTR_ACT_LINK (3 << 4) +#define SDHC_ADMA_ATTR_INT (1 << 2) +#define SDHC_ADMA_ATTR_END (1 << 1) +#define SDHC_ADMA_ATTR_VALID (1 << 0) +#define SDHC_ADMA_ATTR_ACT_MASK ((1 << 4)|(1 << 5)) + +/* Slot interrupt status */ +#define SDHC_SLOT_INT_STATUS 0xFC + +/* HWInit Host Controller Version Register 0x0401 */ +#define SDHC_HCVER 0xFE +#define SD_HOST_SPECv2_VERS 0x2401 + +#define SDHC_REGISTERS_MAP_SIZE 0x100 +#define SDHC_INSERTION_DELAY (get_ticks_per_sec()) +#define SDHC_TRANSFER_DELAY 100 +#define SDHC_ADMA_DESCS_PER_DELAY 5 +#define SDHC_CMD_RESPONSE (3 << 0) + +enum { + sdhc_not_stopped = 0, /* normal SDHC state */ + sdhc_gap_read = 1, /* SDHC stopped at block gap during read operation */ + sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */ +}; + +/* SD/MMC host controller state */ +typedef struct SDHCIState { + SysBusDevice busdev; + SDState *card; + MemoryRegion iomem; + + QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ + QEMUTimer *transfer_timer; + qemu_irq eject_cb; + qemu_irq ro_cb; + qemu_irq irq; + + uint32_t sdmasysad; /* SDMA System Address register */ + uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */ + uint16_t blkcnt; /* Blocks count for current transfer */ + uint32_t argument; /* Command Argument Register */ + uint16_t trnmod; /* Transfer Mode Setting Register */ + uint16_t cmdreg; /* Command Register */ + uint32_t rspreg[4]; /* Response Registers 0-3 */ + uint32_t prnsts; /* Present State Register */ + uint8_t hostctl; /* Host Control Register */ + uint8_t pwrcon; /* Power control Register */ + uint8_t blkgap; /* Block Gap Control Register */ + uint8_t wakcon; /* WakeUp Control Register */ + uint16_t clkcon; /* Clock control Register */ + uint8_t timeoutcon; /* Timeout Control Register */ + uint8_t admaerr; /* ADMA Error Status Register */ + uint16_t norintsts; /* Normal Interrupt Status Register */ + uint16_t errintsts; /* Error Interrupt Status Register */ + uint16_t norintstsen; /* Normal Interrupt Status Enable Register */ + uint16_t errintstsen; /* Error Interrupt Status Enable Register */ + uint16_t norintsigen; /* Normal Interrupt Signal Enable Register */ + uint16_t errintsigen; /* Error Interrupt Signal Enable Register */ + uint16_t acmd12errsts; /* Auto CMD12 error status register */ + uint64_t admasysaddr; /* ADMA System Address Register */ + + uint32_t capareg; /* Capabilities Register */ + uint32_t maxcurr; /* Maximum Current Capabilities Register */ + uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */ + uint32_t buf_maxsz; + uint16_t data_count; /* current element in FIFO buffer */ + uint8_t stopped_state;/* Current SDHC state */ + /* Buffer Data Port Register - virtual access point to R and W buffers */ + /* Software Reset Register - always reads as 0 */ + /* Force Event Auto CMD12 Error Interrupt Reg - write only */ + /* Force Event Error Interrupt Register- write only */ + /* RO Host Controller Version Register always reads as 0x2401 */ +} SDHCIState; + +typedef struct SDHCIClass { + SysBusDeviceClass busdev_class; + + void (*reset)(SDHCIState *s); + uint32_t (*mem_read)(SDHCIState *s, unsigned int offset, unsigned size); + void (*mem_write)(SDHCIState *s, unsigned int offset, uint32_t value, + unsigned size); + void (*send_command)(SDHCIState *s); + bool (*can_issue_command)(SDHCIState *s); + void (*data_transfer)(SDHCIState *s); + void (*end_data_transfer)(SDHCIState *s); + void (*do_sdma_single)(SDHCIState *s); + void (*do_sdma_multi)(SDHCIState *s); + void (*do_adma)(SDHCIState *s); + void (*read_block_from_card)(SDHCIState *s); + void (*write_block_to_card)(SDHCIState *s); + uint32_t (*bdata_read)(SDHCIState *s, unsigned size); + void (*bdata_write)(SDHCIState *s, uint32_t value, unsigned size); +} SDHCIClass; + +extern const VMStateDescription sdhci_vmstate; + +#define TYPE_SDHCI "generic-sdhci" +#define SDHCI(obj) \ + OBJECT_CHECK(SDHCIState, (obj), TYPE_SDHCI) +#define SDHCI_CLASS(klass) \ + OBJECT_CLASS_CHECK(SDHCIClass, (klass), TYPE_SDHCI) +#define SDHCI_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SDHCIClass, (obj), TYPE_SDHCI) + +#endif /* SDHCI_H */ From 80f4d9fcea86aeb3071750c199416cab9abd5c28 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:14 +0000 Subject: [PATCH 1312/1634] vl.c: allow for repeated -sd arguments Allows for repeating of -sd arguments in the same way as -pflash and -mtdblock. Acked-by: Igor Mitsyanko Reviewed-by: Peter Maydell Signed-off-by: Peter Crosthwaite Signed-off-by: Peter Maydell --- vl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vl.c b/vl.c index febd2eaa02..c03edf1bfb 100644 --- a/vl.c +++ b/vl.c @@ -2994,7 +2994,7 @@ int main(int argc, char **argv, char **envp) drive_add(IF_MTD, -1, optarg, MTD_OPTS); break; case QEMU_OPTION_sd: - drive_add(IF_SD, 0, optarg, SD_OPTS); + drive_add(IF_SD, -1, optarg, SD_OPTS); break; case QEMU_OPTION_pflash: drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS); From b972b4e25340abdd23238bc8f3bdacbef533bd5a Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:14 +0000 Subject: [PATCH 1313/1634] xilinx_zynq: Added SD controllers The Xilinx Zynq device has two SDHCI controllers. Added to the machine model. Reviewed-by: Peter Maydell Signed-off-by: Peter Crosthwaite Signed-off-by: Peter Maydell --- hw/xilinx_zynq.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 311f791833..39d9fb3e73 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -187,6 +187,16 @@ static void zynq_init(QEMUMachineInitArgs *args) } } + dev = qdev_create(NULL, "generic-sdhci"); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); + + dev = qdev_create(NULL, "generic-sdhci"); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); + zynq_binfo.ram_size = ram_size; zynq_binfo.kernel_filename = kernel_filename; zynq_binfo.kernel_cmdline = kernel_cmdline; From a7fd6915d84b20d5ff9ae287ddfabb9b222e7067 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:15 +0000 Subject: [PATCH 1314/1634] m25p80.c: Use QOM classes for part differentiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, M25P80 uses an object property to differentiate between flash parts. Changed this over to use QOM sub-classes - the actual names of the different parts are used to create a set of dynamic classes which passes the part info as class data. The object no longer needs to search the known_devices table for itself, instead it just gets its info from its own class. Kept the intermediate class definition private to m25p80.c for the moment, as the expectation is parts will only be added as new entries in the table. We can factor out the TYPE_M25P80 abstraction into a header on a demand basis. Signed-off-by: Peter Crosthwaite Message-id: e24e156d-ff96-4901-997a-e31178b08bee@VA3EHSMHS021.ehs.local Reviewed-by: Andreas Färber Signed-off-by: Peter Maydell --- hw/m25p80.c | 58 +++++++++++++++++++++------------------- hw/petalogix_ml605_mmu.c | 3 +-- hw/xilinx_zynq.c | 3 +-- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/hw/m25p80.c b/hw/m25p80.c index 461b41c4ac..1372d06409 100644 --- a/hw/m25p80.c +++ b/hw/m25p80.c @@ -178,8 +178,6 @@ static const FlashPartInfo known_devices[] = { /* Numonyx -- n25q128 */ { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, - - { }, }; typedef enum { @@ -236,11 +234,23 @@ typedef struct Flash { int64_t dirty_page; - char *part_name; const FlashPartInfo *pi; } Flash; +typedef struct M25P80Class { + SSISlaveClass parent_class; + FlashPartInfo *pi; +} M25P80Class; + +#define TYPE_M25P80 "m25p80-generic" +#define M25P80(obj) \ + OBJECT_CHECK(Flash, (obj), TYPE_M25P80) +#define M25P80_CLASS(klass) \ + OBJECT_CLASS_CHECK(M25P80Class, (klass), TYPE_M25P80) +#define M25P80_GET_CLASS(obj) \ + OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80) + static void bdrv_sync_complete(void *opaque, int ret) { /* do nothing. Masters do not directly interact with the backing store, @@ -571,23 +581,9 @@ static int m25p80_init(SSISlave *ss) { DriveInfo *dinfo; Flash *s = FROM_SSI_SLAVE(Flash, ss); - const FlashPartInfo *i; + M25P80Class *mc = M25P80_GET_CLASS(s); - if (!s->part_name) { /* default to actual m25p80 if no partname given */ - s->part_name = (char *)"m25p80"; - } - - i = known_devices; - for (i = known_devices;; i++) { - assert(i); - if (!i->part_name) { - fprintf(stderr, "Unknown SPI flash part: \"%s\"\n", s->part_name); - return 1; - } else if (!strcmp(i->part_name, s->part_name)) { - s->pi = i; - break; - } - } + s->pi = mc->pi; s->size = s->pi->sector_size * s->pi->n_sectors; s->dirty_page = -1; @@ -635,34 +631,42 @@ static const VMStateDescription vmstate_m25p80 = { } }; -static Property m25p80_properties[] = { - DEFINE_PROP_STRING("partname", Flash, part_name), - DEFINE_PROP_END_OF_LIST(), -}; - static void m25p80_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + M25P80Class *mc = M25P80_CLASS(klass); k->init = m25p80_init; k->transfer = m25p80_transfer8; k->set_cs = m25p80_cs; k->cs_polarity = SSI_CS_LOW; - dc->props = m25p80_properties; dc->vmsd = &vmstate_m25p80; + mc->pi = data; } static const TypeInfo m25p80_info = { - .name = "m25p80", + .name = TYPE_M25P80, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(Flash), - .class_init = m25p80_class_init, + .class_size = sizeof(M25P80Class), + .abstract = true, }; static void m25p80_register_types(void) { + int i; + type_register_static(&m25p80_info); + for (i = 0; i < ARRAY_SIZE(known_devices); ++i) { + TypeInfo ti = { + .name = known_devices[i].part_name, + .parent = TYPE_M25P80, + .class_init = m25p80_class_init, + .class_data = (void *)&known_devices[i], + }; + type_register(&ti); + } } type_init(m25p80_register_types) diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index 82d7183ae5..fe7a932009 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -158,8 +158,7 @@ petalogix_ml605_init(QEMUMachineInitArgs *args) for (i = 0; i < NUM_SPI_FLASHES; i++) { qemu_irq cs_line; - dev = ssi_create_slave_no_init(spi, "m25p80"); - qdev_prop_set_string(dev, "partname", "n25q128"); + dev = ssi_create_slave_no_init(spi, "n25q128"); qdev_init_nofail(dev); cs_line = qdev_get_gpio_in(dev, 0); sysbus_connect_irq(busdev, i+1, cs_line); diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 39d9fb3e73..2f67d90ee1 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -82,8 +82,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); for (j = 0; j < num_ss; ++j) { - flash_dev = ssi_create_slave_no_init(spi, "m25p80"); - qdev_prop_set_string(flash_dev, "partname", "n25q128"); + flash_dev = ssi_create_slave_no_init(spi, "n25q128"); qdev_init_nofail(flash_dev); cs_line = qdev_get_gpio_in(flash_dev, 0); From e3f9d31c9899cc94e124b042d7d5353dbfd812ca Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:15 +0000 Subject: [PATCH 1315/1634] cadence_gem: Flush queued packets The device needs to check for queued RX packets when the RX path is re-enabled. Signed-off-by: Peter Crosthwaite Message-id: 1fa8c88a3b7c654886d0a7484c2463cd4c2a2781.1360901435.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/cadence_gem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index ab86c1702d..e6032ea44f 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -1106,6 +1106,9 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, /* Reset to start of Q when receive disabled. */ s->rx_desc_addr = s->regs[GEM_RXQBASE]; } + if (val & GEM_NWCTRL_RXENA) { + qemu_flush_queued_packets(qemu_get_queue(s->nic)); + } break; case GEM_TXSTATUS: From 1c5d07909aea7657c7c6b24223460150526369ba Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:15 +0000 Subject: [PATCH 1316/1634] cadence_gem: factor out can_rx() logic replication The gem_receive() function replicates the logic for whether or not the device can rx. Just call the actual gem_can_receive() function in place. Signed-off-by: Peter Crosthwaite Message-id: bf7f93969f3e01fbc76d68d2955307fdbad11bb1.1360901435.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/cadence_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index e6032ea44f..966ab4f8a8 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -615,7 +615,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) s = qemu_get_nic_opaque(nc); /* Do nothing if receive is not enabled. */ - if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) { + if (!gem_can_receive(nc)) { return -1; } From ae80a3546f412c407199b9b7ebd52ac604361e10 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:15 +0000 Subject: [PATCH 1317/1634] cadence_gem: fix interrupt events Bits in the ISR were continually mirroring their corresponding TX/RX SR bits. This is incorrect. The ISR bits are only ever set at the time their corresponding event occurs. Signed-off-by: Peter Crosthwaite Message-id: cedfb6d108318846480b416a6041023ea5a353d6.1360901435.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/cadence_gem.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 966ab4f8a8..a1ac069a20 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -427,32 +427,9 @@ static int gem_can_receive(NetClientState *nc) */ static void gem_update_int_status(GemState *s) { - uint32_t new_interrupts = 0; - /* Packet transmitted ? */ - if (s->regs[GEM_TXSTATUS] & GEM_TXSTATUS_TXCMPL) { - new_interrupts |= GEM_INT_TXCMPL; - } - /* End of TX ring ? */ - if (s->regs[GEM_TXSTATUS] & GEM_TXSTATUS_USED) { - new_interrupts |= GEM_INT_TXUSED; - } - - /* Frame received ? */ - if (s->regs[GEM_RXSTATUS] & GEM_RXSTATUS_FRMRCVD) { - new_interrupts |= GEM_INT_RXCMPL; - } - /* RX ring full ? */ - if (s->regs[GEM_RXSTATUS] & GEM_RXSTATUS_NOBUF) { - new_interrupts |= GEM_INT_RXUSED; - } - - s->regs[GEM_ISR] |= new_interrupts & ~(s->regs[GEM_IMR]); - if (s->regs[GEM_ISR]) { DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]); qemu_set_irq(s->irq, 1); - } else { - qemu_set_irq(s->irq, 0); } } @@ -697,6 +674,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) DB_PRINT("descriptor 0x%x owned by sw.\n", (unsigned)packet_desc_addr); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; + s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ gem_update_int_status(s); return -1; @@ -765,6 +743,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) (uint8_t *)&desc[0], sizeof(desc)); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD; + s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ gem_update_int_status(s); @@ -894,6 +873,7 @@ static void gem_transmit(GemState *s) DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr); s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL; + s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ gem_update_int_status(s); @@ -931,6 +911,7 @@ static void gem_transmit(GemState *s) if (tx_desc_get_used(desc)) { s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED; + s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]); gem_update_int_status(s); } } From 5025388b5083f199b05cc252c2b031d9fc230391 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:16 +0000 Subject: [PATCH 1318/1634] cadence_gem: Don't reset rx desc pointer on rx_en This doesn't happen in the real hardware. The Zynq TRM explicitly states that this bit has no effect on the rx descriptor pointer ("The receive queue pointer register is unaffected"). Signed-off-by: Peter Crosthwaite Message-id: 06fdf92b78ee62d8965779bafd29c8df1a5d2718.1360901435.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/cadence_gem.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index a1ac069a20..61f1801273 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -1083,10 +1083,6 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val, /* Reset to start of Q when transmit disabled. */ s->tx_desc_addr = s->regs[GEM_TXQBASE]; } - if (!(val & GEM_NWCTRL_RXENA)) { - /* Reset to start of Q when receive disabled. */ - s->rx_desc_addr = s->regs[GEM_RXQBASE]; - } if (val & GEM_NWCTRL_RXENA) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } From 288f1e3f87ec24abeac38399f175fe74243f7bc5 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Thu, 28 Feb 2013 18:23:16 +0000 Subject: [PATCH 1319/1634] cadence_gem: Add debug msgs for rx desc movement Add some helpful messages that show the rx descriptor pointer moving as packets are rxed. Signed-off-by: Peter Crosthwaite Message-id: 1ef2eb34dade64d589a69a2bcfd5aaddb7d50164.1360901435.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- hw/cadence_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index 61f1801273..de7d15ab76 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -724,7 +724,9 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) s->rx_desc_addr = last_desc_addr; if (rx_desc_get_wrap(desc)) { s->rx_desc_addr = s->regs[GEM_RXQBASE]; + DB_PRINT("wrapping RX descriptor list\n"); } else { + DB_PRINT("incrementing RX descriptor list\n"); s->rx_desc_addr += 8; } From 159b6e9f144c7afdf3ad95c29d1fede9626fa8b1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 3 Feb 2013 20:21:00 +0100 Subject: [PATCH 1320/1634] hw: move char backends to backends/ Braille and msmouse support is in hw/, but it is not hardware. Move it to the backends/ directory. Signed-off-by: Paolo Bonzini --- backends/Makefile.objs | 4 ++++ {hw => backends}/baum.c | 4 ++-- {hw => backends}/msmouse.c | 2 +- hw/Makefile.objs | 4 +--- {hw => include/char}/baum.h | 0 {hw => include/char}/msmouse.h | 0 qemu-char.c | 4 ++-- vl.c | 2 +- 8 files changed, 11 insertions(+), 9 deletions(-) rename {hw => backends}/baum.c (99%) rename {hw => backends}/msmouse.c (99%) rename {hw => include/char}/baum.h (100%) rename {hw => include/char}/msmouse.h (100%) diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 883676106b..464bc3e220 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -1,2 +1,6 @@ common-obj-y += rng.o rng-egd.o common-obj-$(CONFIG_POSIX) += rng-random.o + +common-obj-y += msmouse.o +common-obj-$(CONFIG_BRLAPI) += baum.o +$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) diff --git a/hw/baum.c b/backends/baum.c similarity index 99% rename from hw/baum.c rename to backends/baum.c index 09dcb9cc74..37ccca8211 100644 --- a/hw/baum.c +++ b/backends/baum.c @@ -24,8 +24,8 @@ #include "qemu-common.h" #include "char/char.h" #include "qemu/timer.h" -#include "usb.h" -#include "baum.h" +#include "hw/usb.h" +#include "char/baum.h" #include #include #include diff --git a/hw/msmouse.c b/backends/msmouse.c similarity index 99% rename from hw/msmouse.c rename to backends/msmouse.c index ef47aed4e9..bf2ff2aca8 100644 --- a/hw/msmouse.c +++ b/backends/msmouse.c @@ -25,7 +25,7 @@ #include "qemu-common.h" #include "char/char.h" #include "ui/console.h" -#include "msmouse.h" +#include "char/msmouse.h" #define MSMOUSE_LO6(n) ((n) & 0x3f) #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 40ebe466ad..5750332f54 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -190,10 +190,9 @@ common-obj-$(CONFIG_SSI_SD) += ssi-sd.o common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o -common-obj-y += msmouse.o ps2.o +common-obj-y += ps2.o common-obj-y += qdev-monitor.o common-obj-y += qdev-properties-system.o -common-obj-$(CONFIG_BRLAPI) += baum.o # xen backend driver support common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o @@ -218,5 +217,4 @@ obj-$(CONFIG_KVM) += ivshmem.o obj-$(CONFIG_LINUX) += vfio_pci.o endif -$(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) endif diff --git a/hw/baum.h b/include/char/baum.h similarity index 100% rename from hw/baum.h rename to include/char/baum.h diff --git a/hw/msmouse.h b/include/char/msmouse.h similarity index 100% rename from hw/msmouse.h rename to include/char/msmouse.h diff --git a/qemu-char.c b/qemu-char.c index 160decc2f0..6dc1474546 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -28,8 +28,8 @@ #include "qemu/timer.h" #include "char/char.h" #include "hw/usb.h" -#include "hw/baum.h" -#include "hw/msmouse.h" +#include "char/baum.h" +#include "char/msmouse.h" #include "qmp-commands.h" #include diff --git a/vl.c b/vl.c index c03edf1bfb..e0a8eeb24b 100644 --- a/vl.c +++ b/vl.c @@ -119,7 +119,7 @@ int main(int argc, char **argv) #include "hw/pcmcia.h" #include "hw/pc.h" #include "hw/isa.h" -#include "hw/baum.h" +#include "char/baum.h" #include "hw/bt.h" #include "hw/watchdog.h" #include "hw/smbios.h" From fd7f0d66177ec1058a2a256856ff38fc9ceae5af Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 10:57:50 +0100 Subject: [PATCH 1321/1634] hw: move fifo.[ch] to libqemuutil fifo.c is generic code that can be easily unit tested. So it belongs in libqemuutil. Signed-off-by: Paolo Bonzini --- hw/Makefile.objs | 1 - hw/xilinx_spi.c | 2 +- hw/xilinx_spips.c | 2 +- include/migration/vmstate.h | 2 ++ hw/fifo.h => include/qemu/fifo8.h | 2 +- util/Makefile.objs | 1 + hw/fifo.c => util/fifo8.c | 3 ++- 7 files changed, 8 insertions(+), 5 deletions(-) rename hw/fifo.h => include/qemu/fifo8.h (98%) rename hw/fifo.c => util/fifo8.c (97%) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 5750332f54..6e2275b842 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -44,7 +44,6 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o endif common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-$(CONFIG_SDHCI) += sdhci.o -common-obj-y += fifo.o common-obj-y += pam.o # PPC devices diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c index be581c2ac5..e73c9bd79b 100644 --- a/hw/xilinx_spi.c +++ b/hw/xilinx_spi.c @@ -27,7 +27,7 @@ #include "sysbus.h" #include "sysemu/sysemu.h" #include "qemu/log.h" -#include "fifo.h" +#include "qemu/fifo8.h" #include "ssi.h" diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 42e019dc05..915eb96a48 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -26,7 +26,7 @@ #include "sysemu/sysemu.h" #include "ptimer.h" #include "qemu/log.h" -#include "fifo.h" +#include "qemu/fifo8.h" #include "ssi.h" #include "qemu/bitops.h" diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index f27276c2d8..94a409b708 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -26,6 +26,8 @@ #ifndef QEMU_VMSTATE_H #define QEMU_VMSTATE_H 1 +#include + typedef void SaveStateHandler(QEMUFile *f, void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); diff --git a/hw/fifo.h b/include/qemu/fifo8.h similarity index 98% rename from hw/fifo.h rename to include/qemu/fifo8.h index f23890abf4..d318f71e11 100644 --- a/hw/fifo.h +++ b/include/qemu/fifo8.h @@ -1,7 +1,7 @@ #ifndef FIFO_H #define FIFO_H -#include "hw.h" +#include "migration/vmstate.h" typedef struct { /* All fields are private */ diff --git a/util/Makefile.objs b/util/Makefile.objs index 495a178557..cad5ce87db 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -3,6 +3,7 @@ util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o util-obj-y += bitmap.o bitops.o hbitmap.o +util-obj-y += fifo8.o util-obj-y += acl.o util-obj-y += error.o qemu-error.o util-obj-$(CONFIG_POSIX) += compatfd.o diff --git a/hw/fifo.c b/util/fifo8.c similarity index 97% rename from hw/fifo.c rename to util/fifo8.c index 68a955a77b..013e903c6e 100644 --- a/hw/fifo.c +++ b/util/fifo8.c @@ -12,7 +12,8 @@ * with this program; if not, see . */ -#include "fifo.h" +#include "qemu-common.h" +#include "qemu/fifo8.h" void fifo8_create(Fifo8 *fifo, uint32_t capacity) { From b4a42f81383d60900aae09513f42eb857a5a7c7c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 11:37:52 +0100 Subject: [PATCH 1322/1634] hw: move qdev-monitor.o to toplevel directory qdev-monitor.c is the only "core qdev" file that is not used in user-mode emulation, and it does not define anything that is used by hardware models. Remove it from the hw/ directory and remove hw/qdev-monitor.h from hw/qdev.h too; this requires some files to have some new explicitly includes. Signed-off-by: Paolo Bonzini --- Makefile.objs | 1 + hw/9pfs/virtio-9p-proxy.c | 1 + hw/Makefile.objs | 1 - hw/dataplane/virtio-blk.c | 2 ++ hw/dataplane/vring.c | 1 + hw/pc87312.c | 1 + hw/pc_sysfw.c | 1 + hw/pci/shpc.c | 3 ++- hw/pci/slotid_cap.c | 1 + hw/qdev-addr.c | 1 + hw/qdev.c | 1 + hw/qdev.h | 1 - hw/s390x/sclpconsole.c | 1 + hw/usb/dev-network.c | 1 + hw/virtio-rng.c | 1 + hw/virtio-scsi.c | 1 + hw/xilinx.h | 3 ++- hw/xilinx_axienet.c | 1 + hw/qdev-monitor.h => include/monitor/qdev.h | 3 +-- monitor.c | 2 +- hw/qdev-monitor.c => qdev-monitor.c | 3 ++- util/qemu-config.c | 1 + vl.c | 1 + 23 files changed, 25 insertions(+), 8 deletions(-) rename hw/qdev-monitor.h => include/monitor/qdev.h (80%) rename hw/qdev-monitor.c => qdev-monitor.c (99%) diff --git a/Makefile.objs b/Makefile.objs index a68cdac7ce..2a8174dd15 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -51,6 +51,7 @@ ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ common-obj-y += readline.o +common-obj-y += qdev-monitor.o common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index 54e98759f0..730027900e 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -13,6 +13,7 @@ #include #include "hw/virtio.h" #include "virtio-9p.h" +#include "qemu/error-report.h" #include "fsdev/qemu-fsdev.h" #include "virtio-9p-proxy.h" diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 6e2275b842..f7ee133627 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -190,7 +190,6 @@ common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += ps2.o -common-obj-y += qdev-monitor.o common-obj-y += qdev-properties-system.o # xen backend driver support diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 3f2da22669..8588f93114 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -16,9 +16,11 @@ #include "qemu/iov.h" #include "event-poll.h" #include "qemu/thread.h" +#include "qemu/error-report.h" #include "vring.h" #include "ioq.h" #include "migration/migration.h" +#include "block/block.h" #include "hw/virtio-blk.h" #include "hw/dataplane/virtio-blk.h" diff --git a/hw/dataplane/vring.c b/hw/dataplane/vring.c index d5d4ef45d1..eff5ad8831 100644 --- a/hw/dataplane/vring.c +++ b/hw/dataplane/vring.c @@ -16,6 +16,7 @@ #include "trace.h" #include "hw/dataplane/vring.h" +#include "qemu/error-report.h" /* Map the guest's vring to host memory */ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n) diff --git a/hw/pc87312.c b/hw/pc87312.c index 38af4c1d10..0e9760e6b2 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -24,6 +24,7 @@ */ #include "pc87312.h" +#include "qemu/error-report.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" #include "char/char.h" diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index 7f6c12c8a8..8b65a7a4d8 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -24,6 +24,7 @@ */ #include "sysemu/blockdev.h" +#include "qemu/error-report.h" #include "sysbus.h" #include "hw.h" #include "pc.h" diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c index f07266da66..d35c2ee965 100644 --- a/hw/pci/shpc.c +++ b/hw/pci/shpc.c @@ -1,7 +1,8 @@ +#include "qemu-common.h" #include #include #include "qemu/range.h" -#include "qemu/range.h" +#include "qemu/error-report.h" #include "hw/pci/shpc.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" diff --git a/hw/pci/slotid_cap.c b/hw/pci/slotid_cap.c index 99a30f429d..62f7bae2f1 100644 --- a/hw/pci/slotid_cap.c +++ b/hw/pci/slotid_cap.c @@ -1,5 +1,6 @@ #include "hw/pci/slotid_cap.h" #include "hw/pci/pci.h" +#include "qemu/error-report.h" #define SLOTID_CAP_LENGTH 4 #define SLOTID_NSLOTS_SHIFT (ffs(PCI_SID_ESR_NSLOTS) - 1) diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index b4388f6a66..fc2c437911 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -1,6 +1,7 @@ #include "qdev.h" #include "qdev-addr.h" #include "exec/hwaddr.h" +#include "qapi/qmp/qerror.h" #include "qapi/visitor.h" /* --- target physical address --- */ diff --git a/hw/qdev.c b/hw/qdev.c index 689cd543e9..62bc8990f0 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -28,6 +28,7 @@ #include "qdev.h" #include "sysemu/sysemu.h" #include "qapi/error.h" +#include "qapi/qmp/qerror.h" #include "qapi/visitor.h" int qdev_hotplug = 0; diff --git a/hw/qdev.h b/hw/qdev.h index 365b8d6ca2..f814656e0a 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -4,6 +4,5 @@ #include "hw/hw.h" #include "qdev-core.h" #include "qdev-properties.h" -#include "qdev-monitor.h" #endif diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index effe51110f..475d7ba856 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -14,6 +14,7 @@ #include #include "qemu/thread.h" +#include "qemu/error-report.h" #include "sclp.h" #include "event-facility.h" diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index c08718b679..5473ac2cd5 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -27,6 +27,7 @@ #include "hw/usb.h" #include "hw/usb/desc.h" #include "net/net.h" +#include "qapi/qmp/qerror.h" #include "qemu/queue.h" #include "qemu/config-file.h" #include "sysemu/sysemu.h" diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c index e063127df6..2cdf4ec052 100644 --- a/hw/virtio-rng.c +++ b/hw/virtio-rng.c @@ -11,6 +11,7 @@ #include "qemu/iov.h" #include "qdev.h" +#include "qapi/qmp/qerror.h" #include "virtio.h" #include "virtio-rng.h" #include "qemu/rng.h" diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 0715865489..27070d1eea 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -14,6 +14,7 @@ */ #include "virtio-scsi.h" +#include "qemu/error-report.h" #include #include diff --git a/hw/xilinx.h b/hw/xilinx.h index 09bc2e4913..a78281f730 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -2,8 +2,9 @@ #define HW_XILINX_H 1 -#include "stream.h" #include "qemu-common.h" +#include "qapi/qmp/qerror.h" +#include "stream.h" #include "net/net.h" static inline DeviceState * diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index e5d9251b8b..66b9ec1cc5 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -26,6 +26,7 @@ #include "qemu/log.h" #include "net/net.h" #include "net/checksum.h" +#include "qapi/qmp/qerror.h" #include "stream.h" diff --git a/hw/qdev-monitor.h b/include/monitor/qdev.h similarity index 80% rename from hw/qdev-monitor.h rename to include/monitor/qdev.h index 9ec485028e..8d16e119d3 100644 --- a/hw/qdev-monitor.h +++ b/include/monitor/qdev.h @@ -1,7 +1,7 @@ #ifndef QEMU_QDEV_MONITOR_H #define QEMU_QDEV_MONITOR_H -#include "qdev-core.h" +#include "hw/qdev-core.h" #include "monitor/monitor.h" /*** monitor commands ***/ @@ -9,7 +9,6 @@ void do_info_qtree(Monitor *mon, const QDict *qdict); void do_info_qdm(Monitor *mon, const QDict *qdict); int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); -int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); diff --git a/monitor.c b/monitor.c index 32a6e74fd9..c48530bd55 100644 --- a/monitor.c +++ b/monitor.c @@ -23,7 +23,7 @@ */ #include #include "hw/hw.h" -#include "hw/qdev.h" +#include "monitor/qdev.h" #include "hw/usb.h" #include "hw/pcmcia.h" #include "hw/pc.h" diff --git a/hw/qdev-monitor.c b/qdev-monitor.c similarity index 99% rename from hw/qdev-monitor.c rename to qdev-monitor.c index 4f9a6eb39a..9a78ccff6d 100644 --- a/hw/qdev-monitor.c +++ b/qdev-monitor.c @@ -17,8 +17,9 @@ * License along with this library; if not, see . */ -#include "qdev.h" +#include "hw/qdev.h" #include "monitor/monitor.h" +#include "monitor/qdev.h" #include "qmp-commands.h" #include "sysemu/arch_init.h" #include "qemu/config-file.h" diff --git a/util/qemu-config.c b/util/qemu-config.c index db6ec03a78..01ca8901cf 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -2,6 +2,7 @@ #include "qemu/error-report.h" #include "qemu/option.h" #include "qemu/config-file.h" +#include "qapi/qmp/qerror.h" #include "hw/qdev.h" #include "qapi/error.h" diff --git a/vl.c b/vl.c index e0a8eeb24b..bbdbafdca6 100644 --- a/vl.c +++ b/vl.c @@ -126,6 +126,7 @@ int main(int argc, char **argv) #include "hw/xen.h" #include "hw/qdev.h" #include "hw/loader.h" +#include "monitor/qdev.h" #include "bt/bt.h" #include "net/net.h" #include "net/slirp.h" From 1559e0d4b54d1b0744983b57da893617ceae8b94 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 17:20:47 +0100 Subject: [PATCH 1323/1634] hw: move device-hotplug.o to toplevel, compile it once The situation with device-hotplug.c is similar to qdev-monitor.c. Add a stub for pci_drive_hot_add, so that it can be compiled once, and move it out of hw/. Signed-off-by: Paolo Bonzini --- Makefile.objs | 2 +- hw/device-hotplug.c => device-hotplug.c | 13 ++----------- hw/Makefile.objs | 1 - stubs/Makefile.objs | 1 + stubs/pci-drive-hot-add.c | 10 ++++++++++ 5 files changed, 14 insertions(+), 13 deletions(-) rename hw/device-hotplug.c => device-hotplug.c (88%) create mode 100644 stubs/pci-drive-hot-add.c diff --git a/Makefile.objs b/Makefile.objs index 2a8174dd15..8c90b92d01 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -51,7 +51,7 @@ ifeq ($(CONFIG_SOFTMMU),y) common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/ common-obj-y += net/ common-obj-y += readline.o -common-obj-y += qdev-monitor.o +common-obj-y += qdev-monitor.o device-hotplug.o common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o diff --git a/hw/device-hotplug.c b/device-hotplug.c similarity index 88% rename from hw/device-hotplug.c rename to device-hotplug.c index 88da145a89..103d34ac45 100644 --- a/hw/device-hotplug.c +++ b/device-hotplug.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "boards.h" +#include "hw/hw.h" +#include "hw/boards.h" #include "sysemu/blockdev.h" #include "qemu/config-file.h" #include "sysemu/sysemu.h" @@ -47,15 +47,6 @@ DriveInfo *add_init_drive(const char *optstr) return dinfo; } -#if !defined(TARGET_I386) -int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo) -{ - /* On non-x86 we don't do PCI hotplug */ - monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type); - return -1; -} -#endif - void drive_hot_add(Monitor *mon, const QDict *qdict) { DriveInfo *dinfo = NULL; diff --git a/hw/Makefile.objs b/hw/Makefile.objs index f7ee133627..43f467a1ee 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -206,7 +206,6 @@ obj-$(CONFIG_SOFTMMU) += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ obj-$(CONFIG_VGA) += vga.o -obj-$(CONFIG_SOFTMMU) += device-hotplug.o obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o # Inter-VM PCI shared memory & VFIO PCI device assignment diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index a2603947db..9c55b34354 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -15,6 +15,7 @@ stub-obj-y += mon-printf.o stub-obj-y += mon-print-filename.o stub-obj-y += mon-protocol-event.o stub-obj-y += mon-set-error.o +stub-obj-y += pci-drive-hot-add.o stub-obj-y += reset.o stub-obj-y += set-fd-handler.o stub-obj-y += slirp.o diff --git a/stubs/pci-drive-hot-add.c b/stubs/pci-drive-hot-add.c new file mode 100644 index 0000000000..1d98145802 --- /dev/null +++ b/stubs/pci-drive-hot-add.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo) +{ + /* On non-x86 we don't do PCI hotplug */ + monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type); + return -1; +} From 7e6b14dfb575a687cb26be9995c96e5bbf5cba2e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:32:02 +0100 Subject: [PATCH 1324/1634] virtio-9p: use CONFIG_VIRTFS, not CONFIG_LINUX Signed-off-by: Paolo Bonzini --- hw/virtio-pci.h | 2 +- hw/virtio.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index d24957cc25..e775525c05 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -75,7 +75,7 @@ struct VirtIOPCIProxy { VirtIOBlkConf blk; NICConf nic; uint32_t host_features; -#ifdef CONFIG_LINUX +#ifdef CONFIG_VIRTFS V9fsConf fsconf; #endif virtio_serial_conf serial; diff --git a/hw/virtio.h b/hw/virtio.h index 1e206b8355..ae43d25193 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -19,7 +19,7 @@ #include "qdev.h" #include "sysemu/sysemu.h" #include "qemu/event_notifier.h" -#ifdef CONFIG_LINUX +#ifdef CONFIG_VIRTFS #include "9p.h" #endif @@ -252,7 +252,7 @@ typedef struct VirtIOSCSIConf VirtIOSCSIConf; VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf); typedef struct VirtIORNGConf VirtIORNGConf; VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf); -#ifdef CONFIG_LINUX +#ifdef CONFIG_VIRTFS VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); #endif From 60653b28f505288689d0b44218de4bb9fd254519 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:37:49 +0100 Subject: [PATCH 1325/1634] virtio-9p: remove PCI dependencies from hw/9pfs/ Also move the 9p.h file to 9pfs/virtio-9p-device.h, for consistency with the corresponding .c file. Signed-off-by: Paolo Bonzini --- hw/9pfs/virtio-9p-device.c | 53 +--------------------------- hw/{9p.h => 9pfs/virtio-9p-device.h} | 4 +-- hw/9pfs/virtio-9p.c | 3 +- hw/9pfs/virtio-9p.h | 1 - hw/virtio-pci.c | 50 +++++++++++++++++++++++++- hw/virtio-pci.h | 2 +- hw/virtio.h | 2 +- 7 files changed, 55 insertions(+), 60 deletions(-) rename hw/{9p.h => 9pfs/virtio-9p-device.h} (85%) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 74155fb61e..d321c802f2 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -14,9 +14,9 @@ #include "hw/virtio.h" #include "hw/pc.h" #include "qemu/sockets.h" -#include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" +#include "virtio-9p-device.h" #include "virtio-9p-xattr.h" #include "virtio-9p-coth.h" @@ -136,54 +136,3 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) return &s->vdev; } - -static int virtio_9p_init_pci(PCIDevice *pci_dev) -{ - VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); - VirtIODevice *vdev; - - vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); - vdev->nvectors = proxy->nvectors; - virtio_init_pci(proxy, vdev); - /* make the actual value visible */ - proxy->nvectors = vdev->nvectors; - return 0; -} - -static Property virtio_9p_properties[] = { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), - DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtio_9p_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = virtio_9p_init_pci; - k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; - k->device_id = PCI_DEVICE_ID_VIRTIO_9P; - k->revision = VIRTIO_PCI_ABI_VERSION; - k->class_id = 0x2; - dc->props = virtio_9p_properties; - dc->reset = virtio_pci_reset; -} - -static const TypeInfo virtio_9p_info = { - .name = "virtio-9p-pci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VirtIOPCIProxy), - .class_init = virtio_9p_class_init, -}; - -static void virtio_9p_register_types(void) -{ - type_register_static(&virtio_9p_info); - virtio_9p_set_fd_limit(); -} - -type_init(virtio_9p_register_types) diff --git a/hw/9p.h b/hw/9pfs/virtio-9p-device.h similarity index 85% rename from hw/9p.h rename to hw/9pfs/virtio-9p-device.h index d9951d6bcc..65789db131 100644 --- a/hw/9p.h +++ b/hw/9pfs/virtio-9p-device.h @@ -11,8 +11,8 @@ * */ -#ifndef QEMU_9P_H -#define QEMU_9P_H +#ifndef QEMU_VIRTIO_9P_DEVICE_H +#define QEMU_VIRTIO_9P_DEVICE_H typedef struct V9fsConf { diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index d3ea820eae..5cc4c92012 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -14,7 +14,6 @@ #include "hw/virtio.h" #include "hw/pc.h" #include "qemu/sockets.h" -#include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" #include "virtio-9p-xattr.h" @@ -3269,7 +3268,7 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq) free_pdu(s, pdu); } -void virtio_9p_set_fd_limit(void) +static void __attribute__((__constructor__)) virtio_9p_set_fd_limit(void) { struct rlimit rlim; if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 406fe522db..52b1c6997f 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -389,7 +389,6 @@ static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) } extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq); -extern void virtio_9p_set_fd_limit(void); extern void v9fs_reclaim_fd(V9fsPDU *pdu); extern void v9fs_path_init(V9fsPath *path); extern void v9fs_path_free(V9fsPath *path); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index a869f535de..df1dd7744c 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -255,7 +255,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) proxy->ioeventfd_started = false; } -void virtio_pci_reset(DeviceState *d) +static void virtio_pci_reset(DeviceState *d) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); virtio_pci_stop_ioeventfd(proxy); @@ -1313,6 +1313,51 @@ static const TypeInfo virtio_scsi_info = { .class_init = virtio_scsi_class_init, }; +#ifdef CONFIG_VIRTFS +static int virtio_9p_init_pci(PCIDevice *pci_dev) +{ + VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev; + + vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf); + vdev->nvectors = proxy->nvectors; + virtio_init_pci(proxy, vdev); + /* make the actual value visible */ + proxy->nvectors = vdev->nvectors; + return 0; +} + +static Property virtio_9p_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), + DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_9p_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_9p_init_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_9P; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = 0x2; + dc->props = virtio_9p_properties; + dc->reset = virtio_pci_reset; +} + +static const TypeInfo virtio_9p_info = { + .name = "virtio-9p-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_9p_class_init, +}; +#endif + /* * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. */ @@ -1475,6 +1520,9 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_rng_info); type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); +#ifdef CONFIG_VIRTFS + type_register_static(&virtio_9p_info); +#endif } type_init(virtio_pci_register_types) diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index e775525c05..d01db97e1e 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -22,6 +22,7 @@ #include "virtio-serial.h" #include "virtio-scsi.h" #include "virtio-bus.h" +#include "9pfs/virtio-9p-device.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; @@ -90,7 +91,6 @@ struct VirtIOPCIProxy { }; void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev); -void virtio_pci_reset(DeviceState *d); void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev); /* Virtio ABI version, if we increment this, we break the guest driver. */ diff --git a/hw/virtio.h b/hw/virtio.h index ae43d25193..8cc71e99b6 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -20,7 +20,7 @@ #include "sysemu/sysemu.h" #include "qemu/event_notifier.h" #ifdef CONFIG_VIRTFS -#include "9p.h" +#include "9pfs/virtio-9p-device.h" #endif /* from Linux's linux/virtio_config.h */ From eac7ec7f6a5c9e1a0a082ea8525f31549b1f0cb4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:00:38 +0100 Subject: [PATCH 1326/1634] vt82c686: vt82c686 is not a PCI host bridge Signed-off-by: Paolo Bonzini --- hw/vt82c686.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 2d8e3988db..c2b1bfce10 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -26,8 +26,6 @@ #include "qemu/timer.h" #include "exec/address-spaces.h" -typedef uint32_t pci_addr_t; -#include "pci/pci_host.h" //#define DEBUG_VT82C686B #ifdef DEBUG_VT82C686B From 7948b4b009b60c6e3b21daad29088b204ddb1966 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 3 Feb 2013 20:18:28 +0100 Subject: [PATCH 1327/1634] ppc: do not use ../ in include files This simplifies the scripted execution of the next patch. Signed-off-by: Paolo Bonzini --- hw/ppc/e500-ccsr.h | 2 +- hw/ppc/e500plat.c | 2 +- hw/ppc/mpc8544ds.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/ppc/e500-ccsr.h b/hw/ppc/e500-ccsr.h index f20f51bcd2..12a2ba4b97 100644 --- a/hw/ppc/e500-ccsr.h +++ b/hw/ppc/e500-ccsr.h @@ -1,7 +1,7 @@ #ifndef E500_CCSR_H #define E500_CCSR_H -#include "../sysbus.h" +#include "hw/sysbus.h" typedef struct PPCE500CCSRState { /*< private >*/ diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 25ac4b1dae..4b3057528c 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -12,7 +12,7 @@ #include "config.h" #include "qemu-common.h" #include "e500.h" -#include "../boards.h" +#include "hw/boards.h" #include "sysemu/device_tree.h" #include "hw/pci/pci.h" #include "hw/openpic.h" diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index e25c70b1f3..cf29788c4d 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -12,7 +12,7 @@ #include "config.h" #include "qemu-common.h" #include "e500.h" -#include "../boards.h" +#include "hw/boards.h" #include "sysemu/device_tree.h" #include "hw/openpic.h" From 83c9f4ca794ec3b6fa7e5a5bb055d378916503e0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Feb 2013 15:40:22 +0100 Subject: [PATCH 1328/1634] hw: include hw header files with full paths Done with this script: cd hw for i in `find . -name '*.h' | sed 's/^..//'`; do echo '\,^#.*include.*["<]'$i'[">], s,'$i',hw/&,' done | sed -i -f - `find . -type f` This is so that paths remain valid as files are moved. Instead, files in hw/dataplane are referenced with the relative path. We know they are not going to move to include/, and they are the only include files that are in subdirectories _and_ move. Signed-off-by: Paolo Bonzini --- hw/a15mpcore.c | 2 +- hw/a9mpcore.c | 2 +- hw/a9scu.c | 2 +- hw/ac97.c | 6 ++--- hw/acpi.c | 6 ++--- hw/acpi_ich9.c | 10 ++++---- hw/acpi_ich9.h | 2 +- hw/acpi_piix4.c | 14 +++++------ hw/adb.c | 4 ++-- hw/adb.h | 2 +- hw/adlib.c | 8 +++---- hw/ads7846.c | 2 +- hw/alpha_dp264.c | 16 ++++++------- hw/alpha_pci.c | 2 +- hw/alpha_sys.h | 10 ++++---- hw/alpha_typhoon.c | 6 ++--- hw/an5206.c | 8 +++---- hw/apb_pci.c | 12 +++++----- hw/apic.c | 12 +++++----- hw/apic_common.c | 4 ++-- hw/apic_internal.h | 2 +- hw/apm.c | 6 ++--- hw/apm.h | 2 +- hw/applesmc.c | 4 ++-- hw/arm11mpcore.c | 2 +- hw/arm_boot.c | 8 +++---- hw/arm_gic.c | 4 ++-- hw/arm_gic_common.c | 2 +- hw/arm_gic_internal.h | 2 +- hw/arm_l2x0.c | 2 +- hw/arm_mptimer.c | 2 +- hw/arm_pic.c | 4 ++-- hw/arm_sysctl.c | 6 ++--- hw/arm_timer.c | 6 ++--- hw/armv7m.c | 6 ++--- hw/armv7m_nvic.c | 6 ++--- hw/axis_dev88.c | 12 +++++----- hw/bitbang_i2c.c | 6 ++--- hw/bitbang_i2c.h | 2 +- hw/blizzard.c | 14 +++++------ hw/boards.h | 2 +- hw/bonito.c | 10 ++++---- hw/bt-hci-csr.c | 4 ++-- hw/bt-hci.c | 4 ++-- hw/bt-hid.c | 4 ++-- hw/bt-l2cap.c | 2 +- hw/bt-sdp.c | 2 +- hw/bt.c | 2 +- hw/cadence_gem.c | 2 +- hw/cadence_ttc.c | 2 +- hw/cadence_uart.c | 2 +- hw/cbus.c | 4 ++-- hw/ccid.h | 2 +- hw/cdrom.c | 2 +- hw/cirrus_vga.c | 44 +++++++++++++++++------------------ hw/cirrus_vga_rop.h | 8 +++---- hw/collie.c | 14 +++++------ hw/cris-boot.c | 6 ++--- hw/cris_pic_cpu.c | 6 ++--- hw/cs4231.c | 2 +- hw/cs4231a.c | 8 +++---- hw/cuda.c | 6 ++--- hw/dataplane/event-poll.c | 2 +- hw/dataplane/ioq.c | 2 +- hw/dataplane/virtio-blk.c | 2 +- hw/dataplane/vring.c | 2 +- hw/dataplane/vring.h | 2 +- hw/debugcon.c | 6 ++--- hw/debugexit.c | 4 ++-- hw/dec_pci.c | 12 +++++----- hw/dma.c | 4 ++-- hw/dp8393x.c | 4 ++-- hw/ds1225y.c | 2 +- hw/ds1338.c | 2 +- hw/dummy_m68k.c | 6 ++--- hw/e1000.c | 8 +++---- hw/ecc.c | 4 ++-- hw/eccmemctl.c | 2 +- hw/eepro100.c | 6 ++--- hw/eeprom93xx.c | 4 ++-- hw/empty_slot.c | 6 ++--- hw/es1370.c | 6 ++--- hw/escc.c | 6 ++--- hw/esp-pci.c | 6 ++--- hw/esp.c | 4 ++-- hw/esp.h | 2 +- hw/etraxfs.h | 2 +- hw/etraxfs_dma.c | 4 ++-- hw/etraxfs_eth.c | 4 ++-- hw/etraxfs_pic.c | 4 ++-- hw/etraxfs_ser.c | 2 +- hw/etraxfs_timer.c | 4 ++-- hw/exynos4210.c | 12 +++++----- hw/exynos4210_combiner.c | 4 ++-- hw/exynos4210_fimd.c | 2 +- hw/exynos4210_gic.c | 6 ++--- hw/exynos4210_i2c.c | 4 ++-- hw/exynos4210_mct.c | 6 ++--- hw/exynos4210_pmu.c | 2 +- hw/exynos4210_pwm.c | 6 ++--- hw/exynos4210_rtc.c | 8 +++---- hw/exynos4210_uart.c | 4 ++-- hw/exynos4_boards.c | 8 +++---- hw/fdc.c | 10 ++++---- hw/fmopl.c | 2 +- hw/framebuffer.c | 4 ++-- hw/fw_cfg.c | 8 +++---- hw/g364fb.c | 4 ++-- hw/grackle_pci.c | 6 ++--- hw/grlib.h | 4 ++-- hw/grlib_apbuart.c | 2 +- hw/grlib_gptimer.c | 4 ++-- hw/grlib_irqmp.c | 4 ++-- hw/gt64xxx.c | 10 ++++---- hw/gumstix.c | 10 ++++---- hw/gus.c | 10 ++++---- hw/gusemu_hal.c | 4 ++-- hw/gusemu_mixer.c | 4 ++-- hw/hda-audio.c | 8 +++---- hw/heathrow_pic.c | 4 ++-- hw/hid.c | 4 ++-- hw/highbank.c | 12 +++++----- hw/hpet.c | 12 +++++----- hw/hw.h | 2 +- hw/i2c.c | 2 +- hw/i2c.h | 2 +- hw/i82374.c | 2 +- hw/i82378.c | 8 +++---- hw/i8254.c | 10 ++++---- hw/i8254.h | 4 ++-- hw/i8254_common.c | 10 ++++---- hw/i8254_internal.h | 6 ++--- hw/i8259.c | 8 +++---- hw/i8259_common.c | 4 ++-- hw/i8259_internal.h | 6 ++--- hw/i82801b11.c | 4 ++-- hw/ich9.h | 26 ++++++++++----------- hw/ide.h | 4 ++-- hw/imx_avic.c | 4 ++-- hw/imx_ccm.c | 6 ++--- hw/imx_serial.c | 6 ++--- hw/imx_timer.c | 8 +++---- hw/integratorcp.c | 8 +++---- hw/intel-hda.c | 12 +++++----- hw/intel-hda.h | 2 +- hw/ioapic.c | 10 ++++---- hw/ioapic_common.c | 6 ++--- hw/ioapic_internal.h | 4 ++-- hw/ioh3420.c | 8 +++---- hw/ioh3420.h | 2 +- hw/ipack.c | 2 +- hw/ipack.h | 2 +- hw/ipoctal232.c | 2 +- hw/irq.c | 2 +- hw/isa-bus.c | 6 ++--- hw/isa.h | 2 +- hw/isa_mmio.c | 4 ++-- hw/ivshmem.c | 8 +++---- hw/jazz_led.c | 2 +- hw/kvmvapic.c | 2 +- hw/kzm.c | 14 +++++------ hw/lan9118.c | 6 ++--- hw/lance.c | 6 ++--- hw/leon3.c | 10 ++++---- hw/lm32_boards.c | 16 ++++++------- hw/lm32_hwsetup.h | 2 +- hw/lm32_juart.c | 6 ++--- hw/lm32_pic.c | 8 +++---- hw/lm32_sys.c | 4 ++-- hw/lm32_timer.c | 6 ++--- hw/lm32_uart.c | 4 ++-- hw/lm4549.c | 4 ++-- hw/lm832x.c | 4 ++-- hw/loader.c | 12 +++++----- hw/lpc_ich9.c | 28 +++++++++++----------- hw/lsi53c895a.c | 6 ++--- hw/m25p80.c | 6 ++--- hw/m48t59.c | 8 +++---- hw/mac_dbdma.c | 6 ++--- hw/mac_nvram.c | 6 ++--- hw/macio.c | 10 ++++---- hw/mainstone.c | 14 +++++------ hw/marvell_88w8618_audio.c | 8 +++---- hw/max111x.c | 2 +- hw/max7310.c | 2 +- hw/mc146818rtc.c | 6 ++--- hw/mc146818rtc.h | 4 ++-- hw/mcf5206.c | 6 ++--- hw/mcf5208.c | 10 ++++---- hw/mcf_fec.c | 4 ++-- hw/mcf_intc.c | 4 ++-- hw/mcf_uart.c | 4 ++-- hw/megasas.c | 12 +++++----- hw/microblaze_boot.c | 4 ++-- hw/microblaze_boot.h | 2 +- hw/microblaze_pic_cpu.c | 4 ++-- hw/milkymist-ac97.c | 4 ++-- hw/milkymist-hpdmc.c | 4 ++-- hw/milkymist-hw.h | 4 ++-- hw/milkymist-memcard.c | 6 ++--- hw/milkymist-minimac2.c | 6 ++--- hw/milkymist-pfpu.c | 4 ++-- hw/milkymist-softusb.c | 6 ++--- hw/milkymist-sysctl.c | 6 ++--- hw/milkymist-tmu2.c | 4 ++-- hw/milkymist-uart.c | 4 ++-- hw/milkymist-vgafb.c | 16 ++++++------- hw/milkymist.c | 16 ++++++------- hw/mips_addr.c | 4 ++-- hw/mips_fulong2e.c | 32 ++++++++++++------------- hw/mips_int.c | 4 ++-- hw/mips_jazz.c | 30 ++++++++++++------------ hw/mips_malta.c | 34 +++++++++++++-------------- hw/mips_mipssim.c | 18 +++++++------- hw/mips_r4k.c | 26 ++++++++++----------- hw/mips_timer.c | 4 ++-- hw/mipsnet.c | 4 ++-- hw/mpc8544_guts.c | 4 ++-- hw/mst_fpga.c | 4 ++-- hw/multiboot.c | 8 +++---- hw/musicpal.c | 16 ++++++------- hw/nand.c | 6 ++--- hw/ne2000-isa.c | 10 ++++---- hw/ne2000.c | 8 +++---- hw/nseries.c | 22 +++++++++--------- hw/omap1.c | 10 ++++---- hw/omap2.c | 12 +++++----- hw/omap_clk.c | 4 ++-- hw/omap_dma.c | 6 ++--- hw/omap_dss.c | 4 ++-- hw/omap_gpio.c | 6 ++--- hw/omap_gpmc.c | 6 ++--- hw/omap_gptimer.c | 4 ++-- hw/omap_i2c.c | 8 +++---- hw/omap_intc.c | 6 ++--- hw/omap_l4.c | 4 ++-- hw/omap_lcdc.c | 14 +++++------ hw/omap_mmc.c | 6 ++--- hw/omap_sdrc.c | 4 ++-- hw/omap_spi.c | 4 ++-- hw/omap_sx1.c | 10 ++++---- hw/omap_synctimer.c | 4 ++-- hw/omap_tap.c | 4 ++-- hw/omap_uart.c | 6 ++--- hw/onenand.c | 8 +++---- hw/opencores_eth.c | 4 ++-- hw/openpic.c | 14 +++++------ hw/openrisc_pic.c | 2 +- hw/openrisc_sim.c | 10 ++++---- hw/openrisc_timer.c | 2 +- hw/palm.c | 12 +++++----- hw/pam.c | 2 +- hw/parallel.c | 6 ++--- hw/pc-testdev.c | 6 ++--- hw/pc.c | 36 ++++++++++++++-------------- hw/pc.h | 6 ++--- hw/pc87312.c | 2 +- hw/pc87312.h | 2 +- hw/pc_piix.c | 24 +++++++++---------- hw/pc_q35.c | 16 ++++++------- hw/pc_sysfw.c | 10 ++++---- hw/pci_bridge_dev.c | 12 +++++----- hw/pckbd.c | 8 +++---- hw/pcnet-pci.c | 6 ++--- hw/pcnet.c | 4 ++-- hw/pcspk.c | 10 ++++---- hw/pcspk.h | 4 ++-- hw/petalogix_ml605_mmu.c | 22 +++++++++--------- hw/petalogix_s3adsp1800_mmu.c | 16 ++++++------- hw/pflash_cfi01.c | 6 ++--- hw/pflash_cfi02.c | 6 ++--- hw/piix4.c | 10 ++++---- hw/piix_pci.c | 16 ++++++------- hw/pl011.c | 2 +- hw/pl022.c | 4 ++-- hw/pl031.c | 2 +- hw/pl041.c | 6 ++--- hw/pl050.c | 4 ++-- hw/pl061.c | 2 +- hw/pl080.c | 2 +- hw/pl110.c | 14 +++++------ hw/pl110_template.h | 12 +++++----- hw/pl181.c | 4 ++-- hw/pl190.c | 2 +- hw/pm_smbus.c | 8 +++---- hw/ppc.c | 8 +++---- hw/ppc405.h | 2 +- hw/ppc405_boards.c | 14 +++++------ hw/ppc405_uc.c | 8 +++---- hw/ppc440_bamboo.c | 16 ++++++------- hw/ppc4xx.h | 2 +- hw/ppc4xx_devs.c | 6 ++--- hw/ppc4xx_pci.c | 10 ++++---- hw/ppc_booke.c | 8 +++---- hw/ppce500_pci.c | 8 +++---- hw/ppce500_spin.c | 4 ++-- hw/prep_pci.c | 10 ++++---- hw/ps2.c | 4 ++-- hw/ptimer.c | 4 ++-- hw/puv3.c | 10 ++++---- hw/puv3_dma.c | 6 ++--- hw/puv3_gpio.c | 6 ++--- hw/puv3_intc.c | 4 ++-- hw/puv3_ost.c | 6 ++--- hw/puv3_pm.c | 6 ++--- hw/pxa2xx.c | 10 ++++---- hw/pxa2xx_dma.c | 6 ++--- hw/pxa2xx_gpio.c | 6 ++--- hw/pxa2xx_keypad.c | 4 ++-- hw/pxa2xx_lcd.c | 16 ++++++------- hw/pxa2xx_mmci.c | 8 +++---- hw/pxa2xx_pcmcia.c | 6 ++--- hw/pxa2xx_pic.c | 6 ++--- hw/pxa2xx_timer.c | 6 ++--- hw/q35.c | 4 ++-- hw/q35.h | 22 +++++++++--------- hw/qdev-addr.c | 4 ++-- hw/qdev-properties-system.c | 2 +- hw/qdev-properties.c | 2 +- hw/qdev-properties.h | 2 +- hw/qdev.c | 2 +- hw/qdev.h | 4 ++-- hw/qxl-logger.c | 2 +- hw/qxl-render.c | 2 +- hw/qxl.c | 2 +- hw/qxl.h | 6 ++--- hw/r2d.c | 22 +++++++++--------- hw/rc4030.c | 4 ++-- hw/realview.c | 14 +++++------ hw/realview_gic.c | 2 +- hw/rtl8139.c | 6 ++--- hw/s390x/event-facility.c | 4 ++-- hw/s390x/s390-virtio-ccw.c | 2 +- hw/s390x/sclp.c | 2 +- hw/s390x/sclpconsole.c | 4 ++-- hw/s390x/sclpquiesce.c | 4 ++-- hw/sb16.c | 8 +++---- hw/sbi.c | 2 +- hw/scsi-bus.c | 8 +++---- hw/scsi-disk.c | 4 ++-- hw/scsi-generic.c | 4 ++-- hw/scsi.h | 2 +- hw/sd.c | 4 ++-- hw/sdhci.c | 4 ++-- hw/sdhci.h | 4 ++-- hw/serial-isa.c | 4 ++-- hw/serial-pci.c | 4 ++-- hw/serial.c | 2 +- hw/serial.h | 2 +- hw/sga.c | 6 ++--- hw/sh.h | 2 +- hw/sh7750.c | 10 ++++---- hw/sh7750_regnames.c | 8 +++---- hw/sh_intc.c | 6 ++--- hw/sh_intc.h | 2 +- hw/sh_pci.c | 8 +++---- hw/sh_serial.c | 4 ++-- hw/sh_timer.c | 6 ++--- hw/shix.c | 8 +++---- hw/slavio_intctl.c | 4 ++-- hw/slavio_misc.c | 2 +- hw/slavio_timer.c | 6 ++--- hw/sm501.c | 24 +++++++++---------- hw/smbios.c | 4 ++-- hw/smbus.c | 6 ++--- hw/smbus.h | 2 +- hw/smbus_eeprom.c | 6 ++--- hw/smbus_ich9.c | 14 +++++------ hw/smc91c111.c | 4 ++-- hw/soc_dma.c | 2 +- hw/spapr.c | 4 ++-- hw/spapr_iommu.c | 4 ++-- hw/spapr_llan.c | 2 +- hw/spapr_pci.c | 10 ++++---- hw/spapr_vio.c | 6 ++--- hw/spapr_vscsi.c | 8 +++---- hw/spapr_vty.c | 2 +- hw/sparc32_dma.c | 8 +++---- hw/spitz.c | 22 +++++++++--------- hw/ssd0303.c | 2 +- hw/ssd0323.c | 2 +- hw/ssi-sd.c | 4 ++-- hw/ssi.c | 2 +- hw/ssi.h | 2 +- hw/stellaris.c | 12 +++++----- hw/stellaris_enet.c | 2 +- hw/stellaris_input.c | 4 ++-- hw/stream.c | 2 +- hw/strongarm.c | 8 +++---- hw/sun4c_intctl.c | 6 ++--- hw/sun4m.c | 30 ++++++++++++------------ hw/sun4m.h | 2 +- hw/sun4m_iommu.c | 4 ++-- hw/sun4u.c | 26 ++++++++++----------- hw/sysbus.c | 2 +- hw/sysbus.h | 2 +- hw/tc58128.c | 6 ++--- hw/tc6393xb.c | 16 ++++++------- hw/tcx.c | 4 ++-- hw/tmp105.c | 6 ++--- hw/tmp105.h | 4 ++-- hw/tosa.c | 20 ++++++++-------- hw/tpci200.c | 4 ++-- hw/tsc2005.c | 4 ++-- hw/tsc210x.c | 6 ++--- hw/tusb6010.c | 10 ++++---- hw/twl92230.c | 4 ++-- hw/unin_pci.c | 8 +++---- hw/usb.h | 2 +- hw/versatile_i2c.c | 4 ++-- hw/versatile_pci.c | 6 ++--- hw/versatilepb.c | 14 +++++------ hw/vexpress.c | 12 +++++----- hw/vfio_pci.c | 6 ++--- hw/vga-isa-mm.c | 6 ++--- hw/vga-isa.c | 8 +++---- hw/vga-pci.c | 8 +++---- hw/vga.c | 26 ++++++++++----------- hw/vhost.c | 2 +- hw/vhost_net.c | 6 ++--- hw/virtex_ml507.c | 22 +++++++++--------- hw/virtio-balloon.c | 6 ++--- hw/virtio-balloon.h | 4 ++-- hw/virtio-blk.c | 6 ++--- hw/virtio-blk.h | 2 +- hw/virtio-bus.c | 8 +++---- hw/virtio-bus.h | 4 ++-- hw/virtio-console.c | 2 +- hw/virtio-net.c | 6 ++--- hw/virtio-net.h | 4 ++-- hw/virtio-pci.c | 22 +++++++++--------- hw/virtio-pci.h | 14 +++++------ hw/virtio-rng.c | 6 ++--- hw/virtio-scsi.c | 2 +- hw/virtio-scsi.h | 4 ++-- hw/virtio-serial-bus.c | 4 ++-- hw/virtio-serial.h | 4 ++-- hw/virtio.c | 4 ++-- hw/virtio.h | 6 ++--- hw/vmmouse.c | 8 +++---- hw/vmport.c | 8 +++---- hw/vmware_vga.c | 8 +++---- hw/vt82c686.c | 24 +++++++++---------- hw/wdt_i6300esb.c | 6 ++--- hw/wdt_ib700.c | 8 +++---- hw/wm8750.c | 4 ++-- hw/xen-host-pci-device.c | 2 +- hw/xen-host-pci-device.h | 2 +- hw/xen_apic.c | 2 +- hw/xen_backend.c | 4 ++-- hw/xen_backend.h | 2 +- hw/xen_common.h | 4 ++-- hw/xen_console.c | 4 ++-- hw/xen_devconfig.c | 2 +- hw/xen_disk.c | 6 ++--- hw/xen_domainbuild.c | 4 ++-- hw/xen_domainbuild.h | 2 +- hw/xen_machine_pv.c | 10 ++++---- hw/xen_nic.c | 4 ++-- hw/xen_platform.c | 12 +++++----- hw/xen_pt.c | 8 +++---- hw/xen_pt.h | 6 ++--- hw/xen_pt_config_init.c | 4 ++-- hw/xen_pt_msi.c | 6 ++--- hw/xenfb.c | 4 ++-- hw/xgmac.c | 2 +- hw/xics.c | 2 +- hw/xilinx.h | 2 +- hw/xilinx_axidma.c | 8 +++---- hw/xilinx_axienet.c | 4 ++-- hw/xilinx_ethlite.c | 4 ++-- hw/xilinx_intc.c | 4 ++-- hw/xilinx_spi.c | 4 ++-- hw/xilinx_spips.c | 6 ++--- hw/xilinx_timer.c | 4 ++-- hw/xilinx_uartlite.c | 2 +- hw/xilinx_zynq.c | 12 +++++----- hw/xio3130_downstream.c | 8 +++---- hw/xio3130_downstream.h | 2 +- hw/xio3130_upstream.c | 8 +++---- hw/xio3130_upstream.h | 2 +- hw/xtensa_lx60.c | 12 +++++----- hw/xtensa_pic.c | 2 +- hw/xtensa_sim.c | 4 ++-- hw/z2.c | 16 ++++++------- hw/zaurus.c | 6 ++--- hw/zynq_slcr.c | 4 ++-- 487 files changed, 1604 insertions(+), 1604 deletions(-) diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index fe6c34ca53..d973d53f0a 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -18,7 +18,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" /* A15MP private memory region. */ diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 01aee0264d..0a1a10f37a 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -8,7 +8,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" typedef struct A9MPPrivState { SysBusDevice busdev; diff --git a/hw/a9scu.c b/hw/a9scu.c index 0e9e54d7fb..05897c2fa2 100644 --- a/hw/a9scu.c +++ b/hw/a9scu.c @@ -8,7 +8,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" /* A9MP private memory region. */ diff --git a/hw/ac97.c b/hw/ac97.c index 6c565e755c..c7d601fdb7 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -17,10 +17,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" enum { diff --git a/hw/acpi.c b/hw/acpi.c index 8c9dcc51c4..53e47d5857 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -19,9 +19,9 @@ * GNU GPL, version 2 or (at your option) any later version. */ #include "sysemu/sysemu.h" -#include "hw.h" -#include "pc.h" -#include "acpi.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/acpi.h" #include "monitor/monitor.h" struct acpi_table_header { diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c index d2f9808242..29f84ffb45 100644 --- a/hw/acpi_ich9.c +++ b/hw/acpi_ich9.c @@ -23,16 +23,16 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "acpi.h" +#include "hw/acpi.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" -#include "ich9.h" +#include "hw/ich9.h" //#define DEBUG diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h index ecb82abc65..91c3aeb7ea 100644 --- a/hw/acpi_ich9.h +++ b/hw/acpi_ich9.h @@ -21,7 +21,7 @@ #ifndef HW_ACPI_ICH9_H #define HW_ACPI_ICH9_H -#include "acpi.h" +#include "hw/acpi.h" typedef struct ICH9LPCPMRegs { /* diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 65b26013bd..7a4b712919 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -18,16 +18,16 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "apm.h" -#include "pm_smbus.h" -#include "pci/pci.h" -#include "acpi.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/pm_smbus.h" +#include "hw/pci/pci.h" +#include "hw/acpi.h" #include "sysemu/sysemu.h" #include "qemu/range.h" #include "exec/ioport.h" -#include "fw_cfg.h" +#include "hw/fw_cfg.h" #include "exec/address-spaces.h" //#define DEBUG diff --git a/hw/adb.c b/hw/adb.c index 6cf54650c8..fd9052c16b 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "adb.h" +#include "hw/hw.h" +#include "hw/adb.h" #include "ui/console.h" /* debug ADB */ diff --git a/hw/adb.h b/hw/adb.h index 721f1ac43e..bdfccd4041 100644 --- a/hw/adb.h +++ b/hw/adb.h @@ -26,7 +26,7 @@ #if !defined(__ADB_H__) #define __ADB_H__ -#include "qdev.h" +#include "hw/qdev.h" #define MAX_ADB_DEVICES 16 diff --git a/hw/adlib.c b/hw/adlib.c index 07c69fc967..e6bce59512 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" +#include "hw/isa.h" //#define DEBUG @@ -47,7 +47,7 @@ void YMF262UpdateOneQEMU (int which, INT16 *dst, int length); #define SHIFT 2 #else -#include "fmopl.h" +#include "hw/fmopl.h" #define SHIFT 1 #endif diff --git a/hw/ads7846.c b/hw/ads7846.c index 29e5585d91..5da3dc5b2c 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -10,7 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "ssi.h" +#include "hw/ssi.h" #include "ui/console.h" typedef struct { diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 1cd549c69f..13aaa57b90 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -6,16 +6,16 @@ * that we need to emulate as well. */ -#include "hw.h" +#include "hw/hw.h" #include "elf.h" -#include "loader.h" -#include "boards.h" -#include "alpha_sys.h" +#include "hw/loader.h" +#include "hw/boards.h" +#include "hw/alpha_sys.h" #include "sysemu/sysemu.h" -#include "mc146818rtc.h" -#include "ide.h" -#include "i8254.h" -#include "serial.h" +#include "hw/mc146818rtc.h" +#include "hw/ide.h" +#include "hw/i8254.h" +#include "hw/serial.h" #define MAX_IDE_BUS 2 diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index 7327d488fd..84628686ad 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -7,7 +7,7 @@ */ #include "config.h" -#include "alpha_sys.h" +#include "hw/alpha_sys.h" #include "qemu/log.h" #include "sysemu/sysemu.h" diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index 233a71ecdb..b4ebd2a9cc 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -3,11 +3,11 @@ #ifndef HW_ALPHA_H #define HW_ALPHA_H 1 -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "ide.h" -#include "pc.h" -#include "irq.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/ide.h" +#include "hw/pc.h" +#include "hw/irq.h" PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4], diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index bf9aabfc08..95571ffc5d 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -8,10 +8,10 @@ #include "cpu.h" #include "exec/exec-all.h" -#include "hw.h" -#include "devices.h" +#include "hw/hw.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" -#include "alpha_sys.h" +#include "hw/alpha_sys.h" #include "exec/address-spaces.h" diff --git a/hw/an5206.c b/hw/an5206.c index 924be81d57..7c21c66cde 100644 --- a/hw/an5206.c +++ b/hw/an5206.c @@ -6,10 +6,10 @@ * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" -#include "boards.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/mcf.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 7eb0c2bbcb..7992d6f6fd 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -26,12 +26,12 @@ Ultrasparc PCI host is called the PCI Bus Module (PBM). The APB is the secondary PCI bridge. */ -#include "sysbus.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "pci/pci_bridge.h" -#include "pci/pci_bus.h" -#include "apb_pci.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" +#include "hw/apb_pci.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/apic.c b/hw/apic.c index fd14b73023..8eddba06e5 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -17,14 +17,14 @@ * License along with this library; if not, see */ #include "qemu/thread.h" -#include "apic_internal.h" -#include "apic.h" -#include "ioapic.h" -#include "pci/msi.h" +#include "hw/apic_internal.h" +#include "hw/apic.h" +#include "hw/ioapic.h" +#include "hw/pci/msi.h" #include "qemu/host-utils.h" #include "trace.h" -#include "pc.h" -#include "apic-msidef.h" +#include "hw/pc.h" +#include "hw/apic-msidef.h" #define MAX_APIC_WORDS 8 diff --git a/hw/apic_common.c b/hw/apic_common.c index d8c9810509..d0c261602c 100644 --- a/hw/apic_common.c +++ b/hw/apic_common.c @@ -17,8 +17,8 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see */ -#include "apic.h" -#include "apic_internal.h" +#include "hw/apic.h" +#include "hw/apic_internal.h" #include "trace.h" #include "sysemu/kvm.h" diff --git a/hw/apic_internal.h b/hw/apic_internal.h index 9265e52cd6..578241f861 100644 --- a/hw/apic_internal.h +++ b/hw/apic_internal.h @@ -21,7 +21,7 @@ #define QEMU_APIC_INTERNAL_H #include "exec/memory.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" /* APIC Local Vector Table */ diff --git a/hw/apm.c b/hw/apm.c index 2e1b1372d2..e2846f99c8 100644 --- a/hw/apm.c +++ b/hw/apm.c @@ -20,9 +20,9 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "apm.h" -#include "hw.h" -#include "pci/pci.h" +#include "hw/apm.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" //#define DEBUG diff --git a/hw/apm.h b/hw/apm.h index 9abb47f99f..3edea5f623 100644 --- a/hw/apm.h +++ b/hw/apm.h @@ -3,7 +3,7 @@ #include #include "qemu-common.h" -#include "hw.h" +#include "hw/hw.h" #include "exec/memory.h" typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg); diff --git a/hw/applesmc.c b/hw/applesmc.c index 5a8c4ff2d2..44b9bacd88 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -30,8 +30,8 @@ * */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #include "ui/console.h" #include "qemu/timer.h" diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index ca49948ffc..90dceade71 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" /* MPCore private memory region. */ diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 4065424d60..43253fd34a 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -8,11 +8,11 @@ */ #include "config.h" -#include "hw.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/device_tree.h" #include "qemu/config-file.h" diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 90e43d0728..6b30e0bf42 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -18,8 +18,8 @@ * armv7m_nvic device. */ -#include "sysbus.h" -#include "arm_gic_internal.h" +#include "hw/sysbus.h" +#include "hw/arm_gic_internal.h" //#define DEBUG_GIC diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 40e8dd7045..745b4b2a0a 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -18,7 +18,7 @@ * with this program; if not, see . */ -#include "arm_gic_internal.h" +#include "hw/arm_gic_internal.h" static void gic_save(QEMUFile *f, void *opaque) { diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h index 699352ca8b..b10ac5e9f6 100644 --- a/hw/arm_gic_internal.h +++ b/hw/arm_gic_internal.h @@ -21,7 +21,7 @@ #ifndef QEMU_ARM_GIC_INTERNAL_H #define QEMU_ARM_GIC_INTERNAL_H -#include "sysbus.h" +#include "hw/sysbus.h" /* Maximum number of possible interrupts, determined by the GIC architecture */ #define GIC_MAXIRQ 1020 diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c index ae1e51d009..eb4427d9c4 100644 --- a/hw/arm_l2x0.c +++ b/hw/arm_l2x0.c @@ -18,7 +18,7 @@ * */ -#include "sysbus.h" +#include "hw/sysbus.h" /* L2C-310 r3p2 */ #define CACHE_ID 0x410000c8 diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 7b08aa3644..f59a9f11f0 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -19,7 +19,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" /* This device implements the per-cpu private timer and watchdog block diff --git a/hw/arm_pic.c b/hw/arm_pic.c index ffb4d4171a..a7ad893cc2 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -7,8 +7,8 @@ * This code is licensed under the LGPL */ -#include "hw.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" /* Input 0 is IRQ and input 1 is FIQ. */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 7ecb7da54b..a46f8d450e 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -7,10 +7,10 @@ * This code is licensed under the GPL. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "sysbus.h" -#include "primecell.h" +#include "hw/sysbus.h" +#include "hw/primecell.h" #include "sysemu/sysemu.h" #define LOCK_VALUE 0xa05f diff --git a/hw/arm_timer.c b/hw/arm_timer.c index c1e56be74e..644987046a 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -7,11 +7,11 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "qdev.h" -#include "ptimer.h" +#include "hw/qdev.h" +#include "hw/ptimer.h" /* Common timer implementation. */ diff --git a/hw/armv7m.c b/hw/armv7m.c index 904696ca7f..1d5bb592c4 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -7,9 +7,9 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "loader.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/loader.h" #include "elf.h" /* Bitbanded IO. Each word corresponds to a single bit. */ diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index d5798d0309..4d3042348b 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -10,11 +10,11 @@ * NVIC. Much of that is also implemented here. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "arm-misc.h" +#include "hw/arm-misc.h" #include "exec/address-spaces.h" -#include "arm_gic_internal.h" +#include "hw/arm_gic_internal.h" typedef struct { GICState gic; diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c index dd37fa13e2..eccd423abf 100644 --- a/hw/axis_dev88.c +++ b/hw/axis_dev88.c @@ -22,14 +22,14 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "flash.h" -#include "boards.h" -#include "etraxfs.h" -#include "loader.h" +#include "hw/flash.h" +#include "hw/boards.h" +#include "hw/etraxfs.h" +#include "hw/loader.h" #include "elf.h" -#include "cris-boot.h" +#include "hw/cris-boot.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c index 114508fade..b8e6d3a103 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -9,9 +9,9 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "bitbang_i2c.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/bitbang_i2c.h" +#include "hw/sysbus.h" //#define DEBUG_BITBANG_I2C diff --git a/hw/bitbang_i2c.h b/hw/bitbang_i2c.h index 519d2dc22f..e86062742c 100644 --- a/hw/bitbang_i2c.h +++ b/hw/bitbang_i2c.h @@ -1,7 +1,7 @@ #ifndef BITBANG_I2C_H #define BITBANG_I2C_H -#include "i2c.h" +#include "hw/i2c.h" typedef struct bitbang_i2c_interface bitbang_i2c_interface; diff --git a/hw/blizzard.c b/hw/blizzard.c index 24bde32e5a..805f4d5558 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -20,8 +20,8 @@ #include "qemu-common.h" #include "ui/console.h" -#include "devices.h" -#include "vga_int.h" +#include "hw/devices.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int); @@ -941,15 +941,15 @@ static void blizzard_screen_dump(void *opaque, const char *filename, } #define DEPTH 8 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 15 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 16 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 24 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" #define DEPTH 32 -#include "blizzard_template.h" +#include "hw/blizzard_template.h" void *s1d13745_init(qemu_irq gpio_int) { diff --git a/hw/boards.h b/hw/boards.h index 3813d4e551..425bdc74a8 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -4,7 +4,7 @@ #define HW_BOARDS_H #include "sysemu/blockdev.h" -#include "qdev.h" +#include "hw/qdev.h" #define DEFAULT_MACHINE_OPTIONS \ .boot_order = "cad" diff --git a/hw/bonito.c b/hw/bonito.c index 0498c9be79..3456e7840e 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -39,11 +39,11 @@ #include -#include "hw.h" -#include "pci/pci.h" -#include "pc.h" -#include "mips.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pc.h" +#include "hw/mips.h" +#include "hw/pci/pci_host.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c index 2070bb940c..e4ada3c731 100644 --- a/hw/bt-hci-csr.c +++ b/hw/bt-hci-csr.c @@ -21,9 +21,9 @@ #include "qemu-common.h" #include "char/char.h" #include "qemu/timer.h" -#include "irq.h" +#include "hw/irq.h" #include "bt/bt.h" -#include "bt.h" +#include "hw/bt.h" struct csrhci_s { int enable; diff --git a/hw/bt-hci.c b/hw/bt-hci.c index 69d2c73862..a76edea2c9 100644 --- a/hw/bt-hci.c +++ b/hw/bt-hci.c @@ -20,9 +20,9 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "usb.h" +#include "hw/usb.h" #include "bt/bt.h" -#include "bt.h" +#include "hw/bt.h" struct bt_hci_s { uint8_t *(*evt_packet)(void *opaque); diff --git a/hw/bt-hid.c b/hw/bt-hid.c index cfa7c145b8..69ccf9b432 100644 --- a/hw/bt-hid.c +++ b/hw/bt-hid.c @@ -21,8 +21,8 @@ #include "qemu-common.h" #include "qemu/timer.h" #include "ui/console.h" -#include "hid.h" -#include "bt.h" +#include "hw/hid.h" +#include "hw/bt.h" enum hid_transaction_req { BT_HANDSHAKE = 0x0, diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c index ba061c0da3..521587a112 100644 --- a/hw/bt-l2cap.c +++ b/hw/bt-l2cap.c @@ -19,7 +19,7 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "bt.h" +#include "hw/bt.h" #define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */ diff --git a/hw/bt-sdp.c b/hw/bt-sdp.c index c0431d1a40..218e075df7 100644 --- a/hw/bt-sdp.c +++ b/hw/bt-sdp.c @@ -18,7 +18,7 @@ */ #include "qemu-common.h" -#include "bt.h" +#include "hw/bt.h" struct bt_l2cap_sdp_state_s { struct bt_l2cap_conn_params_s *channel; diff --git a/hw/bt.c b/hw/bt.c index 4f2372d794..24ef4de49d 100644 --- a/hw/bt.c +++ b/hw/bt.c @@ -19,7 +19,7 @@ #include "qemu-common.h" #include "bt/bt.h" -#include "bt.h" +#include "hw/bt.h" /* Slave implementations can ignore this */ static void bt_dummy_lmp_mode_change(struct bt_link_s *link) diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c index de7d15ab76..e177057e49 100644 --- a/hw/cadence_gem.c +++ b/hw/cadence_gem.c @@ -24,7 +24,7 @@ #include /* For crc32 */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" #include "net/checksum.h" diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c index 67028a3f75..ba584f4719 100644 --- a/hw/cadence_ttc.c +++ b/hw/cadence_ttc.c @@ -16,7 +16,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #ifdef CADENCE_TTC_ERR_DEBUG diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c index 5766d38f13..5426f10018 100644 --- a/hw/cadence_uart.c +++ b/hw/cadence_uart.c @@ -16,7 +16,7 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "qemu/timer.h" diff --git a/hw/cbus.c b/hw/cbus.c index 6fd3905448..29b467b61f 100644 --- a/hw/cbus.c +++ b/hw/cbus.c @@ -21,8 +21,8 @@ */ #include "qemu-common.h" -#include "irq.h" -#include "devices.h" +#include "hw/irq.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" //#define DEBUG diff --git a/hw/ccid.h b/hw/ccid.h index 6adc745a6d..9334da8acd 100644 --- a/hw/ccid.h +++ b/hw/ccid.h @@ -10,7 +10,7 @@ #ifndef CCID_H #define CCID_H -#include "qdev.h" +#include "hw/qdev.h" typedef struct CCIDCardState CCIDCardState; typedef struct CCIDCardInfo CCIDCardInfo; diff --git a/hw/cdrom.c b/hw/cdrom.c index 3b99535dce..a018eec40a 100644 --- a/hw/cdrom.c +++ b/hw/cdrom.c @@ -26,7 +26,7 @@ here. */ #include "qemu-common.h" -#include "scsi.h" +#include "hw/scsi.h" static void lba_to_msf(uint8_t *buf, int lba) { diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 2a2c8dad62..7babcb67c8 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -26,11 +26,11 @@ * Reference: Finn Thogersons' VGADOC4b * available at http://home.worldonline.dk/~finth/ */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "ui/console.h" -#include "vga_int.h" -#include "loader.h" +#include "hw/vga_int.h" +#include "hw/loader.h" /* * TODO: @@ -288,63 +288,63 @@ static void cirrus_bitblt_fill_nop(CirrusVGAState *s, #define ROP_NAME 0 #define ROP_FN(d, s) 0 -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_and_dst #define ROP_FN(d, s) (s) & (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_and_notdst #define ROP_FN(d, s) (s) & (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notdst #define ROP_FN(d, s) ~(d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src #define ROP_FN(d, s) s -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME 1 #define ROP_FN(d, s) ~0 -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_and_dst #define ROP_FN(d, s) (~(s)) & (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_xor_dst #define ROP_FN(d, s) (s) ^ (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_or_dst #define ROP_FN(d, s) (s) | (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_or_notdst #define ROP_FN(d, s) (~(s)) | (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_notxor_dst #define ROP_FN(d, s) ~((s) ^ (d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME src_or_notdst #define ROP_FN(d, s) (s) | (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc #define ROP_FN(d, s) (~(s)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_or_dst #define ROP_FN(d, s) (~(s)) | (d) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" #define ROP_NAME notsrc_and_notdst #define ROP_FN(d, s) (~(s)) & (~(d)) -#include "cirrus_vga_rop.h" +#include "hw/cirrus_vga_rop.h" static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = { cirrus_bitblt_rop_fwd_0, @@ -2165,13 +2165,13 @@ static void cirrus_cursor_invalidate(VGACommonState *s1) } #define DEPTH 8 -#include "cirrus_vga_template.h" +#include "hw/cirrus_vga_template.h" #define DEPTH 16 -#include "cirrus_vga_template.h" +#include "hw/cirrus_vga_template.h" #define DEPTH 32 -#include "cirrus_vga_template.h" +#include "hw/cirrus_vga_template.h" static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) { diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h index 9c7bb09286..894610cc22 100644 --- a/hw/cirrus_vga_rop.h +++ b/hw/cirrus_vga_rop.h @@ -191,16 +191,16 @@ glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s, } #define DEPTH 8 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #define DEPTH 16 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #define DEPTH 24 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #define DEPTH 32 -#include "cirrus_vga_rop2.h" +#include "hw/cirrus_vga_rop2.h" #undef ROP_NAME #undef ROP_OP diff --git a/hw/collie.c b/hw/collie.c index d19db590fe..17fddc8d5b 100644 --- a/hw/collie.c +++ b/hw/collie.c @@ -8,13 +8,13 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "sysbus.h" -#include "boards.h" -#include "devices.h" -#include "strongarm.h" -#include "arm-misc.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/devices.h" +#include "hw/strongarm.h" +#include "hw/arm-misc.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/cris-boot.c b/hw/cris-boot.c index b21326fade..c330e22a86 100644 --- a/hw/cris-boot.c +++ b/hw/cris-boot.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/loader.h" #include "elf.h" -#include "cris-boot.h" +#include "hw/cris-boot.h" static void main_cpu_reset(void *opaque) { diff --git a/hw/cris_pic_cpu.c b/hw/cris_pic_cpu.c index 3da0e86536..7f50471e53 100644 --- a/hw/cris_pic_cpu.c +++ b/hw/cris_pic_cpu.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" -#include "etraxfs.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/etraxfs.h" #define D(x) diff --git a/hw/cs4231.c b/hw/cs4231.c index ae384b90fd..2975336057 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/cs4231a.c b/hw/cs4231a.c index 73f08594bf..f005f25899 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" -#include "qdev.h" +#include "hw/isa.h" +#include "hw/qdev.h" #include "qemu/timer.h" /* diff --git a/hw/cuda.c b/hw/cuda.c index b36c53527a..2ae430d326 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -22,9 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" -#include "adb.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/adb.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" diff --git a/hw/dataplane/event-poll.c b/hw/dataplane/event-poll.c index 2b55c6e255..b98acf9aec 100644 --- a/hw/dataplane/event-poll.c +++ b/hw/dataplane/event-poll.c @@ -13,7 +13,7 @@ */ #include -#include "hw/dataplane/event-poll.h" +#include "event-poll.h" /* Add an event notifier and its callback for polling */ void event_poll_add(EventPoll *poll, EventHandler *handler, diff --git a/hw/dataplane/ioq.c b/hw/dataplane/ioq.c index 0c9f5c4d60..f709f87ed6 100644 --- a/hw/dataplane/ioq.c +++ b/hw/dataplane/ioq.c @@ -12,7 +12,7 @@ * */ -#include "hw/dataplane/ioq.h" +#include "ioq.h" void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs) { diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 8588f93114..8319c94b76 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -22,7 +22,7 @@ #include "migration/migration.h" #include "block/block.h" #include "hw/virtio-blk.h" -#include "hw/dataplane/virtio-blk.h" +#include "virtio-blk.h" enum { SEG_MAX = 126, /* maximum number of I/O segments */ diff --git a/hw/dataplane/vring.c b/hw/dataplane/vring.c index eff5ad8831..e3b225315f 100644 --- a/hw/dataplane/vring.c +++ b/hw/dataplane/vring.c @@ -15,7 +15,7 @@ */ #include "trace.h" -#include "hw/dataplane/vring.h" +#include "vring.h" #include "qemu/error-report.h" /* Map the guest's vring to host memory */ diff --git a/hw/dataplane/vring.h b/hw/dataplane/vring.h index 3274f623f5..defb1efcda 100644 --- a/hw/dataplane/vring.h +++ b/hw/dataplane/vring.h @@ -19,7 +19,7 @@ #include #include "qemu-common.h" -#include "hw/dataplane/hostmem.h" +#include "hostmem.h" #include "hw/virtio.h" typedef struct { diff --git a/hw/debugcon.c b/hw/debugcon.c index 81b2bb00fd..cab7691b12 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -24,10 +24,10 @@ * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" -#include "isa.h" -#include "pc.h" +#include "hw/isa.h" +#include "hw/pc.h" #define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" #define ISA_DEBUGCON_DEVICE(obj) \ diff --git a/hw/debugexit.c b/hw/debugexit.c index c1b489ddcb..ba67a8fb41 100644 --- a/hw/debugexit.c +++ b/hw/debugexit.c @@ -7,8 +7,8 @@ * (at your option) any later version. */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit" #define ISA_DEBUG_EXIT_DEVICE(obj) \ diff --git a/hw/dec_pci.c b/hw/dec_pci.c index ee3f4ca834..64a50924f6 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -23,12 +23,12 @@ * THE SOFTWARE. */ -#include "dec_pci.h" -#include "sysbus.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "pci/pci_bridge.h" -#include "pci/pci_bus.h" +#include "hw/dec_pci.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_bus.h" /* debug DEC */ //#define DEBUG_DEC diff --git a/hw/dma.c b/hw/dma.c index 5bdf4358e3..fd1161ca31 100644 --- a/hw/dma.c +++ b/hw/dma.c @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #include "qemu/main-loop.h" /* #define DEBUG_DMA */ diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 808157b38b..8b5ca6a4ec 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -17,10 +17,10 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "net/net.h" -#include "mips.h" +#include "hw/mips.h" //#define DEBUG_SONIC diff --git a/hw/ds1225y.c b/hw/ds1225y.c index a6219a7908..488f1d7241 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" typedef struct { diff --git a/hw/ds1338.c b/hw/ds1338.c index 1da0f96fdc..ae7ca9f82d 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -10,7 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "i2c.h" +#include "hw/i2c.h" /* Size of NVRAM including both the user-accessible area and the * secondary register area. diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c index 3a88805d0f..544d56b59d 100644 --- a/hw/dummy_m68k.c +++ b/hw/dummy_m68k.c @@ -6,9 +6,9 @@ * This code is licensed under the GPL */ -#include "hw.h" -#include "boards.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" diff --git a/hw/e1000.c b/hw/e1000.c index d6fe815eda..ed37061563 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -25,15 +25,15 @@ */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "net/net.h" #include "net/checksum.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" -#include "e1000_hw.h" +#include "hw/e1000_hw.h" #define E1000_DEBUG diff --git a/hw/ecc.c b/hw/ecc.c index 60d1f1d4f2..8c97c33deb 100644 --- a/hw/ecc.c +++ b/hw/ecc.c @@ -11,8 +11,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/flash.h" /* * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux. diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index dbac2c2bbc..6f4a407cbf 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" /* There are 3 versions of this chip used in SMP sun4m systems: diff --git a/hw/eepro100.c b/hw/eepro100.c index 5d237968e7..68d729c17a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -41,10 +41,10 @@ */ #include /* offsetof */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "eeprom93xx.h" +#include "hw/eeprom93xx.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c index 4c7158d1a5..39f560553d 100644 --- a/hw/eeprom93xx.c +++ b/hw/eeprom93xx.c @@ -35,8 +35,8 @@ * - No emulation of EEPROM timings. */ -#include "hw.h" -#include "eeprom93xx.h" +#include "hw/hw.h" +#include "hw/eeprom93xx.h" /* Debug EEPROM emulation. */ //~ #define DEBUG_EEPROM diff --git a/hw/empty_slot.c b/hw/empty_slot.c index d7b54973a4..5234a4ddc6 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -9,9 +9,9 @@ * version. */ -#include "hw.h" -#include "sysbus.h" -#include "empty_slot.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/empty_slot.h" //#define DEBUG_EMPTY_SLOT diff --git a/hw/es1370.c b/hw/es1370.c index 977d2e3767..e64cf23099 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -26,10 +26,10 @@ /* #define VERBOSE_ES1370 */ #define SILENT_ES1370 -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" /* Missing stuff: diff --git a/hw/escc.c b/hw/escc.c index 18c02921e3..baf0219304 100644 --- a/hw/escc.c +++ b/hw/escc.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "sysbus.h" -#include "escc.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/escc.h" #include "char/char.h" #include "ui/console.h" #include "trace.h" diff --git a/hw/esp-pci.c b/hw/esp-pci.c index c949e6e0d9..7599b39d8d 100644 --- a/hw/esp-pci.c +++ b/hw/esp-pci.c @@ -23,9 +23,9 @@ * THE SOFTWARE. */ -#include "pci/pci.h" -#include "eeprom93xx.h" -#include "esp.h" +#include "hw/pci/pci.h" +#include "hw/eeprom93xx.h" +#include "hw/esp.h" #include "trace.h" #include "qemu/log.h" diff --git a/hw/esp.c b/hw/esp.c index 2af48aac4b..5365eacec0 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -23,8 +23,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "esp.h" +#include "hw/sysbus.h" +#include "hw/esp.h" #include "trace.h" #include "qemu/log.h" diff --git a/hw/esp.h b/hw/esp.h index f15cc7b5bd..830673be8f 100644 --- a/hw/esp.h +++ b/hw/esp.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_ESP_H #define QEMU_HW_ESP_H -#include "scsi.h" +#include "hw/scsi.h" /* esp.c */ #define ESP_MAX_DEVS 7 diff --git a/hw/etraxfs.h b/hw/etraxfs.h index 180de5a088..0df4fdd2e9 100644 --- a/hw/etraxfs.h +++ b/hw/etraxfs.h @@ -26,7 +26,7 @@ #define HW_EXTRAXFS_H 1 #include "net/net.h" -#include "etraxfs_dma.h" +#include "hw/etraxfs_dma.h" qemu_irq *cris_pic_init_cpu(CPUCRISState *env); diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c index d41500316f..a84ec1f23c 100644 --- a/hw/etraxfs_dma.c +++ b/hw/etraxfs_dma.c @@ -23,12 +23,12 @@ */ #include #include -#include "hw.h" +#include "hw/hw.h" #include "exec/address-spaces.h" #include "qemu-common.h" #include "sysemu/sysemu.h" -#include "etraxfs_dma.h" +#include "hw/etraxfs_dma.h" #define D(x) diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index ad36411193..591bee245c 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -23,9 +23,9 @@ */ #include -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "etraxfs.h" +#include "hw/etraxfs.h" #define D(x) diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index 64af31c46e..635103c001 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" //#include "pc.h" //#include "etraxfs.h" diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 72c8868639..7e24d34230 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "qemu/log.h" diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index d3dac52315..3cd9476bb1 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #define D(x) diff --git a/hw/exynos4210.c b/hw/exynos4210.c index fa54e42a47..4592514bb2 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -21,13 +21,13 @@ * */ -#include "boards.h" +#include "hw/boards.h" #include "sysemu/sysemu.h" -#include "sysbus.h" -#include "arm-misc.h" -#include "loader.h" -#include "exynos4210.h" -#include "usb/hcd-ehci.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/loader.h" +#include "hw/exynos4210.h" +#include "hw/usb/hcd-ehci.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index ba644b43c2..5818f10132 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -27,9 +27,9 @@ * IRQs are passed to GIC through Combiner. */ -#include "sysbus.h" +#include "hw/sysbus.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" //#define DEBUG_COMBINER diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c index 3d498b77f8..6b31ae33b6 100644 --- a/hw/exynos4210_fimd.c +++ b/hw/exynos4210_fimd.c @@ -24,7 +24,7 @@ #include "qemu-common.h" #include "exec/cpu-all.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "ui/console.h" #include "ui/pixel_ops.h" #include "qemu/bswap.h" diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index 94b138fa46..807849c574 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -20,10 +20,10 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu-common.h" -#include "irq.h" -#include "exynos4210.h" +#include "hw/irq.h" +#include "hw/exynos4210.h" enum ExtGicId { EXT_GIC_ID_MDMA_LCD0 = 66, diff --git a/hw/exynos4210_i2c.c b/hw/exynos4210_i2c.c index cefd736092..9e428759a1 100644 --- a/hw/exynos4210_i2c.c +++ b/hw/exynos4210_i2c.c @@ -21,8 +21,8 @@ */ #include "qemu/timer.h" -#include "sysbus.h" -#include "i2c.h" +#include "hw/sysbus.h" +#include "hw/i2c.h" #ifndef EXYNOS4_I2C_DEBUG #define EXYNOS4_I2C_DEBUG 0 diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c index d7d5904cc0..862c96212b 100644 --- a/hw/exynos4210_mct.c +++ b/hw/exynos4210_mct.c @@ -52,12 +52,12 @@ * there is no way to avoid frequently events). */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "ptimer.h" +#include "hw/ptimer.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" //#define DEBUG_MCT diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c index 7c81a1b628..ba5aa8d0e4 100644 --- a/hw/exynos4210_pmu.c +++ b/hw/exynos4210_pmu.c @@ -24,7 +24,7 @@ * uses PMU INFORM5 register as a holding pen. */ -#include "sysbus.h" +#include "hw/sysbus.h" #ifndef DEBUG_PMU #define DEBUG_PMU 0 diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c index c8656248a8..6d74cd4db5 100644 --- a/hw/exynos4210_pwm.c +++ b/hw/exynos4210_pwm.c @@ -20,12 +20,12 @@ * with this program; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "ptimer.h" +#include "hw/ptimer.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" //#define DEBUG_PWM diff --git a/hw/exynos4210_rtc.c b/hw/exynos4210_rtc.c index 5694a6207b..d170ca755a 100644 --- a/hw/exynos4210_rtc.c +++ b/hw/exynos4210_rtc.c @@ -25,16 +25,16 @@ * CLKOUTEN Bit[9] not used */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "ptimer.h" +#include "hw/ptimer.h" -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" #define DEBUG_RTC 0 diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index bdf797a029..006f3d44fb 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -19,11 +19,11 @@ * */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "char/char.h" -#include "exynos4210.h" +#include "hw/exynos4210.h" #undef DEBUG_UART #undef DEBUG_UART_EXTEND diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index b59e6aabf3..473da349bd 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -22,12 +22,12 @@ */ #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "arm-misc.h" +#include "hw/arm-misc.h" #include "exec/address-spaces.h" -#include "exynos4210.h" -#include "boards.h" +#include "hw/exynos4210.h" +#include "hw/boards.h" #undef DEBUG diff --git a/hw/fdc.c b/hw/fdc.c index 976a587c42..a4bb1290ef 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -27,13 +27,13 @@ * way. There are changes in DOR register and DMA is not available. */ -#include "hw.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/fdc.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "isa.h" -#include "sysbus.h" -#include "qdev-addr.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/qdev-addr.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" #include "qemu/log.h" diff --git a/hw/fmopl.c b/hw/fmopl.c index f0a023477d..e50ba6c0ec 100644 --- a/hw/fmopl.c +++ b/hw/fmopl.c @@ -39,7 +39,7 @@ #include #include //#include "driver.h" /* use M.A.M.E. */ -#include "fmopl.h" +#include "hw/fmopl.h" #ifndef PI #define PI 3.14159265358979323846 diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 2a870961bc..d341aa0c6b 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -17,9 +17,9 @@ - Remove all DisplayState knowledge from devices. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" /* Render an image from a shared memory framebuffer. */ diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index 02618f2480..63a199876c 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "isa.h" -#include "fw_cfg.h" -#include "sysbus.h" +#include "hw/isa.h" +#include "hw/fw_cfg.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" #include "qemu/config-file.h" diff --git a/hw/g364fb.c b/hw/g364fb.c index 0c0c8ba302..7b69815bc9 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -17,11 +17,11 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" #include "ui/pixel_ops.h" #include "trace.h" -#include "sysbus.h" +#include "hw/sysbus.h" typedef struct G364State { /* hardware */ diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 95639d5735..11e47d560e 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -23,9 +23,9 @@ * THE SOFTWARE. */ -#include "pci/pci_host.h" -#include "ppc/mac.h" -#include "pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" /* debug Grackle */ //#define DEBUG_GRACKLE diff --git a/hw/grlib.h b/hw/grlib.h index afd53892b0..470ce72250 100644 --- a/hw/grlib.h +++ b/hw/grlib.h @@ -25,8 +25,8 @@ #ifndef _GRLIB_H_ #define _GRLIB_H_ -#include "qdev.h" -#include "sysbus.h" +#include "hw/qdev.h" +#include "hw/sysbus.h" /* Emulation of GrLib device is base on the GRLIB IP Core User's Manual: * http://www.gaisler.com/products/grlib/grip.pdf diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index ba1685afd1..62f799083c 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "trace.h" diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 7962b74f2c..7043a34684 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "trace.h" diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index ef8dd95ac9..7ee469d191 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -24,10 +24,10 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "cpu.h" -#include "grlib.h" +#include "hw/grlib.h" #include "trace.h" diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 977a2c5e69..c73a58a045 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/pc.h" #include "exec/address-spaces.h" //#define DEBUG diff --git a/hw/gumstix.c b/hw/gumstix.c index bea16058f7..8859b7392f 100644 --- a/hw/gumstix.c +++ b/hw/gumstix.c @@ -34,12 +34,12 @@ * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289 */ -#include "hw.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/pxa.h" #include "net/net.h" -#include "flash.h" -#include "devices.h" -#include "boards.h" +#include "hw/flash.h" +#include "hw/devices.h" +#include "hw/boards.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/gus.c b/hw/gus.c index aa13fccf0d..d2682249ca 100644 --- a/hw/gus.c +++ b/hw/gus.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" -#include "gusemu.h" -#include "gustate.h" +#include "hw/isa.h" +#include "hw/gusemu.h" +#include "hw/gustate.h" #define dolog(...) AUD_log ("audio", __VA_ARGS__) #ifdef DEBUG diff --git a/hw/gusemu_hal.c b/hw/gusemu_hal.c index 6096690735..0eee617652 100644 --- a/hw/gusemu_hal.c +++ b/hw/gusemu_hal.c @@ -26,8 +26,8 @@ * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)? */ -#include "gustate.h" -#include "gusemu.h" +#include "hw/gustate.h" +#include "hw/gusemu.h" #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(GUSword *) (gusptr+(position))) diff --git a/hw/gusemu_mixer.c b/hw/gusemu_mixer.c index 6d8d9ced11..816c58a7ed 100644 --- a/hw/gusemu_mixer.c +++ b/hw/gusemu_mixer.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "gusemu.h" -#include "gustate.h" +#include "hw/gusemu.h" +#include "hw/gustate.h" #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(GUSword *) (gusptr+(position))) diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 3190bd1cf8..6bdd8209fb 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -17,10 +17,10 @@ * along with this program; if not, see . */ -#include "hw.h" -#include "pci/pci.h" -#include "intel-hda.h" -#include "intel-hda-defs.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/intel-hda.h" +#include "hw/intel-hda-defs.h" #include "audio/audio.h" /* -------------------------------------------------------------------------- */ diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index c0a71c3d5f..beb9661182 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -22,8 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" /* debug PIC */ //#define DEBUG_PIC diff --git a/hw/hid.c b/hw/hid.c index 89b5415c0f..28b34747ff 100644 --- a/hw/hid.c +++ b/hw/hid.c @@ -22,10 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" #include "qemu/timer.h" -#include "hid.h" +#include "hw/hid.h" #define HID_USAGE_ERROR_ROLLOVER 0x01 #define HID_USAGE_POSTFAIL 0x02 diff --git a/hw/highbank.c b/hw/highbank.c index defcc092b4..a622224dcc 100644 --- a/hw/highbank.c +++ b/hw/highbank.c @@ -17,14 +17,14 @@ * */ -#include "sysbus.h" -#include "arm-misc.h" -#include "devices.h" -#include "loader.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/loader.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "sysbus.h" +#include "hw/boards.h" +#include "hw/sysbus.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/hpet.c b/hw/hpet.c index 97eaa2f700..6bfbf3a68c 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -24,14 +24,14 @@ * This driver attempts to emulate an HPET device in software. */ -#include "hw.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/pc.h" #include "ui/console.h" #include "qemu/timer.h" -#include "hpet_emul.h" -#include "sysbus.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/hpet_emul.h" +#include "hw/sysbus.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" //#define HPET_DEBUG #ifdef HPET_DEBUG diff --git a/hw/hw.h b/hw/hw.h index dfced97bbc..1553e54aa7 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -9,7 +9,7 @@ #endif #include "exec/ioport.h" -#include "irq.h" +#include "hw/irq.h" #include "block/aio.h" #include "migration/qemu-file.h" #include "migration/vmstate.h" diff --git a/hw/i2c.c b/hw/i2c.c index ec314a40d1..ad361cc57f 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -7,7 +7,7 @@ * This code is licensed under the LGPL. */ -#include "i2c.h" +#include "hw/i2c.h" struct i2c_bus { diff --git a/hw/i2c.h b/hw/i2c.h index 0e80d5a9cb..461392f374 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -1,7 +1,7 @@ #ifndef QEMU_I2C_H #define QEMU_I2C_H -#include "qdev.h" +#include "hw/qdev.h" /* The QEMU I2C implementation only supports simple transfers that complete immediately. It does not support slave devices that need to be able to diff --git a/hw/i82374.c b/hw/i82374.c index 6a62ba2ab8..22115e4fcf 100644 --- a/hw/i82374.c +++ b/hw/i82374.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "isa.h" +#include "hw/isa.h" //#define DEBUG_I82374 diff --git a/hw/i82378.c b/hw/i82378.c index 0914d7bbfb..6f8c48b9ae 100644 --- a/hw/i82378.c +++ b/hw/i82378.c @@ -17,10 +17,10 @@ * License along with this library; if not, see . */ -#include "pci/pci.h" -#include "pc.h" -#include "i8254.h" -#include "pcspk.h" +#include "hw/pci/pci.h" +#include "hw/pc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" //#define DEBUG_I82378 diff --git a/hw/i8254.c b/hw/i8254.c index 394b2e81d7..67bfc6a806 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "qemu/timer.h" -#include "i8254.h" -#include "i8254_internal.h" +#include "hw/i8254.h" +#include "hw/i8254_internal.h" //#define DEBUG_PIT diff --git a/hw/i8254.h b/hw/i8254.h index ba6b598a99..7d4432e722 100644 --- a/hw/i8254.h +++ b/hw/i8254.h @@ -25,8 +25,8 @@ #ifndef HW_I8254_H #define HW_I8254_H -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #define PIT_FREQ 1193182 diff --git a/hw/i8254_common.c b/hw/i8254_common.c index 8c2e45a92e..c6c0c80c24 100644 --- a/hw/i8254_common.c +++ b/hw/i8254_common.c @@ -22,12 +22,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "qemu/timer.h" -#include "i8254.h" -#include "i8254_internal.h" +#include "hw/i8254.h" +#include "hw/i8254_internal.h" /* val must be 0 or 1 */ void pit_set_gate(ISADevice *dev, int channel, int val) diff --git a/hw/i8254_internal.h b/hw/i8254_internal.h index 686f0c2ba9..30d5b1b950 100644 --- a/hw/i8254_internal.h +++ b/hw/i8254_internal.h @@ -25,9 +25,9 @@ #ifndef QEMU_I8254_INTERNAL_H #define QEMU_I8254_INTERNAL_H -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" typedef struct PITChannelState { int count; /* can be 65536 */ diff --git a/hw/i8259.c b/hw/i8259.c index 54fe14447b..1d8275232a 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "monitor/monitor.h" #include "qemu/timer.h" -#include "i8259_internal.h" +#include "hw/i8259_internal.h" /* debug PIC */ //#define DEBUG_PIC diff --git a/hw/i8259_common.c b/hw/i8259_common.c index fc91056afb..98052db1fa 100644 --- a/hw/i8259_common.c +++ b/hw/i8259_common.c @@ -22,8 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "pc.h" -#include "i8259_internal.h" +#include "hw/pc.h" +#include "hw/i8259_internal.h" void pic_reset_common(PICCommonState *s) { diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h index 8785b1da3f..2813ec1baa 100644 --- a/hw/i8259_internal.h +++ b/hw/i8259_internal.h @@ -25,9 +25,9 @@ #ifndef QEMU_I8259_INTERNAL_H #define QEMU_I8259_INTERNAL_H -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" typedef struct PICCommonState PICCommonState; diff --git a/hw/i82801b11.c b/hw/i82801b11.c index 3dc10000a4..992095c80f 100644 --- a/hw/i82801b11.c +++ b/hw/i82801b11.c @@ -41,8 +41,8 @@ * License along with this library; if not, see */ -#include "pci/pci.h" -#include "ich9.h" +#include "hw/pci/pci.h" +#include "hw/ich9.h" /*****************************************************************************/ diff --git a/hw/ich9.h b/hw/ich9.h index d4509bb606..59c25e9aa0 100644 --- a/hw/ich9.h +++ b/hw/ich9.h @@ -1,20 +1,20 @@ #ifndef HW_ICH9_H #define HW_ICH9_H -#include "hw.h" +#include "hw/hw.h" #include "qemu/range.h" -#include "isa.h" -#include "sysbus.h" -#include "pc.h" -#include "apm.h" -#include "ioapic.h" -#include "pci/pci.h" -#include "pci/pcie_host.h" -#include "pci/pci_bridge.h" -#include "acpi.h" -#include "acpi_ich9.h" -#include "pam.h" -#include "pci/pci_bus.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/ioapic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/acpi.h" +#include "hw/acpi_ich9.h" +#include "hw/pam.h" +#include "hw/pci/pci_bus.h" void ich9_lpc_set_irq(void *opaque, int irq_num, int level); int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx); diff --git a/hw/ide.h b/hw/ide.h index 0eb3a74467..35444a39f9 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -1,8 +1,8 @@ #ifndef HW_IDE_H #define HW_IDE_H -#include "isa.h" -#include "pci/pci.h" +#include "hw/isa.h" +#include "hw/pci/pci.h" #include "exec/memory.h" #define MAX_IDE_DEVS 2 diff --git a/hw/imx_avic.c b/hw/imx_avic.c index f1f066cf9c..4e280b6ab9 100644 --- a/hw/imx_avic.c +++ b/hw/imx_avic.c @@ -14,8 +14,8 @@ * TODO: implement vectors. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "qemu/host-utils.h" #define DEBUG_INT 1 diff --git a/hw/imx_ccm.c b/hw/imx_ccm.c index 477903a546..ad7aad3397 100644 --- a/hw/imx_ccm.c +++ b/hw/imx_ccm.c @@ -10,10 +10,10 @@ * the CCM. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "imx.h" +#include "hw/imx.h" #define CKIH_FREQ 26000000 /* 26MHz crystal input */ #define CKIL_FREQ 32768 /* nominal 32khz clock */ diff --git a/hw/imx_serial.c b/hw/imx_serial.c index 2d8253e0ee..746723cd6e 100644 --- a/hw/imx_serial.c +++ b/hw/imx_serial.c @@ -17,11 +17,11 @@ * is a real serial device. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "char/char.h" -#include "imx.h" +#include "hw/imx.h" //#define DEBUG_SERIAL 1 #ifdef DEBUG_SERIAL diff --git a/hw/imx_timer.c b/hw/imx_timer.c index e924c747c5..a8c311141e 100644 --- a/hw/imx_timer.c +++ b/hw/imx_timer.c @@ -11,11 +11,11 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "ptimer.h" -#include "sysbus.h" -#include "imx.h" +#include "hw/ptimer.h" +#include "hw/sysbus.h" +#include "hw/imx.h" //#define DEBUG_TIMER 1 #ifdef DEBUG_TIMER diff --git a/hw/integratorcp.c b/hw/integratorcp.c index 9e3630a43d..e0ba327a55 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -7,10 +7,10 @@ * This code is licensed under the GPL */ -#include "sysbus.h" -#include "devices.h" -#include "boards.h" -#include "arm-misc.h" +#include "hw/sysbus.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" #include "net/net.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 784c229d8f..728b60fb9a 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -17,13 +17,13 @@ * along with this program; if not, see . */ -#include "hw.h" -#include "pci/pci.h" -#include "pci/msi.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" #include "qemu/timer.h" -#include "audiodev.h" -#include "intel-hda.h" -#include "intel-hda-defs.h" +#include "hw/audiodev.h" +#include "hw/intel-hda.h" +#include "hw/intel-hda-defs.h" #include "sysemu/dma.h" /* --------------------------------------------------------------------- */ diff --git a/hw/intel-hda.h b/hw/intel-hda.h index 22e0968d50..2544f0a344 100644 --- a/hw/intel-hda.h +++ b/hw/intel-hda.h @@ -1,7 +1,7 @@ #ifndef HW_INTEL_HDA_H #define HW_INTEL_HDA_H -#include "qdev.h" +#include "hw/qdev.h" /* --------------------------------------------------------------------- */ /* hda bus */ diff --git a/hw/ioapic.c b/hw/ioapic.c index f06c2dcf2e..78629fac6c 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -20,11 +20,11 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "pc.h" -#include "apic.h" -#include "ioapic.h" -#include "ioapic_internal.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/apic.h" +#include "hw/ioapic.h" +#include "hw/ioapic_internal.h" //#define DEBUG_IOAPIC diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c index 7dc552f033..d4aff29544 100644 --- a/hw/ioapic_common.c +++ b/hw/ioapic_common.c @@ -19,9 +19,9 @@ * License along with this library; if not, see . */ -#include "ioapic.h" -#include "ioapic_internal.h" -#include "sysbus.h" +#include "hw/ioapic.h" +#include "hw/ioapic_internal.h" +#include "hw/sysbus.h" void ioapic_reset_common(DeviceState *dev) { diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h index c8447d7f3b..25576c819e 100644 --- a/hw/ioapic_internal.h +++ b/hw/ioapic_internal.h @@ -22,9 +22,9 @@ #ifndef QEMU_IOAPIC_INTERNAL_H #define QEMU_IOAPIC_INTERNAL_H -#include "hw.h" +#include "hw/hw.h" #include "exec/memory.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define MAX_IOAPICS 1 diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 95bceb5347..43f855427b 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -20,10 +20,10 @@ * with this program; if not, see . */ -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/pcie.h" -#include "ioh3420.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/ioh3420.h" #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ #define PCI_DEVICE_ID_IOH_REV 0x2 diff --git a/hw/ioh3420.h b/hw/ioh3420.h index 046cf2c281..7776e5b02d 100644 --- a/hw/ioh3420.h +++ b/hw/ioh3420.h @@ -1,7 +1,7 @@ #ifndef QEMU_IOH3420_H #define QEMU_IOH3420_H -#include "pci/pcie_port.h" +#include "hw/pci/pcie_port.h" PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/ipack.c b/hw/ipack.c index e15540d5cd..b1f46c10a4 100644 --- a/hw/ipack.c +++ b/hw/ipack.c @@ -8,7 +8,7 @@ * later version. */ -#include "ipack.h" +#include "hw/ipack.h" IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot) { diff --git a/hw/ipack.h b/hw/ipack.h index 69e26282d3..f2b7a12e05 100644 --- a/hw/ipack.h +++ b/hw/ipack.h @@ -11,7 +11,7 @@ #ifndef QEMU_IPACK_H #define QEMU_IPACK_H -#include "qdev.h" +#include "hw/qdev.h" typedef struct IPackBus IPackBus; diff --git a/hw/ipoctal232.c b/hw/ipoctal232.c index c1e3b197b5..1da6a99175 100644 --- a/hw/ipoctal232.c +++ b/hw/ipoctal232.c @@ -8,7 +8,7 @@ * later version. */ -#include "ipack.h" +#include "hw/ipack.h" #include "qemu/bitops.h" #include "char/char.h" diff --git a/hw/irq.c b/hw/irq.c index f4e2a7804a..20785428ef 100644 --- a/hw/irq.c +++ b/hw/irq.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "irq.h" +#include "hw/irq.h" struct IRQState { qemu_irq_handler handler; diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 6dc34f09f3..67ff8fd314 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -16,11 +16,11 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "isa.h" +#include "hw/isa.h" #include "exec/address-spaces.h" static ISABus *isabus; diff --git a/hw/isa.h b/hw/isa.h index 7a8874abfd..82da37c11d 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -5,7 +5,7 @@ #include "exec/ioport.h" #include "exec/memory.h" -#include "qdev.h" +#include "hw/qdev.h" #define ISA_NUM_IRQS 16 diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c index 487cf6a8fb..a7860e7459 100644 --- a/hw/isa_mmio.c +++ b/hw/isa_mmio.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" #include "exec/address-spaces.h" static void isa_mmio_writeb (void *opaque, hwaddr addr, diff --git a/hw/ivshmem.c b/hw/ivshmem.c index afaf9b3bbf..68a2cf2e69 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -16,10 +16,10 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "pci/msix.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/pci/msix.h" #include "sysemu/kvm.h" #include "migration/migration.h" #include "qapi/qmp/qerror.h" diff --git a/hw/jazz_led.c b/hw/jazz_led.c index 4822c485f2..a418a7d1b6 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -26,7 +26,7 @@ #include "ui/console.h" #include "ui/pixel_ops.h" #include "trace.h" -#include "sysbus.h" +#include "hw/sysbus.h" typedef enum { REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2, diff --git a/hw/kvmvapic.c b/hw/kvmvapic.c index 9265baf568..c151c95c3e 100644 --- a/hw/kvmvapic.c +++ b/hw/kvmvapic.c @@ -11,7 +11,7 @@ #include "sysemu/sysemu.h" #include "sysemu/cpus.h" #include "sysemu/kvm.h" -#include "apic_internal.h" +#include "hw/apic_internal.h" #define APIC_DEFAULT_ADDRESS 0xfee00000 diff --git a/hw/kzm.c b/hw/kzm.c index fb3316551d..ec50a319ac 100644 --- a/hw/kzm.c +++ b/hw/kzm.c @@ -13,16 +13,16 @@ * i.MX31 SoC */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" -#include "hw.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "serial.h" -#include "imx.h" +#include "hw/boards.h" +#include "hw/serial.h" +#include "hw/imx.h" /* Memory map for Kzm Emulation Baseboard: * 0x00000000-0x00003fff 16k secure ROM IGNORED diff --git a/hw/lan9118.c b/hw/lan9118.c index 0e844e535c..403fb868ae 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -10,11 +10,11 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "devices.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" -#include "ptimer.h" +#include "hw/ptimer.h" /* For crc32 */ #include diff --git a/hw/lance.c b/hw/lance.c index 4b92425299..acfffaed31 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -35,12 +35,12 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" #include "qemu/timer.h" #include "qemu/sockets.h" -#include "sun4m.h" -#include "pcnet.h" +#include "hw/sun4m.h" +#include "hw/pcnet.h" #include "trace.h" typedef struct { diff --git a/hw/leon3.c b/hw/leon3.c index f16a8bb4ec..f58061f8ed 100644 --- a/hw/leon3.c +++ b/hw/leon3.c @@ -21,18 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "char/char.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "trace.h" #include "exec/address-spaces.h" -#include "grlib.h" +#include "hw/grlib.h" /* Default system clock. */ #define CPU_CLK (40 * 1000 * 1000) diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c index 2bc06d7b7b..1ce466a1b1 100644 --- a/hw/lm32_boards.c +++ b/hw/lm32_boards.c @@ -17,16 +17,16 @@ * License along with this library; if not, see . */ -#include "sysbus.h" -#include "hw.h" -#include "flash.h" -#include "devices.h" -#include "boards.h" -#include "loader.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "sysemu/blockdev.h" #include "elf.h" -#include "lm32_hwsetup.h" -#include "lm32.h" +#include "hw/lm32_hwsetup.h" +#include "hw/lm32.h" #include "exec/address-spaces.h" typedef struct { diff --git a/hw/lm32_hwsetup.h b/hw/lm32_hwsetup.h index 853e9abc7b..3449bd8dfc 100644 --- a/hw/lm32_hwsetup.h +++ b/hw/lm32_hwsetup.h @@ -26,7 +26,7 @@ #define QEMU_HW_LM32_HWSETUP_H #include "qemu-common.h" -#include "loader.h" +#include "hw/loader.h" typedef struct { void *data; diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c index 8c82c85f6d..472e9c25fd 100644 --- a/hw/lm32_juart.c +++ b/hw/lm32_juart.c @@ -17,12 +17,12 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "char/char.h" -#include "lm32_juart.h" +#include "hw/lm32_juart.h" enum { LM32_JUART_MIN_SAVE_VERSION = 0, diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c index 42f298ad51..d17c310d5c 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -19,12 +19,12 @@ #include -#include "hw.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/pc.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" -#include "lm32_pic.h" +#include "hw/lm32_pic.h" struct LM32PicState { SysBusDevice busdev; diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c index 187ef6d0d6..33a3b80ce7 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -28,8 +28,8 @@ * the test is passed or any non-zero value to it if the test is failed. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/log.h" #include "qemu/error-report.h" diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c index db527e9dc6..e06fac7082 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -21,11 +21,11 @@ * http://www.latticesemi.com/documents/mico32timer.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/error-report.h" #define DEFAULT_FREQUENCY (50*1000000) diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c index 9c89cca49b..02f6f89174 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -22,8 +22,8 @@ */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "char/char.h" #include "qemu/error-report.h" diff --git a/hw/lm4549.c b/hw/lm4549.c index b3c2d5f25d..67335cba61 100644 --- a/hw/lm4549.c +++ b/hw/lm4549.c @@ -13,9 +13,9 @@ * It supports only one playback voice and no record voice. */ -#include "hw.h" +#include "hw/hw.h" #include "audio/audio.h" -#include "lm4549.h" +#include "hw/lm4549.h" #if 0 #define LM4549_DEBUG 1 diff --git a/hw/lm832x.c b/hw/lm832x.c index 94b8ae06d8..a064dfd172 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -18,8 +18,8 @@ * with this program; if not, see . */ -#include "hw.h" -#include "i2c.h" +#include "hw/hw.h" +#include "hw/i2c.h" #include "qemu/timer.h" #include "ui/console.h" diff --git a/hw/loader.c b/hw/loader.c index 995edc3f98..d2a974beb9 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -42,13 +42,13 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "disas/disas.h" #include "monitor/monitor.h" #include "sysemu/sysemu.h" -#include "uboot_image.h" -#include "loader.h" -#include "fw_cfg.h" +#include "hw/uboot_image.h" +#include "hw/loader.h" +#include "hw/fw_cfg.h" #include "exec/memory.h" #include "exec/address-spaces.h" @@ -260,7 +260,7 @@ static void *load_at(int fd, int offset, int size) #define elf_word uint32_t #define elf_sword int32_t #define bswapSZs bswap32s -#include "elf_ops.h" +#include "hw/elf_ops.h" #undef elfhdr #undef elf_phdr @@ -280,7 +280,7 @@ static void *load_at(int fd, int offset, int size) #define elf_sword int64_t #define bswapSZs bswap64s #define SZ 64 -#include "elf_ops.h" +#include "hw/elf_ops.h" /* return < 0 if error, otherwise the number of bytes loaded in memory */ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index e25689bf87..e55d66a7a4 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -28,21 +28,21 @@ * THE SOFTWARE. */ #include "qemu-common.h" -#include "hw.h" +#include "hw/hw.h" #include "qemu/range.h" -#include "isa.h" -#include "sysbus.h" -#include "pc.h" -#include "apm.h" -#include "ioapic.h" -#include "pci/pci.h" -#include "pci/pcie_host.h" -#include "pci/pci_bridge.h" -#include "ich9.h" -#include "acpi.h" -#include "acpi_ich9.h" -#include "pam.h" -#include "pci/pci_bus.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/ioapic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/pci/pci_bridge.h" +#include "hw/ich9.h" +#include "hw/acpi.h" +#include "hw/acpi_ich9.h" +#include "hw/pam.h" +#include "hw/pci/pci_bus.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 860df328e5..5a8bf4d0e9 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -12,9 +12,9 @@ #include -#include "hw.h" -#include "pci/pci.h" -#include "scsi.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/scsi.h" #include "sysemu/dma.h" //#define DEBUG_LSI diff --git a/hw/m25p80.c b/hw/m25p80.c index 1372d06409..55e9d0d37a 100644 --- a/hw/m25p80.c +++ b/hw/m25p80.c @@ -21,10 +21,10 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/blockdev.h" -#include "ssi.h" -#include "devices.h" +#include "hw/ssi.h" +#include "hw/devices.h" #ifdef M25P80_ERR_DEBUG #define DB_PRINT(...) do { \ diff --git a/hw/m48t59.c b/hw/m48t59.c index 427d95b5a6..39a9d808cd 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "nvram.h" +#include "hw/hw.h" +#include "hw/nvram.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "sysbus.h" -#include "isa.h" +#include "hw/sysbus.h" +#include "hw/isa.h" #include "exec/address-spaces.h" //#define DEBUG_NVRAM diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index b894ab21aa..a1514708de 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -36,9 +36,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" -#include "mac_dbdma.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/mac_dbdma.h" #include "qemu/main-loop.h" /* debug DBDMA */ diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 25121fa482..ed32bde5ab 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -22,10 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "firmware_abi.h" +#include "hw/hw.h" +#include "hw/firmware_abi.h" #include "sysemu/sysemu.h" -#include "ppc/mac.h" +#include "hw/ppc/mac.h" /* debug NVR */ //#define DEBUG_NVR diff --git a/hw/macio.c b/hw/macio.c index 74bdcd1039..792fa390e6 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -22,11 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" -#include "pci/pci.h" -#include "mac_dbdma.h" -#include "escc.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" +#include "hw/mac_dbdma.h" +#include "hw/escc.h" #define TYPE_MACIO "macio" #define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO) diff --git a/hw/mainstone.c b/hw/mainstone.c index d1ff6e76d6..aea908f036 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -11,15 +11,15 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" #include "net/net.h" -#include "devices.h" -#include "boards.h" -#include "flash.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" /* Device addresses */ diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index c792caf271..e042046e4f 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -9,10 +9,10 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "hw.h" -#include "i2c.h" -#include "sysbus.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/sysbus.h" #include "audio/audio.h" #define MP_AUDIO_SIZE 0x00001000 diff --git a/hw/max111x.c b/hw/max111x.c index de1be4ddd6..d477ecdb29 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -10,7 +10,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "ssi.h" +#include "hw/ssi.h" typedef struct { SSISlave ssidev; diff --git a/hw/max7310.c b/hw/max7310.c index c2df0b49eb..e5cb810a27 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -7,7 +7,7 @@ * This file is licensed under GNU GPL. */ -#include "i2c.h" +#include "hw/i2c.h" typedef struct { I2CSlave i2c; diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 2fb11f69a3..a2119ad2f1 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "mc146818rtc.h" +#include "hw/mc146818rtc.h" #include "qapi/visitor.h" #ifdef TARGET_I386 -#include "apic.h" +#include "hw/apic.h" #endif //#define DEBUG_CMOS diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h index f286b6a12a..967403edb5 100644 --- a/hw/mc146818rtc.h +++ b/hw/mc146818rtc.h @@ -1,8 +1,8 @@ #ifndef MC146818RTC_H #define MC146818RTC_H -#include "isa.h" -#include "mc146818rtc_regs.h" +#include "hw/isa.h" +#include "hw/mc146818rtc_regs.h" ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); diff --git a/hw/mcf5206.c b/hw/mcf5206.c index ea2db2325a..58cd8d46c9 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -5,10 +5,10 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/mcf5208.c b/hw/mcf5208.c index 86402d30d5..748bf56983 100644 --- a/hw/mcf5208.c +++ b/hw/mcf5208.c @@ -5,14 +5,14 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "sysemu/sysemu.h" #include "net/net.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 8e60f09fbb..0227bd852c 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -5,9 +5,9 @@ * * This code is licensed under the GPL */ -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" -#include "mcf.h" +#include "hw/mcf.h" /* For crc32 */ #include #include "exec/address-spaces.h" diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c index b213656300..fff27b34aa 100644 --- a/hw/mcf_intc.c +++ b/hw/mcf_intc.c @@ -5,8 +5,8 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "exec/address-spaces.h" typedef struct { diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c index c44344317a..aacf0f05ed 100644 --- a/hw/mcf_uart.c +++ b/hw/mcf_uart.c @@ -5,8 +5,8 @@ * * This code is licensed under the GPL */ -#include "hw.h" -#include "mcf.h" +#include "hw/hw.h" +#include "hw/mcf.h" #include "char/char.h" #include "exec/address-spaces.h" diff --git a/hw/megasas.c b/hw/megasas.c index eb191f5e12..9b815d4b8f 100644 --- a/hw/megasas.c +++ b/hw/megasas.c @@ -18,16 +18,16 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" -#include "pci/msix.h" +#include "hw/pci/msix.h" #include "qemu/iov.h" -#include "scsi.h" -#include "scsi-defs.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" #include "trace.h" -#include "mfi.h" +#include "hw/mfi.h" #define MEGASAS_VERSION "1.70" #define MEGASAS_MAX_FRAMES 2048 /* Firmware limit at 65535 */ diff --git a/hw/microblaze_boot.c b/hw/microblaze_boot.c index 3ec5c0f7dd..e13b3e13bb 100644 --- a/hw/microblaze_boot.c +++ b/hw/microblaze_boot.c @@ -28,10 +28,10 @@ #include "qemu/config-file.h" #include "qemu-common.h" #include "sysemu/device_tree.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" -#include "microblaze_boot.h" +#include "hw/microblaze_boot.h" static struct { diff --git a/hw/microblaze_boot.h b/hw/microblaze_boot.h index c1cf836b99..b14ef2b992 100644 --- a/hw/microblaze_boot.h +++ b/hw/microblaze_boot.h @@ -1,7 +1,7 @@ #ifndef __MICROBLAZE_BOOT__ #define __MICROBLAZE_BOOT__ -#include "hw.h" +#include "hw/hw.h" void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, uint32_t ramsize, const char *dtb_filename, diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze_pic_cpu.c index ff36a526fc..d4743ab390 100644 --- a/hw/microblaze_pic_cpu.c +++ b/hw/microblaze_pic_cpu.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "microblaze_pic_cpu.h" +#include "hw/hw.h" +#include "hw/microblaze_pic_cpu.h" #define D(x) diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c index d51d1ac993..e08e9dca16 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -21,8 +21,8 @@ * http://www.milkymist.org/socdoc/ac97.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "audio/audio.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c index ea4d210685..d922f6ffad 100644 --- a/hw/milkymist-hpdmc.c +++ b/hw/milkymist-hpdmc.c @@ -21,8 +21,8 @@ * http://www.milkymist.org/socdoc/hpdmc.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h index c8bd7e93dd..d49f96b5d4 100644 --- a/hw/milkymist-hw.h +++ b/hw/milkymist-hw.h @@ -1,8 +1,8 @@ #ifndef QEMU_HW_MILKYMIST_H #define QEMU_HW_MILKYMIST_H -#include "qdev.h" -#include "qdev-addr.h" +#include "hw/qdev.h" +#include "hw/qdev-addr.h" #include "net/net.h" static inline DeviceState *milkymist_uart_create(hwaddr base, diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c index 9d15309ab7..d5944bca69 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -21,13 +21,13 @@ * http://www.milkymist.org/socdoc/memcard.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "trace.h" #include "qemu/error-report.h" #include "sysemu/blockdev.h" -#include "sd.h" +#include "hw/sd.h" enum { ENABLE_CMD_TX = (1<<0), diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 9992dcceaf..c20ff904ec 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -22,12 +22,12 @@ * */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "net/net.h" #include "qemu/error-report.h" -#include "qdev-addr.h" +#include "hw/qdev-addr.h" #include diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index c347680ad7..ad44b4db22 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -22,8 +22,8 @@ * */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/log.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index 01660bebf0..d911686de7 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -21,11 +21,11 @@ * not available yet */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "ui/console.h" -#include "hid.h" +#include "hw/hid.h" #include "qemu/error-report.h" enum { diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index e69ac6f047..e083a280c4 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -21,12 +21,12 @@ * http://www.milkymist.org/socdoc/sysctl.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "trace.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/error-report.h" enum { diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c index 42de10aafd..b723a04cc9 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -24,8 +24,8 @@ * */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c index e73eb8476c..ac6f5373ad 100644 --- a/hw/milkymist-uart.c +++ b/hw/milkymist-uart.c @@ -21,8 +21,8 @@ * http://www.milkymist.org/socdoc/uart.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "char/char.h" #include "qemu/error-report.h" diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 4d0a5dfb78..85ebb851bd 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -22,24 +22,24 @@ * http://www.milkymist.org/socdoc/vgafb.pdf */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "trace.h" #include "ui/console.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" #include "ui/pixel_ops.h" #include "qemu/error-report.h" #define BITS 8 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 15 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 16 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 24 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" #define BITS 32 -#include "milkymist-vgafb_template.h" +#include "hw/milkymist-vgafb_template.h" enum { R_CTRL = 0, diff --git a/hw/milkymist.c b/hw/milkymist.c index c04eb35fdd..fd36de57b5 100644 --- a/hw/milkymist.c +++ b/hw/milkymist.c @@ -17,17 +17,17 @@ * License along with this library; if not, see . */ -#include "sysbus.h" -#include "hw.h" -#include "flash.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" -#include "loader.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/blockdev.h" -#include "milkymist-hw.h" -#include "lm32.h" +#include "hw/milkymist-hw.h" +#include "hw/lm32.h" #include "exec/address-spaces.h" #define BIOS_FILENAME "mmone-bios.bin" diff --git a/hw/mips_addr.c b/hw/mips_addr.c index aa1c7d84d6..cddc25cf3f 100644 --- a/hw/mips_addr.c +++ b/hw/mips_addr.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips_cpudevs.h" +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr) { diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 8b532e1e0d..766aa9dfb5 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -18,29 +18,29 @@ * http://www.loongsondeveloper.com/doc/Loongson2EUserGuide.pdf */ -#include "hw.h" -#include "pc.h" -#include "serial.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/fdc.h" #include "net/net.h" -#include "boards.h" -#include "smbus.h" +#include "hw/boards.h" +#include "hw/smbus.h" #include "block/block.h" -#include "flash.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pci/pci.h" +#include "hw/flash.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pci/pci.h" #include "char/char.h" #include "sysemu/sysemu.h" #include "audio/audio.h" #include "qemu/log.h" -#include "loader.h" -#include "mips-bios.h" -#include "ide.h" +#include "hw/loader.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" #include "elf.h" -#include "vt82c686.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/vt82c686.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/mips_int.c b/hw/mips_int.c index 6423fd0bd9..ddd3b1bb01 100644 --- a/hw/mips_int.c +++ b/hw/mips_int.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips_cpudevs.h" +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" #include "cpu.h" static void cpu_mips_irq_request(void *opaque, int irq, int level) diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 17fbdde063..daeb985b1d 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -22,25 +22,25 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pc.h" -#include "serial.h" -#include "isa.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/isa.h" +#include "hw/fdc.h" #include "sysemu/sysemu.h" #include "sysemu/arch_init.h" -#include "boards.h" +#include "hw/boards.h" #include "net/net.h" -#include "esp.h" -#include "mips-bios.h" -#include "loader.h" -#include "mc146818rtc.h" -#include "i8254.h" -#include "pcspk.h" +#include "hw/esp.h" +#include "hw/mips-bios.h" +#include "hw/loader.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" enum jazz_model_e diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2a150dfb84..9a67dce207 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -22,32 +22,32 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "serial.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/fdc.h" #include "net/net.h" -#include "boards.h" -#include "smbus.h" +#include "hw/boards.h" +#include "hw/smbus.h" #include "block/block.h" -#include "flash.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pci/pci.h" +#include "hw/flash.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pci/pci.h" #include "char/char.h" #include "sysemu/sysemu.h" #include "sysemu/arch_init.h" -#include "boards.h" +#include "hw/boards.h" #include "qemu/log.h" -#include "mips-bios.h" -#include "ide.h" -#include "loader.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "sysbus.h" /* SysBusDevice */ +#include "hw/sysbus.h" /* SysBusDevice */ //#define DEBUG_BOARD_INIT diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index b0ab8f69e2..4935c78c01 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -24,18 +24,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "serial.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/serial.h" +#include "hw/isa.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "mips-bios.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/mips-bios.h" +#include "hw/loader.h" #include "elf.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" static struct _loaderparams { diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index 5df7eb4469..539a562620 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -7,23 +7,23 @@ * All peripherial devices are attached to this "bus" with * the standard PC ISA addresses. */ -#include "hw.h" -#include "mips.h" -#include "mips_cpudevs.h" -#include "pc.h" -#include "serial.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/mips.h" +#include "hw/mips_cpudevs.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/isa.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "flash.h" +#include "hw/boards.h" +#include "hw/flash.h" #include "qemu/log.h" -#include "mips-bios.h" -#include "ide.h" -#include "loader.h" +#include "hw/mips-bios.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" -#include "mc146818rtc.h" -#include "i8254.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/mips_timer.c b/hw/mips_timer.c index 83c400c158..9ad13f3924 100644 --- a/hw/mips_timer.c +++ b/hw/mips_timer.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips_cpudevs.h" +#include "hw/hw.h" +#include "hw/mips_cpudevs.h" #include "qemu/timer.h" #define TIMER_FREQ 100 * 1000 * 1000 diff --git a/hw/mipsnet.c b/hw/mipsnet.c index ff6bf7fdcb..ac6193a89e 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -1,7 +1,7 @@ -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" #include "trace.h" -#include "sysbus.h" +#include "hw/sysbus.h" /* MIPSnet register offsets */ diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c index 728723c946..193beab2c2 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -17,9 +17,9 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define MPC8544_GUTS_MMIO_SIZE 0x1000 #define MPC8544_GUTS_RSTCR_RESET 0x02 diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 7ae05e389f..1dd15054d0 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -10,8 +10,8 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" /* Mainstone FPGA for extern irqs */ #define FPGA_GPIO_PIN 0 diff --git a/hw/multiboot.c b/hw/multiboot.c index c4ec2e34a7..3cb228f0ca 100644 --- a/hw/multiboot.c +++ b/hw/multiboot.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "fw_cfg.h" -#include "multiboot.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/fw_cfg.h" +#include "hw/multiboot.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/sysemu.h" diff --git a/hw/musicpal.c b/hw/musicpal.c index 272cb80303..a37dbd7961 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -9,19 +9,19 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "serial.h" +#include "hw/boards.h" +#include "hw/serial.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "block/block.h" -#include "flash.h" +#include "hw/flash.h" #include "ui/console.h" -#include "i2c.h" +#include "hw/i2c.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" #include "ui/pixel_ops.h" diff --git a/hw/nand.c b/hw/nand.c index 4a71265ed3..4176272993 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -18,10 +18,10 @@ #ifndef NAND_IO -# include "hw.h" -# include "flash.h" +# include "hw/hw.h" +# include "hw/flash.h" # include "sysemu/blockdev.h" -# include "sysbus.h" +# include "hw/sysbus.h" #include "qemu/error-report.h" # define NAND_CMD_READ0 0x00 diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 342c6bdad1..47c00c3a76 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" -#include "qdev.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" +#include "hw/qdev.h" #include "net/net.h" -#include "ne2000.h" +#include "hw/ne2000.h" #include "exec/address-spaces.h" typedef struct ISANE2000State { diff --git a/hw/ne2000.c b/hw/ne2000.c index 3dd1c844e8..7dadc1cea7 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "ne2000.h" -#include "loader.h" +#include "hw/ne2000.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" /* debug NE2000 card */ diff --git a/hw/nseries.c b/hw/nseries.c index 99d353aaa9..c5bf9f95b3 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -20,19 +20,19 @@ #include "qemu-common.h" #include "sysemu/sysemu.h" -#include "omap.h" -#include "arm-misc.h" -#include "irq.h" +#include "hw/omap.h" +#include "hw/arm-misc.h" +#include "hw/irq.h" #include "ui/console.h" -#include "boards.h" -#include "i2c.h" -#include "devices.h" -#include "flash.h" -#include "hw.h" -#include "bt.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/i2c.h" +#include "hw/devices.h" +#include "hw/flash.h" +#include "hw/hw.h" +#include "hw/bt.h" +#include "hw/loader.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" /* Nokia N8x0 support */ diff --git a/hw/omap1.c b/hw/omap1.c index 623b101f80..6f0a8ca074 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -16,14 +16,14 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "arm-misc.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/omap.h" #include "sysemu/sysemu.h" -#include "soc_dma.h" +#include "hw/soc_dma.h" #include "sysemu/blockdev.h" #include "qemu/range.h" -#include "sysbus.h" +#include "hw/sysbus.h" /* Should signal the TCMI/GPMC */ uint32_t omap_badwidth_read8(void *opaque, hwaddr addr) diff --git a/hw/omap2.c b/hw/omap2.c index 038a82a517..0a2cd7bab6 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -19,15 +19,15 @@ */ #include "sysemu/blockdev.h" -#include "hw.h" -#include "arm-misc.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/arm-misc.h" +#include "hw/omap.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" #include "char/char.h" -#include "flash.h" -#include "soc_dma.h" -#include "sysbus.h" +#include "hw/flash.h" +#include "hw/soc_dma.h" +#include "hw/sysbus.h" #include "audio/audio.h" /* Enhanced Audio Controller (CODEC only) */ diff --git a/hw/omap_clk.c b/hw/omap_clk.c index 8448006067..c7b5c11626 100644 --- a/hw/omap_clk.c +++ b/hw/omap_clk.c @@ -18,8 +18,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" struct clk { const char *name; diff --git a/hw/omap_dma.c b/hw/omap_dma.c index 0c878b6ef2..0c5902f6f9 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -19,9 +19,9 @@ */ #include "qemu-common.h" #include "qemu/timer.h" -#include "omap.h" -#include "irq.h" -#include "soc_dma.h" +#include "hw/omap.h" +#include "hw/irq.h" +#include "hw/soc_dma.h" struct omap_dma_channel_s { /* transfer data */ diff --git a/hw/omap_dss.c b/hw/omap_dss.c index ae51bdfe41..948ad8fcc5 100644 --- a/hw/omap_dss.c +++ b/hw/omap_dss.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "omap.h" +#include "hw/omap.h" struct omap_dss_s { qemu_irq irq; diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index aadf1cc59f..c79f61c2ba 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -18,9 +18,9 @@ * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/sysbus.h" struct omap_gpio_s { qemu_irq irq; diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c index 02ab0ab568..ebb259c283 100644 --- a/hw/omap_gpmc.c +++ b/hw/omap_gpmc.c @@ -18,9 +18,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "flash.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "hw/omap.h" #include "exec/memory.h" #include "exec/address-spaces.h" diff --git a/hw/omap_gptimer.c b/hw/omap_gptimer.c index a5db710dcb..8485ee84f5 100644 --- a/hw/omap_gptimer.c +++ b/hw/omap_gptimer.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "omap.h" +#include "hw/omap.h" /* GP timers */ struct omap_gp_timer_s { diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index 143b198f1d..92f7b371ea 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -16,10 +16,10 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "i2c.h" -#include "omap.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/omap.h" +#include "hw/sysbus.h" typedef struct OMAPI2CState { diff --git a/hw/omap_intc.c b/hw/omap_intc.c index 4b0acd0f33..7da9c3548c 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/sysbus.h" /* Interrupt Handlers */ struct omap_intr_handler_bank_s { diff --git a/hw/omap_l4.c b/hw/omap_l4.c index 09e983f319..cbe8a06033 100644 --- a/hw/omap_l4.c +++ b/hw/omap_l4.c @@ -17,8 +17,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" struct omap_l4_s { MemoryRegion *address_space; diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index 936850a621..c426f3a13a 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -16,10 +16,10 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "omap.h" -#include "framebuffer.h" +#include "hw/omap.h" +#include "hw/framebuffer.h" #include "ui/pixel_ops.h" struct omap_lcd_panel_s { @@ -70,13 +70,13 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) #define draw_line_func drawfn #define DEPTH 8 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" #define DEPTH 15 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" #define DEPTH 16 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" #define DEPTH 32 -#include "omap_lcd_template.h" +#include "hw/omap_lcd_template.h" static draw_line_func draw_line_table2[33] = { [0 ... 32] = NULL, diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c index 7ecd9bd4ca..6e48110c9e 100644 --- a/hw/omap_mmc.c +++ b/hw/omap_mmc.c @@ -16,9 +16,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" -#include "sd.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/sd.h" struct omap_mmc_s { qemu_irq irq; diff --git a/hw/omap_sdrc.c b/hw/omap_sdrc.c index b0f3b8e675..510e6cc580 100644 --- a/hw/omap_sdrc.c +++ b/hw/omap_sdrc.c @@ -17,8 +17,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" /* SDRAM Controller Subsystem */ struct omap_sdrc_s { diff --git a/hw/omap_spi.c b/hw/omap_spi.c index 8ff01ed99d..1cbd98d338 100644 --- a/hw/omap_spi.c +++ b/hw/omap_spi.c @@ -19,8 +19,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" /* Multichannel SPI */ struct omap_mcspi_s { diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c index 30998c5ff3..85982334bd 100644 --- a/hw/omap_sx1.c +++ b/hw/omap_sx1.c @@ -25,12 +25,12 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "omap.h" -#include "boards.h" -#include "arm-misc.h" -#include "flash.h" +#include "hw/omap.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/omap_synctimer.c b/hw/omap_synctimer.c index 945711eff5..13e7280e69 100644 --- a/hw/omap_synctimer.c +++ b/hw/omap_synctimer.c @@ -17,9 +17,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "omap.h" +#include "hw/omap.h" struct omap_synctimer_s { MemoryRegion iomem; uint32_t val; diff --git a/hw/omap_tap.c b/hw/omap_tap.c index e273e971ed..181ecee1a5 100644 --- a/hw/omap_tap.c +++ b/hw/omap_tap.c @@ -18,8 +18,8 @@ * with this program; if not, see . */ -#include "hw.h" -#include "omap.h" +#include "hw/hw.h" +#include "hw/omap.h" /* TEST-Chip-level TAP */ static uint64_t omap_tap_read(void *opaque, hwaddr addr, diff --git a/hw/omap_uart.c b/hw/omap_uart.c index 0ebfbf8cae..af51ce7534 100644 --- a/hw/omap_uart.c +++ b/hw/omap_uart.c @@ -18,9 +18,9 @@ * with this program; if not, see . */ #include "char/char.h" -#include "hw.h" -#include "omap.h" -#include "serial.h" +#include "hw/hw.h" +#include "hw/omap.h" +#include "hw/serial.h" #include "exec/address-spaces.h" /* UARTs */ diff --git a/hw/onenand.c b/hw/onenand.c index 00a8738caf..ddba366ef5 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -19,13 +19,13 @@ */ #include "qemu-common.h" -#include "hw.h" -#include "flash.h" -#include "irq.h" +#include "hw/hw.h" +#include "hw/flash.h" +#include "hw/irq.h" #include "sysemu/blockdev.h" #include "exec/memory.h" #include "exec/address-spaces.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/error-report.h" /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */ diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index f9ba5eeaba..be64bf2a68 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -31,8 +31,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #include "net/net.h" #include "sysemu/sysemu.h" #include "trace.h" diff --git a/hw/openpic.c b/hw/openpic.c index 20a479c794..03a7075c39 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -33,14 +33,14 @@ * Serial interrupts, as implemented in Raven chipset are not supported yet. * */ -#include "hw.h" -#include "ppc/mac.h" -#include "pci/pci.h" -#include "openpic.h" -#include "sysbus.h" -#include "pci/msi.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" +#include "hw/openpic.h" +#include "hw/sysbus.h" +#include "hw/pci/msi.h" #include "qemu/bitops.h" -#include "ppc.h" +#include "hw/ppc.h" //#define DEBUG_OPENPIC diff --git a/hw/openrisc_pic.c b/hw/openrisc_pic.c index aaeb9a9171..931511ec0f 100644 --- a/hw/openrisc_pic.c +++ b/hw/openrisc_pic.c @@ -18,7 +18,7 @@ * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "cpu.h" /* OpenRISC pic handler */ diff --git a/hw/openrisc_sim.c b/hw/openrisc_sim.c index 30947dee6e..db2aac8cf8 100644 --- a/hw/openrisc_sim.c +++ b/hw/openrisc_sim.c @@ -18,15 +18,15 @@ * License along with this library; if not, see . */ -#include "hw.h" -#include "boards.h" +#include "hw/hw.h" +#include "hw/boards.h" #include "elf.h" -#include "serial.h" +#include "hw/serial.h" #include "net/net.h" -#include "loader.h" +#include "hw/loader.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/qtest.h" #define KERNEL_LOAD_ADDR 0x100 diff --git a/hw/openrisc_timer.c b/hw/openrisc_timer.c index d965be77de..f6c877f425 100644 --- a/hw/openrisc_timer.c +++ b/hw/openrisc_timer.c @@ -19,7 +19,7 @@ */ #include "cpu.h" -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #define TIMER_FREQ (20 * 1000 * 1000) /* 20MHz */ diff --git a/hw/palm.c b/hw/palm.c index a633dfc4b1..91bc74af24 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -16,15 +16,15 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "audio/audio.h" #include "sysemu/sysemu.h" #include "ui/console.h" -#include "omap.h" -#include "boards.h" -#include "arm-misc.h" -#include "devices.h" -#include "loader.h" +#include "hw/omap.h" +#include "hw/boards.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/loader.h" #include "exec/address-spaces.h" static uint32_t static_readb(void *opaque, hwaddr offset) diff --git a/hw/pam.c b/hw/pam.c index 1d72e88e62..6c0061e06e 100644 --- a/hw/pam.c +++ b/hw/pam.c @@ -27,7 +27,7 @@ * THE SOFTWARE. */ #include "sysemu/sysemu.h" -#include "pam.h" +#include "hw/pam.h" void smram_update(MemoryRegion *smram_region, uint8_t smram, uint8_t smm_enabled) diff --git a/hw/parallel.c b/hw/parallel.c index 3a4e06bab0..0b9af43d8b 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -22,10 +22,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" -#include "isa.h" -#include "pc.h" +#include "hw/isa.h" +#include "hw/pc.h" #include "sysemu/sysemu.h" //#define DEBUG_PARALLEL diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c index cf64a1f203..8236bce0c7 100644 --- a/hw/pc-testdev.c +++ b/hw/pc-testdev.c @@ -39,9 +39,9 @@ #if defined(CONFIG_POSIX) #include #endif -#include "hw.h" -#include "qdev.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/qdev.h" +#include "hw/isa.h" #define IOMEM_LEN 0x10000 diff --git a/hw/pc.c b/hw/pc.c index 07caba78ba..309bb83cab 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -21,29 +21,29 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "serial.h" -#include "apic.h" -#include "fdc.h" -#include "ide.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/apic.h" +#include "hw/fdc.h" +#include "hw/ide.h" +#include "hw/pci/pci.h" #include "monitor/monitor.h" -#include "fw_cfg.h" -#include "hpet_emul.h" -#include "smbios.h" -#include "loader.h" +#include "hw/fw_cfg.h" +#include "hw/hpet_emul.h" +#include "hw/smbios.h" +#include "hw/loader.h" #include "elf.h" -#include "multiboot.h" -#include "mc146818rtc.h" -#include "i8254.h" -#include "pcspk.h" -#include "pci/msi.h" -#include "sysbus.h" +#include "hw/multiboot.h" +#include "hw/mc146818rtc.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" +#include "hw/pci/msi.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "kvm_i386.h" -#include "xen.h" +#include "hw/xen.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" #include "ui/qemu-spice.h" diff --git a/hw/pc.h b/hw/pc.h index da1b102ef1..03a0277852 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -4,11 +4,11 @@ #include "qemu-common.h" #include "exec/memory.h" #include "exec/ioport.h" -#include "isa.h" -#include "fdc.h" +#include "hw/isa.h" +#include "hw/fdc.h" #include "net/net.h" #include "exec/memory.h" -#include "ioapic.h" +#include "hw/ioapic.h" /* PC-style peripherals (also used by other machines). */ diff --git a/hw/pc87312.c b/hw/pc87312.c index 0e9760e6b2..c4e4c6273b 100644 --- a/hw/pc87312.c +++ b/hw/pc87312.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "pc87312.h" +#include "hw/pc87312.h" #include "qemu/error-report.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" diff --git a/hw/pc87312.h b/hw/pc87312.h index 7b9e6f6132..ad087c73e5 100644 --- a/hw/pc87312.h +++ b/hw/pc87312.h @@ -25,7 +25,7 @@ #ifndef QEMU_PC87312_H #define QEMU_PC87312_H -#include "isa.h" +#include "hw/isa.h" #define TYPE_PC87312 "pc87312" diff --git a/hw/pc_piix.c b/hw/pc_piix.c index aa9cc81a2d..73a8656df8 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -24,23 +24,23 @@ #include -#include "hw.h" -#include "pc.h" -#include "apic.h" -#include "pci/pci.h" -#include "pci/pci_ids.h" -#include "usb.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/apic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_ids.h" +#include "hw/usb.h" #include "net/net.h" -#include "boards.h" -#include "ide.h" +#include "hw/boards.h" +#include "hw/ide.h" #include "sysemu/kvm.h" -#include "kvm/clock.h" +#include "hw/kvm/clock.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/arch_init.h" #include "sysemu/blockdev.h" -#include "smbus.h" -#include "xen.h" +#include "hw/smbus.h" +#include "hw/xen.h" #include "exec/memory.h" #include "exec/address-spaces.h" #include "cpu.h" diff --git a/hw/pc_q35.c b/hw/pc_q35.c index e22fb9891d..4f5f347309 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -27,17 +27,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/arch_init.h" -#include "smbus.h" -#include "boards.h" -#include "mc146818rtc.h" -#include "xen.h" +#include "hw/smbus.h" +#include "hw/boards.h" +#include "hw/mc146818rtc.h" +#include "hw/xen.h" #include "sysemu/kvm.h" -#include "kvm/clock.h" -#include "q35.h" +#include "hw/kvm/clock.h" +#include "hw/q35.h" #include "exec/address-spaces.h" -#include "ich9.h" +#include "hw/ich9.h" #include "hw/ide/pci.h" #include "hw/ide/ahci.h" #include "hw/usb.h" diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c index 8b65a7a4d8..3e01528e78 100644 --- a/hw/pc_sysfw.c +++ b/hw/pc_sysfw.c @@ -25,13 +25,13 @@ #include "sysemu/blockdev.h" #include "qemu/error-report.h" -#include "sysbus.h" -#include "hw.h" -#include "pc.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/pc.h" #include "hw/boards.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/kvm.h" #define BIOS_FILENAME "bios.bin" diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 1124c53b8c..9cc6a4082d 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -19,13 +19,13 @@ * with this program; if not, see . */ -#include "pci/pci_bridge.h" -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/shpc.h" -#include "pci/slotid_cap.h" +#include "hw/pci/pci_bridge.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/shpc.h" +#include "hw/pci/slotid_cap.h" #include "exec/memory.h" -#include "pci/pci_bus.h" +#include "hw/pci/pci_bus.h" struct PCIBridgeDev { PCIBridge bridge; diff --git a/hw/pckbd.c b/hw/pckbd.c index 3bad09baf2..cc63df0570 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" -#include "pc.h" -#include "ps2.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/pc.h" +#include "hw/ps2.h" #include "sysemu/sysemu.h" /* debug PC keyboard */ diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index df63b22463..55f80ca671 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -27,13 +27,13 @@ * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 */ -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "loader.h" +#include "hw/loader.h" #include "qemu/timer.h" #include "sysemu/dma.h" -#include "pcnet.h" +#include "hw/pcnet.h" //#define PCNET_DEBUG //#define PCNET_DEBUG_IO diff --git a/hw/pcnet.c b/hw/pcnet.c index e0de1e3458..b0b462b02e 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -35,13 +35,13 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -#include "qdev.h" +#include "hw/qdev.h" #include "net/net.h" #include "qemu/timer.h" #include "qemu/sockets.h" #include "sysemu/sysemu.h" -#include "pcnet.h" +#include "hw/pcnet.h" //#define PCNET_DEBUG //#define PCNET_DEBUG_IO diff --git a/hw/pcspk.c b/hw/pcspk.c index dfab9559ae..d533415950 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -22,13 +22,13 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/isa.h" #include "audio/audio.h" #include "qemu/timer.h" -#include "i8254.h" -#include "pcspk.h" +#include "hw/i8254.h" +#include "hw/pcspk.h" #define PCSPK_BUF_LEN 1792 #define PCSPK_SAMPLE_RATE 32000 diff --git a/hw/pcspk.h b/hw/pcspk.h index 7f42bac1c8..f448d221da 100644 --- a/hw/pcspk.h +++ b/hw/pcspk.h @@ -25,8 +25,8 @@ #ifndef HW_PCSPK_H #define HW_PCSPK_H -#include "hw.h" -#include "isa.h" +#include "hw/hw.h" +#include "hw/isa.h" static inline ISADevice *pcspk_init(ISABus *bus, ISADevice *pit) { diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c index fe7a932009..cfc02207ab 100644 --- a/hw/petalogix_ml605_mmu.c +++ b/hw/petalogix_ml605_mmu.c @@ -25,23 +25,23 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #include "net/net.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" -#include "xilinx.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/xilinx.h" #include "sysemu/blockdev.h" -#include "serial.h" +#include "hw/serial.h" #include "exec/address-spaces.h" -#include "ssi.h" +#include "hw/ssi.h" -#include "microblaze_boot.h" -#include "microblaze_pic_cpu.h" +#include "hw/microblaze_boot.h" +#include "hw/microblaze_pic_cpu.h" -#include "stream.h" +#include "hw/stream.h" #define LMB_BRAM_SIZE (128 * 1024) #define FLASH_SIZE (32 * 1024 * 1024) diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c index 8605fb8c00..24983621e5 100644 --- a/hw/petalogix_s3adsp1800_mmu.c +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -23,19 +23,19 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #include "net/net.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" -#include "xilinx.h" +#include "hw/devices.h" +#include "hw/boards.h" +#include "hw/xilinx.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "microblaze_boot.h" -#include "microblaze_pic_cpu.h" +#include "hw/microblaze_boot.h" +#include "hw/microblaze_pic_cpu.h" #define LMB_BRAM_SIZE (128 * 1024) #define FLASH_SIZE (16 * 1024 * 1024) diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c index 123b00653a..5d57babe07 100644 --- a/hw/pflash_cfi01.c +++ b/hw/pflash_cfi01.c @@ -36,13 +36,13 @@ * It does not implement much more ... */ -#include "hw.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/flash.h" #include "block/block.h" #include "qemu/timer.h" #include "exec/address-spaces.h" #include "qemu/host-utils.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define PFLASH_BUG(fmt, ...) \ do { \ diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index 44bd4654f0..37b4fcc234 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -35,13 +35,13 @@ * It does not implement multiple sectors erase */ -#include "hw.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/flash.h" #include "qemu/timer.h" #include "block/block.h" #include "exec/address-spaces.h" #include "qemu/host-utils.h" -#include "sysbus.h" +#include "hw/sysbus.h" //#define PFLASH_DEBUG #ifdef PFLASH_DEBUG diff --git a/hw/piix4.c b/hw/piix4.c index c1cb94d39f..0f5cd014e5 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "isa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/isa.h" +#include "hw/sysbus.h" PCIDevice *piix4_dev; diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 6c77e493e4..ac33db5cde 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -22,15 +22,15 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "pci/pci_host.h" -#include "isa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/isa.h" +#include "hw/sysbus.h" #include "qemu/range.h" -#include "xen.h" -#include "pam.h" +#include "hw/xen.h" +#include "hw/pam.h" #include "sysemu/sysemu.h" /* diff --git a/hw/pl011.c b/hw/pl011.c index 002a50e16a..332d5b970c 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" typedef struct { diff --git a/hw/pl022.c b/hw/pl022.c index c160e9061c..536c2166fe 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -7,8 +7,8 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "ssi.h" +#include "hw/sysbus.h" +#include "hw/ssi.h" //#define DEBUG_PL022 1 diff --git a/hw/pl031.c b/hw/pl031.c index 757867ff79..764940be7e 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -11,7 +11,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" diff --git a/hw/pl041.c b/hw/pl041.c index 0b71c45748..92dddc2923 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -20,10 +20,10 @@ * */ -#include "sysbus.h" +#include "hw/sysbus.h" -#include "pl041.h" -#include "lm4549.h" +#include "hw/pl041.h" +#include "hw/lm4549.h" #if 0 #define PL041_DEBUG_LEVEL 1 diff --git a/hw/pl050.c b/hw/pl050.c index 5d06bc9a3f..bc31ab6885 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -7,8 +7,8 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "ps2.h" +#include "hw/sysbus.h" +#include "hw/ps2.h" typedef struct { SysBusDevice busdev; diff --git a/hw/pl061.c b/hw/pl061.c index a78e819d96..74bc109488 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -8,7 +8,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" //#define DEBUG_PL061 1 diff --git a/hw/pl080.c b/hw/pl080.c index f6bbf98a7e..00b66b45b0 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #define PL080_MAX_CHANNELS 8 #define PL080_CONF_E 0x1 diff --git a/hw/pl110.c b/hw/pl110.c index 3d0ac00ade..924642d697 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -7,9 +7,9 @@ * This code is licensed under the GNU LGPL */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "ui/console.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" #include "ui/pixel_ops.h" #define PL110_CR_EN 0x001 @@ -111,15 +111,15 @@ static const unsigned char *idregs[] = { }; #define BITS 8 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 15 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 16 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 24 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define BITS 32 -#include "pl110_template.h" +#include "hw/pl110_template.h" static int pl110_enabled(pl110_state *s) { diff --git a/hw/pl110_template.h b/hw/pl110_template.h index e738e4a241..ec4bfd6f8c 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -27,20 +27,20 @@ #undef RGB #define BORDER bgr #define ORDER 0 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 1 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 2 -#include "pl110_template.h" +#include "hw/pl110_template.h" #undef BORDER #define RGB #define BORDER rgb #define ORDER 0 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 1 -#include "pl110_template.h" +#include "hw/pl110_template.h" #define ORDER 2 -#include "pl110_template.h" +#include "hw/pl110_template.h" #undef BORDER static drawfn glue(pl110_draw_fn_,BITS)[48] = diff --git a/hw/pl181.c b/hw/pl181.c index 98529f7821..2527296776 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -8,8 +8,8 @@ */ #include "sysemu/blockdev.h" -#include "sysbus.h" -#include "sd.h" +#include "hw/sysbus.h" +#include "hw/sd.h" //#define DEBUG_PL181 1 diff --git a/hw/pl190.c b/hw/pl190.c index 76ac159374..9610673d94 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" /* The number of virtual priority levels. 16 user vectors plus the unvectored IRQ. Chained interrupts would require an additional level diff --git a/hw/pm_smbus.c b/hw/pm_smbus.c index ea1380ca68..790061065c 100644 --- a/hw/pm_smbus.c +++ b/hw/pm_smbus.c @@ -17,10 +17,10 @@ * License along with this library; if not, see * . */ -#include "hw.h" -#include "pc.h" -#include "pm_smbus.h" -#include "smbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pm_smbus.h" +#include "hw/smbus.h" /* no save/load? */ diff --git a/hw/ppc.c b/hw/ppc.c index 8cfb84fa13..c9437fc6a7 100644 --- a/hw/ppc.c +++ b/hw/ppc.c @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" +#include "hw/hw.h" +#include "hw/ppc.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "nvram.h" +#include "hw/nvram.h" #include "qemu/log.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" diff --git a/hw/ppc405.h b/hw/ppc405.h index 535cbfb339..45c2159aa6 100644 --- a/hw/ppc405.h +++ b/hw/ppc405.h @@ -25,7 +25,7 @@ #if !defined(PPC_405_H) #define PPC_405_H -#include "ppc4xx.h" +#include "hw/ppc4xx.h" /* Bootinfo as set-up by u-boot */ typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t; diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c index cf371db053..ba443cf8ef 100644 --- a/hw/ppc405_boards.c +++ b/hw/ppc405_boards.c @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc405.h" -#include "nvram.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" +#include "hw/nvram.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" #include "block/block.h" -#include "boards.h" +#include "hw/boards.h" #include "qemu/log.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index d8cbe875bd..8465f6dcd4 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc405.h" -#include "serial.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" +#include "hw/serial.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "qemu/log.h" diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index 73b5ac725c..66911b58c6 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -14,20 +14,20 @@ #include "config.h" #include "qemu-common.h" #include "net/net.h" -#include "hw.h" -#include "pci/pci.h" -#include "boards.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/boards.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "sysemu/device_tree.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" #include "exec/address-spaces.h" -#include "serial.h" -#include "ppc.h" -#include "ppc405.h" +#include "hw/serial.h" +#include "hw/ppc.h" +#include "hw/ppc405.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h index 59dba9e292..91d84bad63 100644 --- a/hw/ppc4xx.h +++ b/hw/ppc4xx.h @@ -25,7 +25,7 @@ #if !defined(PPC_4XX_H) #define PPC_4XX_H -#include "pci/pci.h" +#include "hw/pci/pci.h" /* PowerPC 4xx core initialization */ PowerPCCPU *ppc4xx_init(const char *cpu_model, diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c index b6bb0e166a..49ec728a7b 100644 --- a/hw/ppc4xx_devs.c +++ b/hw/ppc4xx_devs.c @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc4xx.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc4xx.h" #include "qemu/log.h" #include "exec/address-spaces.h" diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index ba2d669b83..f3bbe88529 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -19,11 +19,11 @@ /* This file implements emulation of the 32-bit PCI controller found in some * 4xx SoCs, such as the 440EP. */ -#include "hw.h" -#include "ppc.h" -#include "ppc4xx.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc4xx.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "exec/address-spaces.h" #undef DEBUG diff --git a/hw/ppc_booke.c b/hw/ppc_booke.c index 25a4e91b69..30375c0c41 100644 --- a/hw/ppc_booke.c +++ b/hw/ppc_booke.c @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" +#include "hw/hw.h" +#include "hw/ppc.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "nvram.h" +#include "hw/nvram.h" #include "qemu/log.h" -#include "loader.h" +#include "hw/loader.h" /* Timer Control Register */ diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 1e1ade3d2e..310ae1c03d 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -14,12 +14,12 @@ * (at your option) any later version. */ -#include "hw.h" +#include "hw/hw.h" #include "hw/ppc/e500-ccsr.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "qemu/bswap.h" -#include "ppce500_pci.h" +#include "hw/ppce500_pci.h" #ifdef DEBUG_PCI #define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 5bdce52e24..d904fbe176 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -27,9 +27,9 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/kvm.h" #define MAX_CPUS 32 diff --git a/hw/prep_pci.c b/hw/prep_pci.c index 52ee5d9401..d21e87671e 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -23,11 +23,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" -#include "pci/pci_bus.h" -#include "pci/pci_host.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_host.h" +#include "hw/pc.h" #include "exec/address-spaces.h" #define TYPE_RAVEN_PCI_DEVICE "raven" diff --git a/hw/ps2.c b/hw/ps2.c index 15cfd5bb76..233a087a5e 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ps2.h" +#include "hw/hw.h" +#include "hw/ps2.h" #include "ui/console.h" #include "sysemu/sysemu.h" diff --git a/hw/ptimer.c b/hw/ptimer.c index 24af6a2afe..4bc96c9fa2 100644 --- a/hw/ptimer.c +++ b/hw/ptimer.c @@ -5,9 +5,9 @@ * * This code is licensed under the GNU LGPL. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/host-utils.h" struct ptimer_state diff --git a/hw/puv3.c b/hw/puv3.c index c722510d7e..f9d0c2bab1 100644 --- a/hw/puv3.c +++ b/hw/puv3.c @@ -13,13 +13,13 @@ #include "ui/console.h" #include "elf.h" #include "exec/address-spaces.h" -#include "sysbus.h" -#include "boards.h" -#include "loader.h" -#include "pc.h" +#include "hw/sysbus.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/pc.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" #define KERNEL_LOAD_ADDR 0x03000000 #define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c index 9de63b4c34..c05a14ea16 100644 --- a/hw/puv3_dma.c +++ b/hw/puv3_dma.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" #define PUV3_DMA_CH_NR (6) #define PUV3_DMA_CH_MASK (0xff) diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c index 152248d291..b2a790b683 100644 --- a/hw/puv3_gpio.c +++ b/hw/puv3_gpio.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" typedef struct { SysBusDevice busdev; diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c index 07f5649065..6bc9e1a752 100644 --- a/hw/puv3_intc.c +++ b/hw/puv3_intc.c @@ -8,10 +8,10 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "sysbus.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" typedef struct { SysBusDevice busdev; diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c index 14c6f21a75..10a522adbb 100644 --- a/hw/puv3_ost.c +++ b/hw/puv3_ost.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "sysbus.h" -#include "ptimer.h" +#include "hw/sysbus.h" +#include "hw/ptimer.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" /* puv3 ostimer implementation. */ typedef struct { diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c index 87a687afae..6b8d94dd07 100644 --- a/hw/puv3_pm.c +++ b/hw/puv3_pm.c @@ -8,11 +8,11 @@ * published by the Free Software Foundation, or any later version. * See the COPYING file in the top-level directory. */ -#include "hw.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sysbus.h" #undef DEBUG_PUV3 -#include "puv3.h" +#include "hw/puv3.h" typedef struct { SysBusDevice busdev; diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d303320d42..c0f50c90fe 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -7,12 +7,12 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "pxa.h" +#include "hw/sysbus.h" +#include "hw/pxa.h" #include "sysemu/sysemu.h" -#include "serial.h" -#include "i2c.h" -#include "ssi.h" +#include "hw/serial.h" +#include "hw/i2c.h" +#include "hw/ssi.h" #include "char/char.h" #include "sysemu/blockdev.h" diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index c0dba45752..1db21c99ab 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -8,9 +8,9 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "pxa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/sysbus.h" #define PXA255_DMA_NUM_CHANNELS 16 #define PXA27X_DMA_NUM_CHANNELS 32 diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index 05d2ad2add..eef8411e86 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -7,9 +7,9 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "sysbus.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/pxa.h" #define PXA2XX_GPIO_BANKS 4 diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c index 4ff04ad63b..32ea7a5d34 100644 --- a/hw/pxa2xx_keypad.c +++ b/hw/pxa2xx_keypad.c @@ -11,8 +11,8 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/pxa.h" #include "ui/console.h" /* diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 512a27e702..6484d27de1 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -10,13 +10,13 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pxa.h" +#include "hw/pxa.h" #include "ui/pixel_ops.h" /* FIXME: For graphic_rotate. Should probably be done in common code. */ #include "sysemu/sysemu.h" -#include "framebuffer.h" +#include "hw/framebuffer.h" struct DMAChannel { uint32_t branch; @@ -976,15 +976,15 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = { }; #define BITS 8 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 15 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 16 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 24 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" #define BITS 32 -#include "pxa2xx_template.h" +#include "hw/pxa2xx_template.h" PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq) diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c index 3589968712..0df83cc1df 100644 --- a/hw/pxa2xx_mmci.c +++ b/hw/pxa2xx_mmci.c @@ -10,10 +10,10 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "sd.h" -#include "qdev.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/sd.h" +#include "hw/qdev.h" struct PXA2xxMMCIState { MemoryRegion iomem; diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c index 3a79c728ab..66fefba58c 100644 --- a/hw/pxa2xx_pcmcia.c +++ b/hw/pxa2xx_pcmcia.c @@ -10,9 +10,9 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pcmcia.h" -#include "pxa.h" +#include "hw/hw.h" +#include "hw/pcmcia.h" +#include "hw/pxa.h" struct PXA2xxPCMCIAState { diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index 90b8fef3f9..145fc78c2f 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -8,9 +8,9 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "pxa.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/sysbus.h" #define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ #define ICMR 0x04 /* Interrupt Controller Mask register */ diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 5c9d2e8bc6..c173fe4c11 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -7,11 +7,11 @@ * This code is licensed under the GPL. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "pxa.h" -#include "sysbus.h" +#include "hw/pxa.h" +#include "hw/sysbus.h" #define OSMR0 0x00 #define OSMR1 0x04 diff --git a/hw/q35.c b/hw/q35.c index efebc2786a..0a25b8bf1f 100644 --- a/hw/q35.c +++ b/hw/q35.c @@ -27,8 +27,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "q35.h" +#include "hw/hw.h" +#include "hw/q35.h" /**************************************************************************** * Q35 host diff --git a/hw/q35.h b/hw/q35.h index 246c12cb04..d766bb7b02 100644 --- a/hw/q35.h +++ b/hw/q35.h @@ -22,18 +22,18 @@ #ifndef HW_Q35_H #define HW_Q35_H -#include "hw.h" +#include "hw/hw.h" #include "qemu/range.h" -#include "isa.h" -#include "sysbus.h" -#include "pc.h" -#include "apm.h" -#include "apic.h" -#include "pci/pci.h" -#include "pci/pcie_host.h" -#include "acpi.h" -#include "acpi_ich9.h" -#include "pam.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/pc.h" +#include "hw/apm.h" +#include "hw/apic.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" +#include "hw/acpi.h" +#include "hw/acpi_ich9.h" +#include "hw/pam.h" #define TYPE_Q35_HOST_DEVICE "q35-pcihost" #define Q35_HOST_DEVICE(obj) \ diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index fc2c437911..2398b4a37f 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -1,5 +1,5 @@ -#include "qdev.h" -#include "qdev-addr.h" +#include "hw/qdev.h" +#include "hw/qdev-addr.h" #include "exec/hwaddr.h" #include "qapi/qmp/qerror.h" #include "qapi/visitor.h" diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c index ce3af22193..87951444a1 100644 --- a/hw/qdev-properties-system.c +++ b/hw/qdev-properties-system.c @@ -11,7 +11,7 @@ */ #include "net/net.h" -#include "qdev.h" +#include "hw/qdev.h" #include "qapi/qmp/qerror.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index a8a31f56e4..0307a7830b 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -1,5 +1,5 @@ #include "net/net.h" -#include "qdev.h" +#include "hw/qdev.h" #include "qapi/qmp/qerror.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h index 20c67f3443..0b0465c9b3 100644 --- a/hw/qdev-properties.h +++ b/hw/qdev-properties.h @@ -1,7 +1,7 @@ #ifndef QEMU_QDEV_PROPERTIES_H #define QEMU_QDEV_PROPERTIES_H -#include "qdev-core.h" +#include "hw/qdev-core.h" /*** qdev-properties.c ***/ diff --git a/hw/qdev.c b/hw/qdev.c index 62bc8990f0..0b20280133 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -25,7 +25,7 @@ inherit from a particular bus (e.g. PCI or I2C) rather than this API directly. */ -#include "qdev.h" +#include "hw/qdev.h" #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qmp/qerror.h" diff --git a/hw/qdev.h b/hw/qdev.h index f814656e0a..5cb8b080a6 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -2,7 +2,7 @@ #define QDEV_H #include "hw/hw.h" -#include "qdev-core.h" -#include "qdev-properties.h" +#include "hw/qdev-core.h" +#include "hw/qdev-properties.h" #endif diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c index 3cd85d9b97..84f9aa1eda 100644 --- a/hw/qxl-logger.c +++ b/hw/qxl-logger.c @@ -20,7 +20,7 @@ */ #include "qemu/timer.h" -#include "qxl.h" +#include "hw/qxl.h" static const char *qxl_type[] = { [ QXL_CMD_NOP ] = "nop", diff --git a/hw/qxl-render.c b/hw/qxl-render.c index 455fb91269..d77df42b7e 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -19,7 +19,7 @@ * along with this program; if not, see . */ -#include "qxl.h" +#include "hw/qxl.h" static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) { diff --git a/hw/qxl.c b/hw/qxl.c index 2e1c5e225b..ef693486c2 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -27,7 +27,7 @@ #include "sysemu/sysemu.h" #include "trace.h" -#include "qxl.h" +#include "hw/qxl.h" /* * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as diff --git a/hw/qxl.h b/hw/qxl.h index f867a1d0ac..36f1a2502b 100644 --- a/hw/qxl.h +++ b/hw/qxl.h @@ -4,9 +4,9 @@ #include "qemu-common.h" #include "ui/console.h" -#include "hw.h" -#include "pci/pci.h" -#include "vga_int.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/vga_int.h" #include "qemu/thread.h" #include "ui/qemu-spice.h" diff --git a/hw/r2d.c b/hw/r2d.c index 2d0dd1ffba..faa03d2069 100644 --- a/hw/r2d.c +++ b/hw/r2d.c @@ -23,19 +23,19 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" -#include "sh.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/devices.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "pci/pci.h" +#include "hw/boards.h" +#include "hw/pci/pci.h" #include "net/net.h" -#include "sh7750_regs.h" -#include "ide.h" -#include "loader.h" -#include "usb.h" -#include "flash.h" +#include "hw/sh7750_regs.h" +#include "hw/ide.h" +#include "hw/loader.h" +#include "hw/usb.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/rc4030.c b/hw/rc4030.c index a0358a319c..b065515e67 100644 --- a/hw/rc4030.c +++ b/hw/rc4030.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "mips.h" +#include "hw/hw.h" +#include "hw/mips.h" #include "qemu/timer.h" /********************************************************/ diff --git a/hw/realview.c b/hw/realview.c index 78da7676c4..5fb490c832 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -7,15 +7,15 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "primecell.h" -#include "devices.h" -#include "pci/pci.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/primecell.h" +#include "hw/devices.h" +#include "hw/pci/pci.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "i2c.h" +#include "hw/boards.h" +#include "hw/i2c.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 8f2a7e2f34..0ec30caa06 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -7,7 +7,7 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" typedef struct { SysBusDevice busdev; diff --git a/hw/rtl8139.c b/hw/rtl8139.c index d7716beb9e..786b875c58 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -51,12 +51,12 @@ /* For crc32 */ #include -#include "hw.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" #include "sysemu/dma.h" #include "qemu/timer.h" #include "net/net.h" -#include "loader.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" #include "qemu/iov.h" diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 6b56995189..0faade0766 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -18,8 +18,8 @@ #include "monitor/monitor.h" #include "sysemu/sysemu.h" -#include "sclp.h" -#include "event-facility.h" +#include "hw/s390x/sclp.h" +#include "hw/s390x/event-facility.h" typedef struct EventTypesBus { BusState qbus; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 6549211820..d4364143ea 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -12,7 +12,7 @@ #include "hw/boards.h" #include "exec/address-spaces.h" #include "s390-virtio.h" -#include "sclp.h" +#include "hw/s390x/sclp.h" #include "ioinst.h" #include "css.h" #include "virtio-ccw.h" diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index a9d3a6a91d..86d6ae0023 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -16,7 +16,7 @@ #include "sysemu/kvm.h" #include "exec/memory.h" -#include "sclp.h" +#include "hw/s390x/sclp.h" static inline S390SCLPDevice *get_event_facility(void) { diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index 475d7ba856..5c881e5f3f 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -16,8 +16,8 @@ #include "qemu/thread.h" #include "qemu/error-report.h" -#include "sclp.h" -#include "event-facility.h" +#include "hw/s390x/sclp.h" +#include "hw/s390x/event-facility.h" #include "char/char.h" typedef struct ASCIIConsoleData { diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 2538498959..5fadc86d42 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -13,8 +13,8 @@ */ #include #include "sysemu/sysemu.h" -#include "sclp.h" -#include "event-facility.h" +#include "hw/s390x/sclp.h" +#include "hw/s390x/event-facility.h" typedef struct SignalQuiesce { EventBufferHeader ebh; diff --git a/hw/sb16.c b/hw/sb16.c index 52dfedf5f1..bd51cebfd8 100644 --- a/hw/sb16.c +++ b/hw/sb16.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "audiodev.h" +#include "hw/hw.h" +#include "hw/audiodev.h" #include "audio/audio.h" -#include "isa.h" -#include "qdev.h" +#include "hw/isa.h" +#include "hw/qdev.h" #include "qemu/timer.h" #include "qemu/host-utils.h" diff --git a/hw/sbi.c b/hw/sbi.c index d58184a6aa..8795749de8 100644 --- a/hw/sbi.c +++ b/hw/sbi.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" //#define DEBUG_IRQ diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index a97f1cdc1c..163d7a1a48 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1,8 +1,8 @@ -#include "hw.h" +#include "hw/hw.h" #include "qemu/error-report.h" -#include "scsi.h" -#include "scsi-defs.h" -#include "qdev.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" +#include "hw/qdev.h" #include "sysemu/blockdev.h" #include "trace.h" #include "sysemu/dma.h" diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index d41158693e..1e128182db 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -30,8 +30,8 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "qemu-common.h" #include "qemu/error-report.h" -#include "scsi.h" -#include "scsi-defs.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" #include "sysemu/sysemu.h" #include "sysemu/blockdev.h" #include "hw/block-common.h" diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 8175474a67..4d04caccce 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -13,7 +13,7 @@ #include "qemu-common.h" #include "qemu/error-report.h" -#include "scsi.h" +#include "hw/scsi.h" #include "sysemu/blockdev.h" #ifdef __linux__ @@ -35,7 +35,7 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) #include #include #include -#include "scsi-defs.h" +#include "hw/scsi-defs.h" #define SCSI_SENSE_BUF_SIZE 96 diff --git a/hw/scsi.h b/hw/scsi.h index a5b5b2ec0d..33e2e0bdf1 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_SCSI_H #define QEMU_HW_SCSI_H -#include "qdev.h" +#include "hw/qdev.h" #include "block/block.h" #include "hw/block-common.h" #include "sysemu/sysemu.h" diff --git a/hw/sd.c b/hw/sd.c index 428bd78e32..a895123867 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -29,9 +29,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "hw.h" +#include "hw/hw.h" #include "block/block.h" -#include "sd.h" +#include "hw/sd.h" #include "qemu/bitmap.h" //#define DEBUG_SD 1 diff --git a/hw/sdhci.c b/hw/sdhci.c index e535df9671..93feada049 100644 --- a/hw/sdhci.c +++ b/hw/sdhci.c @@ -22,14 +22,14 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/blockdev.h" #include "sysemu/dma.h" #include "qemu/timer.h" #include "block/block_int.h" #include "qemu/bitops.h" -#include "sdhci.h" +#include "hw/sdhci.h" /* host controller debug messages */ #ifndef SDHC_DEBUG diff --git a/hw/sdhci.h b/hw/sdhci.h index 931d7406f0..a560c3c93f 100644 --- a/hw/sdhci.h +++ b/hw/sdhci.h @@ -26,8 +26,8 @@ #define SDHCI_H #include "qemu-common.h" -#include "sysbus.h" -#include "sd.h" +#include "hw/sysbus.h" +#include "hw/sd.h" /* R/W SDMA System Address register 0x0 */ #define SDHC_SYSAD 0x00 diff --git a/hw/serial-isa.c b/hw/serial-isa.c index 5a6f51f856..a630a7d506 100644 --- a/hw/serial-isa.c +++ b/hw/serial-isa.c @@ -23,8 +23,8 @@ * THE SOFTWARE. */ -#include "serial.h" -#include "isa.h" +#include "hw/serial.h" +#include "hw/isa.h" typedef struct ISASerialState { ISADevice dev; diff --git a/hw/serial-pci.c b/hw/serial-pci.c index 1c31353f6d..954657ba32 100644 --- a/hw/serial-pci.c +++ b/hw/serial-pci.c @@ -25,8 +25,8 @@ /* see docs/specs/pci-serial.txt */ -#include "serial.h" -#include "pci/pci.h" +#include "hw/serial.h" +#include "hw/pci/pci.h" #define PCI_SERIAL_MAX_PORTS 4 diff --git a/hw/serial.c b/hw/serial.c index f0ce9b0c15..6a83543125 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ -#include "serial.h" +#include "hw/serial.h" #include "char/char.h" #include "qemu/timer.h" #include "exec/address-spaces.h" diff --git a/hw/serial.h b/hw/serial.h index 98ee4241be..814b8c666f 100644 --- a/hw/serial.h +++ b/hw/serial.h @@ -25,7 +25,7 @@ #ifndef HW_SERIAL_H #define HW_SERIAL_H 1 -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" #include "exec/memory.h" diff --git a/hw/sga.c b/hw/sga.c index 29bc3e0246..4b1d4e5369 100644 --- a/hw/sga.c +++ b/hw/sga.c @@ -24,9 +24,9 @@ * sgabios code originally available at code.google.com/p/sgabios * */ -#include "pci/pci.h" -#include "pc.h" -#include "loader.h" +#include "hw/pci/pci.h" +#include "hw/pc.h" +#include "hw/loader.h" #include "sysemu/sysemu.h" #define SGABIOS_FILENAME "sgabios.bin" diff --git a/hw/sh.h b/hw/sh.h index 77bf8aad2c..6230954eac 100644 --- a/hw/sh.h +++ b/hw/sh.h @@ -2,7 +2,7 @@ #define QEMU_SH_H /* Definitions for SH board emulation. */ -#include "sh_intc.h" +#include "hw/sh_intc.h" #define A7ADDR(x) ((x) & 0x1fffffff) #define P4ADDR(x) ((x) | 0xe0000000) diff --git a/hw/sh7750.c b/hw/sh7750.c index 666f8655ed..6778c94f8e 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -23,12 +23,12 @@ * THE SOFTWARE. */ #include -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "sysemu/sysemu.h" -#include "sh7750_regs.h" -#include "sh7750_regnames.h" -#include "sh_intc.h" +#include "hw/sh7750_regs.h" +#include "hw/sh7750_regnames.h" +#include "hw/sh_intc.h" #include "cpu.h" #include "exec/address-spaces.h" diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c index 5a5a2d80de..389698d24a 100644 --- a/hw/sh7750_regnames.c +++ b/hw/sh7750_regnames.c @@ -1,7 +1,7 @@ -#include "hw.h" -#include "sh.h" -#include "sh7750_regs.h" -#include "sh7750_regnames.h" +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/sh7750_regs.h" +#include "hw/sh7750_regnames.h" #define REGNAME(r) {r, #r}, diff --git a/hw/sh_intc.c b/hw/sh_intc.c index c3f77d5092..9e64e4d353 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -8,9 +8,9 @@ * This code is licensed under the GPL. */ -#include "sh_intc.h" -#include "hw.h" -#include "sh.h" +#include "hw/sh_intc.h" +#include "hw/hw.h" +#include "hw/sh.h" //#define DEBUG_INTC //#define DEBUG_INTC_SOURCES diff --git a/hw/sh_intc.h b/hw/sh_intc.h index 6f11beeddd..b7ddcb096a 100644 --- a/hw/sh_intc.h +++ b/hw/sh_intc.h @@ -2,7 +2,7 @@ #define __SH_INTC_H__ #include "qemu-common.h" -#include "irq.h" +#include "hw/irq.h" #include "exec/address-spaces.h" typedef unsigned char intc_enum; diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 077d957003..96535dbe01 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "sysbus.h" -#include "sh.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/sysbus.h" +#include "hw/sh.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "qemu/bswap.h" #include "exec/address-spaces.h" diff --git a/hw/sh_serial.c b/hw/sh_serial.c index 21c5b1362d..40e797c5a2 100644 --- a/hw/sh_serial.c +++ b/hw/sh_serial.c @@ -24,8 +24,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "char/char.h" #include "exec/address-spaces.h" diff --git a/hw/sh_timer.c b/hw/sh_timer.c index 64ea23fce6..b4503230a9 100644 --- a/hw/sh_timer.c +++ b/hw/sh_timer.c @@ -8,11 +8,11 @@ * This code is licensed under the GPL. */ -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "qemu/timer.h" #include "exec/address-spaces.h" -#include "ptimer.h" +#include "hw/ptimer.h" //#define DEBUG_TIMER diff --git a/hw/shix.c b/hw/shix.c index 6f2d55a155..192579d065 100644 --- a/hw/shix.c +++ b/hw/shix.c @@ -27,11 +27,11 @@ More information in target-sh4/README.sh4 */ -#include "hw.h" -#include "sh.h" +#include "hw/hw.h" +#include "hw/sh.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "exec/address-spaces.h" #define BIOS_FILENAME "shix_bios.bin" diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 136ceebc80..b60592b35d 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "sun4m.h" +#include "hw/sun4m.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" //#define DEBUG_IRQ_COUNT diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index af24cc1ae8..a7a9368864 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -23,7 +23,7 @@ */ #include "sysemu/sysemu.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 68a4c0cca4..83f22a0366 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "sun4m.h" +#include "hw/sun4m.h" #include "qemu/timer.h" -#include "ptimer.h" -#include "sysbus.h" +#include "hw/ptimer.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/sm501.c b/hw/sm501.c index b7ac7f9bff..0e019111bb 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -23,12 +23,12 @@ */ #include -#include "hw.h" -#include "serial.h" +#include "hw/hw.h" +#include "hw/serial.h" #include "ui/console.h" -#include "devices.h" -#include "sysbus.h" -#include "qdev-addr.h" +#include "hw/devices.h" +#include "hw/sysbus.h" +#include "hw/qdev-addr.h" #include "qemu/range.h" #include "ui/pixel_ops.h" @@ -1171,28 +1171,28 @@ typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette, int c_y, uint8_t *d, int width); #define DEPTH 8 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define DEPTH 15 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define BGR_FORMAT #define DEPTH 15 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define DEPTH 16 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define BGR_FORMAT #define DEPTH 16 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define DEPTH 32 -#include "sm501_template.h" +#include "hw/sm501_template.h" #define BGR_FORMAT #define DEPTH 32 -#include "sm501_template.h" +#include "hw/sm501_template.h" static draw_line_func * draw_line8_funcs[] = { draw_line8_8, diff --git a/hw/smbios.c b/hw/smbios.c index a7b8bfc383..672ee9b0e7 100644 --- a/hw/smbios.c +++ b/hw/smbios.c @@ -14,8 +14,8 @@ */ #include "sysemu/sysemu.h" -#include "smbios.h" -#include "loader.h" +#include "hw/smbios.h" +#include "hw/loader.h" /* * Structures shared with the BIOS diff --git a/hw/smbus.c b/hw/smbus.c index a908591590..9626415bca 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -9,9 +9,9 @@ /* TODO: Implement PEC. */ -#include "hw.h" -#include "i2c.h" -#include "smbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/smbus.h" //#define DEBUG_SMBUS 1 diff --git a/hw/smbus.h b/hw/smbus.h index 6ed45bd03d..c3db620e00 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include "i2c.h" +#include "hw/i2c.h" #define TYPE_SMBUS_DEVICE "smbus-device" #define SMBUS_DEVICE(obj) \ diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index d36dc7bbe3..dff8403d6c 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -22,9 +22,9 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "i2c.h" -#include "smbus.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/smbus.h" //#define DEBUG diff --git a/hw/smbus_ich9.c b/hw/smbus_ich9.c index 16db3a743c..732ebd3bb0 100644 --- a/hw/smbus_ich9.c +++ b/hw/smbus_ich9.c @@ -24,15 +24,15 @@ * GNU GPL, version 2 or (at your option) any later version. * */ -#include "hw.h" -#include "pc.h" -#include "pm_smbus.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pm_smbus.h" +#include "hw/pci/pci.h" #include "sysemu/sysemu.h" -#include "i2c.h" -#include "smbus.h" +#include "hw/i2c.h" +#include "hw/smbus.h" -#include "ich9.h" +#include "hw/ich9.h" #define TYPE_ICH9_SMB_DEVICE "ICH9 SMB" #define ICH9_SMB_DEVICE(obj) \ diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 67fd074d85..c2feae6eb8 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -7,9 +7,9 @@ * This code is licensed under the GPL */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" -#include "devices.h" +#include "hw/devices.h" /* For crc32 */ #include diff --git a/hw/soc_dma.c b/hw/soc_dma.c index 64e8ee1d13..db5d609388 100644 --- a/hw/soc_dma.c +++ b/hw/soc_dma.c @@ -19,7 +19,7 @@ */ #include "qemu-common.h" #include "qemu/timer.h" -#include "soc_dma.h" +#include "hw/soc_dma.h" static void transfer_mem2mem(struct soc_dma_ch_s *ch) { diff --git a/hw/spapr.c b/hw/spapr.c index e88a27aa71..2709c660c1 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -25,7 +25,7 @@ * */ #include "sysemu/sysemu.h" -#include "hw.h" +#include "hw/hw.h" #include "elf.h" #include "net/net.h" #include "sysemu/blockdev.h" @@ -45,7 +45,7 @@ #include "sysemu/kvm.h" #include "kvm_ppc.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #include "exec/address-spaces.h" #include "hw/usb.h" diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c index d8a098cb1b..8d500bf6be 100644 --- a/hw/spapr_iommu.c +++ b/hw/spapr_iommu.c @@ -16,9 +16,9 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/kvm.h" -#include "qdev.h" +#include "hw/qdev.h" #include "kvm_ppc.h" #include "sysemu/dma.h" #include "exec/address-spaces.h" diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 6ef29362f5..5d2565b484 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -24,7 +24,7 @@ * THE SOFTWARE. * */ -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" #include "hw/qdev.h" #include "hw/spapr.h" diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 4eacbcfd58..36adbc5592 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -22,11 +22,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" -#include "pci/msi.h" -#include "pci/msix.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/pci/pci_host.h" #include "hw/spapr.h" #include "hw/spapr_pci.h" #include "exec/address-spaces.h" diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 34c9ca6b65..6eb3ab5482 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -19,11 +19,11 @@ * License along with this library; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "sysemu/sysemu.h" -#include "boards.h" +#include "hw/boards.h" #include "monitor/monitor.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" #include "hw/sysbus.h" #include "sysemu/kvm.h" diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 7fc0e13f9f..27940949ce 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -31,10 +31,10 @@ * - Add indirect descriptors support * - Maybe do autosense (PAPR seems to mandate it, linux doesn't care) */ -#include "hw.h" -#include "scsi.h" -#include "scsi-defs.h" -#include "srp.h" +#include "hw/hw.h" +#include "hw/scsi.h" +#include "hw/scsi-defs.h" +#include "hw/srp.h" #include "hw/qdev.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 5c63eaafa9..be08571d23 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -1,4 +1,4 @@ -#include "qdev.h" +#include "hw/qdev.h" #include "char/char.h" #include "hw/spapr.h" #include "hw/spapr_vio.h" diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 6d0df51749..18e368ec98 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -25,10 +25,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "sparc32_dma.h" -#include "sun4m.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sparc32_dma.h" +#include "hw/sun4m.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/spitz.c b/hw/spitz.c index 5bc49fcd27..f5832bea93 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -10,23 +10,23 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" #include "sysemu/sysemu.h" -#include "pcmcia.h" -#include "i2c.h" -#include "ssi.h" -#include "flash.h" +#include "hw/pcmcia.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "hw/flash.h" #include "qemu/timer.h" -#include "devices.h" -#include "sharpsl.h" +#include "hw/devices.h" +#include "hw/sharpsl.h" #include "ui/console.h" #include "block/block.h" #include "audio/audio.h" -#include "boards.h" +#include "hw/boards.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" #undef REG_FMT diff --git a/hw/ssd0303.c b/hw/ssd0303.c index 8777b1681a..db50909734 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -10,7 +10,7 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ -#include "i2c.h" +#include "hw/i2c.h" #include "ui/console.h" //#define DEBUG_SSD0303 1 diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 84c86a5244..27b4151994 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -10,7 +10,7 @@ /* The controller can support a variety of different displays, but we only implement one. Most of the commends relating to brightness and geometry setup are ignored. */ -#include "ssi.h" +#include "hw/ssi.h" #include "ui/console.h" //#define DEBUG_SSD0323 1 diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index dca8906e7d..4d3c4f6445 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -11,8 +11,8 @@ */ #include "sysemu/blockdev.h" -#include "ssi.h" -#include "sd.h" +#include "hw/ssi.h" +#include "hw/sd.h" //#define DEBUG_SSI_SD 1 diff --git a/hw/ssi.c b/hw/ssi.c index 0b18176f7a..1264d9da23 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -12,7 +12,7 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "ssi.h" +#include "hw/ssi.h" struct SSIBus { BusState qbus; diff --git a/hw/ssi.h b/hw/ssi.h index a05d60beb4..fdae317295 100644 --- a/hw/ssi.h +++ b/hw/ssi.h @@ -11,7 +11,7 @@ #ifndef QEMU_SSI_H #define QEMU_SSI_H -#include "qdev.h" +#include "hw/qdev.h" typedef struct SSISlave SSISlave; diff --git a/hw/stellaris.c b/hw/stellaris.c index 9b8f2034f1..f4ce7945f3 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -7,14 +7,14 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "ssi.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/ssi.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "qemu/timer.h" -#include "i2c.h" +#include "hw/i2c.h" #include "net/net.h" -#include "boards.h" +#include "hw/boards.h" #include "exec/address-spaces.h" #define GPIO_A 0 diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 6c701fb67b..59b84564a0 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -6,7 +6,7 @@ * * This code is licensed under the GPL. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "net/net.h" #include diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c index 7a95c3fc88..4e407922a0 100644 --- a/hw/stellaris_input.c +++ b/hw/stellaris_input.c @@ -6,8 +6,8 @@ * * This code is licensed under the GPL. */ -#include "hw.h" -#include "devices.h" +#include "hw/hw.h" +#include "hw/devices.h" #include "ui/console.h" typedef struct { diff --git a/hw/stream.c b/hw/stream.c index d4cf84d4c0..a07d6a56d3 100644 --- a/hw/stream.c +++ b/hw/stream.c @@ -1,4 +1,4 @@ -#include "stream.h" +#include "hw/stream.h" void stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app) diff --git a/hw/strongarm.c b/hw/strongarm.c index ab736e300e..49f9577e32 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -26,13 +26,13 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "strongarm.h" +#include "hw/sysbus.h" +#include "hw/strongarm.h" #include "qemu/error-report.h" -#include "arm-misc.h" +#include "hw/arm-misc.h" #include "char/char.h" #include "sysemu/sysemu.h" -#include "ssi.h" +#include "hw/ssi.h" //#define DEBUG diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c index f8f4d023a3..9d443d1b10 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -22,10 +22,10 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "sun4m.h" +#include "hw/hw.h" +#include "hw/sun4m.h" #include "monitor/monitor.h" -#include "sysbus.h" +#include "hw/sysbus.h" //#define DEBUG_IRQ_COUNT //#define DEBUG_IRQ diff --git a/hw/sun4m.c b/hw/sun4m.c index 9903f443cb..37bd04108d 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -21,24 +21,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "sun4m.h" -#include "nvram.h" -#include "sparc32_dma.h" -#include "fdc.h" +#include "hw/sun4m.h" +#include "hw/nvram.h" +#include "hw/sparc32_dma.h" +#include "hw/fdc.h" #include "sysemu/sysemu.h" #include "net/net.h" -#include "boards.h" -#include "firmware_abi.h" -#include "esp.h" -#include "pc.h" -#include "isa.h" -#include "fw_cfg.h" -#include "escc.h" -#include "empty_slot.h" -#include "qdev-addr.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/firmware_abi.h" +#include "hw/esp.h" +#include "hw/pc.h" +#include "hw/isa.h" +#include "hw/fw_cfg.h" +#include "hw/escc.h" +#include "hw/empty_slot.h" +#include "hw/qdev-addr.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/blockdev.h" #include "trace.h" diff --git a/hw/sun4m.h b/hw/sun4m.h index 0361eeed41..0d2cfb807b 100644 --- a/hw/sun4m.h +++ b/hw/sun4m.h @@ -31,6 +31,6 @@ void sun4m_pic_info(Monitor *mon, const QDict *qdict); void sun4m_irq_info(Monitor *mon, const QDict *qdict); /* sparc32_dma.c */ -#include "sparc32_dma.h" +#include "hw/sparc32_dma.h" #endif diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index 8f9635f343..33e77b02a3 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sun4m.h" -#include "sysbus.h" +#include "hw/sun4m.h" +#include "hw/sysbus.h" #include "trace.h" /* diff --git a/hw/sun4u.c b/hw/sun4u.c index 9fbda29ac4..51ffa1c09b 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -21,22 +21,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "pci/pci.h" -#include "apb_pci.h" -#include "pc.h" -#include "serial.h" -#include "nvram.h" -#include "fdc.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" +#include "hw/apb_pci.h" +#include "hw/pc.h" +#include "hw/serial.h" +#include "hw/nvram.h" +#include "hw/fdc.h" #include "net/net.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "firmware_abi.h" -#include "fw_cfg.h" -#include "sysbus.h" -#include "ide.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/firmware_abi.h" +#include "hw/fw_cfg.h" +#include "hw/sysbus.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" diff --git a/hw/sysbus.c b/hw/sysbus.c index 6d9d1df419..74bb4b81de 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -17,7 +17,7 @@ * License along with this library; if not, see . */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "monitor/monitor.h" #include "exec/address-spaces.h" diff --git a/hw/sysbus.h b/hw/sysbus.h index a7fcded6e7..17de506339 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -3,7 +3,7 @@ /* Devices attached directly to the main system bus. */ -#include "qdev.h" +#include "hw/qdev.h" #include "exec/memory.h" #define QDEV_MAX_MMIO 32 diff --git a/hw/tc58128.c b/hw/tc58128.c index 4ce80b18f3..f76f96d9e7 100644 --- a/hw/tc58128.c +++ b/hw/tc58128.c @@ -1,6 +1,6 @@ -#include "hw.h" -#include "sh.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/sh.h" +#include "hw/loader.h" #define CE1 0x0100 #define CE2 0x0200 diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index e815f83198..0755463a1d 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -10,9 +10,9 @@ * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "devices.h" -#include "flash.h" +#include "hw/hw.h" +#include "hw/devices.h" +#include "hw/flash.h" #include "ui/console.h" #include "ui/pixel_ops.h" #include "sysemu/blockdev.h" @@ -421,15 +421,15 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) } #define BITS 8 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 15 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 16 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 24 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" #define BITS 32 -#include "tc6393xb_template.h" +#include "hw/tc6393xb_template.h" static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update) { diff --git a/hw/tcx.c b/hw/tcx.c index 0ce2952f73..896407d865 100644 --- a/hw/tcx.c +++ b/hw/tcx.c @@ -25,8 +25,8 @@ #include "qemu-common.h" #include "ui/console.h" #include "ui/pixel_ops.h" -#include "sysbus.h" -#include "qdev-addr.h" +#include "hw/sysbus.h" +#include "hw/qdev-addr.h" #define MAXX 1024 #define MAXY 768 diff --git a/hw/tmp105.c b/hw/tmp105.c index 3ad2d2f04c..47e5437e0d 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -18,9 +18,9 @@ * with this program; if not, see . */ -#include "hw.h" -#include "i2c.h" -#include "tmp105.h" +#include "hw/hw.h" +#include "hw/i2c.h" +#include "hw/tmp105.h" #include "qapi/visitor.h" static void tmp105_interrupt_update(TMP105State *s) diff --git a/hw/tmp105.h b/hw/tmp105.h index d2189191e2..9a9632c54b 100644 --- a/hw/tmp105.h +++ b/hw/tmp105.h @@ -14,8 +14,8 @@ #ifndef QEMU_TMP105_H #define QEMU_TMP105_H -#include "i2c.h" -#include "tmp105_regs.h" +#include "hw/i2c.h" +#include "hw/tmp105_regs.h" #define TYPE_TMP105 "tmp105" #define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105) diff --git a/hw/tosa.c b/hw/tosa.c index efea109795..747888c64e 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -11,18 +11,18 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" -#include "devices.h" -#include "sharpsl.h" -#include "pcmcia.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/sharpsl.h" +#include "hw/pcmcia.h" #include "block/block.h" -#include "boards.h" -#include "i2c.h" -#include "ssi.h" +#include "hw/boards.h" +#include "hw/i2c.h" +#include "hw/ssi.h" #include "sysemu/blockdev.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "exec/address-spaces.h" #define TOSA_RAM 0x04000000 diff --git a/hw/tpci200.c b/hw/tpci200.c index a4823fb9f2..e3408ef4ba 100644 --- a/hw/tpci200.c +++ b/hw/tpci200.c @@ -8,8 +8,8 @@ * later version. */ -#include "ipack.h" -#include "pci/pci.h" +#include "hw/ipack.h" +#include "hw/pci/pci.h" #include "qemu/bitops.h" #include diff --git a/hw/tsc2005.c b/hw/tsc2005.c index 740ff86aa8..a771cd5e52 100644 --- a/hw/tsc2005.c +++ b/hw/tsc2005.c @@ -18,10 +18,10 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" #include "ui/console.h" -#include "devices.h" +#include "hw/devices.h" #define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10))) diff --git a/hw/tsc210x.c b/hw/tsc210x.c index 2076c355d2..b93e502e05 100644 --- a/hw/tsc210x.c +++ b/hw/tsc210x.c @@ -19,12 +19,12 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "audio/audio.h" #include "qemu/timer.h" #include "ui/console.h" -#include "omap.h" /* For I2SCodec and uWireSlave */ -#include "devices.h" +#include "hw/omap.h" /* For I2SCodec and uWireSlave */ +#include "hw/devices.h" #define TSC_DATA_REGISTERS_PAGE 0x0 #define TSC_CONTROL_REGISTERS_PAGE 0x1 diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 2c7d033651..a5251a34ac 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -20,11 +20,11 @@ */ #include "qemu-common.h" #include "qemu/timer.h" -#include "usb.h" -#include "omap.h" -#include "irq.h" -#include "devices.h" -#include "sysbus.h" +#include "hw/usb.h" +#include "hw/omap.h" +#include "hw/irq.h" +#include "hw/devices.h" +#include "hw/sysbus.h" typedef struct TUSBState { SysBusDevice busdev; diff --git a/hw/twl92230.c b/hw/twl92230.c index 70d9b03e55..7d020c4cba 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -19,9 +19,9 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "i2c.h" +#include "hw/i2c.h" #include "sysemu/sysemu.h" #include "ui/console.h" diff --git a/hw/unin_pci.c b/hw/unin_pci.c index f1c3c20f37..cb95ad1f5e 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc/mac.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" /* debug UniNorth */ //#define DEBUG_UNIN diff --git a/hw/usb.h b/hw/usb.h index 382496cf82..1b10684dde 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include "qdev.h" +#include "hw/qdev.h" #include "qemu/queue.h" /* Constants related to the USB / PCI interaction */ diff --git a/hw/versatile_i2c.c b/hw/versatile_i2c.c index ad71e9d92d..d0444aecac 100644 --- a/hw/versatile_i2c.c +++ b/hw/versatile_i2c.c @@ -21,8 +21,8 @@ * */ -#include "sysbus.h" -#include "bitbang_i2c.h" +#include "hw/sysbus.h" +#include "hw/bitbang_i2c.h" typedef struct { SysBusDevice busdev; diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 9d991599cf..0b97a4073d 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -7,9 +7,9 @@ * This code is licensed under the LGPL. */ -#include "sysbus.h" -#include "pci/pci.h" -#include "pci/pci_host.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" #include "exec/address-spaces.h" typedef struct { diff --git a/hw/versatilepb.c b/hw/versatilepb.c index e0a28f08d3..baaa265888 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -7,17 +7,17 @@ * This code is licensed under the GPL. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "pci/pci.h" -#include "i2c.h" -#include "boards.h" +#include "hw/pci/pci.h" +#include "hw/i2c.h" +#include "hw/boards.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "flash.h" +#include "hw/flash.h" #define VERSATILE_FLASH_ADDR 0x34000000 #define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) diff --git a/hw/vexpress.c b/hw/vexpress.c index 741b044f1d..02922c38b3 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -21,16 +21,16 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "sysbus.h" -#include "arm-misc.h" -#include "primecell.h" -#include "devices.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" +#include "hw/primecell.h" +#include "hw/devices.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" +#include "hw/boards.h" #include "exec/address-spaces.h" #include "sysemu/blockdev.h" -#include "flash.h" +#include "hw/flash.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index ad9ae360b2..288361d0fb 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -31,9 +31,9 @@ #include "exec/address-spaces.h" #include "sysemu/kvm.h" #include "exec/memory.h" -#include "pci/msi.h" -#include "pci/msix.h" -#include "pci/pci.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/pci/pci.h" #include "qemu-common.h" #include "qemu/error-report.h" #include "qemu/queue.h" diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c index 311c966f77..4aa62bf35e 100644 --- a/hw/vga-isa-mm.c +++ b/hw/vga-isa-mm.c @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pc.h" -#include "vga_int.h" +#include "hw/pc.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" diff --git a/hw/vga-isa.c b/hw/vga-isa.c index 762e45aaeb..ffad5226fd 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -23,13 +23,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pc.h" -#include "vga_int.h" +#include "hw/pc.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" -#include "loader.h" +#include "hw/loader.h" typedef struct ISAVGAState { ISADevice dev; diff --git a/hw/vga-pci.c b/hw/vga-pci.c index c491af20e4..18018ff1c3 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -23,13 +23,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "pci/pci.h" -#include "vga_int.h" +#include "hw/pci/pci.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" -#include "loader.h" +#include "hw/loader.h" #define PCI_VGA_IOPORT_OFFSET 0x400 #define PCI_VGA_IOPORT_SIZE (0x3e0 - 0x3c0) diff --git a/hw/vga.c b/hw/vga.c index 1caf23d7b6..2213bc1a88 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -21,15 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "vga.h" +#include "hw/hw.h" +#include "hw/vga.h" #include "ui/console.h" -#include "pc.h" -#include "pci/pci.h" -#include "vga_int.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" -#include "xen.h" +#include "hw/xen.h" #include "trace.h" //#define DEBUG_VGA @@ -986,28 +986,28 @@ typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d, const uint8_t *s, int width); #define DEPTH 8 -#include "vga_template.h" +#include "hw/vga_template.h" #define DEPTH 15 -#include "vga_template.h" +#include "hw/vga_template.h" #define BGR_FORMAT #define DEPTH 15 -#include "vga_template.h" +#include "hw/vga_template.h" #define DEPTH 16 -#include "vga_template.h" +#include "hw/vga_template.h" #define BGR_FORMAT #define DEPTH 16 -#include "vga_template.h" +#include "hw/vga_template.h" #define DEPTH 32 -#include "vga_template.h" +#include "hw/vga_template.h" #define BGR_FORMAT #define DEPTH 32 -#include "vga_template.h" +#include "hw/vga_template.h" static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) { diff --git a/hw/vhost.c b/hw/vhost.c index 8d41fdb53f..2d25d7e300 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -14,7 +14,7 @@ */ #include -#include "vhost.h" +#include "hw/vhost.h" #include "hw/hw.h" #include "qemu/range.h" #include diff --git a/hw/vhost_net.c b/hw/vhost_net.c index d1df0e2447..d3218a07f4 100644 --- a/hw/vhost_net.c +++ b/hw/vhost_net.c @@ -16,8 +16,8 @@ #include "net/net.h" #include "net/tap.h" -#include "virtio-net.h" -#include "vhost_net.h" +#include "hw/virtio-net.h" +#include "hw/vhost_net.h" #include "qemu/error-report.h" #include "config.h" @@ -36,7 +36,7 @@ #include -#include "vhost.h" +#include "hw/vhost.h" struct vhost_net { struct vhost_dev dev; diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index 8c4e8e4313..41eab1697c 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -22,25 +22,25 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" -#include "serial.h" -#include "flash.h" +#include "hw/sysbus.h" +#include "hw/hw.h" +#include "hw/serial.h" +#include "hw/flash.h" #include "sysemu/sysemu.h" -#include "devices.h" -#include "boards.h" +#include "hw/devices.h" +#include "hw/boards.h" #include "sysemu/device_tree.h" -#include "loader.h" +#include "hw/loader.h" #include "elf.h" #include "qemu/log.h" #include "exec/address-spaces.h" -#include "ppc.h" -#include "ppc4xx.h" -#include "ppc405.h" +#include "hw/ppc.h" +#include "hw/ppc4xx.h" +#include "hw/ppc405.h" #include "sysemu/blockdev.h" -#include "xilinx.h" +#include "hw/xilinx.h" #define EPAPR_MAGIC (0x45504150) #define FLASH_SIZE (16 * 1024 * 1024) diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index c0a790264c..6bfcddc379 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -16,11 +16,11 @@ #include "qemu/iov.h" #include "qemu/timer.h" #include "qemu-common.h" -#include "virtio.h" -#include "pc.h" +#include "hw/virtio.h" +#include "hw/pc.h" #include "cpu.h" #include "sysemu/balloon.h" -#include "virtio-balloon.h" +#include "hw/virtio-balloon.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" #include "qapi/visitor.h" diff --git a/hw/virtio-balloon.h b/hw/virtio-balloon.h index b1828f4a48..f37f31b4d7 100644 --- a/hw/virtio-balloon.h +++ b/hw/virtio-balloon.h @@ -15,8 +15,8 @@ #ifndef _QEMU_VIRTIO_BALLOON_H #define _QEMU_VIRTIO_BALLOON_H -#include "virtio.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/pci/pci.h" /* from Linux's linux/virtio_balloon.h */ diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 34913ee40e..248a966357 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -16,11 +16,11 @@ #include "trace.h" #include "hw/block-common.h" #include "sysemu/blockdev.h" -#include "virtio-blk.h" +#include "hw/virtio-blk.h" #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE -#include "hw/dataplane/virtio-blk.h" +#include "dataplane/virtio-blk.h" #endif -#include "scsi-defs.h" +#include "hw/scsi-defs.h" #ifdef __linux__ # include #endif diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h index 43ca492080..7ef2f35852 100644 --- a/hw/virtio-blk.h +++ b/hw/virtio-blk.h @@ -14,7 +14,7 @@ #ifndef _QEMU_VIRTIO_BLK_H #define _QEMU_VIRTIO_BLK_H -#include "virtio.h" +#include "hw/virtio.h" #include "hw/block-common.h" /* from Linux's linux/virtio_blk.h */ diff --git a/hw/virtio-bus.c b/hw/virtio-bus.c index 6045d8ad86..6c2aab00eb 100644 --- a/hw/virtio-bus.c +++ b/hw/virtio-bus.c @@ -22,11 +22,11 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/error-report.h" -#include "qdev.h" -#include "virtio-bus.h" -#include "virtio.h" +#include "hw/qdev.h" +#include "hw/virtio-bus.h" +#include "hw/virtio.h" /* #define DEBUG_VIRTIO_BUS */ diff --git a/hw/virtio-bus.h b/hw/virtio-bus.h index 7584a0e6ae..ae0f7078b4 100644 --- a/hw/virtio-bus.h +++ b/hw/virtio-bus.h @@ -25,9 +25,9 @@ #ifndef VIRTIO_BUS_H #define VIRTIO_BUS_H -#include "qdev.h" +#include "hw/qdev.h" #include "sysemu/sysemu.h" -#include "virtio.h" +#include "hw/virtio.h" #define TYPE_VIRTIO_BUS "virtio-bus" #define VIRTIO_BUS_GET_CLASS(obj) \ diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 46072a086f..b10f5f08d4 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -13,7 +13,7 @@ #include "char/char.h" #include "qemu/error-report.h" #include "trace.h" -#include "virtio-serial.h" +#include "hw/virtio-serial.h" typedef struct VirtConsole { VirtIOSerialPort port; diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 573c669d15..0ad96eefd6 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -12,14 +12,14 @@ */ #include "qemu/iov.h" -#include "virtio.h" +#include "hw/virtio.h" #include "net/net.h" #include "net/checksum.h" #include "net/tap.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "virtio-net.h" -#include "vhost_net.h" +#include "hw/virtio-net.h" +#include "hw/vhost_net.h" #define VIRTIO_NET_VM_VERSION 11 diff --git a/hw/virtio-net.h b/hw/virtio-net.h index e654c13a9f..0c83ca5cfe 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -14,8 +14,8 @@ #ifndef _QEMU_VIRTIO_NET_H #define _QEMU_VIRTIO_NET_H -#include "virtio.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/pci/pci.h" #define ETH_ALEN 6 diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index df1dd7744c..ba4d7d5424 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -17,21 +17,21 @@ #include -#include "virtio.h" -#include "virtio-blk.h" -#include "virtio-net.h" -#include "virtio-serial.h" -#include "virtio-scsi.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/virtio-blk.h" +#include "hw/virtio-net.h" +#include "hw/virtio-serial.h" +#include "hw/virtio-scsi.h" +#include "hw/pci/pci.h" #include "qemu/error-report.h" -#include "pci/msi.h" -#include "pci/msix.h" -#include "loader.h" +#include "hw/pci/msi.h" +#include "hw/pci/msix.h" +#include "hw/loader.h" #include "sysemu/kvm.h" #include "sysemu/blockdev.h" -#include "virtio-pci.h" +#include "hw/virtio-pci.h" #include "qemu/range.h" -#include "virtio-bus.h" +#include "hw/virtio-bus.h" /* from Linux's linux/virtio_pci.h */ diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h index d01db97e1e..2ae96f84d6 100644 --- a/hw/virtio-pci.h +++ b/hw/virtio-pci.h @@ -16,13 +16,13 @@ #define QEMU_VIRTIO_PCI_H #include "hw/pci/msi.h" -#include "virtio-blk.h" -#include "virtio-net.h" -#include "virtio-rng.h" -#include "virtio-serial.h" -#include "virtio-scsi.h" -#include "virtio-bus.h" -#include "9pfs/virtio-9p-device.h" +#include "hw/virtio-blk.h" +#include "hw/virtio-net.h" +#include "hw/virtio-rng.h" +#include "hw/virtio-serial.h" +#include "hw/virtio-scsi.h" +#include "hw/virtio-bus.h" +#include "hw/9pfs/virtio-9p-device.h" typedef struct VirtIOPCIProxy VirtIOPCIProxy; diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c index 2cdf4ec052..54c1421f86 100644 --- a/hw/virtio-rng.c +++ b/hw/virtio-rng.c @@ -10,10 +10,10 @@ */ #include "qemu/iov.h" -#include "qdev.h" +#include "hw/qdev.h" #include "qapi/qmp/qerror.h" -#include "virtio.h" -#include "virtio-rng.h" +#include "hw/virtio.h" +#include "hw/virtio-rng.h" #include "qemu/rng.h" typedef struct VirtIORNG { diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index 27070d1eea..72cc5198d4 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -13,7 +13,7 @@ * */ -#include "virtio-scsi.h" +#include "hw/virtio-scsi.h" #include "qemu/error-report.h" #include #include diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h index 8d9d15f093..81b3279a57 100644 --- a/hw/virtio-scsi.h +++ b/hw/virtio-scsi.h @@ -14,8 +14,8 @@ #ifndef _QEMU_VIRTIO_SCSI_H #define _QEMU_VIRTIO_SCSI_H -#include "virtio.h" -#include "pci/pci.h" +#include "hw/virtio.h" +#include "hw/pci/pci.h" /* The ID for virtio_scsi */ #define VIRTIO_ID_SCSI 8 diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index aa7d0d7fc7..ada1d0100b 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -21,9 +21,9 @@ #include "qemu/iov.h" #include "monitor/monitor.h" #include "qemu/queue.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "trace.h" -#include "virtio-serial.h" +#include "hw/virtio-serial.h" /* The virtio-serial bus on top of which the ports will ride as devices */ struct VirtIOSerialBus { diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index 16e39820a2..d2d9fb773e 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -15,8 +15,8 @@ #ifndef _QEMU_VIRTIO_SERIAL_H #define _QEMU_VIRTIO_SERIAL_H -#include "qdev.h" -#include "virtio.h" +#include "hw/qdev.h" +#include "hw/virtio.h" /* == Interface shared between the guest kernel and qemu == */ diff --git a/hw/virtio.c b/hw/virtio.c index e259348518..26fbc790ec 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -15,9 +15,9 @@ #include "trace.h" #include "qemu/error-report.h" -#include "virtio.h" +#include "hw/virtio.h" #include "qemu/atomic.h" -#include "virtio-bus.h" +#include "hw/virtio-bus.h" /* The alignment to use between consumer and producer parts of vring. * x86 pagesize again. */ diff --git a/hw/virtio.h b/hw/virtio.h index 8cc71e99b6..ca43fd70cd 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -14,13 +14,13 @@ #ifndef _QEMU_VIRTIO_H #define _QEMU_VIRTIO_H -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" -#include "qdev.h" +#include "hw/qdev.h" #include "sysemu/sysemu.h" #include "qemu/event_notifier.h" #ifdef CONFIG_VIRTFS -#include "9pfs/virtio-9p-device.h" +#include "hw/9pfs/virtio-9p-device.h" #endif /* from Linux's linux/virtio_config.h */ diff --git a/hw/vmmouse.c b/hw/vmmouse.c index b9afc2c4e8..a9d227e17d 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" -#include "ps2.h" -#include "pc.h" -#include "qdev.h" +#include "hw/ps2.h" +#include "hw/pc.h" +#include "hw/qdev.h" /* debug only vmmouse */ //#define DEBUG_VMMOUSE diff --git a/hw/vmport.c b/hw/vmport.c index faead3a955..cc1466ae96 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "isa.h" -#include "pc.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/pc.h" #include "sysemu/kvm.h" -#include "qdev.h" +#include "hw/qdev.h" //#define VMPORT_DEBUG diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 8fc201bfb9..db2f187e56 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -21,17 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "loader.h" +#include "hw/hw.h" +#include "hw/loader.h" #include "ui/console.h" -#include "pci/pci.h" +#include "hw/pci/pci.h" #undef VERBOSE #define HW_RECT_ACCEL #define HW_FILL_ACCEL #define HW_MOUSE_ACCEL -#include "vga_int.h" +#include "hw/vga_int.h" /* See http://vmware-svga.sf.net/ for some documentation on VMWare SVGA */ diff --git a/hw/vt82c686.c b/hw/vt82c686.c index c2b1bfce10..452950826c 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -10,18 +10,18 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pc.h" -#include "vt82c686.h" -#include "i2c.h" -#include "smbus.h" -#include "pci/pci.h" -#include "isa.h" -#include "sysbus.h" -#include "mips.h" -#include "apm.h" -#include "acpi.h" -#include "pm_smbus.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/vt82c686.h" +#include "hw/i2c.h" +#include "hw/smbus.h" +#include "hw/pci/pci.h" +#include "hw/isa.h" +#include "hw/sysbus.h" +#include "hw/mips.h" +#include "hw/apm.h" +#include "hw/acpi.h" +#include "hw/pm_smbus.h" #include "sysemu/sysemu.h" #include "qemu/timer.h" #include "exec/address-spaces.h" diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 37ce362811..f13e507fcf 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -23,9 +23,9 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "watchdog.h" -#include "hw.h" -#include "pci/pci.h" +#include "hw/watchdog.h" +#include "hw/hw.h" +#include "hw/pci/pci.h" /*#define I6300ESB_DEBUG 1*/ diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index 599a86f5f6..6c52808ac0 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -21,10 +21,10 @@ #include "qemu-common.h" #include "qemu/timer.h" -#include "watchdog.h" -#include "hw.h" -#include "isa.h" -#include "pc.h" +#include "hw/watchdog.h" +#include "hw/hw.h" +#include "hw/isa.h" +#include "hw/pc.h" /*#define IB700_DEBUG 1*/ diff --git a/hw/wm8750.c b/hw/wm8750.c index d3ea5ba8f5..0904cf496d 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -7,8 +7,8 @@ * This file is licensed under GNU GPL. */ -#include "hw.h" -#include "i2c.h" +#include "hw/hw.h" +#include "hw/i2c.h" #include "audio/audio.h" #define IN_PORT_N 3 diff --git a/hw/xen-host-pci-device.c b/hw/xen-host-pci-device.c index 743b37b991..ff2e876b3d 100644 --- a/hw/xen-host-pci-device.c +++ b/hw/xen-host-pci-device.c @@ -7,7 +7,7 @@ */ #include "qemu-common.h" -#include "xen-host-pci-device.h" +#include "hw/xen-host-pci-device.h" #define XEN_HOST_PCI_MAX_EXT_CAP \ ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4)) diff --git a/hw/xen-host-pci-device.h b/hw/xen-host-pci-device.h index 942b24dccc..c2486f0c19 100644 --- a/hw/xen-host-pci-device.h +++ b/hw/xen-host-pci-device.h @@ -1,7 +1,7 @@ #ifndef XEN_HOST_PCI_DEVICE_H #define XEN_HOST_PCI_DEVICE_H -#include "pci/pci.h" +#include "hw/pci/pci.h" enum { XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1, diff --git a/hw/xen_apic.c b/hw/xen_apic.c index 1d1d15c289..8f387b6403 100644 --- a/hw/xen_apic.c +++ b/hw/xen_apic.c @@ -11,7 +11,7 @@ */ #include "hw/apic_internal.h" #include "hw/pci/msi.h" -#include "xen.h" +#include "hw/xen.h" static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/xen_backend.c b/hw/xen_backend.c index 3fa30098ca..24381b55e5 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -34,10 +34,10 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" #include "qemu/log.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include diff --git a/hw/xen_backend.h b/hw/xen_backend.h index f37afb1f05..6d5c699c51 100644 --- a/hw/xen_backend.h +++ b/hw/xen_backend.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_XEN_BACKEND_H #define QEMU_HW_XEN_BACKEND_H 1 -#include "xen_common.h" +#include "hw/xen_common.h" #include "sysemu/sysemu.h" #include "net/net.h" diff --git a/hw/xen_common.h b/hw/xen_common.h index 95bc9a7825..c37bde3f7e 100644 --- a/hw/xen_common.h +++ b/hw/xen_common.h @@ -14,8 +14,8 @@ #endif #include -#include "hw.h" -#include "xen.h" +#include "hw/hw.h" +#include "hw/xen.h" #include "qemu/queue.h" /* diff --git a/hw/xen_console.c b/hw/xen_console.c index 44141f8692..a8db6f8d8f 100644 --- a/hw/xen_console.c +++ b/hw/xen_console.c @@ -29,9 +29,9 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "char/char.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c index e2ba741d54..cdcaf62f26 100644 --- a/hw/xen_devconfig.c +++ b/hw/xen_devconfig.c @@ -1,4 +1,4 @@ -#include "xen_backend.h" +#include "hw/xen_backend.h" #include "sysemu/blockdev.h" /* ------------------------------------------------------------- */ diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 7fea87156d..cc09a2f1fa 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -35,9 +35,9 @@ #include #include -#include "hw.h" -#include "xen_backend.h" -#include "xen_blkif.h" +#include "hw/hw.h" +#include "hw/xen_backend.h" +#include "hw/xen_blkif.h" #include "sysemu/blockdev.h" /* ------------------------------------------------------------- */ diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c index a4272f0680..d477061545 100644 --- a/hw/xen_domainbuild.c +++ b/hw/xen_domainbuild.c @@ -1,6 +1,6 @@ #include -#include "xen_backend.h" -#include "xen_domainbuild.h" +#include "hw/xen_backend.h" +#include "hw/xen_domainbuild.h" #include "qemu/timer.h" #include "qemu/log.h" diff --git a/hw/xen_domainbuild.h b/hw/xen_domainbuild.h index dea0121868..681cbe5fd8 100644 --- a/hw/xen_domainbuild.h +++ b/hw/xen_domainbuild.h @@ -1,7 +1,7 @@ #ifndef QEMU_HW_XEN_DOMAINBUILD_H #define QEMU_HW_XEN_DOMAINBUILD_H 1 -#include "xen_common.h" +#include "hw/xen_common.h" int xenstore_domain_init1(const char *kernel, const char *ramdisk, const char *cmdline); diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c index 66e898123e..a8177b6340 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -22,11 +22,11 @@ * THE SOFTWARE. */ -#include "hw.h" -#include "pc.h" -#include "boards.h" -#include "xen_backend.h" -#include "xen_domainbuild.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/boards.h" +#include "hw/xen_backend.h" +#include "hw/xen_domainbuild.h" #include "sysemu/blockdev.h" static void xen_init_pv(QEMUMachineInitArgs *args) diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 34961c287a..b6d36793b3 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -35,11 +35,11 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "net/net.h" #include "net/checksum.h" #include "net/util.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include diff --git a/hw/xen_platform.c b/hw/xen_platform.c index 8866468c99..5e11c950ab 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -25,12 +25,12 @@ #include -#include "hw.h" -#include "pc.h" -#include "pci/pci.h" -#include "irq.h" -#include "xen_common.h" -#include "xen_backend.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci.h" +#include "hw/irq.h" +#include "hw/xen_common.h" +#include "hw/xen_backend.h" #include "trace.h" #include "exec/address-spaces.h" diff --git a/hw/xen_pt.c b/hw/xen_pt.c index 9db5f6e964..ce695d0e64 100644 --- a/hw/xen_pt.c +++ b/hw/xen_pt.c @@ -54,10 +54,10 @@ #include -#include "pci/pci.h" -#include "xen.h" -#include "xen_backend.h" -#include "xen_pt.h" +#include "hw/pci/pci.h" +#include "hw/xen.h" +#include "hw/xen_backend.h" +#include "hw/xen_pt.h" #include "qemu/range.h" #include "exec/address-spaces.h" diff --git a/hw/xen_pt.h b/hw/xen_pt.h index e3497302cf..1cd9f44704 100644 --- a/hw/xen_pt.h +++ b/hw/xen_pt.h @@ -2,9 +2,9 @@ #define XEN_PT_H #include "qemu-common.h" -#include "xen_common.h" -#include "pci/pci.h" -#include "xen-host-pci-device.h" +#include "hw/xen_common.h" +#include "hw/pci/pci.h" +#include "hw/xen-host-pci-device.h" void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3); diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c index 54a179af90..55838216d9 100644 --- a/hw/xen_pt_config_init.c +++ b/hw/xen_pt_config_init.c @@ -13,8 +13,8 @@ */ #include "qemu/timer.h" -#include "xen_backend.h" -#include "xen_pt.h" +#include "hw/xen_backend.h" +#include "hw/xen_pt.h" #define XEN_PT_MERGE_VALUE(value, data, val_mask) \ (((value) & (val_mask)) | ((data) & ~(val_mask))) diff --git a/hw/xen_pt_msi.c b/hw/xen_pt_msi.c index db757cd1f1..a54ee2bfd9 100644 --- a/hw/xen_pt_msi.c +++ b/hw/xen_pt_msi.c @@ -11,9 +11,9 @@ #include -#include "xen_backend.h" -#include "xen_pt.h" -#include "apic-msidef.h" +#include "hw/xen_backend.h" +#include "hw/xen_pt.h" +#include "hw/apic-msidef.h" #define XEN_PT_AUTO_ASSIGN -1 diff --git a/hw/xenfb.c b/hw/xenfb.c index 7f1f6b4643..3462ded619 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -35,10 +35,10 @@ #include #include -#include "hw.h" +#include "hw/hw.h" #include "ui/console.h" #include "char/char.h" -#include "xen_backend.h" +#include "hw/xen_backend.h" #include #include diff --git a/hw/xgmac.c b/hw/xgmac.c index 50722988b9..5275f4810d 100644 --- a/hw/xgmac.c +++ b/hw/xgmac.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #include "qemu/log.h" #include "net/net.h" diff --git a/hw/xics.c b/hw/xics.c index 9ef0d61377..c3ef12fff4 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -25,7 +25,7 @@ * */ -#include "hw.h" +#include "hw/hw.h" #include "trace.h" #include "hw/spapr.h" #include "hw/xics.h" diff --git a/hw/xilinx.h b/hw/xilinx.h index a78281f730..6c1ee21c54 100644 --- a/hw/xilinx.h +++ b/hw/xilinx.h @@ -4,7 +4,7 @@ #include "qemu-common.h" #include "qapi/qmp/qerror.h" -#include "stream.h" +#include "hw/stream.h" #include "net/net.h" static inline DeviceState * diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index cc51584dfc..8db1a74acf 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -22,13 +22,13 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/timer.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/log.h" -#include "qdev-addr.h" +#include "hw/qdev-addr.h" -#include "stream.h" +#include "hw/stream.h" #define D(x) diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index 66b9ec1cc5..5785290224 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -22,13 +22,13 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "qemu/log.h" #include "net/net.h" #include "net/checksum.h" #include "qapi/qmp/qerror.h" -#include "stream.h" +#include "hw/stream.h" #define DPHY(x) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 21c6f8c49c..b2e35237f8 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #include "net/net.h" #define D(x) diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index 0c34149c27..b106e724ab 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "hw.h" +#include "hw/sysbus.h" +#include "hw/hw.h" #define D(x) diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c index e73c9bd79b..f6bd3bac23 100644 --- a/hw/xilinx_spi.c +++ b/hw/xilinx_spi.c @@ -24,12 +24,12 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/log.h" #include "qemu/fifo8.h" -#include "ssi.h" +#include "hw/ssi.h" #ifdef XILINX_SPI_ERR_DEBUG #define DB_PRINT(...) do { \ diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 915eb96a48..6c21b9668b 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -22,12 +22,12 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "ptimer.h" +#include "hw/ptimer.h" #include "qemu/log.h" #include "qemu/fifo8.h" -#include "ssi.h" +#include "hw/ssi.h" #include "qemu/bitops.h" #ifdef XILINX_SPIPS_ERR_DEBUG diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index aa162efaad..0c39cff089 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#include "sysbus.h" -#include "ptimer.h" +#include "hw/sysbus.h" +#include "hw/ptimer.h" #include "qemu/log.h" #define D(x) diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index 9963982ef6..079f4d4e1a 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -#include "sysbus.h" +#include "hw/sysbus.h" #include "char/char.h" #define DUART(x) diff --git a/hw/xilinx_zynq.c b/hw/xilinx_zynq.c index 2f67d90ee1..f78c47e43e 100644 --- a/hw/xilinx_zynq.c +++ b/hw/xilinx_zynq.c @@ -15,16 +15,16 @@ * with this program; if not, see . */ -#include "sysbus.h" -#include "arm-misc.h" +#include "hw/sysbus.h" +#include "hw/arm-misc.h" #include "net/net.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "flash.h" +#include "hw/boards.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" -#include "loader.h" -#include "ssi.h" +#include "hw/loader.h" +#include "hw/ssi.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 7f00bc8256..4bccd0ddcd 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -19,10 +19,10 @@ * with this program; if not, see . */ -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/pcie.h" -#include "xio3130_downstream.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/xio3130_downstream.h" #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ #define XIO3130_REVISION 0x1 diff --git a/hw/xio3130_downstream.h b/hw/xio3130_downstream.h index 559dff6565..8426d9ffa6 100644 --- a/hw/xio3130_downstream.h +++ b/hw/xio3130_downstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_DOWNSTREAM_H #define QEMU_XIO3130_DOWNSTREAM_H -#include "pci/pcie_port.h" +#include "hw/pci/pcie_port.h" PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 70b15d37c8..82556aaadc 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -19,10 +19,10 @@ * with this program; if not, see . */ -#include "pci/pci_ids.h" -#include "pci/msi.h" -#include "pci/pcie.h" -#include "xio3130_upstream.h" +#include "hw/pci/pci_ids.h" +#include "hw/pci/msi.h" +#include "hw/pci/pcie.h" +#include "hw/xio3130_upstream.h" #define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */ #define XIO3130_REVISION 0x2 diff --git a/hw/xio3130_upstream.h b/hw/xio3130_upstream.h index fa09656b35..08c1d5f75b 100644 --- a/hw/xio3130_upstream.h +++ b/hw/xio3130_upstream.h @@ -1,7 +1,7 @@ #ifndef QEMU_XIO3130_UPSTREAM_H #define QEMU_XIO3130_UPSTREAM_H -#include "pci/pcie_port.h" +#include "hw/pci/pcie_port.h" PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c index a810b9eae0..f2a63d82da 100644 --- a/hw/xtensa_lx60.c +++ b/hw/xtensa_lx60.c @@ -26,18 +26,18 @@ */ #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/memory.h" #include "exec/address-spaces.h" -#include "serial.h" +#include "hw/serial.h" #include "net/net.h" -#include "sysbus.h" -#include "flash.h" +#include "hw/sysbus.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "char/char.h" -#include "xtensa_bootparam.h" +#include "hw/xtensa_bootparam.h" typedef struct LxBoardDesc { size_t flash_size; diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c index 97d36be272..f485a1465c 100644 --- a/hw/xtensa_pic.c +++ b/hw/xtensa_pic.c @@ -25,7 +25,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/log.h" #include "qemu/timer.h" diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c index 864e57c52c..5241f8d734 100644 --- a/hw/xtensa_sim.c +++ b/hw/xtensa_sim.c @@ -26,8 +26,8 @@ */ #include "sysemu/sysemu.h" -#include "boards.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/loader.h" #include "elf.h" #include "exec/memory.h" #include "exec/address-spaces.h" diff --git a/hw/z2.c b/hw/z2.c index 731550f2d8..cbb6d8085e 100644 --- a/hw/z2.c +++ b/hw/z2.c @@ -11,15 +11,15 @@ * GNU GPL, version 2 or (at your option) any later version. */ -#include "hw.h" -#include "pxa.h" -#include "arm-misc.h" -#include "devices.h" -#include "i2c.h" -#include "ssi.h" -#include "boards.h" +#include "hw/hw.h" +#include "hw/pxa.h" +#include "hw/arm-misc.h" +#include "hw/devices.h" +#include "hw/i2c.h" +#include "hw/ssi.h" +#include "hw/boards.h" #include "sysemu/sysemu.h" -#include "flash.h" +#include "hw/flash.h" #include "sysemu/blockdev.h" #include "ui/console.h" #include "audio/audio.h" diff --git a/hw/zaurus.c b/hw/zaurus.c index 2defe3b48d..7d3258cc66 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -15,9 +15,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, see . */ -#include "hw.h" -#include "sharpsl.h" -#include "sysbus.h" +#include "hw/hw.h" +#include "hw/sharpsl.h" +#include "hw/sysbus.h" #undef REG_FMT #define REG_FMT "0x%02lx" diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c index 27b00f07d4..8418327261 100644 --- a/hw/zynq_slcr.c +++ b/hw/zynq_slcr.c @@ -14,9 +14,9 @@ * with this program; if not, see . */ -#include "hw.h" +#include "hw/hw.h" #include "qemu/timer.h" -#include "sysbus.h" +#include "hw/sysbus.h" #include "sysemu/sysemu.h" #ifdef ZYNQ_ARM_SLCR_ERR_DEBUG From 320ba5fe494c0ef59080eac33801ec1e453663fa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:36:30 +0100 Subject: [PATCH 1329/1634] build: always link device_tree.o into emulators if libfdt available Signed-off-by: Paolo Bonzini --- Makefile.target | 1 + configure | 7 +------ hw/arm/Makefile.objs | 1 - hw/microblaze/Makefile.objs | 1 - hw/ppc/Makefile.objs | 1 - 5 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Makefile.target b/Makefile.target index ca657b325a..2bd6d1471c 100644 --- a/Makefile.target +++ b/Makefile.target @@ -111,6 +111,7 @@ CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y) obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o obj-y += qtest.o obj-y += hw/ +obj-$(CONFIG_FDT) += device_tree.o obj-$(CONFIG_KVM) += kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o obj-y += memory.o savevm.o cputlb.o diff --git a/configure b/configure index 19738ac968..8fdc2cf68d 100755 --- a/configure +++ b/configure @@ -2416,6 +2416,7 @@ int main(void) { return 0; } EOF if compile_prog "" "$fdt_libs" ; then fdt=yes + libs_softmmu="$libs_softmmu $fdt_libs" else if test "$fdt" = "yes" ; then feature_not_found "fdt" @@ -3981,7 +3982,6 @@ case "$target_arch2" in target_nptl="yes" gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" target_llong_alignment=4 - target_libs_softmmu="$fdt_libs" ;; cris) target_nptl="yes" @@ -4000,7 +4000,6 @@ case "$target_arch2" in TARGET_ARCH=microblaze bflt="yes" target_nptl="yes" - target_libs_softmmu="$fdt_libs" ;; mips|mipsel) TARGET_ARCH=mips @@ -4025,21 +4024,18 @@ case "$target_arch2" in ppc) gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_nptl="yes" - target_libs_softmmu="$fdt_libs" ;; ppcemb) TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_nptl="yes" - target_libs_softmmu="$fdt_libs" ;; ppc64) TARGET_BASE_ARCH=ppc TARGET_ABI_DIR=ppc gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml" target_long_alignment=8 - target_libs_softmmu="$fdt_libs" ;; ppc64abi32) TARGET_ARCH=ppc64 @@ -4047,7 +4043,6 @@ case "$target_arch2" in TARGET_ABI_DIR=ppc echo "TARGET_ABI32=y" >> $config_target_mak gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml" - target_libs_softmmu="$fdt_libs" ;; sh4|sh4eb) TARGET_ARCH=sh4 diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 4c109858fd..3eb1366aee 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -31,6 +31,5 @@ obj-y += strongarm.o obj-y += collie.o obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o obj-y += kzm.o -obj-$(CONFIG_FDT) += ../device_tree.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index 3028e651c8..2ff8048a98 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -5,6 +5,5 @@ obj-y += xilinx_spi.o obj-y += microblaze_pic_cpu.o obj-y += xilinx_ethlite.o -obj-$(CONFIG_FDT) += ../device_tree.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index f7620509a9..bbbe78e1f5 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -16,7 +16,6 @@ obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o obj-y += virtex_ml507.o # PowerPC OpenPIC obj-y += openpic.o -obj-$(CONFIG_FDT) += ../device_tree.o # Xilinx PPC peripherals obj-y += xilinx_ethlite.o From e4c8b28cde12d01ada8fe869567dc5717a2dfcb7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:52:23 +0100 Subject: [PATCH 1330/1634] ppc: express FDT dependency of pSeries and e500 boards via default-configs/ Signed-off-by: Paolo Bonzini --- configure | 3 --- default-configs/ppc-softmmu.mak | 1 + default-configs/ppc64-softmmu.mak | 2 ++ default-configs/ppcemb-softmmu.mak | 1 + hw/ppc/Makefile.objs | 4 ++-- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/configure b/configure index 8fdc2cf68d..ae3d9c5378 100755 --- a/configure +++ b/configure @@ -4144,9 +4144,6 @@ case "$target_arch2" in i386|x86_64) echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak esac -if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then - echo "CONFIG_PSERIES=y" >> $config_target_mak -fi if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak fi diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index f9f8a8159b..c209a8da65 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -40,3 +40,4 @@ CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y CONFIG_XILINX=y +CONFIG_E500=$(CONFIG_FDT) diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index dc44294378..8d490bd72e 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -40,3 +40,5 @@ CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y CONFIG_XILINX=y +CONFIG_PSERIES=$(CONFIG_FDT) +CONFIG_E500=$(CONFIG_FDT) diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 1c6bcf93fc..7f13421d93 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -35,3 +35,4 @@ CONFIG_PFLASH_CFI02=y CONFIG_PTIMER=y CONFIG_I8259=y CONFIG_XILINX=y +CONFIG_E500=$(CONFIG_FDT) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index bbbe78e1f5..9141373f40 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -11,7 +11,7 @@ obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o obj-y += ppc440_bamboo.o # PowerPC E500 boards -obj-$(CONFIG_FDT) += mpc8544_guts.o ppce500_spin.o +obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o # PowerPC 440 Xilinx ML507 reference board. obj-y += virtex_ml507.o # PowerPC OpenPIC @@ -29,4 +29,4 @@ obj-y += mac_oldworld.o # NewWorld PowerMac obj-y += mac_newworld.o # e500 -obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o +obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o From 530182169e897c0e401b245552a4c58dc6846912 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:03:15 +0100 Subject: [PATCH 1331/1634] hw: move boards and other isolated files to hw/ARCH Signed-off-by: Paolo Bonzini --- hw/Makefile.objs | 1 - hw/alpha/Makefile.objs | 4 ++- hw/{alpha_dp264.c => alpha/dp264.c} | 0 hw/{alpha_pci.c => alpha/pci.c} | 0 hw/arm/Makefile.objs | 31 +++++++++---------- hw/{arm_boot.c => arm/boot.c} | 0 hw/{ => arm}/collie.c | 0 hw/{ => arm}/exynos4_boards.c | 0 hw/{ => arm}/gumstix.c | 0 hw/{ => arm}/highbank.c | 0 hw/{ => arm}/integratorcp.c | 0 hw/{ => arm}/kzm.c | 0 hw/{ => arm}/mainstone.c | 0 hw/{ => arm}/musicpal.c | 0 hw/{ => arm}/nseries.c | 0 hw/{ => arm}/omap_sx1.c | 0 hw/{ => arm}/palm.c | 0 hw/{arm_pic.c => arm/pic_cpu.c} | 0 hw/{ => arm}/realview.c | 0 hw/{ => arm}/spitz.c | 0 hw/{ => arm}/stellaris.c | 0 hw/{ => arm}/tosa.c | 0 hw/{ => arm}/versatilepb.c | 0 hw/{ => arm}/vexpress.c | 0 hw/{ => arm}/xilinx_zynq.c | 0 hw/{ => arm}/z2.c | 0 hw/cris/Makefile.objs | 10 +++--- hw/{ => cris}/axis_dev88.c | 0 hw/{cris-boot.c => cris/boot.c} | 0 hw/{cris_pic_cpu.c => cris/pic_cpu.c} | 0 hw/i386/Makefile.objs | 13 +++++--- hw/{ => i386}/multiboot.c | 0 hw/{ => i386}/pc.c | 0 hw/{ => i386}/pc_piix.c | 0 hw/{ => i386}/pc_q35.c | 0 hw/{ => i386}/smbios.c | 0 hw/{ => i386}/xen_domainbuild.c | 0 hw/{ => i386}/xen_machine_pv.c | 0 hw/lm32/Makefile.objs | 8 ++--- hw/{ => lm32}/lm32_boards.c | 0 hw/{ => lm32}/milkymist.c | 0 hw/m68k/Makefile.objs | 7 +++-- hw/{ => m68k}/an5206.c | 0 hw/{ => m68k}/dummy_m68k.c | 0 hw/{ => m68k}/mcf5208.c | 0 hw/microblaze/Makefile.objs | 10 +++--- hw/{microblaze_boot.c => microblaze/boot.c} | 0 hw/{ => microblaze}/petalogix_ml605_mmu.c | 0 .../petalogix_s3adsp1800_mmu.c | 0 .../pic_cpu.c} | 0 hw/mips/Makefile.objs | 8 +++-- hw/{mips_addr.c => mips/addr.c} | 0 hw/{mips_timer.c => mips/cputimer.c} | 0 hw/{ => mips}/mips_fulong2e.c | 0 hw/{ => mips}/mips_int.c | 0 hw/{ => mips}/mips_jazz.c | 0 hw/{ => mips}/mips_malta.c | 0 hw/{ => mips}/mips_mipssim.c | 0 hw/{ => mips}/mips_r4k.c | 0 hw/openrisc/Makefile.objs | 5 ++- hw/{openrisc_timer.c => openrisc/cputimer.c} | 0 hw/{ => openrisc}/openrisc_sim.c | 0 hw/{openrisc_pic.c => openrisc/pic_cpu.c} | 0 hw/ppc/Makefile.objs | 17 +++++----- hw/{ => ppc}/ppc.c | 0 hw/{ => ppc}/ppc405_boards.c | 0 hw/{ => ppc}/ppc405_uc.c | 0 hw/{ => ppc}/ppc440_bamboo.c | 0 hw/{ => ppc}/ppc_booke.c | 0 hw/{ => ppc}/spapr.c | 0 hw/{ => ppc}/virtex_ml507.c | 0 hw/sh4/Makefile.objs | 4 ++- hw/{ => sh4}/r2d.c | 0 hw/{ => sh4}/shix.c | 0 hw/sparc/Makefile.objs | 6 ++-- hw/{ => sparc}/leon3.c | 0 hw/{ => sparc}/sun4m.c | 0 hw/sparc64/Makefile.objs | 4 ++- hw/{ => sparc64}/sun4u.c | 0 hw/unicore32/Makefile.objs | 2 -- hw/{ => unicore32}/puv3.c | 0 hw/xtensa/Makefile.objs | 4 +-- hw/{xtensa_pic.c => xtensa/pic_cpu.c} | 0 hw/{ => xtensa}/xtensa_lx60.c | 0 hw/{ => xtensa}/xtensa_sim.c | 0 85 files changed, 72 insertions(+), 62 deletions(-) rename hw/{alpha_dp264.c => alpha/dp264.c} (100%) rename hw/{alpha_pci.c => alpha/pci.c} (100%) rename hw/{arm_boot.c => arm/boot.c} (100%) rename hw/{ => arm}/collie.c (100%) rename hw/{ => arm}/exynos4_boards.c (100%) rename hw/{ => arm}/gumstix.c (100%) rename hw/{ => arm}/highbank.c (100%) rename hw/{ => arm}/integratorcp.c (100%) rename hw/{ => arm}/kzm.c (100%) rename hw/{ => arm}/mainstone.c (100%) rename hw/{ => arm}/musicpal.c (100%) rename hw/{ => arm}/nseries.c (100%) rename hw/{ => arm}/omap_sx1.c (100%) rename hw/{ => arm}/palm.c (100%) rename hw/{arm_pic.c => arm/pic_cpu.c} (100%) rename hw/{ => arm}/realview.c (100%) rename hw/{ => arm}/spitz.c (100%) rename hw/{ => arm}/stellaris.c (100%) rename hw/{ => arm}/tosa.c (100%) rename hw/{ => arm}/versatilepb.c (100%) rename hw/{ => arm}/vexpress.c (100%) rename hw/{ => arm}/xilinx_zynq.c (100%) rename hw/{ => arm}/z2.c (100%) rename hw/{ => cris}/axis_dev88.c (100%) rename hw/{cris-boot.c => cris/boot.c} (100%) rename hw/{cris_pic_cpu.c => cris/pic_cpu.c} (100%) rename hw/{ => i386}/multiboot.c (100%) rename hw/{ => i386}/pc.c (100%) rename hw/{ => i386}/pc_piix.c (100%) rename hw/{ => i386}/pc_q35.c (100%) rename hw/{ => i386}/smbios.c (100%) rename hw/{ => i386}/xen_domainbuild.c (100%) rename hw/{ => i386}/xen_machine_pv.c (100%) rename hw/{ => lm32}/lm32_boards.c (100%) rename hw/{ => lm32}/milkymist.c (100%) rename hw/{ => m68k}/an5206.c (100%) rename hw/{ => m68k}/dummy_m68k.c (100%) rename hw/{ => m68k}/mcf5208.c (100%) rename hw/{microblaze_boot.c => microblaze/boot.c} (100%) rename hw/{ => microblaze}/petalogix_ml605_mmu.c (100%) rename hw/{ => microblaze}/petalogix_s3adsp1800_mmu.c (100%) rename hw/{microblaze_pic_cpu.c => microblaze/pic_cpu.c} (100%) rename hw/{mips_addr.c => mips/addr.c} (100%) rename hw/{mips_timer.c => mips/cputimer.c} (100%) rename hw/{ => mips}/mips_fulong2e.c (100%) rename hw/{ => mips}/mips_int.c (100%) rename hw/{ => mips}/mips_jazz.c (100%) rename hw/{ => mips}/mips_malta.c (100%) rename hw/{ => mips}/mips_mipssim.c (100%) rename hw/{ => mips}/mips_r4k.c (100%) rename hw/{openrisc_timer.c => openrisc/cputimer.c} (100%) rename hw/{ => openrisc}/openrisc_sim.c (100%) rename hw/{openrisc_pic.c => openrisc/pic_cpu.c} (100%) rename hw/{ => ppc}/ppc.c (100%) rename hw/{ => ppc}/ppc405_boards.c (100%) rename hw/{ => ppc}/ppc405_uc.c (100%) rename hw/{ => ppc}/ppc440_bamboo.c (100%) rename hw/{ => ppc}/ppc_booke.c (100%) rename hw/{ => ppc}/spapr.c (100%) rename hw/{ => ppc}/virtex_ml507.c (100%) rename hw/{ => sh4}/r2d.c (100%) rename hw/{ => sh4}/shix.c (100%) rename hw/{ => sparc}/leon3.c (100%) rename hw/{ => sparc}/sun4m.c (100%) rename hw/{ => sparc64}/sun4u.c (100%) rename hw/{ => unicore32}/puv3.c (100%) rename hw/{xtensa_pic.c => xtensa/pic_cpu.c} (100%) rename hw/{ => xtensa}/xtensa_lx60.c (100%) rename hw/{ => xtensa}/xtensa_sim.c (100%) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 43f467a1ee..eb7eb31a19 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -206,7 +206,6 @@ obj-$(CONFIG_SOFTMMU) += vhost_net.o obj-$(CONFIG_VHOST_NET) += vhost.o obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ obj-$(CONFIG_VGA) += vga.o -obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o # Inter-VM PCI shared memory & VFIO PCI device assignment ifeq ($(CONFIG_PCI), y) diff --git a/hw/alpha/Makefile.objs b/hw/alpha/Makefile.objs index af1c07fa7c..db868d2ea6 100644 --- a/hw/alpha/Makefile.objs +++ b/hw/alpha/Makefile.objs @@ -1,4 +1,6 @@ obj-y = mc146818rtc.o -obj-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o +obj-y += alpha_typhoon.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += dp264.o pci.o diff --git a/hw/alpha_dp264.c b/hw/alpha/dp264.c similarity index 100% rename from hw/alpha_dp264.c rename to hw/alpha/dp264.c diff --git a/hw/alpha_pci.c b/hw/alpha/pci.c similarity index 100% rename from hw/alpha_pci.c rename to hw/alpha/pci.c diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 3eb1366aee..c09cc3aae8 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -1,35 +1,32 @@ -obj-y = integratorcp.o versatilepb.o arm_pic.o -obj-y += arm_boot.o -obj-y += xilinx_zynq.o zynq_slcr.o +obj-y += zynq_slcr.o obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += a9scu.o -obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o +obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o -obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o +obj-y += exynos4210_uart.o exynos4210_pwm.o obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o obj-y += exynos4210_rtc.o exynos4210_i2c.o obj-y += arm_mptimer.o a15mpcore.o -obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o -obj-y += highbank.o +obj-y += armv7m.o armv7m_nvic.o stellaris_enet.o obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o -obj-y += gumstix.o -obj-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o +obj-y += zaurus.o ide/microdrive.o tc6393xb.o obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ omap_gpio.o omap_intc.o omap_uart.o obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o -obj-y += omap_sx1.o palm.o tsc210x.o -obj-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o -obj-y += mst_fpga.o mainstone.o -obj-y += z2.o -obj-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o +obj-y += tsc210x.o +obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o +obj-y += mst_fpga.o +obj-y += bitbang_i2c.o marvell_88w8618_audio.o obj-y += framebuffer.o -obj-y += vexpress.o obj-y += strongarm.o -obj-y += collie.o obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o -obj-y += kzm.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o +obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o +obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o +obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o diff --git a/hw/arm_boot.c b/hw/arm/boot.c similarity index 100% rename from hw/arm_boot.c rename to hw/arm/boot.c diff --git a/hw/collie.c b/hw/arm/collie.c similarity index 100% rename from hw/collie.c rename to hw/arm/collie.c diff --git a/hw/exynos4_boards.c b/hw/arm/exynos4_boards.c similarity index 100% rename from hw/exynos4_boards.c rename to hw/arm/exynos4_boards.c diff --git a/hw/gumstix.c b/hw/arm/gumstix.c similarity index 100% rename from hw/gumstix.c rename to hw/arm/gumstix.c diff --git a/hw/highbank.c b/hw/arm/highbank.c similarity index 100% rename from hw/highbank.c rename to hw/arm/highbank.c diff --git a/hw/integratorcp.c b/hw/arm/integratorcp.c similarity index 100% rename from hw/integratorcp.c rename to hw/arm/integratorcp.c diff --git a/hw/kzm.c b/hw/arm/kzm.c similarity index 100% rename from hw/kzm.c rename to hw/arm/kzm.c diff --git a/hw/mainstone.c b/hw/arm/mainstone.c similarity index 100% rename from hw/mainstone.c rename to hw/arm/mainstone.c diff --git a/hw/musicpal.c b/hw/arm/musicpal.c similarity index 100% rename from hw/musicpal.c rename to hw/arm/musicpal.c diff --git a/hw/nseries.c b/hw/arm/nseries.c similarity index 100% rename from hw/nseries.c rename to hw/arm/nseries.c diff --git a/hw/omap_sx1.c b/hw/arm/omap_sx1.c similarity index 100% rename from hw/omap_sx1.c rename to hw/arm/omap_sx1.c diff --git a/hw/palm.c b/hw/arm/palm.c similarity index 100% rename from hw/palm.c rename to hw/arm/palm.c diff --git a/hw/arm_pic.c b/hw/arm/pic_cpu.c similarity index 100% rename from hw/arm_pic.c rename to hw/arm/pic_cpu.c diff --git a/hw/realview.c b/hw/arm/realview.c similarity index 100% rename from hw/realview.c rename to hw/arm/realview.c diff --git a/hw/spitz.c b/hw/arm/spitz.c similarity index 100% rename from hw/spitz.c rename to hw/arm/spitz.c diff --git a/hw/stellaris.c b/hw/arm/stellaris.c similarity index 100% rename from hw/stellaris.c rename to hw/arm/stellaris.c diff --git a/hw/tosa.c b/hw/arm/tosa.c similarity index 100% rename from hw/tosa.c rename to hw/arm/tosa.c diff --git a/hw/versatilepb.c b/hw/arm/versatilepb.c similarity index 100% rename from hw/versatilepb.c rename to hw/arm/versatilepb.c diff --git a/hw/vexpress.c b/hw/arm/vexpress.c similarity index 100% rename from hw/vexpress.c rename to hw/arm/vexpress.c diff --git a/hw/xilinx_zynq.c b/hw/arm/xilinx_zynq.c similarity index 100% rename from hw/xilinx_zynq.c rename to hw/arm/xilinx_zynq.c diff --git a/hw/z2.c b/hw/arm/z2.c similarity index 100% rename from hw/z2.c rename to hw/arm/z2.c diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs index aa9298a0ed..a94c62450d 100644 --- a/hw/cris/Makefile.objs +++ b/hw/cris/Makefile.objs @@ -1,8 +1,3 @@ -# Boards -obj-y = cris_pic_cpu.o -obj-y += cris-boot.o -obj-y += axis_dev88.o - # IO blocks obj-y += etraxfs_dma.o obj-y += etraxfs_pic.o @@ -11,3 +6,8 @@ obj-y += etraxfs_timer.o obj-y += etraxfs_ser.o obj-y := $(addprefix ../,$(obj-y)) + +# Boards +obj-y += pic_cpu.o +obj-y += boot.o +obj-y += axis_dev88.o diff --git a/hw/axis_dev88.c b/hw/cris/axis_dev88.c similarity index 100% rename from hw/axis_dev88.c rename to hw/cris/axis_dev88.c diff --git a/hw/cris-boot.c b/hw/cris/boot.c similarity index 100% rename from hw/cris-boot.c rename to hw/cris/boot.c diff --git a/hw/cris_pic_cpu.c b/hw/cris/pic_cpu.c similarity index 100% rename from hw/cris_pic_cpu.c rename to hw/cris/pic_cpu.c diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 025803aa66..5d071f418e 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,12 +1,11 @@ -obj-y += mc146818rtc.o pc.o +obj-y += mc146818rtc.o obj-y += apic_common.o apic.o kvmvapic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o -obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o -obj-y += debugcon.o debugexit.o multiboot.o -obj-y += pc_piix.o +obj-y += pci/pci-hotplug.o wdt_ib700.o +obj-y += debugcon.o debugexit.o obj-y += pc_sysfw.o -obj-y += lpc_ich9.o q35.o pc_q35.o +obj-y += lpc_ich9.o q35.o obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o @@ -15,3 +14,7 @@ obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o obj-y += pc-testdev.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += multiboot.o smbios.o +obj-y += pc.o pc_piix.o pc_q35.o +obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o diff --git a/hw/multiboot.c b/hw/i386/multiboot.c similarity index 100% rename from hw/multiboot.c rename to hw/i386/multiboot.c diff --git a/hw/pc.c b/hw/i386/pc.c similarity index 100% rename from hw/pc.c rename to hw/i386/pc.c diff --git a/hw/pc_piix.c b/hw/i386/pc_piix.c similarity index 100% rename from hw/pc_piix.c rename to hw/i386/pc_piix.c diff --git a/hw/pc_q35.c b/hw/i386/pc_q35.c similarity index 100% rename from hw/pc_q35.c rename to hw/i386/pc_q35.c diff --git a/hw/smbios.c b/hw/i386/smbios.c similarity index 100% rename from hw/smbios.c rename to hw/i386/smbios.c diff --git a/hw/xen_domainbuild.c b/hw/i386/xen_domainbuild.c similarity index 100% rename from hw/xen_domainbuild.c rename to hw/i386/xen_domainbuild.c diff --git a/hw/xen_machine_pv.c b/hw/i386/xen_machine_pv.c similarity index 100% rename from hw/xen_machine_pv.c rename to hw/i386/xen_machine_pv.c diff --git a/hw/lm32/Makefile.objs b/hw/lm32/Makefile.objs index 4e1843c11d..4592fe5fc8 100644 --- a/hw/lm32/Makefile.objs +++ b/hw/lm32/Makefile.objs @@ -1,7 +1,3 @@ -# LM32 boards -obj-y += lm32_boards.o -obj-y += milkymist.o - # LM32 peripherals obj-y += lm32_pic.o obj-y += lm32_juart.o @@ -21,3 +17,7 @@ obj-y += milkymist-vgafb.o obj-y += framebuffer.o obj-y := $(addprefix ../,$(obj-y)) + +# LM32 boards +obj-y += lm32_boards.o +obj-y += milkymist.o diff --git a/hw/lm32_boards.c b/hw/lm32/lm32_boards.c similarity index 100% rename from hw/lm32_boards.c rename to hw/lm32/lm32_boards.c diff --git a/hw/milkymist.c b/hw/lm32/milkymist.c similarity index 100% rename from hw/milkymist.c rename to hw/lm32/milkymist.c diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs index 93b6d25baf..7c033a886c 100644 --- a/hw/m68k/Makefile.objs +++ b/hw/m68k/Makefile.objs @@ -1,4 +1,7 @@ -obj-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o -obj-y += dummy_m68k.o +obj-y = mcf5206.o mcf_uart.o mcf_intc.o mcf_fec.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += an5206.o mcf5208.o +obj-y += dummy_m68k.o + diff --git a/hw/an5206.c b/hw/m68k/an5206.c similarity index 100% rename from hw/an5206.c rename to hw/m68k/an5206.c diff --git a/hw/dummy_m68k.c b/hw/m68k/dummy_m68k.c similarity index 100% rename from hw/dummy_m68k.c rename to hw/m68k/dummy_m68k.c diff --git a/hw/mcf5208.c b/hw/m68k/mcf5208.c similarity index 100% rename from hw/mcf5208.c rename to hw/m68k/mcf5208.c diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index 2ff8048a98..9e7f249941 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -1,9 +1,9 @@ -obj-y = petalogix_s3adsp1800_mmu.o -obj-y += petalogix_ml605_mmu.o -obj-y += microblaze_boot.o obj-y += xilinx_spi.o - -obj-y += microblaze_pic_cpu.o obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += petalogix_s3adsp1800_mmu.o +obj-y += petalogix_ml605_mmu.o +obj-y += boot.o +obj-y += pic_cpu.o diff --git a/hw/microblaze_boot.c b/hw/microblaze/boot.c similarity index 100% rename from hw/microblaze_boot.c rename to hw/microblaze/boot.c diff --git a/hw/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c similarity index 100% rename from hw/petalogix_ml605_mmu.c rename to hw/microblaze/petalogix_ml605_mmu.c diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c similarity index 100% rename from hw/petalogix_s3adsp1800_mmu.c rename to hw/microblaze/petalogix_s3adsp1800_mmu.c diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze/pic_cpu.c similarity index 100% rename from hw/microblaze_pic_cpu.c rename to hw/microblaze/pic_cpu.c diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs index 29a5d0db04..1e3bca1c37 100644 --- a/hw/mips/Makefile.objs +++ b/hw/mips/Makefile.objs @@ -1,6 +1,8 @@ -obj-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o -obj-y += mips_addr.o mips_timer.o mips_int.o obj-y += gt64xxx.o mc146818rtc.o -obj-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o +obj-$(CONFIG_FULONG) += bonito.o vt82c686.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o +obj-y += addr.o cputimer.o mips_int.o +obj-$(CONFIG_FULONG) += mips_fulong2e.o diff --git a/hw/mips_addr.c b/hw/mips/addr.c similarity index 100% rename from hw/mips_addr.c rename to hw/mips/addr.c diff --git a/hw/mips_timer.c b/hw/mips/cputimer.c similarity index 100% rename from hw/mips_timer.c rename to hw/mips/cputimer.c diff --git a/hw/mips_fulong2e.c b/hw/mips/mips_fulong2e.c similarity index 100% rename from hw/mips_fulong2e.c rename to hw/mips/mips_fulong2e.c diff --git a/hw/mips_int.c b/hw/mips/mips_int.c similarity index 100% rename from hw/mips_int.c rename to hw/mips/mips_int.c diff --git a/hw/mips_jazz.c b/hw/mips/mips_jazz.c similarity index 100% rename from hw/mips_jazz.c rename to hw/mips/mips_jazz.c diff --git a/hw/mips_malta.c b/hw/mips/mips_malta.c similarity index 100% rename from hw/mips_malta.c rename to hw/mips/mips_malta.c diff --git a/hw/mips_mipssim.c b/hw/mips/mips_mipssim.c similarity index 100% rename from hw/mips_mipssim.c rename to hw/mips/mips_mipssim.c diff --git a/hw/mips_r4k.c b/hw/mips/mips_r4k.c similarity index 100% rename from hw/mips_r4k.c rename to hw/mips/mips_r4k.c diff --git a/hw/openrisc/Makefile.objs b/hw/openrisc/Makefile.objs index 38ff8f5d6d..61246b149b 100644 --- a/hw/openrisc/Makefile.objs +++ b/hw/openrisc/Makefile.objs @@ -1,3 +1,2 @@ -obj-y = openrisc_pic.o openrisc_sim.o openrisc_timer.o - -obj-y := $(addprefix ../,$(obj-y)) +obj-y = pic_cpu.o cputimer.o +obj-y += openrisc_sim.o diff --git a/hw/openrisc_timer.c b/hw/openrisc/cputimer.c similarity index 100% rename from hw/openrisc_timer.c rename to hw/openrisc/cputimer.c diff --git a/hw/openrisc_sim.c b/hw/openrisc/openrisc_sim.c similarity index 100% rename from hw/openrisc_sim.c rename to hw/openrisc/openrisc_sim.c diff --git a/hw/openrisc_pic.c b/hw/openrisc/pic_cpu.c similarity index 100% rename from hw/openrisc_pic.c rename to hw/openrisc/pic_cpu.c diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 9141373f40..294d0de211 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,19 +1,14 @@ -# shared objects -obj-y = ppc.o ppc_booke.o # PREP target obj-y += mc146818rtc.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o +obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o # PowerPC 4xx boards -obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o -obj-y += ppc440_bamboo.o +obj-y += ppc4xx_devs.o ppc4xx_pci.o # PowerPC E500 boards obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o -# PowerPC 440 Xilinx ML507 reference board. -obj-y += virtex_ml507.o # PowerPC OpenPIC obj-y += openpic.o @@ -22,6 +17,12 @@ obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) +# shared objects +obj-y += ppc.o ppc_booke.o +# IBM pSeries (sPAPR) +obj-$(CONFIG_PSERIES) += spapr.o +# PowerPC 4xx boards +obj-y += ppc405_boards.o ppc405_uc.o ppc440_bamboo.o # PReP obj-y += prep.o # OldWorld PowerMac @@ -30,3 +31,5 @@ obj-y += mac_oldworld.o obj-y += mac_newworld.o # e500 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o +# PowerPC 440 Xilinx ML507 reference board. +obj-y += virtex_ml507.o diff --git a/hw/ppc.c b/hw/ppc/ppc.c similarity index 100% rename from hw/ppc.c rename to hw/ppc/ppc.c diff --git a/hw/ppc405_boards.c b/hw/ppc/ppc405_boards.c similarity index 100% rename from hw/ppc405_boards.c rename to hw/ppc/ppc405_boards.c diff --git a/hw/ppc405_uc.c b/hw/ppc/ppc405_uc.c similarity index 100% rename from hw/ppc405_uc.c rename to hw/ppc/ppc405_uc.c diff --git a/hw/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c similarity index 100% rename from hw/ppc440_bamboo.c rename to hw/ppc/ppc440_bamboo.c diff --git a/hw/ppc_booke.c b/hw/ppc/ppc_booke.c similarity index 100% rename from hw/ppc_booke.c rename to hw/ppc/ppc_booke.c diff --git a/hw/spapr.c b/hw/ppc/spapr.c similarity index 100% rename from hw/spapr.c rename to hw/ppc/spapr.c diff --git a/hw/virtex_ml507.c b/hw/ppc/virtex_ml507.c similarity index 100% rename from hw/virtex_ml507.c rename to hw/ppc/virtex_ml507.c diff --git a/hw/sh4/Makefile.objs b/hw/sh4/Makefile.objs index 68c5921790..b2e1f1e044 100644 --- a/hw/sh4/Makefile.objs +++ b/hw/sh4/Makefile.objs @@ -1,5 +1,7 @@ -obj-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o +obj-y = sh7750.o sh7750_regnames.o tc58128.o obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o obj-y += ide/mmio.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += shix.o r2d.o diff --git a/hw/r2d.c b/hw/sh4/r2d.c similarity index 100% rename from hw/r2d.c rename to hw/sh4/r2d.c diff --git a/hw/shix.c b/hw/sh4/shix.c similarity index 100% rename from hw/shix.c rename to hw/sh4/shix.c diff --git a/hw/sparc/Makefile.objs b/hw/sparc/Makefile.objs index a39a511c52..71bbddf8c3 100644 --- a/hw/sparc/Makefile.objs +++ b/hw/sparc/Makefile.objs @@ -1,8 +1,10 @@ -obj-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o +obj-y = lance.o tcx.o sun4m_iommu.o slavio_intctl.o obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o -obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o leon3.o +obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o # GRLIB obj-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += sun4m.o leon3.o diff --git a/hw/leon3.c b/hw/sparc/leon3.c similarity index 100% rename from hw/leon3.c rename to hw/sparc/leon3.c diff --git a/hw/sun4m.c b/hw/sparc/sun4m.c similarity index 100% rename from hw/sun4m.c rename to hw/sparc/sun4m.c diff --git a/hw/sparc64/Makefile.objs b/hw/sparc64/Makefile.objs index 8c65fc4215..4df0d90ec2 100644 --- a/hw/sparc64/Makefile.objs +++ b/hw/sparc64/Makefile.objs @@ -1,4 +1,6 @@ -obj-y = sun4u.o apb_pci.o +obj-y = apb_pci.o obj-y += mc146818rtc.o obj-y := $(addprefix ../,$(obj-y)) + +obj-y += sun4u.o diff --git a/hw/sun4u.c b/hw/sparc64/sun4u.c similarity index 100% rename from hw/sun4u.c rename to hw/sparc64/sun4u.c diff --git a/hw/unicore32/Makefile.objs b/hw/unicore32/Makefile.objs index 0725ce3ca7..e0fd628523 100644 --- a/hw/unicore32/Makefile.objs +++ b/hw/unicore32/Makefile.objs @@ -2,5 +2,3 @@ # PKUnity-v3 SoC and board information obj-${CONFIG_PUV3} += puv3.o - -obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/puv3.c b/hw/unicore32/puv3.c similarity index 100% rename from hw/puv3.c rename to hw/unicore32/puv3.c diff --git a/hw/xtensa/Makefile.objs b/hw/xtensa/Makefile.objs index 79698e903d..6ead7820c4 100644 --- a/hw/xtensa/Makefile.objs +++ b/hw/xtensa/Makefile.objs @@ -1,5 +1,3 @@ -obj-y += xtensa_pic.o +obj-y += pic_cpu.o obj-y += xtensa_sim.o obj-y += xtensa_lx60.o - -obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/xtensa_pic.c b/hw/xtensa/pic_cpu.c similarity index 100% rename from hw/xtensa_pic.c rename to hw/xtensa/pic_cpu.c diff --git a/hw/xtensa_lx60.c b/hw/xtensa/xtensa_lx60.c similarity index 100% rename from hw/xtensa_lx60.c rename to hw/xtensa/xtensa_lx60.c diff --git a/hw/xtensa_sim.c b/hw/xtensa/xtensa_sim.c similarity index 100% rename from hw/xtensa_sim.c rename to hw/xtensa/xtensa_sim.c From dd285b06490d7ef5f7b2f5e6c87b85ddf4345078 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: [PATCH 1332/1634] arm: move files referencing CPU to hw/arm/ Signed-off-by: Paolo Bonzini --- hw/arm/Makefile.objs | 13 ++++++++----- hw/{ => arm}/armv7m.c | 0 hw/{ => arm}/exynos4210.c | 0 hw/{ => arm}/omap1.c | 0 hw/{ => arm}/omap2.c | 0 hw/{ => arm}/pxa2xx.c | 0 hw/{ => arm}/pxa2xx_gpio.c | 0 hw/{ => arm}/pxa2xx_pic.c | 0 8 files changed, 8 insertions(+), 5 deletions(-) rename hw/{ => arm}/armv7m.c (100%) rename hw/{ => arm}/exynos4210.c (100%) rename hw/{ => arm}/omap1.c (100%) rename hw/{ => arm}/omap2.c (100%) rename hw/{ => arm}/pxa2xx.c (100%) rename hw/{ => arm}/pxa2xx_gpio.c (100%) rename hw/{ => arm}/pxa2xx_pic.c (100%) diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index c09cc3aae8..aebbc866e2 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -3,18 +3,18 @@ obj-y += xilinx_spips.o obj-y += arm_gic.o arm_gic_common.o obj-y += a9scu.o obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o -obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o +obj-y += exynos4210_gic.o exynos4210_combiner.o obj-y += exynos4210_uart.o exynos4210_pwm.o obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o obj-y += exynos4210_rtc.o exynos4210_i2c.o obj-y += arm_mptimer.o a15mpcore.o -obj-y += armv7m.o armv7m_nvic.o stellaris_enet.o -obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o +obj-y += armv7m_nvic.o stellaris_enet.o +obj-y += pxa2xx_timer.o pxa2xx_dma.o obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o obj-y += zaurus.o ide/microdrive.o tc6393xb.o -obj-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ +obj-y += omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ omap_gpio.o omap_intc.o omap_uart.o -obj-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ +obj-y += omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o obj-y += tsc210x.o obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o @@ -30,3 +30,6 @@ obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o + +obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o +obj-y += omap1.o omap2.o diff --git a/hw/armv7m.c b/hw/arm/armv7m.c similarity index 100% rename from hw/armv7m.c rename to hw/arm/armv7m.c diff --git a/hw/exynos4210.c b/hw/arm/exynos4210.c similarity index 100% rename from hw/exynos4210.c rename to hw/arm/exynos4210.c diff --git a/hw/omap1.c b/hw/arm/omap1.c similarity index 100% rename from hw/omap1.c rename to hw/arm/omap1.c diff --git a/hw/omap2.c b/hw/arm/omap2.c similarity index 100% rename from hw/omap2.c rename to hw/arm/omap2.c diff --git a/hw/pxa2xx.c b/hw/arm/pxa2xx.c similarity index 100% rename from hw/pxa2xx.c rename to hw/arm/pxa2xx.c diff --git a/hw/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c similarity index 100% rename from hw/pxa2xx_gpio.c rename to hw/arm/pxa2xx_gpio.c diff --git a/hw/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c similarity index 100% rename from hw/pxa2xx_pic.c rename to hw/arm/pxa2xx_pic.c From 8786b05e7bf3c4fc7a25fa14f1736a716cd8a8c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: [PATCH 1333/1634] i386: move files referencing CPU to hw/i386/ Signed-off-by: Paolo Bonzini --- hw/i386/Makefile.objs | 4 +++- hw/{ => i386}/kvmvapic.c | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename hw/{ => i386}/kvmvapic.c (100%) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 5d071f418e..a78c0b2921 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,5 +1,5 @@ obj-y += mc146818rtc.o -obj-y += apic_common.o apic.o kvmvapic.o +obj-y += apic_common.o apic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o obj-y += pci/pci-hotplug.o wdt_ib700.o @@ -18,3 +18,5 @@ obj-y := $(addprefix ../,$(obj-y)) obj-y += multiboot.o smbios.o obj-y += pc.o pc_piix.o pc_q35.o obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o + +obj-y += kvmvapic.o diff --git a/hw/kvmvapic.c b/hw/i386/kvmvapic.c similarity index 100% rename from hw/kvmvapic.c rename to hw/i386/kvmvapic.c From 9743b581a819a05668e6a1f60e3ee6486d25f141 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: [PATCH 1334/1634] m68k: move files referencing CPU to hw/m68k/ Signed-off-by: Paolo Bonzini --- hw/m68k/Makefile.objs | 3 ++- hw/{ => m68k}/mcf5206.c | 0 hw/{ => m68k}/mcf_intc.c | 0 3 files changed, 2 insertions(+), 1 deletion(-) rename hw/{ => m68k}/mcf5206.c (100%) rename hw/{ => m68k}/mcf_intc.c (100%) diff --git a/hw/m68k/Makefile.objs b/hw/m68k/Makefile.objs index 7c033a886c..ede32a7c4e 100644 --- a/hw/m68k/Makefile.objs +++ b/hw/m68k/Makefile.objs @@ -1,7 +1,8 @@ -obj-y = mcf5206.o mcf_uart.o mcf_intc.o mcf_fec.o +obj-y = mcf_uart.o mcf_fec.o obj-y := $(addprefix ../,$(obj-y)) obj-y += an5206.o mcf5208.o obj-y += dummy_m68k.o +obj-y += mcf5206.o mcf_intc.o diff --git a/hw/mcf5206.c b/hw/m68k/mcf5206.c similarity index 100% rename from hw/mcf5206.c rename to hw/m68k/mcf5206.c diff --git a/hw/mcf_intc.c b/hw/m68k/mcf_intc.c similarity index 100% rename from hw/mcf_intc.c rename to hw/m68k/mcf_intc.c From c68c4a56e93f54b374c5207f0185f8e9fa2aec3b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: [PATCH 1335/1634] ppc: move files referencing CPU to hw/ppc/ Signed-off-by: Paolo Bonzini --- hw/ppc/Makefile.objs | 13 ++++++------- hw/{ => ppc}/mpc8544_guts.c | 0 hw/{ => ppc}/ppc4xx_devs.c | 0 hw/{ => ppc}/ppce500_spin.c | 0 hw/{ => ppc}/spapr_vio.c | 0 hw/{ => ppc}/xics.c | 0 6 files changed, 6 insertions(+), 7 deletions(-) rename hw/{ => ppc}/mpc8544_guts.c (100%) rename hw/{ => ppc}/ppc4xx_devs.c (100%) rename hw/{ => ppc}/ppce500_spin.c (100%) rename hw/{ => ppc}/spapr_vio.c (100%) rename hw/{ => ppc}/xics.c (100%) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 294d0de211..acc9961ab0 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,14 +1,12 @@ # PREP target obj-y += mc146818rtc.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o spapr_vio.o -obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o +obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o +obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o # PowerPC 4xx boards -obj-y += ppc4xx_devs.o ppc4xx_pci.o -# PowerPC E500 boards -obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o +obj-y += ppc4xx_pci.o # PowerPC OpenPIC obj-y += openpic.o @@ -20,9 +18,9 @@ obj-y := $(addprefix ../,$(obj-y)) # shared objects obj-y += ppc.o ppc_booke.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr.o +obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o # PowerPC 4xx boards -obj-y += ppc405_boards.o ppc405_uc.o ppc440_bamboo.o +obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o # PReP obj-y += prep.o # OldWorld PowerMac @@ -31,5 +29,6 @@ obj-y += mac_oldworld.o obj-y += mac_newworld.o # e500 obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o +obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o # PowerPC 440 Xilinx ML507 reference board. obj-y += virtex_ml507.o diff --git a/hw/mpc8544_guts.c b/hw/ppc/mpc8544_guts.c similarity index 100% rename from hw/mpc8544_guts.c rename to hw/ppc/mpc8544_guts.c diff --git a/hw/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c similarity index 100% rename from hw/ppc4xx_devs.c rename to hw/ppc/ppc4xx_devs.c diff --git a/hw/ppce500_spin.c b/hw/ppc/ppce500_spin.c similarity index 100% rename from hw/ppce500_spin.c rename to hw/ppc/ppce500_spin.c diff --git a/hw/spapr_vio.c b/hw/ppc/spapr_vio.c similarity index 100% rename from hw/spapr_vio.c rename to hw/ppc/spapr_vio.c diff --git a/hw/xics.c b/hw/ppc/xics.c similarity index 100% rename from hw/xics.c rename to hw/ppc/xics.c From 9f64bd8aec7c31c76fa0954aaee1475d482662b4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 12:20:00 +0100 Subject: [PATCH 1336/1634] ppc: move more files to hw/ppc These sPAPR files do not implement devices, move them over. Signed-off-by: Paolo Bonzini --- hw/ppc/Makefile.objs | 8 ++++---- hw/{ => ppc}/spapr_events.c | 0 hw/{ => ppc}/spapr_hcall.c | 0 hw/{ => ppc}/spapr_iommu.c | 0 hw/{ => ppc}/spapr_rtas.c | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename hw/{ => ppc}/spapr_events.c (100%) rename hw/{ => ppc}/spapr_hcall.c (100%) rename hw/{ => ppc}/spapr_iommu.c (100%) rename hw/{ => ppc}/spapr_rtas.c (100%) diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index acc9961ab0..4de02098e2 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,10 +1,9 @@ # PREP target obj-y += mc146818rtc.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o -obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o spapr_iommu.o -obj-$(CONFIG_PSERIES) += spapr_events.o spapr_nvram.o +obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o +obj-$(CONFIG_PSERIES) += spapr_nvram.o # PowerPC 4xx boards obj-y += ppc4xx_pci.o # PowerPC OpenPIC @@ -18,7 +17,8 @@ obj-y := $(addprefix ../,$(obj-y)) # shared objects obj-y += ppc.o ppc_booke.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o +obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o spapr_events.o +obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o # PowerPC 4xx boards obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o # PReP diff --git a/hw/spapr_events.c b/hw/ppc/spapr_events.c similarity index 100% rename from hw/spapr_events.c rename to hw/ppc/spapr_events.c diff --git a/hw/spapr_hcall.c b/hw/ppc/spapr_hcall.c similarity index 100% rename from hw/spapr_hcall.c rename to hw/ppc/spapr_hcall.c diff --git a/hw/spapr_iommu.c b/hw/ppc/spapr_iommu.c similarity index 100% rename from hw/spapr_iommu.c rename to hw/ppc/spapr_iommu.c diff --git a/hw/spapr_rtas.c b/hw/ppc/spapr_rtas.c similarity index 100% rename from hw/spapr_rtas.c rename to hw/ppc/spapr_rtas.c From 7a2771d1541ec9a0c585e9b853e5f4dc036919ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2013 15:22:56 +0100 Subject: [PATCH 1337/1634] sh: move files referencing CPU to hw/sh4/ Signed-off-by: Paolo Bonzini --- hw/sh4/Makefile.objs | 4 +++- hw/{ => sh4}/sh7750.c | 0 hw/{ => sh4}/sh7750_regnames.c | 0 3 files changed, 3 insertions(+), 1 deletion(-) rename hw/{ => sh4}/sh7750.c (100%) rename hw/{ => sh4}/sh7750_regnames.c (100%) diff --git a/hw/sh4/Makefile.objs b/hw/sh4/Makefile.objs index b2e1f1e044..72b6a1fcb4 100644 --- a/hw/sh4/Makefile.objs +++ b/hw/sh4/Makefile.objs @@ -1,7 +1,9 @@ -obj-y = sh7750.o sh7750_regnames.o tc58128.o +obj-y = tc58128.o obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o obj-y += ide/mmio.o obj-y := $(addprefix ../,$(obj-y)) obj-y += shix.o r2d.o + +obj-y += sh7750.o sh7750_regnames.o diff --git a/hw/sh7750.c b/hw/sh4/sh7750.c similarity index 100% rename from hw/sh7750.c rename to hw/sh4/sh7750.c diff --git a/hw/sh7750_regnames.c b/hw/sh4/sh7750_regnames.c similarity index 100% rename from hw/sh7750_regnames.c rename to hw/sh4/sh7750_regnames.c From 07ca08bac88f116e9beb05d48d07b406ace8fbc0 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 27 Feb 2013 16:09:38 +0000 Subject: [PATCH 1338/1634] tcg-sparc: fix build Fix build breakage by 803d805bcef4ea7b7d6ef0b4929263e1160d6b3c: make tcg_out_addsub2() always available. Signed-off-by: Blue Swirl --- tcg/sparc/tcg-target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index 6d489fcc52..025af9b379 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -776,6 +776,7 @@ static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret, break; } } +#endif static void tcg_out_addsub2(TCGContext *s, TCGArg rl, TCGArg rh, TCGArg al, TCGArg ah, TCGArg bl, int blconst, @@ -792,7 +793,6 @@ static void tcg_out_addsub2(TCGContext *s, TCGArg rl, TCGArg rh, tcg_out_arithc(s, rh, ah, bh, bhconst, oph); tcg_out_mov(s, TCG_TYPE_I32, rl, tmp); } -#endif /* Generate global QEMU prologue and epilogue code */ static void tcg_target_qemu_prologue(TCGContext *s) From 0980011b4f66482d2733ab2dd0f2f61747772c6b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Feb 2013 18:10:00 +0000 Subject: [PATCH 1339/1634] tcg: Document tcg_qemu_tb_exec() and provide constants for low bit uses Document tcg_qemu_tb_exec(). In particular, its return value is a combination of a pointer to the next translation block and some extra information in the low two bits. Provide some #defines for the values passed in these bits to improve code clarity. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- cpu-exec.c | 9 ++++---- include/exec/gen-icount.h | 2 +- tcg/tcg.h | 44 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index afbe4977ab..2c6b0918de 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -72,7 +72,7 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles, next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr); cpu->current_tb = NULL; - if ((next_tb & 3) == 2) { + if ((next_tb & TB_EXIT_MASK) == TB_EXIT_ICOUNT_EXPIRED) { /* Restore PC. This may happen if async event occurs before the TB starts executing. */ cpu_pc_from_tb(env, tb); @@ -584,7 +584,8 @@ int cpu_exec(CPUArchState *env) spans two pages, we cannot safely do a direct jump. */ if (next_tb != 0 && tb->page_addr[1] == -1) { - tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb); + tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK), + next_tb & TB_EXIT_MASK, tb); } spin_unlock(&tcg_ctx.tb_ctx.tb_lock); @@ -598,10 +599,10 @@ int cpu_exec(CPUArchState *env) tc_ptr = tb->tc_ptr; /* execute the generated code */ next_tb = tcg_qemu_tb_exec(env, tc_ptr); - if ((next_tb & 3) == 2) { + if ((next_tb & TB_EXIT_MASK) == TB_EXIT_ICOUNT_EXPIRED) { /* Instruction counter expired. */ int insns_left; - tb = (TranslationBlock *)(next_tb & ~3); + tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); /* Restore PC. */ cpu_pc_from_tb(env, tb); insns_left = env->icount_decr.u32; diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 8043b3ba26..c858a738c0 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -32,7 +32,7 @@ static void gen_icount_end(TranslationBlock *tb, int num_insns) if (use_icount) { *icount_arg = num_insns; gen_set_label(icount_label); - tcg_gen_exit_tb((tcg_target_long)tb + 2); + tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_ICOUNT_EXPIRED); } } diff --git a/tcg/tcg.h b/tcg/tcg.h index b195396b0f..f5d0aed495 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -677,7 +677,49 @@ TCGv_i64 tcg_const_i64(int64_t val); TCGv_i32 tcg_const_local_i32(int32_t val); TCGv_i64 tcg_const_local_i64(int64_t val); -/* TCG targets may use a different definition of tcg_qemu_tb_exec. */ +/** + * tcg_qemu_tb_exec: + * @env: CPUArchState * for the CPU + * @tb_ptr: address of generated code for the TB to execute + * + * Start executing code from a given translation block. + * Where translation blocks have been linked, execution + * may proceed from the given TB into successive ones. + * Control eventually returns only when some action is needed + * from the top-level loop: either control must pass to a TB + * which has not yet been directly linked, or an asynchronous + * event such as an interrupt needs handling. + * + * The return value is a pointer to the next TB to execute + * (if known; otherwise zero). This pointer is assumed to be + * 4-aligned, and the bottom two bits are used to return further + * information: + * 0, 1: the link between this TB and the next is via the specified + * TB index (0 or 1). That is, we left the TB via (the equivalent + * of) "goto_tb ". The main loop uses this to determine + * how to link the TB just executed to the next. + * 2: we are using instruction counting code generation, and we + * did not start executing this TB because the instruction counter + * would hit zero midway through it. In this case the next-TB pointer + * returned is the TB we were about to execute, and the caller must + * arrange to execute the remaining count of instructions. + * + * If the bottom two bits indicate an exit-via-index then the CPU + * state is correctly synchronised and ready for execution of the next + * TB (and in particular the guest PC is the address to execute next). + * Otherwise, we gave up on execution of this TB before it started, and + * the caller must fix up the CPU state by calling cpu_pc_from_tb() + * with the next-TB pointer we return. + * + * Note that TCG targets may use a different definition of tcg_qemu_tb_exec + * to this default (which just calls the prologue.code emitted by + * tcg_target_qemu_prologue()). + */ +#define TB_EXIT_MASK 3 +#define TB_EXIT_IDX0 0 +#define TB_EXIT_IDX1 1 +#define TB_EXIT_ICOUNT_EXPIRED 2 + #if !defined(tcg_qemu_tb_exec) # define tcg_qemu_tb_exec(env, tb_ptr) \ ((tcg_target_ulong (*)(void *, void *))tcg_ctx.code_gen_prologue)(env, \ From fadf982584b040527aeee0ede270a4d01463d293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 22 Feb 2013 18:10:01 +0000 Subject: [PATCH 1340/1634] cpu: Introduce ENV_OFFSET macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce ENV_OFFSET macros which can be used in non-target-specific code that needs to generate TCG instructions which reference CPUState fields given the cpu_env register that TCG targets set up with a pointer to the CPUArchState struct. Signed-off-by: Andreas Färber Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- target-alpha/cpu-qom.h | 1 + target-arm/cpu-qom.h | 2 ++ target-cris/cpu-qom.h | 1 + target-i386/cpu-qom.h | 1 + target-lm32/cpu-qom.h | 1 + target-m68k/cpu-qom.h | 1 + target-microblaze/cpu-qom.h | 1 + target-mips/cpu-qom.h | 1 + target-openrisc/cpu.h | 2 ++ target-ppc/cpu-qom.h | 3 ++- target-s390x/cpu-qom.h | 1 + target-sh4/cpu-qom.h | 1 + target-sparc/cpu-qom.h | 1 + target-unicore32/cpu-qom.h | 1 + target-xtensa/cpu-qom.h | 1 + 15 files changed, 18 insertions(+), 1 deletion(-) diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h index c0f6c6d165..252bd14821 100644 --- a/target-alpha/cpu-qom.h +++ b/target-alpha/cpu-qom.h @@ -72,5 +72,6 @@ static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env) #define ENV_GET_CPU(e) CPU(alpha_env_get_cpu(e)) +#define ENV_OFFSET offsetof(AlphaCPU, env) #endif diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index aff7bf302e..7539727768 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -109,6 +109,8 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) #define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e)) +#define ENV_OFFSET offsetof(ARMCPU, env) + void register_cp_regs_for_features(ARMCPU *cpu); #endif diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h index 2bac71fd81..11e528661d 100644 --- a/target-cris/cpu-qom.h +++ b/target-cris/cpu-qom.h @@ -71,5 +71,6 @@ static inline CRISCPU *cris_env_get_cpu(CPUCRISState *env) #define ENV_GET_CPU(e) CPU(cris_env_get_cpu(e)) +#define ENV_OFFSET offsetof(CRISCPU, env) #endif diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 48e6b54b1f..b7bdcb6892 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -74,5 +74,6 @@ static inline X86CPU *x86_env_get_cpu(CPUX86State *env) #define ENV_GET_CPU(e) CPU(x86_env_get_cpu(e)) +#define ENV_OFFSET offsetof(X86CPU, env) #endif diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h index d7525b300c..c0b6ce5897 100644 --- a/target-lm32/cpu-qom.h +++ b/target-lm32/cpu-qom.h @@ -69,5 +69,6 @@ static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env) #define ENV_GET_CPU(e) CPU(lm32_env_get_cpu(e)) +#define ENV_OFFSET offsetof(LM32CPU, env) #endif diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h index 20e5684552..f4c33b2eb3 100644 --- a/target-m68k/cpu-qom.h +++ b/target-m68k/cpu-qom.h @@ -68,5 +68,6 @@ static inline M68kCPU *m68k_env_get_cpu(CPUM68KState *env) #define ENV_GET_CPU(e) CPU(m68k_env_get_cpu(e)) +#define ENV_OFFSET offsetof(M68kCPU, env) #endif diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h index 5ea911c8e4..a0248a5a22 100644 --- a/target-microblaze/cpu-qom.h +++ b/target-microblaze/cpu-qom.h @@ -68,5 +68,6 @@ static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env) #define ENV_GET_CPU(e) CPU(mb_env_get_cpu(e)) +#define ENV_OFFSET offsetof(MicroBlazeCPU, env) #endif diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h index 55aa692a85..c6bcddfb9a 100644 --- a/target-mips/cpu-qom.h +++ b/target-mips/cpu-qom.h @@ -72,5 +72,6 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env) #define ENV_GET_CPU(e) CPU(mips_env_get_cpu(e)) +#define ENV_OFFSET offsetof(MIPSCPU, env) #endif diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index 419f007991..4cfd1c74fb 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -340,6 +340,8 @@ static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env) #define ENV_GET_CPU(e) CPU(openrisc_env_get_cpu(e)) +#define ENV_OFFSET offsetof(OpenRISCCPU, env) + OpenRISCCPU *cpu_openrisc_init(const char *cpu_model); void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf); diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 2b82cdbe40..4e8ceca574 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -78,7 +78,8 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) #define ENV_GET_CPU(e) CPU(ppc_env_get_cpu(e)) +#define ENV_OFFSET offsetof(PowerPCCPU, env) + PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); - #endif diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index 237184f55a..f6e514570c 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -69,5 +69,6 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env) #define ENV_GET_CPU(e) CPU(s390_env_get_cpu(e)) +#define ENV_OFFSET offsetof(S390CPU, env) #endif diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h index d368db1b0a..f4e8976478 100644 --- a/target-sh4/cpu-qom.h +++ b/target-sh4/cpu-qom.h @@ -68,5 +68,6 @@ static inline SuperHCPU *sh_env_get_cpu(CPUSH4State *env) #define ENV_GET_CPU(e) CPU(sh_env_get_cpu(e)) +#define ENV_OFFSET offsetof(SuperHCPU, env) #endif diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h index 89cd1cf2d3..efeeca0d97 100644 --- a/target-sparc/cpu-qom.h +++ b/target-sparc/cpu-qom.h @@ -73,5 +73,6 @@ static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env) #define ENV_GET_CPU(e) CPU(sparc_env_get_cpu(e)) +#define ENV_OFFSET offsetof(SPARCCPU, env) #endif diff --git a/target-unicore32/cpu-qom.h b/target-unicore32/cpu-qom.h index 625c6143db..c6590bdf01 100644 --- a/target-unicore32/cpu-qom.h +++ b/target-unicore32/cpu-qom.h @@ -58,5 +58,6 @@ static inline UniCore32CPU *uc32_env_get_cpu(CPUUniCore32State *env) #define ENV_GET_CPU(e) CPU(uc32_env_get_cpu(e)) +#define ENV_OFFSET offsetof(UniCore32CPU, env) #endif diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h index 270de16583..c78136bf72 100644 --- a/target-xtensa/cpu-qom.h +++ b/target-xtensa/cpu-qom.h @@ -78,5 +78,6 @@ static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env) #define ENV_GET_CPU(e) CPU(xtensa_env_get_cpu(e)) +#define ENV_OFFSET offsetof(XtensaCPU, env) #endif From 77211379d73ea0c89c0b5bb6eee74b17cb06f9a8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Feb 2013 18:10:02 +0000 Subject: [PATCH 1341/1634] cpu-exec: wrap tcg_qemu_tb_exec() in a fn to restore the PC If tcg_qemu_tb_exec() returns a value whose low bits don't indicate a link to an indexed next TB, this means that the TB execution never started (eg because the instruction counter hit zero). In this case the guest PC has to be reset to the address of the start of the TB. Refactor the cpu-exec code to make all tcg_qemu_tb_exec() calls pass through a wrapper function which does this restoration if necessary. Note that the apparent change in cpu_exec_nocache() from calling cpu_pc_from_tb() with the old TB to calling it with the TB returned by do_tcg_qemu_tb_exec() is safe, because in the nocache case we can guarantee that the TB we try to execute is not linked to any others, so the only possible returned TB is the one we started at. That is, we should arguably previously have included in cpu_exec_nocache() an assert(next_tb & ~TB_EXIT_MASK) == tb), since the API requires restore from next_tb but we were using tb. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- cpu-exec.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 2c6b0918de..f9ea080e31 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -51,13 +51,28 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc) } #endif +/* Execute a TB, and fix up the CPU state afterwards if necessary */ +static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr) +{ + CPUArchState *env = cpu->env_ptr; + tcg_target_ulong next_tb = tcg_qemu_tb_exec(env, tb_ptr); + if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) { + /* We didn't start executing this TB (eg because the instruction + * counter hit zero); we must restore the guest PC to the address + * of the start of the TB. + */ + TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); + cpu_pc_from_tb(env, tb); + } + return next_tb; +} + /* Execute the code without caching the generated code. An interpreter could be used if available. */ static void cpu_exec_nocache(CPUArchState *env, int max_cycles, TranslationBlock *orig_tb) { CPUState *cpu = ENV_GET_CPU(env); - tcg_target_ulong next_tb; TranslationBlock *tb; /* Should never happen. @@ -69,14 +84,8 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles, max_cycles); cpu->current_tb = tb; /* execute the generated code */ - next_tb = tcg_qemu_tb_exec(env, tb->tc_ptr); + cpu_tb_exec(cpu, tb->tc_ptr); cpu->current_tb = NULL; - - if ((next_tb & TB_EXIT_MASK) == TB_EXIT_ICOUNT_EXPIRED) { - /* Restore PC. This may happen if async event occurs before - the TB starts executing. */ - cpu_pc_from_tb(env, tb); - } tb_phys_invalidate(tb, -1); tb_free(tb); } @@ -598,13 +607,11 @@ int cpu_exec(CPUArchState *env) if (likely(!cpu->exit_request)) { tc_ptr = tb->tc_ptr; /* execute the generated code */ - next_tb = tcg_qemu_tb_exec(env, tc_ptr); + next_tb = cpu_tb_exec(cpu, tc_ptr); if ((next_tb & TB_EXIT_MASK) == TB_EXIT_ICOUNT_EXPIRED) { /* Instruction counter expired. */ int insns_left; tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); - /* Restore PC. */ - cpu_pc_from_tb(env, tb); insns_left = env->icount_decr.u32; if (env->icount_extra && insns_left >= 0) { /* Refill decrementer and continue execution. */ From 378df4b23753a11be650af7664ca76bc75cb9f01 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Feb 2013 18:10:03 +0000 Subject: [PATCH 1342/1634] Handle CPU interrupts by inline checking of a flag Fix some of the nasty TCG race conditions and crashes by implementing cpu_exit() as setting a flag which is checked at the start of each TB. This avoids crashes if a thread or signal handler calls cpu_exit() while the execution thread is itself modifying the TB graph (which may happen in system emulation mode as well as in linux-user mode with a multithreaded guest binary). This fixes the crashes seen in LP:668799; however there are another class of crashes described in LP:1098729 which stem from the fact that in linux-user with a multithreaded guest all threads will use and modify the same global TCG date structures (including the generated code buffer) without any kind of locking. This means that multithreaded guest binaries are still in the "unsupported" category. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- cpu-exec.c | 25 ++++++++++++++++++++++++- exec.c | 2 +- include/exec/gen-icount.h | 12 ++++++++++++ include/qom/cpu.h | 3 +++ tcg/tcg.h | 5 +++++ translate-all.c | 4 ++-- 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index f9ea080e31..9092145d0b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -64,6 +64,12 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr) TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); cpu_pc_from_tb(env, tb); } + if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) { + /* We were asked to stop executing TBs (probably a pending + * interrupt. We've now stopped, so clear the flag. + */ + cpu->tcg_exit_req = 0; + } return next_tb; } @@ -608,7 +614,20 @@ int cpu_exec(CPUArchState *env) tc_ptr = tb->tc_ptr; /* execute the generated code */ next_tb = cpu_tb_exec(cpu, tc_ptr); - if ((next_tb & TB_EXIT_MASK) == TB_EXIT_ICOUNT_EXPIRED) { + switch (next_tb & TB_EXIT_MASK) { + case TB_EXIT_REQUESTED: + /* Something asked us to stop executing + * chained TBs; just continue round the main + * loop. Whatever requested the exit will also + * have set something else (eg exit_request or + * interrupt_request) which we will handle + * next time around the loop. + */ + tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); + next_tb = 0; + break; + case TB_EXIT_ICOUNT_EXPIRED: + { /* Instruction counter expired. */ int insns_left; tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK); @@ -632,6 +651,10 @@ int cpu_exec(CPUArchState *env) next_tb = 0; cpu_loop_exit(env); } + break; + } + default: + break; } } cpu->current_tb = NULL; diff --git a/exec.c b/exec.c index a41bcb8694..46a283071a 100644 --- a/exec.c +++ b/exec.c @@ -495,7 +495,7 @@ void cpu_exit(CPUArchState *env) CPUState *cpu = ENV_GET_CPU(env); cpu->exit_request = 1; - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } void cpu_abort(CPUArchState *env, const char *fmt, ...) diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index c858a738c0..384153b4c4 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -7,10 +7,19 @@ static TCGArg *icount_arg; static int icount_label; +static int exitreq_label; static inline void gen_icount_start(void) { TCGv_i32 count; + TCGv_i32 flag; + + exitreq_label = gen_new_label(); + flag = tcg_temp_local_new_i32(); + tcg_gen_ld_i32(flag, cpu_env, + offsetof(CPUState, tcg_exit_req) - ENV_OFFSET); + tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label); + tcg_temp_free_i32(flag); if (!use_icount) return; @@ -29,6 +38,9 @@ static inline void gen_icount_start(void) static void gen_icount_end(TranslationBlock *tb, int num_insns) { + gen_set_label(exitreq_label); + tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_REQUESTED); + if (use_icount) { *icount_arg = num_insns; gen_set_label(icount_label); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ee1a7c878a..ab2657c558 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -71,6 +71,8 @@ struct kvm_run; * @created: Indicates whether the CPU thread has been successfully created. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. + * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this + * CPU and return to its top level loop. * @env_ptr: Pointer to subclass-specific CPUArchState field. * @current_tb: Currently executing TB. * @kvm_fd: vCPU file descriptor for KVM. @@ -100,6 +102,7 @@ struct CPUState { bool stop; bool stopped; volatile sig_atomic_t exit_request; + volatile sig_atomic_t tcg_exit_req; void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; diff --git a/tcg/tcg.h b/tcg/tcg.h index f5d0aed495..df375cf31e 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -703,6 +703,10 @@ TCGv_i64 tcg_const_local_i64(int64_t val); * would hit zero midway through it. In this case the next-TB pointer * returned is the TB we were about to execute, and the caller must * arrange to execute the remaining count of instructions. + * 3: we stopped because the CPU's exit_request flag was set + * (usually meaning that there is an interrupt that needs to be + * handled). The next-TB pointer returned is the TB we were + * about to execute when we noticed the pending exit request. * * If the bottom two bits indicate an exit-via-index then the CPU * state is correctly synchronised and ready for execution of the next @@ -719,6 +723,7 @@ TCGv_i64 tcg_const_local_i64(int64_t val); #define TB_EXIT_IDX0 0 #define TB_EXIT_IDX1 1 #define TB_EXIT_ICOUNT_EXPIRED 2 +#define TB_EXIT_REQUESTED 3 #if !defined(tcg_qemu_tb_exec) # define tcg_qemu_tb_exec(env, tb_ptr) \ diff --git a/translate-all.c b/translate-all.c index b50fb89528..9741d96395 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1475,7 +1475,7 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask) cpu_abort(env, "Raised interrupt while not in I/O function"); } } else { - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } } @@ -1626,7 +1626,7 @@ void cpu_interrupt(CPUArchState *env, int mask) CPUState *cpu = ENV_GET_CPU(env); env->interrupt_request |= mask; - cpu_unlink_tb(cpu); + cpu->tcg_exit_req = 1; } /* From 3a808cc407744c30daa7470b5f191cde1fbc1aae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Feb 2013 18:10:04 +0000 Subject: [PATCH 1343/1634] translate-all.c: Remove cpu_unlink_tb() The (unsafe) function cpu_unlink_tb() is now unused, so we can simply remove it and any code that was only used by it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- translate-all.c | 69 ------------------------------------------------- 1 file changed, 69 deletions(-) diff --git a/translate-all.c b/translate-all.c index 9741d96395..90ea002935 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1349,55 +1349,6 @@ static TranslationBlock *tb_find_pc(uintptr_t tc_ptr) return &tcg_ctx.tb_ctx.tbs[m_max]; } -static void tb_reset_jump_recursive(TranslationBlock *tb); - -static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) -{ - TranslationBlock *tb1, *tb_next, **ptb; - unsigned int n1; - - tb1 = tb->jmp_next[n]; - if (tb1 != NULL) { - /* find head of list */ - for (;;) { - n1 = (uintptr_t)tb1 & 3; - tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3); - if (n1 == 2) { - break; - } - tb1 = tb1->jmp_next[n1]; - } - /* we are now sure now that tb jumps to tb1 */ - tb_next = tb1; - - /* remove tb from the jmp_first list */ - ptb = &tb_next->jmp_first; - for (;;) { - tb1 = *ptb; - n1 = (uintptr_t)tb1 & 3; - tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3); - if (n1 == n && tb1 == tb) { - break; - } - ptb = &tb1->jmp_next[n1]; - } - *ptb = tb->jmp_next[n]; - tb->jmp_next[n] = NULL; - - /* suppress the jump to next tb in generated code */ - tb_reset_jump(tb, n); - - /* suppress jumps in the tb on which we could have jumped */ - tb_reset_jump_recursive(tb_next); - } -} - -static void tb_reset_jump_recursive(TranslationBlock *tb) -{ - tb_reset_jump_recursive2(tb, 0); - tb_reset_jump_recursive2(tb, 1); -} - #if defined(TARGET_HAS_ICE) && !defined(CONFIG_USER_ONLY) void tb_invalidate_phys_addr(hwaddr addr) { @@ -1416,26 +1367,6 @@ void tb_invalidate_phys_addr(hwaddr addr) } #endif /* TARGET_HAS_ICE && !defined(CONFIG_USER_ONLY) */ -void cpu_unlink_tb(CPUState *cpu) -{ - /* FIXME: TB unchaining isn't SMP safe. For now just ignore the - problem and hope the cpu will stop of its own accord. For userspace - emulation this often isn't actually as bad as it sounds. Often - signals are used primarily to interrupt blocking syscalls. */ - TranslationBlock *tb; - static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; - - spin_lock(&interrupt_lock); - tb = cpu->current_tb; - /* if the cpu is currently executing code, we must unlink it and - all the potentially executing TB */ - if (tb) { - cpu->current_tb = NULL; - tb_reset_jump_recursive(tb); - } - spin_unlock(&interrupt_lock); -} - void tb_check_watchpoint(CPUArchState *env) { TranslationBlock *tb; From 806f352d3d6f7b326b0ab3a49c622b124459dc8d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Feb 2013 18:10:05 +0000 Subject: [PATCH 1344/1634] gen-icount.h: Rename gen_icount_start/end to gen_tb_start/end The gen_icount_start/end functions are now somewhat misnamed since they are useful for generic "start/end of TB" code, used for more than just icount. Rename them to gen_tb_start/end. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Blue Swirl --- include/exec/gen-icount.h | 4 ++-- target-alpha/translate.c | 4 ++-- target-arm/translate.c | 4 ++-- target-cris/translate.c | 4 ++-- target-i386/translate.c | 4 ++-- target-lm32/translate.c | 4 ++-- target-m68k/translate.c | 4 ++-- target-microblaze/translate.c | 4 ++-- target-mips/translate.c | 4 ++-- target-openrisc/translate.c | 4 ++-- target-ppc/translate.c | 4 ++-- target-s390x/translate.c | 4 ++-- target-sh4/translate.c | 4 ++-- target-sparc/translate.c | 4 ++-- target-unicore32/translate.c | 4 ++-- target-xtensa/translate.c | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 384153b4c4..4e3b17b083 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -9,7 +9,7 @@ static TCGArg *icount_arg; static int icount_label; static int exitreq_label; -static inline void gen_icount_start(void) +static inline void gen_tb_start(void) { TCGv_i32 count; TCGv_i32 flag; @@ -36,7 +36,7 @@ static inline void gen_icount_start(void) tcg_temp_free_i32(count); } -static void gen_icount_end(TranslationBlock *tb, int num_insns) +static void gen_tb_end(TranslationBlock *tb, int num_insns) { gen_set_label(exitreq_label); tcg_gen_exit_tb((tcg_target_long)tb + TB_EXIT_REQUESTED); diff --git a/target-alpha/translate.c b/target-alpha/translate.c index f8f76957a9..657f5e1e5f 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -3411,7 +3411,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); do { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { @@ -3478,7 +3478,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, abort(); } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-arm/translate.c b/target-arm/translate.c index f2f649dffd..db63c6ef7d 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9808,7 +9808,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); tcg_clear_temp_count(); @@ -10011,7 +10011,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, } done_generating: - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS diff --git a/target-cris/translate.c b/target-cris/translate.c index 14c167fb0b..ec71ef4721 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3250,7 +3250,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, max_insns = CF_COUNT_MASK; } - gen_icount_start(); + gen_tb_start(); do { check_breakpoint(env, dc); @@ -3391,7 +3391,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, break; } } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-i386/translate.c b/target-i386/translate.c index 3b92f3b227..705147a00b 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -8324,7 +8324,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); for(;;) { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { @@ -8382,7 +8382,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, } if (tb->cflags & CF_LAST_IO) gen_io_end(); - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; /* we don't forget to fill the last values */ if (search_pc) { diff --git a/target-lm32/translate.c b/target-lm32/translate.c index ccaf838afa..695d9c59b2 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -1040,7 +1040,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, max_insns = CF_COUNT_MASK; } - gen_icount_start(); + gen_tb_start(); do { check_breakpoint(env, dc); @@ -1102,7 +1102,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, } } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 3f1478cc20..20a86d8efe 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2999,7 +2999,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); do { pc_offset = dc->pc - pc_start; gen_throws_exception = NULL; @@ -3063,7 +3063,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, break; } } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index 687b7d1433..a74da8e1a5 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1770,7 +1770,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); do { #if SIM_COMPAT @@ -1894,7 +1894,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, break; } } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-mips/translate.c b/target-mips/translate.c index f10a533e80..6ce2f03ddb 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15596,7 +15596,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, if (max_insns == 0) max_insns = CF_COUNT_MASK; LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); - gen_icount_start(); + gen_tb_start(); while (ctx.bstate == BS_NONE) { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { @@ -15694,7 +15694,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, } } done_generating: - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index 23e853e488..0eafd0296c 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -1696,7 +1696,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, max_insns = CF_COUNT_MASK; } - gen_icount_start(); + gen_tb_start(); do { check_breakpoint(cpu, dc); @@ -1779,7 +1779,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, } } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 80d5366d27..fa9e9e3857 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9557,7 +9557,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); /* Set env in case of segfault during code fetch */ while (ctx.exception == POWERPC_EXCP_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end) { @@ -9669,7 +9669,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, /* Generate the return instruction */ tcg_gen_exit_tb(0); } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (unlikely(search_pc)) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-s390x/translate.c b/target-s390x/translate.c index bdf69a3c7c..88e481cdbc 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -4769,7 +4769,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, max_insns = CF_COUNT_MASK; } - gen_icount_start(); + gen_tb_start(); do { if (search_pc) { @@ -4845,7 +4845,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, abort(); } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index d255066e0a..7f300e3444 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1959,7 +1959,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); while (ctx.bstate == BS_NONE && tcg_ctx.gen_opc_ptr < gen_opc_end) { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { @@ -2029,7 +2029,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, } } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { i = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 12276d5608..eb6e800977 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -5249,7 +5249,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, max_insns = tb->cflags & CF_COUNT_MASK; if (max_insns == 0) max_insns = CF_COUNT_MASK; - gen_icount_start(); + gen_tb_start(); do { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { @@ -5319,7 +5319,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, tcg_gen_exit_tb(0); } } - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (spc) { j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index d5039e2093..151e35e6bb 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -1921,7 +1921,7 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, } #endif - gen_icount_start(); + gen_tb_start(); do { if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { @@ -2041,7 +2041,7 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, } done_generating: - gen_icount_end(tb, num_insns); + gen_tb_end(tb, num_insns); *tcg_ctx.gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 11e06a34f5..06d68dbaeb 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -2913,7 +2913,7 @@ static void gen_intermediate_code_internal( dc.next_icount = tcg_temp_local_new_i32(); } - gen_icount_start(); + gen_tb_start(); if (env->singlestep_enabled && env->exception_taken) { env->exception_taken = 0; @@ -2991,7 +2991,7 @@ static void gen_intermediate_code_internal( if (dc.is_jmp == DISAS_NEXT) { gen_jumpi(&dc, dc.pc, 0); } - gen_icount_end(tb, insn_count); + gen_tb_end(tb, insn_count); *tcg_ctx.gen_opc_ptr = INDEX_op_end; if (search_pc) { From 02d583c7232d65920634f7553700eb348f84e472 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sun, 24 Feb 2013 20:46:11 +0000 Subject: [PATCH 1345/1634] ide/macio: Fix macio DMA initialisation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 07a7484e5d713f1eb7c1c37b18a8ab0d56d88875 accidentally introduced a bug in the initialisation of the second macio DMA device which could cause some DMA operations to segfault QEMU. CC: Andreas Färber Signed-off-by: Mark Cave-Ayland Acked-by: Andreas Färber Signed-off-by: Stefan Hajnoczi --- hw/macio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/macio.c b/hw/macio.c index 74bdcd1039..0c6a6b8e7a 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -188,7 +188,7 @@ static int macio_newworld_initfn(PCIDevice *d) sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]); sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]); sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]); - macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x1a); + macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a); ret = qdev_init(DEVICE(&ns->ide[1])); if (ret < 0) { return ret; From 69b302b2044a9a0f6d157d25b39a91ff7124c61f Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 22 Feb 2013 14:37:10 +0100 Subject: [PATCH 1346/1634] virtio-blk: fix unplug + virsh reboot virtio-blk registers a vmstate change handler. Unfortunately this handler is not unregistered on unplug, leading to some random crashes if the system is restarted, e.g. via virsh reboot. Lets unregister the vmstate change handler if the device is removed. Signed-off-by: Christian Borntraeger Signed-off-by: Stefan Hajnoczi --- hw/virtio-blk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 34913ee40e..f5e6ee90b6 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -36,6 +36,7 @@ typedef struct VirtIOBlock VirtIOBlkConf *blk; unsigned short sector_mask; DeviceState *qdev; + VMChangeStateEntry *change; #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE VirtIOBlockDataPlane *dataplane; #endif @@ -681,7 +682,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk) } #endif - qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); + s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); s->qdev = dev; register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); @@ -702,6 +703,7 @@ void virtio_blk_exit(VirtIODevice *vdev) virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; #endif + qemu_del_vm_change_state_handler(s->change); unregister_savevm(s->qdev, "virtio-blk", s); blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); From 2c20e711de308cdebc91ae4b7a983396b56f1de0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 10:40:34 +0100 Subject: [PATCH 1347/1634] dataplane: remove EventPoll in favor of AioContext During the review of the dataplane code, the EventPoll API morphed itself (not concidentially) into something very very similar to an AioContext. Thus, it is trivial to convert virtio-blk-dataplane to use AioContext, and a first baby step towards letting dataplane talk directly to the QEMU block layer. The only interesting note is the value-copy of EventNotifiers. At least in my opinion this is part of the EventNotifier API and is even portable to Windows. Of course, in this case you should not close the notifier's underlying file descriptors or handle with event_notifier_cleanup. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- hw/dataplane/Makefile.objs | 2 +- hw/dataplane/event-poll.c | 100 ------------------------------------- hw/dataplane/event-poll.h | 40 --------------- hw/dataplane/virtio-blk.c | 48 ++++++++++-------- 4 files changed, 29 insertions(+), 161 deletions(-) delete mode 100644 hw/dataplane/event-poll.c delete mode 100644 hw/dataplane/event-poll.h diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs index 3e47d0537e..701111ccb9 100644 --- a/hw/dataplane/Makefile.objs +++ b/hw/dataplane/Makefile.objs @@ -1 +1 @@ -obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o ioq.o virtio-blk.o +obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o ioq.o virtio-blk.o diff --git a/hw/dataplane/event-poll.c b/hw/dataplane/event-poll.c deleted file mode 100644 index 2b55c6e255..0000000000 --- a/hw/dataplane/event-poll.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Event loop with file descriptor polling - * - * Copyright 2012 IBM, Corp. - * Copyright 2012 Red Hat, Inc. and/or its affiliates - * - * Authors: - * Stefan Hajnoczi - * - * 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 -#include "hw/dataplane/event-poll.h" - -/* Add an event notifier and its callback for polling */ -void event_poll_add(EventPoll *poll, EventHandler *handler, - EventNotifier *notifier, EventCallback *callback) -{ - struct epoll_event event = { - .events = EPOLLIN, - .data.ptr = handler, - }; - handler->notifier = notifier; - handler->callback = callback; - if (epoll_ctl(poll->epoll_fd, EPOLL_CTL_ADD, - event_notifier_get_fd(notifier), &event) != 0) { - fprintf(stderr, "failed to add event handler to epoll: %m\n"); - exit(1); - } -} - -/* Event callback for stopping event_poll() */ -static void handle_stop(EventHandler *handler) -{ - /* Do nothing */ -} - -void event_poll_init(EventPoll *poll) -{ - /* Create epoll file descriptor */ - poll->epoll_fd = epoll_create1(EPOLL_CLOEXEC); - if (poll->epoll_fd < 0) { - fprintf(stderr, "epoll_create1 failed: %m\n"); - exit(1); - } - - /* Set up stop notifier */ - if (event_notifier_init(&poll->stop_notifier, 0) < 0) { - fprintf(stderr, "failed to init stop notifier\n"); - exit(1); - } - event_poll_add(poll, &poll->stop_handler, - &poll->stop_notifier, handle_stop); -} - -void event_poll_cleanup(EventPoll *poll) -{ - event_notifier_cleanup(&poll->stop_notifier); - close(poll->epoll_fd); - poll->epoll_fd = -1; -} - -/* Block until the next event and invoke its callback */ -void event_poll(EventPoll *poll) -{ - EventHandler *handler; - struct epoll_event event; - int nevents; - - /* Wait for the next event. Only do one event per call to keep the - * function simple, this could be changed later. */ - do { - nevents = epoll_wait(poll->epoll_fd, &event, 1, -1); - } while (nevents < 0 && errno == EINTR); - if (unlikely(nevents != 1)) { - fprintf(stderr, "epoll_wait failed: %m\n"); - exit(1); /* should never happen */ - } - - /* Find out which event handler has become active */ - handler = event.data.ptr; - - /* Clear the eventfd */ - event_notifier_test_and_clear(handler->notifier); - - /* Handle the event */ - handler->callback(handler); -} - -/* Stop event_poll() - * - * This function can be used from another thread. - */ -void event_poll_notify(EventPoll *poll) -{ - event_notifier_set(&poll->stop_notifier); -} diff --git a/hw/dataplane/event-poll.h b/hw/dataplane/event-poll.h deleted file mode 100644 index 3e8d3ec7d5..0000000000 --- a/hw/dataplane/event-poll.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Event loop with file descriptor polling - * - * Copyright 2012 IBM, Corp. - * Copyright 2012 Red Hat, Inc. and/or its affiliates - * - * Authors: - * Stefan Hajnoczi - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef EVENT_POLL_H -#define EVENT_POLL_H - -#include "qemu/event_notifier.h" - -typedef struct EventHandler EventHandler; -typedef void EventCallback(EventHandler *handler); -struct EventHandler { - EventNotifier *notifier; /* eventfd */ - EventCallback *callback; /* callback function */ -}; - -typedef struct { - int epoll_fd; /* epoll(2) file descriptor */ - EventNotifier stop_notifier; /* stop poll notifier */ - EventHandler stop_handler; /* stop poll handler */ -} EventPoll; - -void event_poll_add(EventPoll *poll, EventHandler *handler, - EventNotifier *notifier, EventCallback *callback); -void event_poll_init(EventPoll *poll); -void event_poll_cleanup(EventPoll *poll); -void event_poll(EventPoll *poll); -void event_poll_notify(EventPoll *poll); - -#endif /* EVENT_POLL_H */ diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index 3f2da22669..aa9b04078b 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -14,13 +14,13 @@ #include "trace.h" #include "qemu/iov.h" -#include "event-poll.h" #include "qemu/thread.h" #include "vring.h" #include "ioq.h" #include "migration/migration.h" #include "hw/virtio-blk.h" #include "hw/dataplane/virtio-blk.h" +#include "block/aio.h" enum { SEG_MAX = 126, /* maximum number of I/O segments */ @@ -51,9 +51,14 @@ struct VirtIOBlockDataPlane { Vring vring; /* virtqueue vring */ EventNotifier *guest_notifier; /* irq */ - EventPoll event_poll; /* event poller */ - EventHandler io_handler; /* Linux AIO completion handler */ - EventHandler notify_handler; /* virtqueue notify handler */ + /* Note that these EventNotifiers are assigned by value. This is + * fine as long as you do not call event_notifier_cleanup on them + * (because you don't own the file descriptor or handle; you just + * use it). + */ + AioContext *ctx; + EventNotifier io_notifier; /* Linux AIO completion */ + EventNotifier host_notifier; /* doorbell */ IOQueue ioqueue; /* Linux AIO queue (should really be per dataplane thread) */ @@ -256,10 +261,10 @@ static int process_request(IOQueue *ioq, struct iovec iov[], } } -static void handle_notify(EventHandler *handler) +static void handle_notify(EventNotifier *e) { - VirtIOBlockDataPlane *s = container_of(handler, VirtIOBlockDataPlane, - notify_handler); + VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, + host_notifier); /* There is one array of iovecs into which all new requests are extracted * from the vring. Requests are read from the vring and the translated @@ -286,6 +291,7 @@ static void handle_notify(EventHandler *handler) unsigned int out_num = 0, in_num = 0; unsigned int num_queued; + event_notifier_test_and_clear(&s->host_notifier); for (;;) { /* Disable guest->host notifies to avoid unnecessary vmexits */ vring_disable_notification(s->vdev, &s->vring); @@ -334,11 +340,12 @@ static void handle_notify(EventHandler *handler) } } -static void handle_io(EventHandler *handler) +static void handle_io(EventNotifier *e) { - VirtIOBlockDataPlane *s = container_of(handler, VirtIOBlockDataPlane, - io_handler); + VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, + io_notifier); + event_notifier_test_and_clear(&s->io_notifier); if (ioq_run_completion(&s->ioqueue, complete_request, s) > 0) { notify_guest(s); } @@ -348,7 +355,7 @@ static void handle_io(EventHandler *handler) * requests. */ if (unlikely(vring_more_avail(&s->vring))) { - handle_notify(&s->notify_handler); + handle_notify(&s->host_notifier); } } @@ -357,7 +364,7 @@ static void *data_plane_thread(void *opaque) VirtIOBlockDataPlane *s = opaque; do { - event_poll(&s->event_poll); + aio_poll(s->ctx, true); } while (!s->stopping || s->num_reqs > 0); return NULL; } @@ -445,7 +452,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) return; } - event_poll_init(&s->event_poll); + s->ctx = aio_context_new(); /* Set up guest notifier (irq) */ if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, @@ -462,17 +469,16 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) fprintf(stderr, "virtio-blk failed to set host notifier\n"); exit(1); } - event_poll_add(&s->event_poll, &s->notify_handler, - virtio_queue_get_host_notifier(vq), - handle_notify); + s->host_notifier = *virtio_queue_get_host_notifier(vq); + aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify, NULL); /* Set up ioqueue */ ioq_init(&s->ioqueue, s->fd, REQ_MAX); for (i = 0; i < ARRAY_SIZE(s->requests); i++) { ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb); } - event_poll_add(&s->event_poll, &s->io_handler, - ioq_get_notifier(&s->ioqueue), handle_io); + s->io_notifier = *ioq_get_notifier(&s->ioqueue); + aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io, NULL); s->started = true; trace_virtio_blk_data_plane_start(s); @@ -498,15 +504,17 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) qemu_bh_delete(s->start_bh); s->start_bh = NULL; } else { - event_poll_notify(&s->event_poll); + aio_notify(s->ctx); qemu_thread_join(&s->thread); } + aio_set_event_notifier(s->ctx, &s->io_notifier, NULL, NULL); ioq_cleanup(&s->ioqueue); + aio_set_event_notifier(s->ctx, &s->host_notifier, NULL, NULL); s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, 0, false); - event_poll_cleanup(&s->event_poll); + aio_context_unref(s->ctx); /* Clean up guest notifier (irq) */ s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, false); From 4ef7b8944cc5eae66159c60066b21466e2dc1ee4 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Fri, 22 Feb 2013 12:39:49 +0900 Subject: [PATCH 1348/1634] slirp/tcp_subr.c: fix coding style in tcp_connect Fix coding style in tcp_connect before the next patch. Signed-off-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- slirp/tcp_subr.c | 142 ++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 69 deletions(-) diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 1542e43619..317dc07a06 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -384,83 +384,87 @@ int tcp_fconnect(struct socket *so) * the time it gets to accept(), so... We simply accept * here and SYN the local-host. */ -void -tcp_connect(struct socket *inso) +void tcp_connect(struct socket *inso) { - Slirp *slirp = inso->slirp; - struct socket *so; - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - struct tcpcb *tp; - int s, opt; + Slirp *slirp = inso->slirp; + struct socket *so; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct tcpcb *tp; + int s, opt; - DEBUG_CALL("tcp_connect"); - DEBUG_ARG("inso = %lx", (long)inso); + DEBUG_CALL("tcp_connect"); + DEBUG_ARG("inso = %lx", (long)inso); - /* - * If it's an SS_ACCEPTONCE socket, no need to socreate() - * another socket, just use the accept() socket. - */ - if (inso->so_state & SS_FACCEPTONCE) { - /* FACCEPTONCE already have a tcpcb */ - so = inso; - } else { - if ((so = socreate(slirp)) == NULL) { - /* If it failed, get rid of the pending connection */ - closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); - return; - } - if (tcp_attach(so) < 0) { - free(so); /* NOT sofree */ - return; - } - so->so_laddr = inso->so_laddr; - so->so_lport = inso->so_lport; - } - - (void) tcp_mss(sototcpcb(so), 0); - - if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { - tcp_close(sototcpcb(so)); /* This will sofree() as well */ - return; - } - socket_set_nonblock(s); - opt = 1; - setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); - opt = 1; - setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); - opt = 1; - setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); - - so->so_fport = addr.sin_port; - so->so_faddr = addr.sin_addr; - /* Translate connections from localhost to the real hostname */ - if (so->so_faddr.s_addr == 0 || - (so->so_faddr.s_addr & loopback_mask) == - (loopback_addr.s_addr & loopback_mask)) { - so->so_faddr = slirp->vhost_addr; + /* + * If it's an SS_ACCEPTONCE socket, no need to socreate() + * another socket, just use the accept() socket. + */ + if (inso->so_state & SS_FACCEPTONCE) { + /* FACCEPTONCE already have a tcpcb */ + so = inso; + } else { + so = socreate(slirp); + if (so == NULL) { + /* If it failed, get rid of the pending connection */ + closesocket(accept(inso->s, (struct sockaddr *)&addr, &addrlen)); + return; } + if (tcp_attach(so) < 0) { + free(so); /* NOT sofree */ + return; + } + so->so_laddr = inso->so_laddr; + so->so_lport = inso->so_lport; + } - /* Close the accept() socket, set right state */ - if (inso->so_state & SS_FACCEPTONCE) { - closesocket(so->s); /* If we only accept once, close the accept() socket */ - so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ - /* if it's not FACCEPTONCE, it's already NOFDREF */ - } - so->s = s; - so->so_state |= SS_INCOMING; + tcp_mss(sototcpcb(so), 0); - so->so_iptos = tcp_tos(so); - tp = sototcpcb(so); + s = accept(inso->s, (struct sockaddr *)&addr, &addrlen); + if (s < 0) { + tcp_close(sototcpcb(so)); /* This will sofree() as well */ + return; + } + socket_set_nonblock(s); + opt = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)); + opt = 1; + setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int)); + opt = 1; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(int)); - tcp_template(tp); + so->so_fport = addr.sin_port; + so->so_faddr = addr.sin_addr; + /* Translate connections from localhost to the real hostname */ + if (so->so_faddr.s_addr == 0 || + (so->so_faddr.s_addr & loopback_mask) == + (loopback_addr.s_addr & loopback_mask)) { + so->so_faddr = slirp->vhost_addr; + } - tp->t_state = TCPS_SYN_SENT; - tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; - tp->iss = slirp->tcp_iss; - slirp->tcp_iss += TCP_ISSINCR/2; - tcp_sendseqinit(tp); - tcp_output(tp); + /* Close the accept() socket, set right state */ + if (inso->so_state & SS_FACCEPTONCE) { + /* If we only accept once, close the accept() socket */ + closesocket(so->s); + + /* Don't select it yet, even though we have an FD */ + /* if it's not FACCEPTONCE, it's already NOFDREF */ + so->so_state = SS_NOFDREF; + } + so->s = s; + so->so_state |= SS_INCOMING; + + so->so_iptos = tcp_tos(so); + tp = sototcpcb(so); + + tcp_template(tp); + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = slirp->tcp_iss; + slirp->tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); } /* From bf1c852aa9cbe21beeb7c37d03e167c33ac196b2 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Fri, 22 Feb 2013 12:39:50 +0900 Subject: [PATCH 1349/1634] move socket_set_nodelay to osdep.c Signed-off-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 11 +---------- gdbstub.c | 5 ++--- include/qemu/sockets.h | 1 + qemu-char.c | 6 ------ slirp/tcp_subr.c | 3 +-- util/osdep.c | 6 ++++++ 6 files changed, 11 insertions(+), 21 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index d466b232d7..51e75ad7a1 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -787,15 +787,6 @@ static int aio_flush_request(void *opaque) !QLIST_EMPTY(&s->pending_aio_head); } -static int set_nodelay(int fd) -{ - int ret, opt; - - opt = 1; - ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)); - return ret; -} - /* * Return a socket discriptor to read/write objects. * @@ -814,7 +805,7 @@ static int get_sheep_fd(BDRVSheepdogState *s) socket_set_nonblock(fd); - ret = set_nodelay(fd); + ret = socket_set_nodelay(fd); if (ret) { error_report("%s", strerror(errno)); closesocket(fd); diff --git a/gdbstub.c b/gdbstub.c index 32dfea9ed0..e414ad9157 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2841,7 +2841,7 @@ static void gdb_accept(void) GDBState *s; struct sockaddr_in sockaddr; socklen_t len; - int val, fd; + int fd; for(;;) { len = sizeof(sockaddr); @@ -2858,8 +2858,7 @@ static void gdb_accept(void) } /* set short latency */ - val = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); + socket_set_nodelay(fd); s = g_malloc0(sizeof(GDBState)); s->c_cpu = first_cpu; diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 803ae1798c..6125bf7bdf 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -34,6 +34,7 @@ int inet_aton(const char *cp, struct in_addr *ia); int qemu_socket(int domain, int type, int protocol); int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); int socket_set_cork(int fd, int v); +int socket_set_nodelay(int fd); void socket_set_block(int fd); void socket_set_nonblock(int fd); int send_all(int fd, const void *buf, int len1); diff --git a/qemu-char.c b/qemu-char.c index 160decc2f0..36295b1bcd 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2365,12 +2365,6 @@ static void tcp_chr_telnet_init(int fd) send(fd, (char *)buf, 3, 0); } -static void socket_set_nodelay(int fd) -{ - int val = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); -} - static int tcp_chr_add_client(CharDriverState *chr, int fd) { TCPCharDriver *s = chr->opaque; diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 317dc07a06..7b7ad60aea 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -430,8 +430,7 @@ void tcp_connect(struct socket *inso) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)); opt = 1; setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int)); - opt = 1; - setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(int)); + socket_set_nodelay(s); so->so_fport = addr.sin_port; so->so_faddr = addr.sin_addr; diff --git a/util/osdep.c b/util/osdep.c index 5b51a0322e..c4082610df 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -63,6 +63,12 @@ int socket_set_cork(int fd, int v) #endif } +int socket_set_nodelay(int fd) +{ + int v = 1; + return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); +} + int qemu_madvise(void *addr, size_t len, int advice) { if (advice == QEMU_MADV_INVALID) { From 5d6768e3b8908a60f0a3016b7fa24194f6b47c80 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Fri, 22 Feb 2013 12:39:51 +0900 Subject: [PATCH 1350/1634] sheepdog: accept URIs The URI syntax is consistent with the NBD and Gluster syntax. The syntax is sheepdog[+tcp]://[host:port]/vdiname[#snapid|#tag] Signed-off-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 139 +++++++++++++++++++++++++++++++++++------------ qemu-doc.texi | 16 +++--- qemu-options.hx | 18 ++---- 3 files changed, 117 insertions(+), 56 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 51e75ad7a1..bfa8a00dda 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -13,6 +13,7 @@ */ #include "qemu-common.h" +#include "qemu/uri.h" #include "qemu/error-report.h" #include "qemu/sockets.h" #include "block/block_int.h" @@ -816,8 +817,52 @@ static int get_sheep_fd(BDRVSheepdogState *s) return fd; } +static int sd_parse_uri(BDRVSheepdogState *s, const char *filename, + char *vdi, uint32_t *snapid, char *tag) +{ + URI *uri; + QueryParams *qp = NULL; + int ret = 0; + + uri = uri_parse(filename); + if (!uri) { + return -EINVAL; + } + + if (uri->path == NULL || !strcmp(uri->path, "/")) { + ret = -EINVAL; + goto out; + } + pstrcpy(vdi, SD_MAX_VDI_LEN, uri->path + 1); + + /* sheepdog[+tcp]://[host:port]/vdiname */ + s->addr = g_strdup(uri->server ?: SD_DEFAULT_ADDR); + if (uri->port) { + s->port = g_strdup_printf("%d", uri->port); + } else { + s->port = g_strdup(SD_DEFAULT_PORT); + } + + /* snapshot tag */ + if (uri->fragment) { + *snapid = strtoul(uri->fragment, NULL, 10); + if (*snapid == 0) { + pstrcpy(tag, SD_MAX_VDI_TAG_LEN, uri->fragment); + } + } else { + *snapid = CURRENT_VDI_ID; /* search current vdi */ + } + +out: + if (qp) { + query_params_free(qp); + } + uri_free(uri); + return ret; +} + /* - * Parse a filename + * Parse a filename (old syntax) * * filename must be one of the following formats: * 1. [vdiname] @@ -836,9 +881,11 @@ static int get_sheep_fd(BDRVSheepdogState *s) static int parse_vdiname(BDRVSheepdogState *s, const char *filename, char *vdi, uint32_t *snapid, char *tag) { - char *p, *q; - int nr_sep; + char *p, *q, *uri; + const char *host_spec, *vdi_spec; + int nr_sep, ret; + strstart(filename, "sheepdog:", (const char **)&filename); p = q = g_strdup(filename); /* count the number of separators */ @@ -851,38 +898,32 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename, } p = q; - /* use the first two tokens as hostname and port number. */ + /* use the first two tokens as host_spec. */ if (nr_sep >= 2) { - s->addr = p; + host_spec = p; p = strchr(p, ':'); - *p++ = '\0'; - - s->port = p; + p++; p = strchr(p, ':'); *p++ = '\0'; } else { - s->addr = NULL; - s->port = 0; + host_spec = ""; } - pstrcpy(vdi, SD_MAX_VDI_LEN, p); + vdi_spec = p; - p = strchr(vdi, ':'); + p = strchr(vdi_spec, ':'); if (p) { - *p++ = '\0'; - *snapid = strtoul(p, NULL, 10); - if (*snapid == 0) { - pstrcpy(tag, SD_MAX_VDI_TAG_LEN, p); - } - } else { - *snapid = CURRENT_VDI_ID; /* search current vdi */ + *p++ = '#'; } - if (s->addr == NULL) { - g_free(q); - } + uri = g_strdup_printf("sheepdog://%s/%s", host_spec, vdi_spec); - return 0; + ret = sd_parse_uri(s, uri, vdi, snapid, tag); + + g_free(q); + g_free(uri); + + return ret; } static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid, @@ -1097,16 +1138,19 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) uint32_t snapid; char *buf = NULL; - strstart(filename, "sheepdog:", (const char **)&filename); - QLIST_INIT(&s->inflight_aio_head); QLIST_INIT(&s->pending_aio_head); s->fd = -1; memset(vdi, 0, sizeof(vdi)); memset(tag, 0, sizeof(tag)); - if (parse_vdiname(s, filename, vdi, &snapid, tag) < 0) { - ret = -EINVAL; + + if (strstr(filename, "://")) { + ret = sd_parse_uri(s, filename, vdi, &snapid, tag); + } else { + ret = parse_vdiname(s, filename, vdi, &snapid, tag); + } + if (ret < 0) { goto out; } s->fd = get_sheep_fd(s); @@ -1275,17 +1319,17 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN]; uint32_t snapid; bool prealloc = false; - const char *vdiname; s = g_malloc0(sizeof(BDRVSheepdogState)); - strstart(filename, "sheepdog:", &vdiname); - memset(vdi, 0, sizeof(vdi)); memset(tag, 0, sizeof(tag)); - if (parse_vdiname(s, vdiname, vdi, &snapid, tag) < 0) { - error_report("invalid filename"); - ret = -EINVAL; + if (strstr(filename, "://")) { + ret = sd_parse_uri(s, filename, vdi, &snapid, tag); + } else { + ret = parse_vdiname(s, filename, vdi, &snapid, tag); + } + if (ret < 0) { goto out; } @@ -1392,6 +1436,7 @@ static void sd_close(BlockDriverState *bs) qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); g_free(s->addr); + g_free(s->port); } static int64_t sd_getlength(BlockDriverState *bs) @@ -2054,7 +2099,7 @@ static QEMUOptionParameter sd_create_options[] = { { NULL } }; -BlockDriver bdrv_sheepdog = { +static BlockDriver bdrv_sheepdog = { .format_name = "sheepdog", .protocol_name = "sheepdog", .instance_size = sizeof(BDRVSheepdogState), @@ -2079,8 +2124,34 @@ BlockDriver bdrv_sheepdog = { .create_options = sd_create_options, }; +static BlockDriver bdrv_sheepdog_tcp = { + .format_name = "sheepdog", + .protocol_name = "sheepdog+tcp", + .instance_size = sizeof(BDRVSheepdogState), + .bdrv_file_open = sd_open, + .bdrv_close = sd_close, + .bdrv_create = sd_create, + .bdrv_getlength = sd_getlength, + .bdrv_truncate = sd_truncate, + + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, + .bdrv_co_flush_to_disk = sd_co_flush_to_disk, + + .bdrv_snapshot_create = sd_snapshot_create, + .bdrv_snapshot_goto = sd_snapshot_goto, + .bdrv_snapshot_delete = sd_snapshot_delete, + .bdrv_snapshot_list = sd_snapshot_list, + + .bdrv_save_vmstate = sd_save_vmstate, + .bdrv_load_vmstate = sd_load_vmstate, + + .create_options = sd_create_options, +}; + static void bdrv_sheepdog_init(void) { bdrv_register(&bdrv_sheepdog); + bdrv_register(&bdrv_sheepdog_tcp); } block_init(bdrv_sheepdog_init); diff --git a/qemu-doc.texi b/qemu-doc.texi index 747e052fcb..2083e29a97 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -830,7 +830,7 @@ QEMU-based virtual machines. You can create a Sheepdog disk image with the command: @example -qemu-img create sheepdog:@var{image} @var{size} +qemu-img create sheepdog:///@var{image} @var{size} @end example where @var{image} is the Sheepdog image name and @var{size} is its size. @@ -838,29 +838,29 @@ size. To import the existing @var{filename} to Sheepdog, you can use a convert command. @example -qemu-img convert @var{filename} sheepdog:@var{image} +qemu-img convert @var{filename} sheepdog:///@var{image} @end example You can boot from the Sheepdog disk image with the command: @example -qemu-system-i386 sheepdog:@var{image} +qemu-system-i386 sheepdog:///@var{image} @end example You can also create a snapshot of the Sheepdog image like qcow2. @example -qemu-img snapshot -c @var{tag} sheepdog:@var{image} +qemu-img snapshot -c @var{tag} sheepdog:///@var{image} @end example where @var{tag} is a tag name of the newly created snapshot. To boot from the Sheepdog snapshot, specify the tag name of the snapshot. @example -qemu-system-i386 sheepdog:@var{image}:@var{tag} +qemu-system-i386 sheepdog:///@var{image}#@var{tag} @end example You can create a cloned image from the existing snapshot. @example -qemu-img create -b sheepdog:@var{base}:@var{tag} sheepdog:@var{image} +qemu-img create -b sheepdog:///@var{base}#@var{tag} sheepdog:///@var{image} @end example where @var{base} is a image name of the source snapshot and @var{tag} is its tag name. @@ -868,8 +868,8 @@ is its tag name. If the Sheepdog daemon doesn't run on the local host, you need to specify one of the Sheepdog servers to connect to. @example -qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size} -qemu-system-i386 sheepdog:@var{hostname}:@var{port}:@var{image} +qemu-img create sheepdog://@var{hostname}:@var{port}/@var{image} @var{size} +qemu-system-i386 sheepdog://@var{hostname}:@var{port}/@var{image} @end example @node disk_images_iscsi diff --git a/qemu-options.hx b/qemu-options.hx index 797d992804..e8fb78c5eb 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2099,23 +2099,13 @@ QEMU supports using either local sheepdog devices or remote networked devices. Syntax for specifying a sheepdog device -@table @list -``sheepdog:'' - -``sheepdog::'' - -``sheepdog::'' - -``sheepdog:::'' - -``sheepdog::::'' - -``sheepdog::::'' -@end table +@example +sheepdog[+tcp]://[host:port]/vdiname[#snapid|#tag] +@end example Example @example -qemu-system-i386 --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine +qemu-system-i386 --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine @end example See also @url{http://http://www.osrg.net/sheepdog/}. From 25af257d219ed2708b3bcf7f1fabf93234d27620 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Fri, 22 Feb 2013 12:39:52 +0900 Subject: [PATCH 1351/1634] sheepdog: use inet_connect to simplify connect code This uses the form ":" for the representation of the sheepdog server to use inet_connect. Signed-off-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 113 +++++++++++++---------------------------------- 1 file changed, 31 insertions(+), 82 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index bfa8a00dda..b5cbdfee83 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -22,7 +22,7 @@ #define SD_PROTO_VER 0x01 #define SD_DEFAULT_ADDR "localhost" -#define SD_DEFAULT_PORT "7000" +#define SD_DEFAULT_PORT 7000 #define SD_OP_CREATE_AND_WRITE_OBJ 0x01 #define SD_OP_READ_OBJ 0x02 @@ -298,8 +298,7 @@ typedef struct BDRVSheepdogState { bool is_snapshot; uint32_t cache_flags; - char *addr; - char *port; + char *host_spec; int fd; CoMutex lock; @@ -447,56 +446,18 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, return acb; } -static int connect_to_sdog(const char *addr, const char *port) +static int connect_to_sdog(BDRVSheepdogState *s) { - char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; - int fd, ret; - struct addrinfo hints, *res, *res0; + int fd; + Error *err = NULL; - if (!addr) { - addr = SD_DEFAULT_ADDR; - port = SD_DEFAULT_PORT; + fd = inet_connect(s->host_spec, &err); + + if (err != NULL) { + qerror_report_err(err); + error_free(err); } - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - - ret = getaddrinfo(addr, port, &hints, &res0); - if (ret) { - error_report("unable to get address info %s, %s", - addr, strerror(errno)); - return -errno; - } - - for (res = res0; res; res = res->ai_next) { - ret = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), - sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); - if (ret) { - continue; - } - - fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (fd < 0) { - continue; - } - - reconnect: - ret = connect(fd, res->ai_addr, res->ai_addrlen); - if (ret < 0) { - if (errno == EINTR) { - goto reconnect; - } - close(fd); - break; - } - - dprintf("connected to %s:%s\n", addr, port); - goto success; - } - fd = -errno; - error_report("failed connect to %s:%s", addr, port); -success: - freeaddrinfo(res0); return fd; } @@ -798,9 +759,8 @@ static int get_sheep_fd(BDRVSheepdogState *s) { int ret, fd; - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { - error_report("%s", strerror(errno)); return fd; } @@ -836,12 +796,8 @@ static int sd_parse_uri(BDRVSheepdogState *s, const char *filename, pstrcpy(vdi, SD_MAX_VDI_LEN, uri->path + 1); /* sheepdog[+tcp]://[host:port]/vdiname */ - s->addr = g_strdup(uri->server ?: SD_DEFAULT_ADDR); - if (uri->port) { - s->port = g_strdup_printf("%d", uri->port); - } else { - s->port = g_strdup(SD_DEFAULT_PORT); - } + s->host_spec = g_strdup_printf("%s:%d", uri->server ?: SD_DEFAULT_ADDR, + uri->port ?: SD_DEFAULT_PORT); /* snapshot tag */ if (uri->fragment) { @@ -935,7 +891,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid, unsigned int wlen, rlen = 0; char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN]; - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { return fd; } @@ -1178,9 +1134,8 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags) s->is_snapshot = true; } - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { - error_report("failed to connect"); ret = fd; goto out; } @@ -1213,9 +1168,8 @@ out: return ret; } -static int do_sd_create(char *filename, int64_t vdi_size, - uint32_t base_vid, uint32_t *vdi_id, int snapshot, - const char *addr, const char *port) +static int do_sd_create(BDRVSheepdogState *s, char *filename, int64_t vdi_size, + uint32_t base_vid, uint32_t *vdi_id, int snapshot) { SheepdogVdiReq hdr; SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; @@ -1223,7 +1177,7 @@ static int do_sd_create(char *filename, int64_t vdi_size, unsigned int wlen, rlen = 0; char buf[SD_MAX_VDI_LEN]; - fd = connect_to_sdog(addr, port); + fd = connect_to_sdog(s); if (fd < 0) { return fd; } @@ -1390,7 +1344,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) bdrv_delete(bs); } - ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s->addr, s->port); + ret = do_sd_create(s, vdi, vdi_size, base_vid, &vid, 0); if (!prealloc || ret) { goto out; } @@ -1411,7 +1365,7 @@ static void sd_close(BlockDriverState *bs) dprintf("%s\n", s->name); - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { return; } @@ -1435,8 +1389,7 @@ static void sd_close(BlockDriverState *bs) qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL); closesocket(s->fd); - g_free(s->addr); - g_free(s->port); + g_free(s->host_spec); } static int64_t sd_getlength(BlockDriverState *bs) @@ -1460,7 +1413,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset) return -EINVAL; } - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { return fd; } @@ -1536,17 +1489,15 @@ static int sd_create_branch(BDRVSheepdogState *s) buf = g_malloc(SD_INODE_SIZE); - ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &vid, 1, - s->addr, s->port); + ret = do_sd_create(s, s->name, s->inode.vdi_size, s->inode.vdi_id, &vid, 1); if (ret) { goto out; } dprintf("%" PRIx32 " is created.\n", vid); - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { - error_report("failed to connect"); ret = fd; goto out; } @@ -1805,7 +1756,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id); /* refresh inode. */ - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { ret = fd; goto cleanup; @@ -1818,8 +1769,8 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) goto cleanup; } - ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid, 1, - s->addr, s->port); + ret = do_sd_create(s, s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid, + 1); if (ret < 0) { error_report("failed to create inode for snapshot. %s", strerror(errno)); @@ -1874,9 +1825,8 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) goto out; } - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { - error_report("failed to connect"); ret = fd; goto out; } @@ -1938,7 +1888,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) vdi_inuse = g_malloc(max); - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { ret = fd; goto out; @@ -1965,9 +1915,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT); start_nr = hval & (SD_NR_VDIS - 1); - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { - error_report("failed to connect"); ret = fd; goto out; } @@ -2024,7 +1973,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, uint32_t vdi_index; uint64_t offset; - fd = connect_to_sdog(s->addr, s->port); + fd = connect_to_sdog(s); if (fd < 0) { return fd; } From 1b8bbb46e7593b92ded74cc2a5461202c2b6c05c Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Fri, 22 Feb 2013 12:39:53 +0900 Subject: [PATCH 1352/1634] sheepdog: add support for connecting to unix domain socket This patch adds support for a unix domain socket for a connection between qemu and local sheepdog server. You can use the unix domain socket with the following syntax: $ qemu sheepdog+unix:///?socket=[#snapid] Signed-off-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 82 +++++++++++++++++++++++++++++++++++++++++------- qemu-doc.texi | 6 ++++ qemu-options.hx | 2 +- 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index b5cbdfee83..c711c28613 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -299,6 +299,7 @@ typedef struct BDRVSheepdogState { uint32_t cache_flags; char *host_spec; + bool is_unix; int fd; CoMutex lock; @@ -451,7 +452,18 @@ static int connect_to_sdog(BDRVSheepdogState *s) int fd; Error *err = NULL; - fd = inet_connect(s->host_spec, &err); + if (s->is_unix) { + fd = unix_connect(s->host_spec, &err); + } else { + fd = inet_connect(s->host_spec, &err); + + if (err == NULL) { + int ret = socket_set_nodelay(fd); + if (ret < 0) { + error_report("%s", strerror(errno)); + } + } + } if (err != NULL) { qerror_report_err(err); @@ -757,7 +769,7 @@ static int aio_flush_request(void *opaque) */ static int get_sheep_fd(BDRVSheepdogState *s) { - int ret, fd; + int fd; fd = connect_to_sdog(s); if (fd < 0) { @@ -766,13 +778,6 @@ static int get_sheep_fd(BDRVSheepdogState *s) socket_set_nonblock(fd); - ret = socket_set_nodelay(fd); - if (ret) { - error_report("%s", strerror(errno)); - closesocket(fd); - return -errno; - } - qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s); return fd; } @@ -789,15 +794,42 @@ static int sd_parse_uri(BDRVSheepdogState *s, const char *filename, return -EINVAL; } + /* transport */ + if (!strcmp(uri->scheme, "sheepdog")) { + s->is_unix = false; + } else if (!strcmp(uri->scheme, "sheepdog+tcp")) { + s->is_unix = false; + } else if (!strcmp(uri->scheme, "sheepdog+unix")) { + s->is_unix = true; + } else { + ret = -EINVAL; + goto out; + } + if (uri->path == NULL || !strcmp(uri->path, "/")) { ret = -EINVAL; goto out; } pstrcpy(vdi, SD_MAX_VDI_LEN, uri->path + 1); - /* sheepdog[+tcp]://[host:port]/vdiname */ - s->host_spec = g_strdup_printf("%s:%d", uri->server ?: SD_DEFAULT_ADDR, - uri->port ?: SD_DEFAULT_PORT); + qp = query_params_parse(uri->query); + if (qp->n > 1 || (s->is_unix && !qp->n) || (!s->is_unix && qp->n)) { + ret = -EINVAL; + goto out; + } + + if (s->is_unix) { + /* sheepdog+unix:///vdiname?socket=path */ + if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) { + ret = -EINVAL; + goto out; + } + s->host_spec = g_strdup(qp->p[0].value); + } else { + /* sheepdog[+tcp]://[host:port]/vdiname */ + s->host_spec = g_strdup_printf("%s:%d", uri->server ?: SD_DEFAULT_ADDR, + uri->port ?: SD_DEFAULT_PORT); + } /* snapshot tag */ if (uri->fragment) { @@ -2098,9 +2130,35 @@ static BlockDriver bdrv_sheepdog_tcp = { .create_options = sd_create_options, }; +static BlockDriver bdrv_sheepdog_unix = { + .format_name = "sheepdog", + .protocol_name = "sheepdog+unix", + .instance_size = sizeof(BDRVSheepdogState), + .bdrv_file_open = sd_open, + .bdrv_close = sd_close, + .bdrv_create = sd_create, + .bdrv_getlength = sd_getlength, + .bdrv_truncate = sd_truncate, + + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, + .bdrv_co_flush_to_disk = sd_co_flush_to_disk, + + .bdrv_snapshot_create = sd_snapshot_create, + .bdrv_snapshot_goto = sd_snapshot_goto, + .bdrv_snapshot_delete = sd_snapshot_delete, + .bdrv_snapshot_list = sd_snapshot_list, + + .bdrv_save_vmstate = sd_save_vmstate, + .bdrv_load_vmstate = sd_load_vmstate, + + .create_options = sd_create_options, +}; + static void bdrv_sheepdog_init(void) { bdrv_register(&bdrv_sheepdog); bdrv_register(&bdrv_sheepdog_tcp); + bdrv_register(&bdrv_sheepdog_unix); } block_init(bdrv_sheepdog_init); diff --git a/qemu-doc.texi b/qemu-doc.texi index 2083e29a97..af84bef0e9 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -865,6 +865,12 @@ qemu-img create -b sheepdog:///@var{base}#@var{tag} sheepdog:///@var{image} where @var{base} is a image name of the source snapshot and @var{tag} is its tag name. +You can use an unix socket instead of an inet socket: + +@example +qemu-system-i386 sheepdog+unix:///@var{image}?socket=@var{path} +@end example + If the Sheepdog daemon doesn't run on the local host, you need to specify one of the Sheepdog servers to connect to. @example diff --git a/qemu-options.hx b/qemu-options.hx index e8fb78c5eb..f598d7a395 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2100,7 +2100,7 @@ devices. Syntax for specifying a sheepdog device @example -sheepdog[+tcp]://[host:port]/vdiname[#snapid|#tag] +sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag] @end example Example From 272d2d8e1241b92ab9be87b2c8fb590fd84987a8 Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Tue, 26 Feb 2013 09:55:48 -0500 Subject: [PATCH 1353/1634] block: for HMP commit() operations on 'all', skip non-COW drives During a commit of 'all' using the HMP non-live commit, the operation is aborted and returns error on the first error enountered. When non-COW drives are in use (e.g. ejected floppy, cdrom, or drives without a backing parent), that means a commit all will return an error of either -ENOMEDIUM or -ENOTSUP. This is not desirable, so for the 'all' commit case, only attempt the commit if both bs->drv and bs->backing_hd are present. More succinctly: 'commit all' now means a commit on all COW drives. This means an individual commit to a specific non-COW drive will still return the appropriate error (-ENOMEDIUM if eject / not present, -ENOTSUP if no backing file). Reported-by: Jan Kiszka Signed-off-by: Jeff Cody Reviewed-by: Paolo Bonzini Reviewed-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- block.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 4582961965..124a9ebf65 100644 --- a/block.c +++ b/block.c @@ -1640,9 +1640,11 @@ int bdrv_commit_all(void) BlockDriverState *bs; QTAILQ_FOREACH(bs, &bdrv_states, list) { - int ret = bdrv_commit(bs); - if (ret < 0) { - return ret; + if (bs->drv && bs->backing_hd) { + int ret = bdrv_commit(bs); + if (ret < 0) { + return ret; + } } } return 0; From 20c334a797bf46a4ee59a6e42be6d5e7c3cda585 Mon Sep 17 00:00:00 2001 From: Petar Jovanovic Date: Mon, 25 Feb 2013 16:45:40 +0100 Subject: [PATCH 1354/1634] target-mips: fix DSP overflow macro and affected routines The previous implementation incorrectly used same macro to detect overflow for addition and subtraction. This patch makes distinction between these two, and creates separate macros. The affected routines are changed accordingly. This change also includes additions to the existing tests for SUBQ_S_PH and SUBQ_S_W that would trigger the fixed issue, and it removes dead code from the test file. The last test case in subq_s_w.c is a bug found/reported/ isolated by Klaus Peichl from Dolby. Signed-off-by: Petar Jovanovic Signed-off-by: Aurelien Jarno --- target-mips/dsp_helper.c | 90 ++++++++++++++------------- tests/tcg/mips/mips32-dsp/subq_s_ph.c | 22 ++++++- tests/tcg/mips/mips32-dsp/subq_s_w.c | 38 +++++++---- 3 files changed, 95 insertions(+), 55 deletions(-) diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 841f47b91d..ffa9396c4b 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -44,7 +44,8 @@ typedef union { /*** MIPS DSP internal functions begin ***/ #define MIPSDSP_ABS(x) (((x) >= 0) ? x : -x) -#define MIPSDSP_OVERFLOW(a, b, c, d) (!(!((a ^ b ^ -1) & (a ^ c) & d))) +#define MIPSDSP_OVERFLOW_ADD(a, b, c, d) (~(a ^ b) & (a ^ c) & d) +#define MIPSDSP_OVERFLOW_SUB(a, b, c, d) ((a ^ b) & (a ^ c) & d) static inline void set_DSPControl_overflow_flag(uint32_t flag, int position, CPUMIPSState *env) @@ -142,7 +143,7 @@ static inline int16_t mipsdsp_add_i16(int16_t a, int16_t b, CPUMIPSState *env) tempI = a + b; - if (MIPSDSP_OVERFLOW(a, b, tempI, 0x8000)) { + if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x8000)) { set_DSPControl_overflow_flag(1, 20, env); } @@ -156,7 +157,7 @@ static inline int16_t mipsdsp_sat_add_i16(int16_t a, int16_t b, tempS = a + b; - if (MIPSDSP_OVERFLOW(a, b, tempS, 0x8000)) { + if (MIPSDSP_OVERFLOW_ADD(a, b, tempS, 0x8000)) { if (a > 0) { tempS = 0x7FFF; } else { @@ -175,7 +176,7 @@ static inline int32_t mipsdsp_sat_add_i32(int32_t a, int32_t b, tempI = a + b; - if (MIPSDSP_OVERFLOW(a, b, tempI, 0x80000000)) { + if (MIPSDSP_OVERFLOW_ADD(a, b, tempI, 0x80000000)) { if (a > 0) { tempI = 0x7FFFFFFF; } else { @@ -858,7 +859,7 @@ static inline uint16_t mipsdsp_sub_i16(int16_t a, int16_t b, CPUMIPSState *env) int16_t temp; temp = a - b; - if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) { + if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) { set_DSPControl_overflow_flag(1, 20, env); } @@ -871,8 +872,8 @@ static inline uint16_t mipsdsp_sat16_sub(int16_t a, int16_t b, int16_t temp; temp = a - b; - if (MIPSDSP_OVERFLOW(a, -b, temp, 0x8000)) { - if (a > 0) { + if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x8000)) { + if (a >= 0) { temp = 0x7FFF; } else { temp = 0x8000; @@ -889,8 +890,8 @@ static inline uint32_t mipsdsp_sat32_sub(int32_t a, int32_t b, int32_t temp; temp = a - b; - if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) { - if (a > 0) { + if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) { + if (a >= 0) { temp = 0x7FFFFFFF; } else { temp = 0x80000000; @@ -1004,7 +1005,7 @@ static inline uint32_t mipsdsp_sub32(int32_t a, int32_t b, CPUMIPSState *env) int32_t temp; temp = a - b; - if (MIPSDSP_OVERFLOW(a, -b, temp, 0x80000000)) { + if (MIPSDSP_OVERFLOW_SUB(a, b, temp, 0x80000000)) { set_DSPControl_overflow_flag(1, 20, env); } @@ -1017,7 +1018,7 @@ static inline int32_t mipsdsp_add_i32(int32_t a, int32_t b, CPUMIPSState *env) temp = a + b; - if (MIPSDSP_OVERFLOW(a, b, temp, 0x80000000)) { + if (MIPSDSP_OVERFLOW_ADD(a, b, temp, 0x80000000)) { set_DSPControl_overflow_flag(1, 20, env); } @@ -2488,37 +2489,42 @@ DP_QH(dpsq_s_w_qh, 0, 1); #endif #define DP_L_W(name, is_add) \ -void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \ - CPUMIPSState *env) \ -{ \ - int32_t temp63; \ - int64_t dotp, acc; \ - uint64_t temp; \ - \ - dotp = mipsdsp_mul_q31_q31(ac, rs, rt, env); \ - acc = ((uint64_t)env->active_tc.HI[ac] << 32) | \ - ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); \ - if (!is_add) { \ - dotp = -dotp; \ - } \ - \ - temp = acc + dotp; \ - if (MIPSDSP_OVERFLOW((uint64_t)acc, (uint64_t)dotp, temp, \ - (0x01ull << 63))) { \ - temp63 = (temp >> 63) & 0x01; \ - if (temp63 == 1) { \ - temp = (0x01ull << 63) - 1; \ - } else { \ - temp = 0x01ull << 63; \ - } \ - \ - set_DSPControl_overflow_flag(1, 16 + ac, env); \ - } \ - \ - env->active_tc.HI[ac] = (target_long)(int32_t) \ - ((temp & MIPSDSP_LHI) >> 32); \ - env->active_tc.LO[ac] = (target_long)(int32_t) \ - (temp & MIPSDSP_LLO); \ +void helper_##name(uint32_t ac, target_ulong rs, target_ulong rt, \ + CPUMIPSState *env) \ +{ \ + int32_t temp63; \ + int64_t dotp, acc; \ + uint64_t temp; \ + bool overflow; \ + \ + dotp = mipsdsp_mul_q31_q31(ac, rs, rt, env); \ + acc = ((uint64_t)env->active_tc.HI[ac] << 32) | \ + ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); \ + if (is_add) { \ + temp = acc + dotp; \ + overflow = MIPSDSP_OVERFLOW_ADD((uint64_t)acc, (uint64_t)dotp, \ + temp, (0x01ull << 63)); \ + } else { \ + temp = acc - dotp; \ + overflow = MIPSDSP_OVERFLOW_SUB((uint64_t)acc, (uint64_t)dotp, \ + temp, (0x01ull << 63)); \ + } \ + \ + if (overflow) { \ + temp63 = (temp >> 63) & 0x01; \ + if (temp63 == 1) { \ + temp = (0x01ull << 63) - 1; \ + } else { \ + temp = 0x01ull << 63; \ + } \ + \ + set_DSPControl_overflow_flag(1, 16 + ac, env); \ + } \ + \ + env->active_tc.HI[ac] = (target_long)(int32_t) \ + ((temp & MIPSDSP_LHI) >> 32); \ + env->active_tc.LO[ac] = (target_long)(int32_t) \ + (temp & MIPSDSP_LLO); \ } DP_L_W(dpaq_sa_l_w, 1); diff --git a/tests/tcg/mips/mips32-dsp/subq_s_ph.c b/tests/tcg/mips/mips32-dsp/subq_s_ph.c index 8e36dadef9..64c89ebd51 100644 --- a/tests/tcg/mips/mips32-dsp/subq_s_ph.c +++ b/tests/tcg/mips/mips32-dsp/subq_s_ph.c @@ -12,7 +12,8 @@ int main() resultdsp = 0x01; __asm - ("subq_s.ph %0, %2, %3\n\t" + ("wrdsp $0\n\t" + "subq_s.ph %0, %2, %3\n\t" "rddsp %1\n\t" : "=r"(rd), "=r"(dsp) : "r"(rs), "r"(rt) @@ -27,7 +28,24 @@ int main() resultdsp = 0x01; __asm - ("subq_s.ph %0, %2, %3\n\t" + ("wrdsp $0\n\t" + "subq_s.ph %0, %2, %3\n\t" + "rddsp %1\n\t" + : "=r"(rd), "=r"(dsp) + : "r"(rs), "r"(rt) + ); + dsp = (dsp >> 20) & 0x01; + assert(dsp == resultdsp); + assert(rd == result); + + rs = 0x12340000; + rt = 0x87658000; + result = 0x7FFF7FFF; + resultdsp = 0x01; + + __asm + ("wrdsp $0\n\t" + "subq_s.ph %0, %2, %3\n\t" "rddsp %1\n\t" : "=r"(rd), "=r"(dsp) : "r"(rs), "r"(rt) diff --git a/tests/tcg/mips/mips32-dsp/subq_s_w.c b/tests/tcg/mips/mips32-dsp/subq_s_w.c index 09022e9c85..9d456a90f4 100644 --- a/tests/tcg/mips/mips32-dsp/subq_s_w.c +++ b/tests/tcg/mips/mips32-dsp/subq_s_w.c @@ -12,7 +12,8 @@ int main() resultdsp = 0x01; __asm - ("subq_s.w %0, %2, %3\n\t" + ("wrdsp $0\n\t" + "subq_s.w %0, %2, %3\n\t" "rddsp %1\n\t" : "=r"(rd), "=r"(dsp) : "r"(rs), "r"(rt) @@ -24,10 +25,11 @@ int main() rs = 0x66666; rt = 0x55555; result = 0x11111; - resultdsp = 0x01; + resultdsp = 0x0; __asm - ("subq_s.w %0, %2, %3\n\t" + ("wrdsp $0\n\t" + "subq_s.w %0, %2, %3\n\t" "rddsp %1\n\t" : "=r"(rd), "=r"(dsp) : "r"(rs), "r"(rt) @@ -36,23 +38,37 @@ int main() assert(dsp == resultdsp); assert(rd == result); - -#if 0 - rs = 0x35555555; - rt = 0xf5555555; - result = 0x80000000; + rs = 0x0; + rt = 0x80000000; + result = 0x7FFFFFFF; resultdsp = 0x01; __asm - ("subq_s.w %0, %2, %3\n\t" + ("wrdsp $0\n\t" + "subq_s.w %0, %2, %3\n\t" "rddsp %1\n\t" : "=r"(rd), "=r"(dsp) : "r"(rs), "r"(rt) ); - dsp = (dsp >> 20) & 0x01; assert(dsp == resultdsp); assert(rd == result); -#endif + + rs = 0x80000000; + rt = 0x80000000; + result = 0; + resultdsp = 0x00; + + __asm + ("wrdsp $0\n\t" + "subq_s.w %0, %2, %3\n\t" + "rddsp %1\n\t" + : "=r"(rd), "=r"(dsp) + : "r"(rs), "r"(rt) + ); + dsp = (dsp >> 20) & 0x01; + assert(dsp == resultdsp); + assert(rd == result); + return 0; } From 54b2f42cb1eef758b6070e805a5d6f7a84315ace Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Thu, 10 Jan 2013 16:50:22 -0600 Subject: [PATCH 1355/1634] target-mips: Translate breaks and traps into the appropriate signal GCC and GAS are capable of generating traps or breaks to check for division by zero. Additionally, GAS is capable of generating traps or breaks to check for overflow on certain division and multiplication operations. The Linux kernel translates these traps and breaks into signals. This patch implements the corresponding feature in QEMU. Signed-off-by: Meador Inge Signed-off-by: Aurelien Jarno --- linux-user/main.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 29845f9c81..cb14c0bcad 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2186,6 +2186,33 @@ static int do_store_exclusive(CPUMIPSState *env) return segv; } +/* Break codes */ +enum { + BRK_OVERFLOW = 6, + BRK_DIVZERO = 7 +}; + +static int do_break(CPUMIPSState *env, target_siginfo_t *info, + unsigned int code) +{ + int ret = -1; + + switch (code) { + case BRK_OVERFLOW: + case BRK_DIVZERO: + info->si_signo = TARGET_SIGFPE; + info->si_errno = 0; + info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; + queue_signal(env, info->si_signo, &*info); + ret = 0; + break; + default: + break; + } + + return ret; +} + void cpu_loop(CPUMIPSState *env) { CPUState *cs = CPU(mips_env_get_cpu(env)); @@ -2302,8 +2329,55 @@ done_syscall: info.si_code = TARGET_ILL_ILLOPC; queue_signal(env, info.si_signo, &info); break; + /* The code below was inspired by the MIPS Linux kernel trap + * handling code in arch/mips/kernel/traps.c. + */ + case EXCP_BREAK: + { + abi_ulong trap_instr; + unsigned int code; + + ret = get_user_ual(trap_instr, env->active_tc.PC); + if (ret != 0) { + goto error; + } + + /* As described in the original Linux kernel code, the + * below checks on 'code' are to work around an old + * assembly bug. + */ + code = ((trap_instr >> 6) & ((1 << 20) - 1)); + if (code >= (1 << 10)) { + code >>= 10; + } + + if (do_break(env, &info, code) != 0) { + goto error; + } + } + break; + case EXCP_TRAP: + { + abi_ulong trap_instr; + unsigned int code = 0; + + ret = get_user_ual(trap_instr, env->active_tc.PC); + if (ret != 0) { + goto error; + } + + /* The immediate versions don't provide a code. */ + if (!(trap_instr & 0xFC000000)) { + code = ((trap_instr >> 6) & ((1 << 10) - 1)); + } + + if (do_break(env, &info, code) != 0) { + goto error; + } + } + break; default: - // error: +error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); cpu_dump_state(env, stderr, fprintf, 0); From 26135ead80fa1fd13e95c162dacfd06f2ba82981 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 21 Jan 2013 20:43:31 +0000 Subject: [PATCH 1356/1634] target-mips: Fix accumulator selection for MIPS16 and microMIPS Add accumulator arguments to gen_HILO and gen_muldiv, rather than extracting the accumulator directly from ctx->opcode. The extraction was only right for the standard encoding: MIPS16 doesn't have access to the DSP registers, while microMIPS encodes the accumulator register in a different field (bits 14 and 15). Passing the accumulator register is probably an over-generalisation for division and 64-bit multiplication, which never access anything other than HI and LO, and which always pass 0 as the new argument. Separating them felt a bit fussy though. Signed-off-by: Richard Sandiford Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 148 +++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 84 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 6ce2f03ddb..a51f4303ab 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2582,10 +2582,9 @@ static void gen_shift(DisasContext *ctx, uint32_t opc, } /* Arithmetic on HI/LO registers */ -static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) +static void gen_HILO(DisasContext *ctx, uint32_t opc, int acc, int reg) { const char *opn = "hilo"; - unsigned int acc; if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) { /* Treat as NOP. */ @@ -2593,12 +2592,6 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) return; } - if (opc == OPC_MFHI || opc == OPC_MFLO) { - acc = ((ctx->opcode) >> 21) & 0x03; - } else { - acc = ((ctx->opcode) >> 11) & 0x03; - } - if (acc != 0) { check_dsp(ctx); } @@ -2661,12 +2654,11 @@ static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg) MIPS_DEBUG("%s %s", opn, regnames[reg]); } -static void gen_muldiv (DisasContext *ctx, uint32_t opc, - int rs, int rt) +static void gen_muldiv(DisasContext *ctx, uint32_t opc, + int acc, int rs, int rt) { const char *opn = "mul/div"; TCGv t0, t1; - unsigned int acc; t0 = tcg_temp_new(); t1 = tcg_temp_new(); @@ -2674,6 +2666,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, gen_load_gpr(t0, rs); gen_load_gpr(t1, rt); + if (acc != 0) { + check_dsp(ctx); + } + switch (opc) { case OPC_DIV: { @@ -2688,10 +2684,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, tcg_gen_or_tl(t2, t2, t3); tcg_gen_movi_tl(t3, 0); tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); - tcg_gen_div_tl(cpu_LO[0], t0, t1); - tcg_gen_rem_tl(cpu_HI[0], t0, t1); - tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]); - tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]); + tcg_gen_div_tl(cpu_LO[acc], t0, t1); + tcg_gen_rem_tl(cpu_HI[acc], t0, t1); + tcg_gen_ext32s_tl(cpu_LO[acc], cpu_LO[acc]); + tcg_gen_ext32s_tl(cpu_HI[acc], cpu_HI[acc]); tcg_temp_free(t3); tcg_temp_free(t2); } @@ -2704,10 +2700,10 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, tcg_gen_ext32u_tl(t0, t0); tcg_gen_ext32u_tl(t1, t1); tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); - tcg_gen_divu_tl(cpu_LO[0], t0, t1); - tcg_gen_remu_tl(cpu_HI[0], t0, t1); - tcg_gen_ext32s_tl(cpu_LO[0], cpu_LO[0]); - tcg_gen_ext32s_tl(cpu_HI[0], cpu_HI[0]); + tcg_gen_divu_tl(cpu_LO[acc], t0, t1); + tcg_gen_remu_tl(cpu_HI[acc], t0, t1); + tcg_gen_ext32s_tl(cpu_LO[acc], cpu_LO[acc]); + tcg_gen_ext32s_tl(cpu_HI[acc], cpu_HI[acc]); tcg_temp_free(t3); tcg_temp_free(t2); } @@ -2717,11 +2713,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_i32 t3 = tcg_temp_new_i32(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } - tcg_gen_trunc_tl_i32(t2, t0); tcg_gen_trunc_tl_i32(t3, t1); tcg_gen_muls2_i32(t2, t3, t2, t3); @@ -2736,11 +2727,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i32 t2 = tcg_temp_new_i32(); TCGv_i32 t3 = tcg_temp_new_i32(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } - tcg_gen_trunc_tl_i32(t2, t0); tcg_gen_trunc_tl_i32(t3, t1); tcg_gen_mulu2_i32(t2, t3, t2, t3); @@ -2763,8 +2749,8 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, tcg_gen_or_tl(t2, t2, t3); tcg_gen_movi_tl(t3, 0); tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); - tcg_gen_div_tl(cpu_LO[0], t0, t1); - tcg_gen_rem_tl(cpu_HI[0], t0, t1); + tcg_gen_div_tl(cpu_LO[acc], t0, t1); + tcg_gen_rem_tl(cpu_HI[acc], t0, t1); tcg_temp_free(t3); tcg_temp_free(t2); } @@ -2775,19 +2761,19 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, TCGv t2 = tcg_const_tl(0); TCGv t3 = tcg_const_tl(1); tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); - tcg_gen_divu_i64(cpu_LO[0], t0, t1); - tcg_gen_remu_i64(cpu_HI[0], t0, t1); + tcg_gen_divu_i64(cpu_LO[acc], t0, t1); + tcg_gen_remu_i64(cpu_HI[acc], t0, t1); tcg_temp_free(t3); tcg_temp_free(t2); } opn = "ddivu"; break; case OPC_DMULT: - tcg_gen_muls2_i64(cpu_LO[0], cpu_HI[0], t0, t1); + tcg_gen_muls2_i64(cpu_LO[acc], cpu_HI[acc], t0, t1); opn = "dmult"; break; case OPC_DMULTU: - tcg_gen_mulu2_i64(cpu_LO[0], cpu_HI[0], t0, t1); + tcg_gen_mulu2_i64(cpu_LO[acc], cpu_HI[acc], t0, t1); opn = "dmultu"; break; #endif @@ -2795,10 +2781,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext_tl_i64(t2, t0); tcg_gen_ext_tl_i64(t3, t1); @@ -2819,10 +2801,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext32u_tl(t0, t0); tcg_gen_ext32u_tl(t1, t1); @@ -2845,10 +2823,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext_tl_i64(t2, t0); tcg_gen_ext_tl_i64(t3, t1); @@ -2869,10 +2843,6 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, { TCGv_i64 t2 = tcg_temp_new_i64(); TCGv_i64 t3 = tcg_temp_new_i64(); - acc = ((ctx->opcode) >> 11) & 0x03; - if (acc != 0) { - check_dsp(ctx); - } tcg_gen_ext32u_tl(t0, t0); tcg_gen_ext32u_tl(t1, t1); @@ -10135,7 +10105,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, gen_logic(ctx, OPC_NOR, rx, ry, 0); break; case RR_MFHI: - gen_HILO(ctx, OPC_MFHI, rx); + gen_HILO(ctx, OPC_MFHI, 0, rx); break; case RR_CNVT: switch (cnvt_op) { @@ -10167,7 +10137,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, } break; case RR_MFLO: - gen_HILO(ctx, OPC_MFLO, rx); + gen_HILO(ctx, OPC_MFLO, 0, rx); break; #if defined (TARGET_MIPS64) case RR_DSRA: @@ -10188,33 +10158,33 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, break; #endif case RR_MULT: - gen_muldiv(ctx, OPC_MULT, rx, ry); + gen_muldiv(ctx, OPC_MULT, 0, rx, ry); break; case RR_MULTU: - gen_muldiv(ctx, OPC_MULTU, rx, ry); + gen_muldiv(ctx, OPC_MULTU, 0, rx, ry); break; case RR_DIV: - gen_muldiv(ctx, OPC_DIV, rx, ry); + gen_muldiv(ctx, OPC_DIV, 0, rx, ry); break; case RR_DIVU: - gen_muldiv(ctx, OPC_DIVU, rx, ry); + gen_muldiv(ctx, OPC_DIVU, 0, rx, ry); break; #if defined (TARGET_MIPS64) case RR_DMULT: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DMULT, rx, ry); + gen_muldiv(ctx, OPC_DMULT, 0, rx, ry); break; case RR_DMULTU: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DMULTU, rx, ry); + gen_muldiv(ctx, OPC_DMULTU, 0, rx, ry); break; case RR_DDIV: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DDIV, rx, ry); + gen_muldiv(ctx, OPC_DDIV, 0, rx, ry); break; case RR_DDIVU: check_mips_64(ctx); - gen_muldiv(ctx, OPC_DDIVU, rx, ry); + gen_muldiv(ctx, OPC_DDIVU, 0, rx, ry); break; #endif default: @@ -10923,11 +10893,11 @@ static void gen_pool16c_insn(DisasContext *ctx, int *is_branch) break; case MFHI16 + 0: case MFHI16 + 1: - gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode)); + gen_HILO(ctx, OPC_MFHI, 0, uMIPS_RS5(ctx->opcode)); break; case MFLO16 + 0: case MFLO16 + 1: - gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode)); + gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode)); break; case BREAK16: generate_exception(ctx, EXCP_BREAK); @@ -11125,30 +11095,34 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, break; case MULT: mips32_op = OPC_MULT; - goto do_muldiv; + goto do_mul; case MULTU: mips32_op = OPC_MULTU; - goto do_muldiv; + goto do_mul; case DIV: mips32_op = OPC_DIV; - goto do_muldiv; + goto do_div; case DIVU: mips32_op = OPC_DIVU; - goto do_muldiv; + goto do_div; + do_div: + check_insn(ctx, ISA_MIPS32); + gen_muldiv(ctx, mips32_op, 0, rs, rt); + break; case MADD: mips32_op = OPC_MADD; - goto do_muldiv; + goto do_mul; case MADDU: mips32_op = OPC_MADDU; - goto do_muldiv; + goto do_mul; case MSUB: mips32_op = OPC_MSUB; - goto do_muldiv; + goto do_mul; case MSUBU: mips32_op = OPC_MSUBU; - do_muldiv: + do_mul: check_insn(ctx, ISA_MIPS32); - gen_muldiv(ctx, mips32_op, rs, rt); + gen_muldiv(ctx, mips32_op, (ctx->opcode >> 14) & 3, rs, rt); break; default: goto pool32axf_invalid; @@ -11285,18 +11259,18 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, } break; case 0x35: - switch (minor) { + switch (minor & 3) { case MFHI32: - gen_HILO(ctx, OPC_MFHI, rs); + gen_HILO(ctx, OPC_MFHI, minor >> 2, rs); break; case MFLO32: - gen_HILO(ctx, OPC_MFLO, rs); + gen_HILO(ctx, OPC_MFLO, minor >> 2, rs); break; case MTHI32: - gen_HILO(ctx, OPC_MTHI, rs); + gen_HILO(ctx, OPC_MTHI, minor >> 2, rs); break; case MTLO32: - gen_HILO(ctx, OPC_MTLO, rs); + gen_HILO(ctx, OPC_MTLO, minor >> 2, rs); break; default: goto pool32axf_invalid; @@ -14469,13 +14443,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_XOR: gen_logic(ctx, op1, rd, rs, rt); break; - case OPC_MULT ... OPC_DIVU: + case OPC_MULT: + case OPC_MULTU: if (sa) { check_insn(ctx, INSN_VR54XX); op1 = MASK_MUL_VR54XX(ctx->opcode); gen_mul_vr54xx(ctx, op1, rd, rs, rt); - } else - gen_muldiv(ctx, op1, rs, rt); + } else { + gen_muldiv(ctx, op1, rd & 3, rs, rt); + } + break; + case OPC_DIV: + case OPC_DIVU: + gen_muldiv(ctx, op1, 0, rs, rt); break; case OPC_JR ... OPC_JALR: gen_compute_branch(ctx, op1, 4, rs, rd, sa); @@ -14487,11 +14467,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) break; case OPC_MFHI: /* Move from HI/LO */ case OPC_MFLO: - gen_HILO(ctx, op1, rd); + gen_HILO(ctx, op1, rs & 3, rd); break; case OPC_MTHI: case OPC_MTLO: /* Move to HI/LO */ - gen_HILO(ctx, op1, rs); + gen_HILO(ctx, op1, rd & 3, rs); break; case OPC_PMON: /* Pmon entry point, also R4010 selsl */ #ifdef MIPS_STRICT_STANDARD @@ -14611,7 +14591,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_DMULT ... OPC_DDIVU: check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); - gen_muldiv(ctx, op1, rs, rt); + gen_muldiv(ctx, op1, 0, rs, rt); break; #endif default: /* Invalid */ @@ -14626,7 +14606,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */ case OPC_MSUB ... OPC_MSUBU: check_insn(ctx, ISA_MIPS32); - gen_muldiv(ctx, op1, rs, rt); + gen_muldiv(ctx, op1, rd & 3, rs, rt); break; case OPC_MUL: gen_arith(ctx, op1, rd, rs, rt); From 81465888c5306cd94abb9847e560796fd13d3c2f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:31:17 +0000 Subject: [PATCH 1357/1634] target-arm: Factor out handling of SRS instruction Factor out the handling of the SRS instruction rather than duplicating it between the Thumb and ARM decoders. This in passing fixes two bugs in the Thumb decoder's SRS handling which didn't exist in the ARM decoder: * (LP:1079080) storing CPSR rather than SPSR (fixed in the ARM decoder in commit c67b6b71 in 2009) * failing to free the 'addr' TCG temp in the writeback case Reported-by: Cesson Vincent Signed-off-by: Peter Maydell --- target-arm/translate.c | 136 +++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index db63c6ef7d..e16c113348 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -6601,6 +6601,70 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, } #endif +/* gen_srs: + * @env: CPUARMState + * @s: DisasContext + * @mode: mode field from insn (which stack to store to) + * @amode: addressing mode (DA/IA/DB/IB), encoded as per P,U bits in ARM insn + * @writeback: true if writeback bit set + * + * Generate code for the SRS (Store Return State) insn. + */ +static void gen_srs(DisasContext *s, + uint32_t mode, uint32_t amode, bool writeback) +{ + int32_t offset; + TCGv_i32 addr = tcg_temp_new_i32(); + TCGv_i32 tmp = tcg_const_i32(mode); + gen_helper_get_r13_banked(addr, cpu_env, tmp); + tcg_temp_free_i32(tmp); + switch (amode) { + case 0: /* DA */ + offset = -4; + break; + case 1: /* IA */ + offset = 0; + break; + case 2: /* DB */ + offset = -8; + break; + case 3: /* IB */ + offset = 4; + break; + default: + abort(); + } + tcg_gen_addi_i32(addr, addr, offset); + tmp = load_reg(s, 14); + gen_st32(tmp, addr, 0); + tmp = load_cpu_field(spsr); + tcg_gen_addi_i32(addr, addr, 4); + gen_st32(tmp, addr, 0); + if (writeback) { + switch (amode) { + case 0: + offset = -8; + break; + case 1: + offset = 4; + break; + case 2: + offset = -4; + break; + case 3: + offset = 0; + break; + default: + abort(); + } + tcg_gen_addi_i32(addr, addr, offset); + tmp = tcg_const_i32(mode); + gen_helper_set_r13_banked(cpu_env, tmp, addr); + tcg_temp_free_i32(tmp); + } + tcg_temp_free_i32(addr); +} + static void disas_arm_insn(CPUARMState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; @@ -6693,49 +6757,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) } } else if ((insn & 0x0e5fffe0) == 0x084d0500) { /* srs */ - int32_t offset; - if (IS_USER(s)) + if (IS_USER(s)) { goto illegal_op; + } ARCH(6); - op1 = (insn & 0x1f); - addr = tcg_temp_new_i32(); - tmp = tcg_const_i32(op1); - gen_helper_get_r13_banked(addr, cpu_env, tmp); - tcg_temp_free_i32(tmp); - i = (insn >> 23) & 3; - switch (i) { - case 0: offset = -4; break; /* DA */ - case 1: offset = 0; break; /* IA */ - case 2: offset = -8; break; /* DB */ - case 3: offset = 4; break; /* IB */ - default: abort(); - } - if (offset) - tcg_gen_addi_i32(addr, addr, offset); - tmp = load_reg(s, 14); - gen_st32(tmp, addr, 0); - tmp = load_cpu_field(spsr); - tcg_gen_addi_i32(addr, addr, 4); - gen_st32(tmp, addr, 0); - if (insn & (1 << 21)) { - /* Base writeback. */ - switch (i) { - case 0: offset = -8; break; - case 1: offset = 4; break; - case 2: offset = -4; break; - case 3: offset = 0; break; - default: abort(); - } - if (offset) - tcg_gen_addi_i32(addr, addr, offset); - tmp = tcg_const_i32(op1); - gen_helper_set_r13_banked(cpu_env, tmp, addr); - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(addr); - } else { - tcg_temp_free_i32(addr); - } - return; + gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21)); } else if ((insn & 0x0e50ffe0) == 0x08100a00) { /* rfe */ int32_t offset; @@ -8180,32 +8206,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw gen_rfe(s, tmp, tmp2); } else { /* srs */ - op = (insn & 0x1f); - addr = tcg_temp_new_i32(); - tmp = tcg_const_i32(op); - gen_helper_get_r13_banked(addr, cpu_env, tmp); - tcg_temp_free_i32(tmp); - if ((insn & (1 << 24)) == 0) { - tcg_gen_addi_i32(addr, addr, -8); - } - tmp = load_reg(s, 14); - gen_st32(tmp, addr, 0); - tcg_gen_addi_i32(addr, addr, 4); - tmp = tcg_temp_new_i32(); - gen_helper_cpsr_read(tmp, cpu_env); - gen_st32(tmp, addr, 0); - if (insn & (1 << 21)) { - if ((insn & (1 << 24)) == 0) { - tcg_gen_addi_i32(addr, addr, -4); - } else { - tcg_gen_addi_i32(addr, addr, 4); - } - tmp = tcg_const_i32(op); - gen_helper_set_r13_banked(cpu_env, tmp, addr); - tcg_temp_free_i32(tmp); - } else { - tcg_temp_free_i32(addr); - } + gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2, + insn & (1 << 21)); } } else { int i, loaded_base = 0; From 00115976bb066d4b33dbb07a92f8bde5ec8b9518 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:31:17 +0000 Subject: [PATCH 1358/1634] target-arm: Don't decode RFE or SRS on M profile cores M profile cores do not have the RFE or SRS instructions, so correctly UNDEF these insn patterns on those cores. Signed-off-by: Peter Maydell --- target-arm/translate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index e16c113348..35a21be931 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8180,9 +8180,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw } else { /* Load/store multiple, RFE, SRS. */ if (((insn >> 23) & 1) == ((insn >> 24) & 1)) { - /* Not available in user mode. */ - if (IS_USER(s)) + /* RFE, SRS: not available in user mode or on M profile */ + if (IS_USER(s) || IS_M(env)) { goto illegal_op; + } if (insn & (1 << 20)) { /* rfe */ addr = load_reg(s, rn); From 2e07b297e0b450fe38bab115f71749e032d7191c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:40 +0000 Subject: [PATCH 1359/1634] oslib-posix: Align to permit transparent hugepages on ARM Linux ARM Linux (like x86-64 Linux) can use transparent hugepages for KVM if memory blocks are 2MiB aligned; set QEMU_VMALLOC_ALIGN accordingly. Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini --- util/oslib-posix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index b4152fb33c..433dd6888b 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -35,7 +35,7 @@ extern int daemon(int, int); #endif -#if defined(__linux__) && defined(__x86_64__) +#if defined(__linux__) && (defined(__x86_64__) || defined(__arm__)) /* Use 2 MiB alignment so transparent hugepages can be used by KVM. Valgrind does not support alignments larger than 1 MiB, therefore we need special code which handles running on Valgrind. */ From eadd0e4413c9b69015c798909f48ec48ab0c7bd4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:40 +0000 Subject: [PATCH 1360/1634] linux-headers: resync from mainline to add ARM KVM headers Resync QEMU's copy of the Linux kernel headers from git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master commit 2ef14f4. This adds the ARM KVM headers, since ARM KVM support has just hit mainline via Russell's ARM tree. This is not a pure sync -- I have removed by hand some changes that would have reverted updates for s390x and ppc which have not yet hit mainline. Signed-off-by: Peter Maydell --- linux-headers/asm-arm/kvm.h | 180 +++++++++++++++++++++++++++ linux-headers/asm-arm/kvm_para.h | 1 + linux-headers/asm-generic/kvm_para.h | 4 + linux-headers/linux/kvm.h | 17 +++ 4 files changed, 202 insertions(+) create mode 100644 linux-headers/asm-arm/kvm.h create mode 100644 linux-headers/asm-arm/kvm_para.h create mode 100644 linux-headers/asm-generic/kvm_para.h diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h new file mode 100644 index 0000000000..023bfeb367 --- /dev/null +++ b/linux-headers/asm-arm/kvm.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2012 - Virtual Open Systems and Columbia University + * Author: Christoffer Dall + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARM_KVM_H__ +#define __ARM_KVM_H__ + +#include +#include + +#define __KVM_HAVE_GUEST_DEBUG +#define __KVM_HAVE_IRQ_LINE + +#define KVM_REG_SIZE(id) \ + (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) + +/* Valid for svc_regs, abt_regs, und_regs, irq_regs in struct kvm_regs */ +#define KVM_ARM_SVC_sp svc_regs[0] +#define KVM_ARM_SVC_lr svc_regs[1] +#define KVM_ARM_SVC_spsr svc_regs[2] +#define KVM_ARM_ABT_sp abt_regs[0] +#define KVM_ARM_ABT_lr abt_regs[1] +#define KVM_ARM_ABT_spsr abt_regs[2] +#define KVM_ARM_UND_sp und_regs[0] +#define KVM_ARM_UND_lr und_regs[1] +#define KVM_ARM_UND_spsr und_regs[2] +#define KVM_ARM_IRQ_sp irq_regs[0] +#define KVM_ARM_IRQ_lr irq_regs[1] +#define KVM_ARM_IRQ_spsr irq_regs[2] + +/* Valid only for fiq_regs in struct kvm_regs */ +#define KVM_ARM_FIQ_r8 fiq_regs[0] +#define KVM_ARM_FIQ_r9 fiq_regs[1] +#define KVM_ARM_FIQ_r10 fiq_regs[2] +#define KVM_ARM_FIQ_fp fiq_regs[3] +#define KVM_ARM_FIQ_ip fiq_regs[4] +#define KVM_ARM_FIQ_sp fiq_regs[5] +#define KVM_ARM_FIQ_lr fiq_regs[6] +#define KVM_ARM_FIQ_spsr fiq_regs[7] + +struct kvm_regs { + struct pt_regs usr_regs;/* R0_usr - R14_usr, PC, CPSR */ + __u32 svc_regs[3]; /* SP_svc, LR_svc, SPSR_svc */ + __u32 abt_regs[3]; /* SP_abt, LR_abt, SPSR_abt */ + __u32 und_regs[3]; /* SP_und, LR_und, SPSR_und */ + __u32 irq_regs[3]; /* SP_irq, LR_irq, SPSR_irq */ + __u32 fiq_regs[8]; /* R8_fiq - R14_fiq, SPSR_fiq */ +}; + +/* Supported Processor Types */ +#define KVM_ARM_TARGET_CORTEX_A15 0 +#define KVM_ARM_NUM_TARGETS 1 + +/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ +#define KVM_ARM_DEVICE_TYPE_SHIFT 0 +#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT) +#define KVM_ARM_DEVICE_ID_SHIFT 16 +#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT) + +/* Supported device IDs */ +#define KVM_ARM_DEVICE_VGIC_V2 0 + +/* Supported VGIC address types */ +#define KVM_VGIC_V2_ADDR_TYPE_DIST 0 +#define KVM_VGIC_V2_ADDR_TYPE_CPU 1 + +#define KVM_VGIC_V2_DIST_SIZE 0x1000 +#define KVM_VGIC_V2_CPU_SIZE 0x2000 + +#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ + +struct kvm_vcpu_init { + __u32 target; + __u32 features[7]; +}; + +struct kvm_sregs { +}; + +struct kvm_fpu { +}; + +struct kvm_guest_debug_arch { +}; + +struct kvm_debug_exit_arch { +}; + +struct kvm_sync_regs { +}; + +struct kvm_arch_memory_slot { +}; + +/* If you need to interpret the index values, here is the key: */ +#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000 +#define KVM_REG_ARM_COPROC_SHIFT 16 +#define KVM_REG_ARM_32_OPC2_MASK 0x0000000000000007 +#define KVM_REG_ARM_32_OPC2_SHIFT 0 +#define KVM_REG_ARM_OPC1_MASK 0x0000000000000078 +#define KVM_REG_ARM_OPC1_SHIFT 3 +#define KVM_REG_ARM_CRM_MASK 0x0000000000000780 +#define KVM_REG_ARM_CRM_SHIFT 7 +#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800 +#define KVM_REG_ARM_32_CRN_SHIFT 11 + +/* Normal registers are mapped as coprocessor 16. */ +#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) + +/* Some registers need more space to represent values. */ +#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00 +#define KVM_REG_ARM_DEMUX_ID_SHIFT 8 +#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT) +#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF +#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0 + +/* VFP registers: we could overload CP10 like ARM does, but that's ugly. */ +#define KVM_REG_ARM_VFP (0x0012 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_VFP_MASK 0x000000000000FFFF +#define KVM_REG_ARM_VFP_BASE_REG 0x0 +#define KVM_REG_ARM_VFP_FPSID 0x1000 +#define KVM_REG_ARM_VFP_FPSCR 0x1001 +#define KVM_REG_ARM_VFP_MVFR1 0x1006 +#define KVM_REG_ARM_VFP_MVFR0 0x1007 +#define KVM_REG_ARM_VFP_FPEXC 0x1008 +#define KVM_REG_ARM_VFP_FPINST 0x1009 +#define KVM_REG_ARM_VFP_FPINST2 0x100A + + +/* KVM_IRQ_LINE irq field index values */ +#define KVM_ARM_IRQ_TYPE_SHIFT 24 +#define KVM_ARM_IRQ_TYPE_MASK 0xff +#define KVM_ARM_IRQ_VCPU_SHIFT 16 +#define KVM_ARM_IRQ_VCPU_MASK 0xff +#define KVM_ARM_IRQ_NUM_SHIFT 0 +#define KVM_ARM_IRQ_NUM_MASK 0xffff + +/* irq_type field */ +#define KVM_ARM_IRQ_TYPE_CPU 0 +#define KVM_ARM_IRQ_TYPE_SPI 1 +#define KVM_ARM_IRQ_TYPE_PPI 2 + +/* out-of-kernel GIC cpu interrupt injection irq_number field */ +#define KVM_ARM_IRQ_CPU_IRQ 0 +#define KVM_ARM_IRQ_CPU_FIQ 1 + +/* Highest supported SPI, from VGIC_NR_IRQS */ +#define KVM_ARM_IRQ_GIC_MAX 127 + +/* PSCI interface */ +#define KVM_PSCI_FN_BASE 0x95c1ba5e +#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n)) + +#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0) +#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1) +#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) +#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) + +#define KVM_PSCI_RET_SUCCESS 0 +#define KVM_PSCI_RET_NI ((unsigned long)-1) +#define KVM_PSCI_RET_INVAL ((unsigned long)-2) +#define KVM_PSCI_RET_DENIED ((unsigned long)-3) + +#endif /* __ARM_KVM_H__ */ diff --git a/linux-headers/asm-arm/kvm_para.h b/linux-headers/asm-arm/kvm_para.h new file mode 100644 index 0000000000..14fab8f0b9 --- /dev/null +++ b/linux-headers/asm-arm/kvm_para.h @@ -0,0 +1 @@ +#include diff --git a/linux-headers/asm-generic/kvm_para.h b/linux-headers/asm-generic/kvm_para.h new file mode 100644 index 0000000000..486f0af73c --- /dev/null +++ b/linux-headers/asm-generic/kvm_para.h @@ -0,0 +1,4 @@ +/* + * There isn't anything here, but the file must not be empty or patch + * will delete it. + */ diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 5af935761c..caca979c49 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -115,6 +115,7 @@ struct kvm_irq_level { * ACPI gsi notion of irq. * For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23.. + * For ARM: See Documentation/virtual/kvm/api.txt */ union { __u32 irq; @@ -662,6 +663,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_PPC_HTAB_FD 84 #define KVM_CAP_S390_CSS_SUPPORT 85 #define KVM_CAP_PPC_EPR 86 +#define KVM_CAP_ARM_PSCI 87 +#define KVM_CAP_ARM_SET_DEVICE_ADDR 88 #ifdef KVM_CAP_IRQ_ROUTING @@ -791,6 +794,11 @@ struct kvm_dirty_tlb { #define KVM_REG_SIZE_U512 0x0060000000000000ULL #define KVM_REG_SIZE_U1024 0x0070000000000000ULL +struct kvm_reg_list { + __u64 n; /* number of regs */ + __u64 reg[0]; +}; + struct kvm_one_reg { __u64 id; __u64 addr; @@ -804,6 +812,11 @@ struct kvm_msi { __u8 pad[16]; }; +struct kvm_arm_device_addr { + __u64 id; + __u64 addr; +}; + /* * ioctls for VM fds */ @@ -889,6 +902,8 @@ struct kvm_s390_ucas_mapping { #define KVM_ALLOCATE_RMA _IOR(KVMIO, 0xa9, struct kvm_allocate_rma) /* Available with KVM_CAP_PPC_HTAB_FD */ #define KVM_PPC_GET_HTAB_FD _IOW(KVMIO, 0xaa, struct kvm_get_htab_fd) +/* Available with KVM_CAP_ARM_SET_DEVICE_ADDR */ +#define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr) /* * ioctls for vcpu fds @@ -959,6 +974,8 @@ struct kvm_s390_ucas_mapping { #define KVM_SET_ONE_REG _IOW(KVMIO, 0xac, struct kvm_one_reg) /* VM is being stopped by host */ #define KVM_KVMCLOCK_CTRL _IO(KVMIO, 0xad) +#define KVM_ARM_VCPU_INIT _IOW(KVMIO, 0xae, struct kvm_vcpu_init) +#define KVM_GET_REG_LIST _IOWR(KVMIO, 0xb0, struct kvm_reg_list) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) From f5206413affd658e2fdcf893c810d715b2c7fec6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:40 +0000 Subject: [PATCH 1361/1634] target-arm: Drop CPUARMState* argument from bank_number() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the CPUARMState* argument from bank_number(), since we only use it for passing to cpu_abort(). Use hw_error() instead. This avoids propagating further interfaces using env pointers. In the long term this function's callers need auditing to fix problems where badly behaved guests can pass invalid bank numbers. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber --- target-arm/helper.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index e97e1a59c7..7fa4ba0adc 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1617,7 +1617,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode) #else /* Map CPU modes onto saved register banks. */ -static inline int bank_number(CPUARMState *env, int mode) +static inline int bank_number(int mode) { switch (mode) { case ARM_CPU_MODE_USR: @@ -1634,8 +1634,7 @@ static inline int bank_number(CPUARMState *env, int mode) case ARM_CPU_MODE_FIQ: return 5; } - cpu_abort(env, "Bad mode %x\n", mode); - return -1; + hw_error("bank number requested for bad CPSR mode value 0x%x\n", mode); } void switch_mode(CPUARMState *env, int mode) @@ -1655,12 +1654,12 @@ void switch_mode(CPUARMState *env, int mode) memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); } - i = bank_number(env, old_mode); + i = bank_number(old_mode); env->banked_r13[i] = env->regs[13]; env->banked_r14[i] = env->regs[14]; env->banked_spsr[i] = env->spsr; - i = bank_number(env, mode); + i = bank_number(mode); env->regs[13] = env->banked_r13[i]; env->regs[14] = env->banked_r14[i]; env->spsr = env->banked_spsr[i]; @@ -2530,7 +2529,7 @@ void HELPER(set_r13_banked)(CPUARMState *env, uint32_t mode, uint32_t val) if ((env->uncached_cpsr & CPSR_M) == mode) { env->regs[13] = val; } else { - env->banked_r13[bank_number(env, mode)] = val; + env->banked_r13[bank_number(mode)] = val; } } @@ -2539,7 +2538,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode) if ((env->uncached_cpsr & CPSR_M) == mode) { return env->regs[13]; } else { - return env->banked_r13[bank_number(env, mode)]; + return env->banked_r13[bank_number(mode)]; } } From 494b00c76afb906a2d093b71c8772331c2a19a89 Mon Sep 17 00:00:00 2001 From: Christoffer Dall Date: Tue, 5 Mar 2013 00:34:41 +0000 Subject: [PATCH 1362/1634] ARM: KVM: Add support for KVM on ARM architecture Add basic support for KVM on ARM architecture. Signed-off-by: Christoffer Dall [PMM: Minor tweaks and code cleanup, switch to ONE_REG] Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini --- hw/arm_pic.c | 26 +++ target-arm/Makefile.objs | 1 + target-arm/cpu.h | 1 + target-arm/helper.c | 2 +- target-arm/kvm.c | 334 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 target-arm/kvm.c diff --git a/hw/arm_pic.c b/hw/arm_pic.c index ffb4d4171a..394bc93cb9 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -9,6 +9,7 @@ #include "hw.h" #include "arm-misc.h" +#include "sysemu/kvm.h" /* Input 0 is IRQ and input 1 is FIQ. */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) @@ -34,7 +35,32 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level) } } +static void kvm_arm_pic_cpu_handler(void *opaque, int irq, int level) +{ +#ifdef CONFIG_KVM + ARMCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT; + + switch (irq) { + case ARM_PIC_CPU_IRQ: + kvm_irq |= KVM_ARM_IRQ_CPU_IRQ; + break; + case ARM_PIC_CPU_FIQ: + kvm_irq |= KVM_ARM_IRQ_CPU_FIQ; + break; + default: + hw_error("kvm_arm_pic_cpu_handler: Bad interrupt line %d\n", irq); + } + kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT; + kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0); +#endif +} + qemu_irq *arm_pic_init_cpu(ARMCPU *cpu) { + if (kvm_enabled()) { + return qemu_allocate_irqs(kvm_arm_pic_cpu_handler, cpu, 2); + } return qemu_allocate_irqs(arm_pic_cpu_handler, cpu, 2); } diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs index b6f1a9ebf6..d89b57c114 100644 --- a/target-arm/Makefile.objs +++ b/target-arm/Makefile.objs @@ -1,4 +1,5 @@ obj-y += arm-semi.o obj-$(CONFIG_SOFTMMU) += machine.o +obj-$(CONFIG_KVM) += kvm.o obj-y += translate.o op_helper.o helper.o cpu.o obj-y += neon_helper.o iwmmxt_helper.o diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 2902ba575b..c28a0d94c3 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -237,6 +237,7 @@ void arm_translate_init(void); void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu); int cpu_arm_exec(CPUARMState *s); void do_interrupt(CPUARMState *); +int bank_number(int mode); void switch_mode(CPUARMState *, int); uint32_t do_arm_semihosting(CPUARMState *env); diff --git a/target-arm/helper.c b/target-arm/helper.c index 7fa4ba0adc..6cad936d3e 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1617,7 +1617,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode) #else /* Map CPU modes onto saved register banks. */ -static inline int bank_number(int mode) +int bank_number(int mode) { switch (mode) { case ARM_CPU_MODE_USR: diff --git a/target-arm/kvm.c b/target-arm/kvm.c new file mode 100644 index 0000000000..499b427bc9 --- /dev/null +++ b/target-arm/kvm.c @@ -0,0 +1,334 @@ +/* + * ARM implementation of KVM hooks + * + * Copyright Christoffer Dall 2009-2010 + * + * 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 +#include +#include +#include + +#include + +#include "qemu-common.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "sysemu/kvm.h" +#include "cpu.h" +#include "hw/arm-misc.h" + +const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO +}; + +int kvm_arch_init(KVMState *s) +{ + /* For ARM interrupt delivery is always asynchronous, + * whether we are using an in-kernel VGIC or not. + */ + kvm_async_interrupts_allowed = true; + return 0; +} + +unsigned long kvm_arch_vcpu_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + +int kvm_arch_init_vcpu(CPUState *cs) +{ + struct kvm_vcpu_init init; + + init.target = KVM_ARM_TARGET_CORTEX_A15; + memset(init.features, 0, sizeof(init.features)); + return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init); +} + +typedef struct Reg { + uint64_t id; + int offset; +} Reg; + +#define COREREG(KERNELNAME, QEMUFIELD) \ + { \ + KVM_REG_ARM | KVM_REG_SIZE_U32 | \ + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \ + offsetof(CPUARMState, QEMUFIELD) \ + } + +#define CP15REG(CRN, CRM, OPC1, OPC2, QEMUFIELD) \ + { \ + KVM_REG_ARM | KVM_REG_SIZE_U32 | \ + (15 << KVM_REG_ARM_COPROC_SHIFT) | \ + ((CRN) << KVM_REG_ARM_32_CRN_SHIFT) | \ + ((CRM) << KVM_REG_ARM_CRM_SHIFT) | \ + ((OPC1) << KVM_REG_ARM_OPC1_SHIFT) | \ + ((OPC2) << KVM_REG_ARM_32_OPC2_SHIFT), \ + offsetof(CPUARMState, QEMUFIELD) \ + } + +static const Reg regs[] = { + /* R0_usr .. R14_usr */ + COREREG(usr_regs.uregs[0], regs[0]), + COREREG(usr_regs.uregs[1], regs[1]), + COREREG(usr_regs.uregs[2], regs[2]), + COREREG(usr_regs.uregs[3], regs[3]), + COREREG(usr_regs.uregs[4], regs[4]), + COREREG(usr_regs.uregs[5], regs[5]), + COREREG(usr_regs.uregs[6], regs[6]), + COREREG(usr_regs.uregs[7], regs[7]), + COREREG(usr_regs.uregs[8], usr_regs[0]), + COREREG(usr_regs.uregs[9], usr_regs[1]), + COREREG(usr_regs.uregs[10], usr_regs[2]), + COREREG(usr_regs.uregs[11], usr_regs[3]), + COREREG(usr_regs.uregs[12], usr_regs[4]), + COREREG(usr_regs.uregs[13], banked_r13[0]), + COREREG(usr_regs.uregs[14], banked_r14[0]), + /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */ + COREREG(svc_regs[0], banked_r13[1]), + COREREG(svc_regs[1], banked_r14[1]), + COREREG(svc_regs[2], banked_spsr[1]), + COREREG(abt_regs[0], banked_r13[2]), + COREREG(abt_regs[1], banked_r14[2]), + COREREG(abt_regs[2], banked_spsr[2]), + COREREG(und_regs[0], banked_r13[3]), + COREREG(und_regs[1], banked_r14[3]), + COREREG(und_regs[2], banked_spsr[3]), + COREREG(irq_regs[0], banked_r13[4]), + COREREG(irq_regs[1], banked_r14[4]), + COREREG(irq_regs[2], banked_spsr[4]), + /* R8_fiq .. R14_fiq and SPSR_fiq */ + COREREG(fiq_regs[0], fiq_regs[0]), + COREREG(fiq_regs[1], fiq_regs[1]), + COREREG(fiq_regs[2], fiq_regs[2]), + COREREG(fiq_regs[3], fiq_regs[3]), + COREREG(fiq_regs[4], fiq_regs[4]), + COREREG(fiq_regs[5], banked_r13[5]), + COREREG(fiq_regs[6], banked_r14[5]), + COREREG(fiq_regs[7], banked_spsr[5]), + /* R15 */ + COREREG(usr_regs.uregs[15], regs[15]), + /* A non-comprehensive set of cp15 registers. + * TODO: drive this from the cp_regs hashtable instead. + */ + CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */ + CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */ + CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */ +}; + +int kvm_arch_put_registers(CPUState *cs, int level) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + struct kvm_one_reg r; + int mode, bn; + int ret, i; + uint32_t cpsr; + uint64_t ttbr; + + /* Make sure the banked regs are properly set */ + mode = env->uncached_cpsr & CPSR_M; + bn = bank_number(mode); + if (mode == ARM_CPU_MODE_FIQ) { + memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t)); + } else { + memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t)); + } + env->banked_r13[bn] = env->regs[13]; + env->banked_r14[bn] = env->regs[14]; + env->banked_spsr[bn] = env->spsr; + + /* Now we can safely copy stuff down to the kernel */ + for (i = 0; i < ARRAY_SIZE(regs); i++) { + r.id = regs[i].id; + r.addr = (uintptr_t)(env) + regs[i].offset; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + if (ret) { + return ret; + } + } + + /* Special cases which aren't a single CPUARMState field */ + cpsr = cpsr_read(env); + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr); + r.addr = (uintptr_t)(&cpsr); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + if (ret) { + return ret; + } + + /* TTBR0: cp15 crm=2 opc1=0 */ + ttbr = ((uint64_t)env->cp15.c2_base0_hi << 32) | env->cp15.c2_base0; + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) | + (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT); + r.addr = (uintptr_t)(&ttbr); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + if (ret) { + return ret; + } + + /* TTBR1: cp15 crm=2 opc1=1 */ + ttbr = ((uint64_t)env->cp15.c2_base1_hi << 32) | env->cp15.c2_base1; + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) | + (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT); + r.addr = (uintptr_t)(&ttbr); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + + return ret; +} + +int kvm_arch_get_registers(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + struct kvm_one_reg r; + int mode, bn; + int ret, i; + uint32_t cpsr; + uint64_t ttbr; + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + r.id = regs[i].id; + r.addr = (uintptr_t)(env) + regs[i].offset; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + } + + /* Special cases which aren't a single CPUARMState field */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr); + r.addr = (uintptr_t)(&cpsr); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + cpsr_write(env, cpsr, 0xffffffff); + + /* TTBR0: cp15 crm=2 opc1=0 */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) | + (2 << KVM_REG_ARM_CRM_SHIFT) | (0 << KVM_REG_ARM_OPC1_SHIFT); + r.addr = (uintptr_t)(&ttbr); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + env->cp15.c2_base0_hi = ttbr >> 32; + env->cp15.c2_base0 = ttbr; + + /* TTBR1: cp15 crm=2 opc1=1 */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | (15 << KVM_REG_ARM_COPROC_SHIFT) | + (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT); + r.addr = (uintptr_t)(&ttbr); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + env->cp15.c2_base1_hi = ttbr >> 32; + env->cp15.c2_base1 = ttbr; + + /* Make sure the current mode regs are properly set */ + mode = env->uncached_cpsr & CPSR_M; + bn = bank_number(mode); + if (mode == ARM_CPU_MODE_FIQ) { + memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t)); + } else { + memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t)); + } + env->regs[13] = env->banked_r13[bn]; + env->regs[14] = env->banked_r14[bn]; + env->spsr = env->banked_spsr[bn]; + + /* The main GET_ONE_REG loop above set c2_control, but we need to + * update some extra cached precomputed values too. + * When this is driven from the cp_regs hashtable then this ugliness + * can disappear because we'll use the access function which sets + * these values automatically. + */ + env->cp15.c2_mask = ~(0xffffffffu >> env->cp15.c2_control); + env->cp15.c2_base_mask = ~(0x3fffu >> env->cp15.c2_control); + + return 0; +} + +void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) +{ +} + +void kvm_arch_post_run(CPUState *cs, struct kvm_run *run) +{ +} + +int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) +{ + return 0; +} + +void kvm_arch_reset_vcpu(CPUState *cs) +{ +} + +bool kvm_arch_stop_on_emulation_error(CPUState *cs) +{ + return true; +} + +int kvm_arch_process_async_events(CPUState *cs) +{ + return 0; +} + +int kvm_arch_on_sigbus_vcpu(CPUState *cs, int code, void *addr) +{ + return 1; +} + +int kvm_arch_on_sigbus(int code, void *addr) +{ + return 1; +} + +void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); +} + +int kvm_arch_insert_sw_breakpoint(CPUState *cs, + struct kvm_sw_breakpoint *bp) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + return -EINVAL; +} + +int kvm_arch_insert_hw_breakpoint(target_ulong addr, + target_ulong len, int type) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + return -EINVAL; +} + +int kvm_arch_remove_hw_breakpoint(target_ulong addr, + target_ulong len, int type) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + return -EINVAL; +} + +int kvm_arch_remove_sw_breakpoint(CPUState *cs, + struct kvm_sw_breakpoint *bp) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); + return -EINVAL; +} + +void kvm_arch_remove_all_hw_breakpoints(void) +{ + qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); +} From 81635574f6e7f4d18ea059ecbeeec93c3ffc284c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:41 +0000 Subject: [PATCH 1363/1634] ARM KVM: save and load VFP registers from kernel Add support for saving and restoring VFP register state from the kernel. This includes a check that the KVM-created CPU has full VFP support (as the TCG Cortex-A15 model always does), since for the moment ARM QEMU doesn't have any way to tweak optional features on created CPUs. Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini --- target-arm/kvm.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 499b427bc9..9173d0a175 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -43,10 +43,28 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) int kvm_arch_init_vcpu(CPUState *cs) { struct kvm_vcpu_init init; + int ret; + uint64_t v; + struct kvm_one_reg r; init.target = KVM_ARM_TARGET_CORTEX_A15; memset(init.features, 0, sizeof(init.features)); - return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init); + ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init); + if (ret) { + return ret; + } + /* Query the kernel to make sure it supports 32 VFP + * registers: QEMU's "cortex-a15" CPU is always a + * VFP-D32 core. The simplest way to do this is just + * to attempt to read register d31. + */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | 31; + r.addr = (uintptr_t)(&v); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret == ENOENT) { + return EINVAL; + } + return ret; } typedef struct Reg { @@ -72,6 +90,13 @@ typedef struct Reg { offsetof(CPUARMState, QEMUFIELD) \ } +#define VFPSYSREG(R) \ + { \ + KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | \ + KVM_REG_ARM_VFP_##R, \ + offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R]) \ + } + static const Reg regs[] = { /* R0_usr .. R14_usr */ COREREG(usr_regs.uregs[0], regs[0]), @@ -119,6 +144,13 @@ static const Reg regs[] = { CP15REG(1, 0, 0, 0, cp15.c1_sys), /* SCTLR */ CP15REG(2, 0, 0, 2, cp15.c2_control), /* TTBCR */ CP15REG(3, 0, 0, 0, cp15.c3), /* DACR */ + /* VFP system registers */ + VFPSYSREG(FPSID), + VFPSYSREG(MVFR1), + VFPSYSREG(MVFR0), + VFPSYSREG(FPEXC), + VFPSYSREG(FPINST), + VFPSYSREG(FPINST2), }; int kvm_arch_put_registers(CPUState *cs, int level) @@ -128,7 +160,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) struct kvm_one_reg r; int mode, bn; int ret, i; - uint32_t cpsr; + uint32_t cpsr, fpscr; uint64_t ttbr; /* Make sure the banked regs are properly set */ @@ -179,6 +211,26 @@ int kvm_arch_put_registers(CPUState *cs, int level) (2 << KVM_REG_ARM_CRM_SHIFT) | (1 << KVM_REG_ARM_OPC1_SHIFT); r.addr = (uintptr_t)(&ttbr); ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + if (ret) { + return ret; + } + + /* VFP registers */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; + for (i = 0; i < 32; i++) { + r.addr = (uintptr_t)(&env->vfp.regs[i]); + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); + if (ret) { + return ret; + } + r.id++; + } + + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | + KVM_REG_ARM_VFP_FPSCR; + fpscr = vfp_get_fpscr(env); + r.addr = (uintptr_t)&fpscr; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &r); return ret; } @@ -190,7 +242,7 @@ int kvm_arch_get_registers(CPUState *cs) struct kvm_one_reg r; int mode, bn; int ret, i; - uint32_t cpsr; + uint32_t cpsr, fpscr; uint64_t ttbr; for (i = 0; i < ARRAY_SIZE(regs); i++) { @@ -255,6 +307,26 @@ int kvm_arch_get_registers(CPUState *cs) env->cp15.c2_mask = ~(0xffffffffu >> env->cp15.c2_control); env->cp15.c2_base_mask = ~(0x3fffu >> env->cp15.c2_control); + /* VFP registers */ + r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP; + for (i = 0; i < 32; i++) { + r.addr = (uintptr_t)(&env->vfp.regs[i]); + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + r.id++; + } + + r.id = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | + KVM_REG_ARM_VFP_FPSCR; + r.addr = (uintptr_t)&fpscr; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &r); + if (ret) { + return ret; + } + vfp_set_fpscr(env, fpscr); + return 0; } From 9ecb992674cec86091b4fce3bd66faee8b56b165 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:41 +0000 Subject: [PATCH 1364/1634] hw/arm_gic: Add presave/postload hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add presave/postload hooks to the ARM GIC common base class. These will be used by the KVM in-kernel GIC subclass to sync state between kernel and userspace when migrating. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Reviewed-by: Paolo Bonzini --- hw/arm_gic_common.c | 10 ++++++++++ hw/arm_gic_internal.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 40e8dd7045..29476227f6 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -23,9 +23,14 @@ static void gic_save(QEMUFile *f, void *opaque) { GICState *s = (GICState *)opaque; + ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s); int i; int j; + if (c->pre_save) { + c->pre_save(s); + } + qemu_put_be32(f, s->enabled); for (i = 0; i < s->num_cpu; i++) { qemu_put_be32(f, s->cpu_enabled[i]); @@ -57,6 +62,7 @@ static void gic_save(QEMUFile *f, void *opaque) static int gic_load(QEMUFile *f, void *opaque, int version_id) { GICState *s = (GICState *)opaque; + ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s); int i; int j; @@ -91,6 +97,10 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) s->irq_state[i].trigger = qemu_get_byte(f); } + if (c->post_load) { + c->post_load(s); + } + return 0; } diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h index 699352ca8b..3640be0031 100644 --- a/hw/arm_gic_internal.h +++ b/hw/arm_gic_internal.h @@ -118,6 +118,8 @@ void gic_init_irqs_and_distributor(GICState *s, int num_irq); typedef struct ARMGICCommonClass { SysBusDeviceClass parent_class; + void (*pre_save)(GICState *s); + void (*post_load)(GICState *s); } ARMGICCommonClass; #define TYPE_ARM_GIC "arm_gic" From 53111180946a56d314a9c1d07d09b9ef91e847b9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:42 +0000 Subject: [PATCH 1365/1634] hw/arm_gic: Convert ARM GIC classes to use init/realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the ARM GIC classes to use init/realize rather than SysBusDevice::init. (We have to do them all in one patch to avoid unconverted subclasses calling a nonexistent SysBusDevice init function in the base class and crashing.) Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber --- hw/arm_gic.c | 23 +++++++++++++---------- hw/arm_gic_common.c | 26 +++++++++++++++----------- hw/arm_gic_internal.h | 2 +- hw/armv7m_nvic.c | 15 ++++++++------- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 90e43d0728..250e720d18 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -659,14 +659,18 @@ void gic_init_irqs_and_distributor(GICState *s, int num_irq) memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000); } -static int arm_gic_init(SysBusDevice *dev) +static void arm_gic_realize(DeviceState *dev, Error **errp) { - /* Device instance init function for the GIC sysbus device */ + /* Device instance realize function for the GIC sysbus device */ int i; - GICState *s = FROM_SYSBUS(GICState, dev); + GICState *s = ARM_GIC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); ARMGICClass *agc = ARM_GIC_GET_CLASS(s); - agc->parent_init(dev); + agc->parent_realize(dev, errp); + if (error_is_set(errp)) { + return; + } gic_init_irqs_and_distributor(s, s->num_irq); @@ -686,22 +690,21 @@ static int arm_gic_init(SysBusDevice *dev) "gic_cpu", 0x100); } /* Distributor */ - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); /* cpu interfaces (one for "current cpu" plus one per cpu) */ for (i = 0; i <= NUM_CPU(s); i++) { - sysbus_init_mmio(dev, &s->cpuiomem[i]); + sysbus_init_mmio(sbd, &s->cpuiomem[i]); } - return 0; } static void arm_gic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); ARMGICClass *agc = ARM_GIC_CLASS(klass); - agc->parent_init = sbc->init; - sbc->init = arm_gic_init; + dc->no_user = 1; + agc->parent_realize = dc->realize; + dc->realize = arm_gic_realize; } static const TypeInfo arm_gic_info = { diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c index 29476227f6..20da9d2b18 100644 --- a/hw/arm_gic_common.c +++ b/hw/arm_gic_common.c @@ -104,31 +104,35 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static int arm_gic_common_init(SysBusDevice *dev) +static void arm_gic_common_realize(DeviceState *dev, Error **errp) { - GICState *s = FROM_SYSBUS(GICState, dev); + GICState *s = ARM_GIC_COMMON(dev); int num_irq = s->num_irq; if (s->num_cpu > NCPU) { - hw_error("requested %u CPUs exceeds GIC maximum %d\n", - s->num_cpu, NCPU); + error_setg(errp, "requested %u CPUs exceeds GIC maximum %d", + s->num_cpu, NCPU); + return; } s->num_irq += GIC_BASE_IRQ; if (s->num_irq > GIC_MAXIRQ) { - hw_error("requested %u interrupt lines exceeds GIC maximum %d\n", - num_irq, GIC_MAXIRQ); + error_setg(errp, + "requested %u interrupt lines exceeds GIC maximum %d", + num_irq, GIC_MAXIRQ); + return; } /* ITLinesNumber is represented as (N / 32) - 1 (see * gic_dist_readb) so this is an implementation imposed * restriction, not an architectural one: */ if (s->num_irq < 32 || (s->num_irq % 32)) { - hw_error("%d interrupt lines unsupported: not divisible by 32\n", - num_irq); + error_setg(errp, + "%d interrupt lines unsupported: not divisible by 32", + num_irq); + return; } register_savevm(NULL, "arm_gic", -1, 3, gic_save, gic_load, s); - return 0; } static void arm_gic_common_reset(DeviceState *dev) @@ -173,12 +177,12 @@ static Property arm_gic_common_properties[] = { static void arm_gic_common_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = arm_gic_common_reset; + dc->realize = arm_gic_common_realize; dc->props = arm_gic_common_properties; dc->no_user = 1; - sc->init = arm_gic_common_init; } static const TypeInfo arm_gic_common_type = { diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h index 3640be0031..3ba37f30f5 100644 --- a/hw/arm_gic_internal.h +++ b/hw/arm_gic_internal.h @@ -132,7 +132,7 @@ typedef struct ARMGICCommonClass { typedef struct ARMGICClass { ARMGICCommonClass parent_class; - int (*parent_init)(SysBusDevice *dev); + DeviceRealize parent_realize; } ARMGICClass; #endif /* !QEMU_ARM_GIC_INTERNAL_H */ diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index d5798d0309..3c7967464a 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -41,7 +41,7 @@ typedef struct NVICClass { /*< private >*/ ARMGICClass parent_class; /*< public >*/ - int (*parent_init)(SysBusDevice *dev); + DeviceRealize parent_realize; void (*parent_reset)(DeviceState *dev); } NVICClass; @@ -465,7 +465,7 @@ static void armv7m_nvic_reset(DeviceState *dev) systick_reset(s); } -static int armv7m_nvic_init(SysBusDevice *dev) +static void armv7m_nvic_realize(DeviceState *dev, Error **errp) { nvic_state *s = NVIC(dev); NVICClass *nc = NVIC_GET_CLASS(s); @@ -475,7 +475,10 @@ static int armv7m_nvic_init(SysBusDevice *dev) /* Tell the common code we're an NVIC */ s->gic.revision = 0xffffffff; s->num_irq = s->gic.num_irq; - nc->parent_init(dev); + nc->parent_realize(dev, errp); + if (error_is_set(errp)) { + return; + } gic_init_irqs_and_distributor(&s->gic, s->num_irq); /* The NVIC and system controller register area looks like this: * 0..0xff : system control registers, including systick @@ -503,7 +506,6 @@ static int armv7m_nvic_init(SysBusDevice *dev) */ memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container); s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); - return 0; } static void armv7m_nvic_instance_init(Object *obj) @@ -526,13 +528,12 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data) { NVICClass *nc = NVIC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); nc->parent_reset = dc->reset; - nc->parent_init = sdc->init; - sdc->init = armv7m_nvic_init; + nc->parent_realize = dc->realize; dc->vmsd = &vmstate_nvic; dc->reset = armv7m_nvic_reset; + dc->realize = armv7m_nvic_realize; } static const TypeInfo armv7m_nvic_info = { From eb035b48d5ff26a155f37106f693acb8b8487d80 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:42 +0000 Subject: [PATCH 1366/1634] target-arm: Use MemoryListener to identify GIC base address for KVM When using an in-kernel GIC with KVM, we need to tell the kernel where the GIC's memory mapped registers live. Do this by registering a MemoryListener which tracks where the board model maps the A15's private peripherals, so we can finish the GIC initialisation when the GIC is actually mapped. Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini --- target-arm/kvm.c | 87 ++++++++++++++++++++++++++++++++++++++++++++ target-arm/kvm_arm.h | 32 ++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 target-arm/kvm_arm.h diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 9173d0a175..82e2e084c3 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -19,6 +19,7 @@ #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "kvm_arm.h" #include "cpu.h" #include "hw/arm-misc.h" @@ -67,6 +68,92 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } +/* We track all the KVM devices which need their memory addresses + * passing to the kernel in a list of these structures. + * When board init is complete we run through the list and + * tell the kernel the base addresses of the memory regions. + * We use a MemoryListener to track mapping and unmapping of + * the regions during board creation, so the board models don't + * need to do anything special for the KVM case. + */ +typedef struct KVMDevice { + struct kvm_arm_device_addr kda; + MemoryRegion *mr; + QSLIST_ENTRY(KVMDevice) entries; +} KVMDevice; + +static QSLIST_HEAD(kvm_devices_head, KVMDevice) kvm_devices_head; + +static void kvm_arm_devlistener_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMDevice *kd; + + QSLIST_FOREACH(kd, &kvm_devices_head, entries) { + if (section->mr == kd->mr) { + kd->kda.addr = section->offset_within_address_space; + } + } +} + +static void kvm_arm_devlistener_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMDevice *kd; + + QSLIST_FOREACH(kd, &kvm_devices_head, entries) { + if (section->mr == kd->mr) { + kd->kda.addr = -1; + } + } +} + +static MemoryListener devlistener = { + .region_add = kvm_arm_devlistener_add, + .region_del = kvm_arm_devlistener_del, +}; + +static void kvm_arm_machine_init_done(Notifier *notifier, void *data) +{ + KVMDevice *kd, *tkd; + + memory_listener_unregister(&devlistener); + QSLIST_FOREACH_SAFE(kd, &kvm_devices_head, entries, tkd) { + if (kd->kda.addr != -1) { + if (kvm_vm_ioctl(kvm_state, KVM_ARM_SET_DEVICE_ADDR, + &kd->kda) < 0) { + fprintf(stderr, "KVM_ARM_SET_DEVICE_ADDRESS failed: %s\n", + strerror(errno)); + abort(); + } + } + g_free(kd); + } +} + +static Notifier notify = { + .notify = kvm_arm_machine_init_done, +}; + +void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid) +{ + KVMDevice *kd; + + if (!kvm_irqchip_in_kernel()) { + return; + } + + if (QSLIST_EMPTY(&kvm_devices_head)) { + memory_listener_register(&devlistener, NULL); + qemu_add_machine_init_done_notifier(¬ify); + } + kd = g_new0(KVMDevice, 1); + kd->mr = mr; + kd->kda.id = devid; + kd->kda.addr = -1; + QSLIST_INSERT_HEAD(&kvm_devices_head, kd, entries); +} + typedef struct Reg { uint64_t id; int offset; diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h new file mode 100644 index 0000000000..b1c54ffb5d --- /dev/null +++ b/target-arm/kvm_arm.h @@ -0,0 +1,32 @@ +/* + * QEMU KVM support -- ARM specific functions. + * + * Copyright (c) 2012 Linaro Limited + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_KVM_ARM_H +#define QEMU_KVM_ARM_H + +#include "sysemu/kvm.h" +#include "exec/memory.h" + +/** + * kvm_arm_register_device: + * @mr: memory region for this device + * @devid: the KVM device ID + * + * Remember the memory region @mr, and when it is mapped by the + * machine model, tell the kernel that base address using the + * KVM_SET_DEVICE_ADDRESS ioctl. @devid should be the ID of + * the device as defined by KVM_SET_DEVICE_ADDRESS. + * The machine model may map and unmap the device multiple times; + * the kernel will only be told the final address at the point + * where machine init is complete. + */ +void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid); + +#endif From ed46676160d94d279e32ce955fd60b76c7a1b370 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:43 +0000 Subject: [PATCH 1367/1634] hw/kvm/arm_gic: Implement support for KVM in-kernel ARM GIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement support for using the KVM in-kernel GIC for ARM. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber --- hw/a15mpcore.c | 8 ++- hw/arm/Makefile.objs | 1 + hw/kvm/arm_gic.c | 167 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 hw/kvm/arm_gic.c diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index fe6c34ca53..97abe413c8 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -19,6 +19,7 @@ */ #include "sysbus.h" +#include "sysemu/kvm.h" /* A15MP private memory region. */ @@ -40,8 +41,13 @@ static int a15mp_priv_init(SysBusDevice *dev) { A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev); SysBusDevice *busdev; + const char *gictype = "arm_gic"; - s->gic = qdev_create(NULL, "arm_gic"); + if (kvm_irqchip_in_kernel()) { + gictype = "kvm-arm-gic"; + } + + s->gic = qdev_create(NULL, gictype); qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq); qdev_prop_set_uint32(s->gic, "revision", 2); diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 4c109858fd..0e7df6098a 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -32,5 +32,6 @@ obj-y += collie.o obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o obj-y += kzm.o obj-$(CONFIG_FDT) += ../device_tree.o +obj-$(CONFIG_KVM) += kvm/arm_gic.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c new file mode 100644 index 0000000000..22b40b4f84 --- /dev/null +++ b/hw/kvm/arm_gic.c @@ -0,0 +1,167 @@ +/* + * ARM Generic Interrupt Controller using KVM in-kernel support + * + * Copyright (c) 2012 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "hw/sysbus.h" +#include "sysemu/kvm.h" +#include "kvm_arm.h" +#include "hw/arm_gic_internal.h" + +#define TYPE_KVM_ARM_GIC "kvm-arm-gic" +#define KVM_ARM_GIC(obj) \ + OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC) +#define KVM_ARM_GIC_CLASS(klass) \ + OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC) +#define KVM_ARM_GIC_GET_CLASS(obj) \ + OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC) + +typedef struct KVMARMGICClass { + ARMGICCommonClass parent_class; + DeviceRealize parent_realize; + void (*parent_reset)(DeviceState *dev); +} KVMARMGICClass; + +static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) +{ + /* Meaning of the 'irq' parameter: + * [0..N-1] : external interrupts + * [N..N+31] : PPI (internal) interrupts for CPU 0 + * [N+32..N+63] : PPI (internal interrupts for CPU 1 + * ... + * Convert this to the kernel's desired encoding, which + * has separate fields in the irq number for type, + * CPU number and interrupt number. + */ + GICState *s = (GICState *)opaque; + int kvm_irq, irqtype, cpu; + + if (irq < (s->num_irq - GIC_INTERNAL)) { + /* External interrupt. The kernel numbers these like the GIC + * hardware, with external interrupt IDs starting after the + * internal ones. + */ + irqtype = KVM_ARM_IRQ_TYPE_SPI; + cpu = 0; + irq += GIC_INTERNAL; + } else { + /* Internal interrupt: decode into (cpu, interrupt id) */ + irqtype = KVM_ARM_IRQ_TYPE_PPI; + irq -= (s->num_irq - GIC_INTERNAL); + cpu = irq / GIC_INTERNAL; + irq %= GIC_INTERNAL; + } + kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT) + | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq; + + kvm_set_irq(kvm_state, kvm_irq, !!level); +} + +static void kvm_arm_gic_put(GICState *s) +{ + /* TODO: there isn't currently a kernel interface to set the GIC state */ +} + +static void kvm_arm_gic_get(GICState *s) +{ + /* TODO: there isn't currently a kernel interface to get the GIC state */ +} + +static void kvm_arm_gic_reset(DeviceState *dev) +{ + GICState *s = ARM_GIC_COMMON(dev); + KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); + + kgc->parent_reset(dev); + kvm_arm_gic_put(s); +} + +static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) +{ + int i; + GICState *s = KVM_ARM_GIC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); + + kgc->parent_realize(dev, errp); + if (error_is_set(errp)) { + return; + } + + i = s->num_irq - GIC_INTERNAL; + /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. + * GPIO array layout is thus: + * [0..N-1] SPIs + * [N..N+31] PPIs for CPU 0 + * [N+32..N+63] PPIs for CPU 1 + * ... + */ + i += (GIC_INTERNAL * s->num_cpu); + qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i); + /* We never use our outbound IRQ lines but provide them so that + * we maintain the same interface as the non-KVM GIC. + */ + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->parent_irq[i]); + } + /* Distributor */ + memory_region_init_reservation(&s->iomem, "kvm-gic_dist", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + kvm_arm_register_device(&s->iomem, + (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT) + | KVM_VGIC_V2_ADDR_TYPE_DIST); + /* CPU interface for current core. Unlike arm_gic, we don't + * provide the "interface for core #N" memory regions, because + * cores with a VGIC don't have those. + */ + memory_region_init_reservation(&s->cpuiomem[0], "kvm-gic_cpu", 0x1000); + sysbus_init_mmio(sbd, &s->cpuiomem[0]); + kvm_arm_register_device(&s->cpuiomem[0], + (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT) + | KVM_VGIC_V2_ADDR_TYPE_CPU); +} + +static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass); + KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass); + + agcc->pre_save = kvm_arm_gic_get; + agcc->post_load = kvm_arm_gic_put; + kgc->parent_realize = dc->realize; + kgc->parent_reset = dc->reset; + dc->realize = kvm_arm_gic_realize; + dc->reset = kvm_arm_gic_reset; + dc->no_user = 1; +} + +static const TypeInfo kvm_arm_gic_info = { + .name = TYPE_KVM_ARM_GIC, + .parent = TYPE_ARM_GIC_COMMON, + .instance_size = sizeof(GICState), + .class_init = kvm_arm_gic_class_init, + .class_size = sizeof(KVMARMGICClass), +}; + +static void kvm_arm_gic_register_types(void) +{ + type_register_static(&kvm_arm_gic_info); +} + +type_init(kvm_arm_gic_register_types) From 68b05c427b0d220e38bfa21ee6df7970f158b377 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:43 +0000 Subject: [PATCH 1368/1634] configure: Enable KVM on ARM Enable KVM on ARM hosts, now that all the necessary components for it exist. Signed-off-by: Peter Maydell Reviewed-by: Paolo Bonzini --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 19738ac968..b4deb9bf4b 100755 --- a/configure +++ b/configure @@ -4129,7 +4129,7 @@ case "$target_arch2" in echo "CONFIG_NO_XEN=y" >> $config_target_mak esac case "$target_arch2" in - i386|x86_64|ppcemb|ppc|ppc64|s390x) + arm|i386|x86_64|ppcemb|ppc|ppc64|s390x) # Make sure the target and host cpus are compatible if test "$kvm" = "yes" -a "$target_softmmu" = "yes" -a \ \( "$target_arch2" = "$cpu" -o \ From ed4659d10fa2ec16ace367e4fffe6f7ced73112c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 5 Mar 2013 00:34:43 +0000 Subject: [PATCH 1369/1634] MAINTAINERS: add entry for ARM KVM guest cores Add an entry indicating maintainer status for the ARM KVM code. Signed-off-by: Peter Maydell --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 21043e4b4a..2439614ad2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -140,6 +140,11 @@ S: Supported F: kvm-* F: */kvm.* +ARM +M: Peter Maydell +S: Maintained +F: target-arm/kvm.c + PPC M: Alexander Graf S: Maintained From 2c3c6689b32529b56261bbbca36ba8544a34dd60 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 10 Feb 2013 10:30:41 -0800 Subject: [PATCH 1370/1634] mips-linux-user: Delete n32 and n64 signal stubs Deleting these first makes the next patch much easier to read. This doesn't cause any sort of compilation failure because we have not yet enabled n32/n64 compilation. This is dead code. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- linux-user/signal.c | 58 --------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 67c23118a0..b2f1d29401 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -2438,64 +2438,6 @@ void sparc64_get_context(CPUSPARCState *env) force_sig(TARGET_SIGSEGV); } #endif -#elif defined(TARGET_ABI_MIPSN64) - -# warning signal handling not implemented - -static void setup_frame(int sig, struct target_sigaction *ka, - target_sigset_t *set, CPUMIPSState *env) -{ - fprintf(stderr, "setup_frame: not implemented\n"); -} - -static void setup_rt_frame(int sig, struct target_sigaction *ka, - target_siginfo_t *info, - target_sigset_t *set, CPUMIPSState *env) -{ - fprintf(stderr, "setup_rt_frame: not implemented\n"); -} - -long do_sigreturn(CPUMIPSState *env) -{ - fprintf(stderr, "do_sigreturn: not implemented\n"); - return -TARGET_ENOSYS; -} - -long do_rt_sigreturn(CPUMIPSState *env) -{ - fprintf(stderr, "do_rt_sigreturn: not implemented\n"); - return -TARGET_ENOSYS; -} - -#elif defined(TARGET_ABI_MIPSN32) - -# warning signal handling not implemented - -static void setup_frame(int sig, struct target_sigaction *ka, - target_sigset_t *set, CPUMIPSState *env) -{ - fprintf(stderr, "setup_frame: not implemented\n"); -} - -static void setup_rt_frame(int sig, struct target_sigaction *ka, - target_siginfo_t *info, - target_sigset_t *set, CPUMIPSState *env) -{ - fprintf(stderr, "setup_rt_frame: not implemented\n"); -} - -long do_sigreturn(CPUMIPSState *env) -{ - fprintf(stderr, "do_sigreturn: not implemented\n"); - return -TARGET_ENOSYS; -} - -long do_rt_sigreturn(CPUMIPSState *env) -{ - fprintf(stderr, "do_rt_sigreturn: not implemented\n"); - return -TARGET_ENOSYS; -} - #elif defined(TARGET_ABI_MIPSO32) struct target_sigcontext { From ff97090469eb4a5f21a1f482b27382b8205d1232 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 10 Feb 2013 10:30:42 -0800 Subject: [PATCH 1371/1634] mips-linux-user: Share o32 code for n32 and n64 signals Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- linux-user/signal.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index b2f1d29401..7da676f64c 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -2438,8 +2438,9 @@ void sparc64_get_context(CPUSPARCState *env) force_sig(TARGET_SIGSEGV); } #endif -#elif defined(TARGET_ABI_MIPSO32) +#elif defined(TARGET_MIPS) || defined(TARGET_MIPS64) +# if defined(TARGET_ABI_MIPSO32) struct target_sigcontext { uint32_t sc_regmask; /* Unused */ uint32_t sc_status; @@ -2461,6 +2462,25 @@ struct target_sigcontext { target_ulong sc_hi3; target_ulong sc_lo3; }; +# else /* N32 || N64 */ +struct target_sigcontext { + uint64_t sc_regs[32]; + uint64_t sc_fpregs[32]; + uint64_t sc_mdhi; + uint64_t sc_hi1; + uint64_t sc_hi2; + uint64_t sc_hi3; + uint64_t sc_mdlo; + uint64_t sc_lo1; + uint64_t sc_lo2; + uint64_t sc_lo3; + uint64_t sc_pc; + uint32_t sc_fpc_csr; + uint32_t sc_used_math; + uint32_t sc_dsp; + uint32_t sc_reserved; +}; +# endif /* O32 */ struct sigframe { uint32_t sf_ass[4]; /* argument save space for o32 */ @@ -2646,6 +2666,7 @@ restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) #endif return err; } + /* * Determine which stack to use.. */ @@ -2672,6 +2693,7 @@ get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size) return (sp - frame_size) & ~7; } +# if defined(TARGET_ABI_MIPSO32) /* compare linux/arch/mips/kernel/signal.c:setup_frame() */ static void setup_frame(int sig, struct target_sigaction * ka, target_sigset_t *set, CPUMIPSState *regs) @@ -2769,6 +2791,7 @@ badframe: force_sig(TARGET_SIGSEGV/*, current*/); return 0; } +# endif /* O32 */ static void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, @@ -5499,10 +5522,15 @@ void process_pending_signals(CPUArchState *cpu_env) } #endif /* prepare the stack frame of the virtual CPU */ +#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) + /* These targets do not have traditional signals. */ + setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env); +#else if (sa->sa_flags & TARGET_SA_SIGINFO) setup_rt_frame(sig, sa, &q->info, &target_old_set, cpu_env); else setup_frame(sig, sa, &target_old_set, cpu_env); +#endif if (sa->sa_flags & TARGET_SA_RESETHAND) sa->_sa_handler = TARGET_SIG_DFL; } From 51cd14d3f56f15cb82e63d694a023ce2b02334f9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 10 Feb 2013 10:30:43 -0800 Subject: [PATCH 1372/1634] mips-linux-user: Enable mips64 and mipsn32 linux-user targets At this point we can enable compilation, though things still don't work. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index 19738ac968..08dcc26434 100755 --- a/configure +++ b/configure @@ -986,6 +986,10 @@ microblaze-linux-user \ microblazeel-linux-user \ mips-linux-user \ mipsel-linux-user \ +mips64-linux-user \ +mips64el-linux-user \ +mipsn32-linux-user \ +mipsn32el-linux-user \ or32-linux-user \ ppc-linux-user \ ppc64-linux-user \ From 084d0497a0edf060d8f61c798217b6d0622a5feb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 10 Feb 2013 10:30:44 -0800 Subject: [PATCH 1373/1634] mips-linux-user: Save and restore fpu and dsp from sigcontext Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- linux-user/signal.c | 167 +++++++++++---------------------------- target-mips/cpu.h | 3 + target-mips/dsp_helper.c | 16 +++- 3 files changed, 63 insertions(+), 123 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 7da676f64c..1055507224 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -2508,18 +2508,17 @@ struct target_rt_sigframe { /* Install trampoline to jump back from signal handler */ static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) { - int err; + int err = 0; /* - * Set up the return code ... - * - * li v0, __NR__foo_sigreturn - * syscall - */ + * Set up the return code ... + * + * li v0, __NR__foo_sigreturn + * syscall + */ - err = __put_user(0x24020000 + syscall, tramp + 0); + err |= __put_user(0x24020000 + syscall, tramp + 0); err |= __put_user(0x0000000c , tramp + 1); - /* flush_cache_sigtramp((unsigned long) tramp); */ return err; } @@ -2527,74 +2526,37 @@ static inline int setup_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) { int err = 0; + int i; err |= __put_user(regs->active_tc.PC, &sc->sc_pc); -#define save_gp_reg(i) do { \ - err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \ - } while(0) - __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); - save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); - save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); - save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); - save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); - save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); - save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); - save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); - save_gp_reg(31); -#undef save_gp_reg + __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; ++i) { + err |= __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); + } err |= __put_user(regs->active_tc.HI[0], &sc->sc_mdhi); err |= __put_user(regs->active_tc.LO[0], &sc->sc_mdlo); - /* Not used yet, but might be useful if we ever have DSP suppport */ -#if 0 - if (cpu_has_dsp) { - err |= __put_user(mfhi1(), &sc->sc_hi1); - err |= __put_user(mflo1(), &sc->sc_lo1); - err |= __put_user(mfhi2(), &sc->sc_hi2); - err |= __put_user(mflo2(), &sc->sc_lo2); - err |= __put_user(mfhi3(), &sc->sc_hi3); - err |= __put_user(mflo3(), &sc->sc_lo3); - err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + /* Rather than checking for dsp existence, always copy. The storage + would just be garbage otherwise. */ + err |= __put_user(regs->active_tc.HI[1], &sc->sc_hi1); + err |= __put_user(regs->active_tc.HI[2], &sc->sc_hi2); + err |= __put_user(regs->active_tc.HI[3], &sc->sc_hi3); + err |= __put_user(regs->active_tc.LO[1], &sc->sc_lo1); + err |= __put_user(regs->active_tc.LO[2], &sc->sc_lo2); + err |= __put_user(regs->active_tc.LO[3], &sc->sc_lo3); + { + uint32_t dsp = cpu_rddsp(0x3ff, regs); + err |= __put_user(dsp, &sc->sc_dsp); } - /* same with 64 bit */ -#ifdef CONFIG_64BIT - err |= __put_user(regs->hi, &sc->sc_hi[0]); - err |= __put_user(regs->lo, &sc->sc_lo[0]); - if (cpu_has_dsp) { - err |= __put_user(mfhi1(), &sc->sc_hi[1]); - err |= __put_user(mflo1(), &sc->sc_lo[1]); - err |= __put_user(mfhi2(), &sc->sc_hi[2]); - err |= __put_user(mflo2(), &sc->sc_lo[2]); - err |= __put_user(mfhi3(), &sc->sc_hi[3]); - err |= __put_user(mflo3(), &sc->sc_lo[3]); - err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + + err |= __put_user(1, &sc->sc_used_math); + + for (i = 0; i < 32; ++i) { + err |= __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); } -#endif -#endif -#if 0 - err |= __put_user(!!used_math(), &sc->sc_used_math); - - if (!used_math()) - goto out; - - /* - * Save FPU state to signal context. Signal handler will "inherit" - * current FPU state. - */ - preempt_disable(); - - if (!is_fpu_owner()) { - own_fpu(); - restore_fp(current); - } - err |= save_fp_context(sc); - - preempt_enable(); - out: -#endif return err; } @@ -2602,68 +2564,33 @@ static inline int restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) { int err = 0; + int i; err |= __get_user(regs->CP0_EPC, &sc->sc_pc); err |= __get_user(regs->active_tc.HI[0], &sc->sc_mdhi); err |= __get_user(regs->active_tc.LO[0], &sc->sc_mdlo); -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); \ - } while(0) - restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); - restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); - restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); - restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); - restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); - restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); - restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); - restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); - restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); - restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); - restore_gp_reg(31); -#undef restore_gp_reg - -#if 0 - if (cpu_has_dsp) { - err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); - err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); - err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); - err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); - err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); - err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); - err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); - } -#ifdef CONFIG_64BIT - err |= __get_user(regs->hi, &sc->sc_hi[0]); - err |= __get_user(regs->lo, &sc->sc_lo[0]); - if (cpu_has_dsp) { - err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg); - err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg); - err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg); - err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg); - err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg); - err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg); - err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); - } -#endif - - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - preempt_disable(); - - if (used_math()) { - /* restore fpu context if we have used it before */ - own_fpu(); - err |= restore_fp_context(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(); + for (i = 1; i < 32; ++i) { + err |= __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); + } + + err |= __get_user(regs->active_tc.HI[1], &sc->sc_hi1); + err |= __get_user(regs->active_tc.HI[2], &sc->sc_hi2); + err |= __get_user(regs->active_tc.HI[3], &sc->sc_hi3); + err |= __get_user(regs->active_tc.LO[1], &sc->sc_lo1); + err |= __get_user(regs->active_tc.LO[2], &sc->sc_lo2); + err |= __get_user(regs->active_tc.LO[3], &sc->sc_lo3); + { + uint32_t dsp; + err |= __get_user(dsp, &sc->sc_dsp); + cpu_wrdsp(dsp, 0x3ff, regs); + } + + for (i = 0; i < 32; ++i) { + err |= __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); } - preempt_enable(); -#endif return err; } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 0e198b12db..ca63148b18 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -504,6 +504,9 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); #define cpu_signal_handler cpu_mips_signal_handler #define cpu_list mips_cpu_list +extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env); +extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env); + #define CPU_SAVE_VERSION 3 /* MMU modes definitions. We carefully match the indices with our diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index ffa9396c4b..472be35bbf 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -3643,7 +3643,7 @@ void helper_dmthlip(target_ulong rs, target_ulong ac, CPUMIPSState *env) } #endif -void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env) +void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env) { uint8_t mask[6]; uint8_t i; @@ -3709,7 +3709,12 @@ void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env) env->active_tc.DSPControl = dsp; } -target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env) +void helper_wrdsp(target_ulong rs, target_ulong mask_num, CPUMIPSState *env) +{ + return cpu_wrdsp(rs, mask_num, env); +} + +uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env) { uint8_t mask[6]; uint32_t ruler, i; @@ -3718,7 +3723,7 @@ target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env) ruler = 0x01; for (i = 0; i < 6; i++) { - mask[i] = (masknum & ruler) >> i ; + mask[i] = (mask_num & ruler) >> i ; ruler = ruler << 1; } @@ -3760,6 +3765,11 @@ target_ulong helper_rddsp(target_ulong masknum, CPUMIPSState *env) return temp; } +target_ulong helper_rddsp(target_ulong mask_num, CPUMIPSState *env) +{ + return cpu_rddsp(mask_num, env); +} + #undef MIPSDSP_LHI #undef MIPSDSP_LLO From ff4f7382815d31933fe0cbedce03270e4b62b771 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 10 Feb 2013 10:30:45 -0800 Subject: [PATCH 1374/1634] mips-linux-user: Fix n32 and n64 syscalls Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- linux-user/main.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index cb14c0bcad..d8b0cd65fa 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1787,8 +1787,8 @@ void cpu_loop(CPUPPCState *env) #ifdef TARGET_MIPS -#define MIPS_SYS(name, args) args, - +# ifdef TARGET_ABI_MIPSO32 +# define MIPS_SYS(name, args) args, static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_syscall , 8) /* 4000 */ MIPS_SYS(sys_exit , 1) @@ -2134,8 +2134,8 @@ static const uint8_t mips_syscall_args[] = { MIPS_SYS(sys_clock_adjtime, 2) MIPS_SYS(sys_syncfs, 1) }; - -#undef MIPS_SYS +# undef MIPS_SYS +# endif /* O32 */ static int do_store_exclusive(CPUMIPSState *env) { @@ -2217,8 +2217,11 @@ void cpu_loop(CPUMIPSState *env) { CPUState *cs = CPU(mips_env_get_cpu(env)); target_siginfo_t info; - int trapnr, ret; + int trapnr; + abi_long ret; +# ifdef TARGET_ABI_MIPSO32 unsigned int syscall_num; +# endif for(;;) { cpu_exec_start(cs); @@ -2226,8 +2229,9 @@ void cpu_loop(CPUMIPSState *env) cpu_exec_end(cs); switch(trapnr) { case EXCP_SYSCALL: - syscall_num = env->active_tc.gpr[2] - 4000; env->active_tc.PC += 4; +# ifdef TARGET_ABI_MIPSO32 + syscall_num = env->active_tc.gpr[2] - 4000; if (syscall_num >= sizeof(mips_syscall_args)) { ret = -TARGET_ENOSYS; } else { @@ -2266,12 +2270,19 @@ void cpu_loop(CPUMIPSState *env) arg5, arg6, arg7, arg8); } done_syscall: +# else + ret = do_syscall(env, env->active_tc.gpr[2], + env->active_tc.gpr[4], env->active_tc.gpr[5], + env->active_tc.gpr[6], env->active_tc.gpr[7], + env->active_tc.gpr[8], env->active_tc.gpr[9], + env->active_tc.gpr[10], env->active_tc.gpr[11]); +# endif /* O32 */ if (ret == -TARGET_QEMU_ESIGRETURN) { /* Returning from a successful sigreturn syscall. Avoid clobbering register state. */ break; } - if ((unsigned int)ret >= (unsigned int)(-1133)) { + if ((abi_ulong)ret >= (abi_ulong)-1133) { env->active_tc.gpr[7] = 1; /* error flag */ ret = -ret; } else { From 68473f15d4c9948986618f63828825beafcaf1cf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 10 Feb 2013 10:30:46 -0800 Subject: [PATCH 1375/1634] mips64-linux-user: Enable 64-bit address mode and fpu Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target-mips/translate.c b/target-mips/translate.c index a51f4303ab..694f07c49f 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15944,6 +15944,14 @@ void cpu_state_reset(CPUMIPSState *env) #if defined(CONFIG_USER_ONLY) env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU); +# ifdef TARGET_MIPS64 + /* Enable 64-bit register mode. */ + env->CP0_Status |= (1 << CP0St_PX); +# endif +# ifdef TARGET_ABI_MIPSN64 + /* Enable 64-bit address mode. */ + env->CP0_Status |= (1 << CP0St_UX); +# endif /* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR hardware registers. */ env->CP0_HWREna |= 0x0000000F; @@ -15953,6 +15961,10 @@ void cpu_state_reset(CPUMIPSState *env) if (env->CP0_Config3 & (1 << CP0C3_DSPP)) { env->CP0_Status |= (1 << CP0St_MX); } + /* Enable 64-bit FPU if the target cpu supports it. */ + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { + env->CP0_Status |= (1 << CP0St_FR); + } #else if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, From 597e2cec8096e0703506abcbbf66938b5ac04368 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 10 Feb 2013 10:30:50 -0800 Subject: [PATCH 1376/1634] mipsn32-linux-user: Configure the architecture properly N32 is a 64-bit cpu with a 32-bit address space. We have existing cpp defines for this situation, but weren't using them. This does mean that the linux-user/mipsn32 directory must be merged with the linux-user/mips64 directory, and differences must be resolved via ifdefs. Signed-off-by: Richard Henderson Signed-off-by: Aurelien Jarno --- configure | 3 +- linux-user/mips64/syscall.h | 18 +- linux-user/mips64/syscall_nr.h | 920 +++++++++++++++++++---------- linux-user/mipsn32/syscall.h | 224 ------- linux-user/mipsn32/syscall_nr.h | 311 ---------- linux-user/mipsn32/target_signal.h | 29 - linux-user/mipsn32/termbits.h | 245 -------- 7 files changed, 628 insertions(+), 1122 deletions(-) delete mode 100644 linux-user/mipsn32/syscall.h delete mode 100644 linux-user/mipsn32/syscall_nr.h delete mode 100644 linux-user/mipsn32/target_signal.h delete mode 100644 linux-user/mipsn32/termbits.h diff --git a/configure b/configure index 08dcc26434..3e1d7811b1 100755 --- a/configure +++ b/configure @@ -4012,9 +4012,10 @@ case "$target_arch2" in target_nptl="yes" ;; mipsn32|mipsn32el) - TARGET_ARCH=mipsn32 + TARGET_ARCH=mips64 TARGET_BASE_ARCH=mips echo "TARGET_ABI_MIPSN32=y" >> $config_target_mak + echo "TARGET_ABI32=y" >> $config_target_mak ;; mips64|mips64el) TARGET_ARCH=mips64 diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index e436ea57dc..cd707df32f 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -3,16 +3,16 @@ stack during a system call. */ struct target_pt_regs { - /* Saved main processor registers. */ - abi_ulong regs[32]; + /* Saved main processor registers. */ + target_ulong regs[32]; - /* Saved special registers. */ - abi_ulong cp0_status; - abi_ulong lo; - abi_ulong hi; - abi_ulong cp0_badvaddr; - abi_ulong cp0_cause; - abi_ulong cp0_epc; + /* Saved special registers. */ + target_ulong cp0_status; + target_ulong lo; + target_ulong hi; + target_ulong cp0_badvaddr; + target_ulong cp0_cause; + target_ulong cp0_epc; }; /* Target errno definitions taken from asm-mips/errno.h */ diff --git a/linux-user/mips64/syscall_nr.h b/linux-user/mips64/syscall_nr.h index 36d27b5159..0f4a6b107b 100644 --- a/linux-user/mips64/syscall_nr.h +++ b/linux-user/mips64/syscall_nr.h @@ -1,306 +1,620 @@ +#ifdef TARGET_ABI32 +/* + * Linux N32 syscalls are in the range from 6000 to 6999. + */ +#define TARGET_NR_Linux 6000 +#define TARGET_NR_read (TARGET_NR_Linux + 0) +#define TARGET_NR_write (TARGET_NR_Linux + 1) +#define TARGET_NR_open (TARGET_NR_Linux + 2) +#define TARGET_NR_close (TARGET_NR_Linux + 3) +#define TARGET_NR_stat (TARGET_NR_Linux + 4) +#define TARGET_NR_fstat (TARGET_NR_Linux + 5) +#define TARGET_NR_lstat (TARGET_NR_Linux + 6) +#define TARGET_NR_poll (TARGET_NR_Linux + 7) +#define TARGET_NR_lseek (TARGET_NR_Linux + 8) +#define TARGET_NR_mmap (TARGET_NR_Linux + 9) +#define TARGET_NR_mprotect (TARGET_NR_Linux + 10) +#define TARGET_NR_munmap (TARGET_NR_Linux + 11) +#define TARGET_NR_brk (TARGET_NR_Linux + 12) +#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 13) +#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 14) +#define TARGET_NR_ioctl (TARGET_NR_Linux + 15) +#define TARGET_NR_pread64 (TARGET_NR_Linux + 16) +#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 17) +#define TARGET_NR_readv (TARGET_NR_Linux + 18) +#define TARGET_NR_writev (TARGET_NR_Linux + 19) +#define TARGET_NR_access (TARGET_NR_Linux + 20) +#define TARGET_NR_pipe (TARGET_NR_Linux + 21) +#define TARGET_NR__newselect (TARGET_NR_Linux + 22) +#define TARGET_NR_sched_yield (TARGET_NR_Linux + 23) +#define TARGET_NR_mremap (TARGET_NR_Linux + 24) +#define TARGET_NR_msync (TARGET_NR_Linux + 25) +#define TARGET_NR_mincore (TARGET_NR_Linux + 26) +#define TARGET_NR_madvise (TARGET_NR_Linux + 27) +#define TARGET_NR_shmget (TARGET_NR_Linux + 28) +#define TARGET_NR_shmat (TARGET_NR_Linux + 29) +#define TARGET_NR_shmctl (TARGET_NR_Linux + 30) +#define TARGET_NR_dup (TARGET_NR_Linux + 31) +#define TARGET_NR_dup2 (TARGET_NR_Linux + 32) +#define TARGET_NR_pause (TARGET_NR_Linux + 33) +#define TARGET_NR_nanosleep (TARGET_NR_Linux + 34) +#define TARGET_NR_getitimer (TARGET_NR_Linux + 35) +#define TARGET_NR_setitimer (TARGET_NR_Linux + 36) +#define TARGET_NR_alarm (TARGET_NR_Linux + 37) +#define TARGET_NR_getpid (TARGET_NR_Linux + 38) +#define TARGET_NR_sendfile (TARGET_NR_Linux + 39) +#define TARGET_NR_socket (TARGET_NR_Linux + 40) +#define TARGET_NR_connect (TARGET_NR_Linux + 41) +#define TARGET_NR_accept (TARGET_NR_Linux + 42) +#define TARGET_NR_sendto (TARGET_NR_Linux + 43) +#define TARGET_NR_recvfrom (TARGET_NR_Linux + 44) +#define TARGET_NR_sendmsg (TARGET_NR_Linux + 45) +#define TARGET_NR_recvmsg (TARGET_NR_Linux + 46) +#define TARGET_NR_shutdown (TARGET_NR_Linux + 47) +#define TARGET_NR_bind (TARGET_NR_Linux + 48) +#define TARGET_NR_listen (TARGET_NR_Linux + 49) +#define TARGET_NR_getsockname (TARGET_NR_Linux + 50) +#define TARGET_NR_getpeername (TARGET_NR_Linux + 51) +#define TARGET_NR_socketpair (TARGET_NR_Linux + 52) +#define TARGET_NR_setsockopt (TARGET_NR_Linux + 53) +#define TARGET_NR_getsockopt (TARGET_NR_Linux + 54) +#define TARGET_NR_clone (TARGET_NR_Linux + 55) +#define TARGET_NR_fork (TARGET_NR_Linux + 56) +#define TARGET_NR_execve (TARGET_NR_Linux + 57) +#define TARGET_NR_exit (TARGET_NR_Linux + 58) +#define TARGET_NR_wait4 (TARGET_NR_Linux + 59) +#define TARGET_NR_kill (TARGET_NR_Linux + 60) +#define TARGET_NR_uname (TARGET_NR_Linux + 61) +#define TARGET_NR_semget (TARGET_NR_Linux + 62) +#define TARGET_NR_semop (TARGET_NR_Linux + 63) +#define TARGET_NR_semctl (TARGET_NR_Linux + 64) +#define TARGET_NR_shmdt (TARGET_NR_Linux + 65) +#define TARGET_NR_msgget (TARGET_NR_Linux + 66) +#define TARGET_NR_msgsnd (TARGET_NR_Linux + 67) +#define TARGET_NR_msgrcv (TARGET_NR_Linux + 68) +#define TARGET_NR_msgctl (TARGET_NR_Linux + 69) +#define TARGET_NR_fcntl (TARGET_NR_Linux + 70) +#define TARGET_NR_flock (TARGET_NR_Linux + 71) +#define TARGET_NR_fsync (TARGET_NR_Linux + 72) +#define TARGET_NR_fdatasync (TARGET_NR_Linux + 73) +#define TARGET_NR_truncate (TARGET_NR_Linux + 74) +#define TARGET_NR_ftruncate (TARGET_NR_Linux + 75) +#define TARGET_NR_getdents (TARGET_NR_Linux + 76) +#define TARGET_NR_getcwd (TARGET_NR_Linux + 77) +#define TARGET_NR_chdir (TARGET_NR_Linux + 78) +#define TARGET_NR_fchdir (TARGET_NR_Linux + 79) +#define TARGET_NR_rename (TARGET_NR_Linux + 80) +#define TARGET_NR_mkdir (TARGET_NR_Linux + 81) +#define TARGET_NR_rmdir (TARGET_NR_Linux + 82) +#define TARGET_NR_creat (TARGET_NR_Linux + 83) +#define TARGET_NR_link (TARGET_NR_Linux + 84) +#define TARGET_NR_unlink (TARGET_NR_Linux + 85) +#define TARGET_NR_symlink (TARGET_NR_Linux + 86) +#define TARGET_NR_readlink (TARGET_NR_Linux + 87) +#define TARGET_NR_chmod (TARGET_NR_Linux + 88) +#define TARGET_NR_fchmod (TARGET_NR_Linux + 89) +#define TARGET_NR_chown (TARGET_NR_Linux + 90) +#define TARGET_NR_fchown (TARGET_NR_Linux + 91) +#define TARGET_NR_lchown (TARGET_NR_Linux + 92) +#define TARGET_NR_umask (TARGET_NR_Linux + 93) +#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 94) +#define TARGET_NR_getrlimit (TARGET_NR_Linux + 95) +#define TARGET_NR_getrusage (TARGET_NR_Linux + 96) +#define TARGET_NR_sysinfo (TARGET_NR_Linux + 97) +#define TARGET_NR_times (TARGET_NR_Linux + 98) +#define TARGET_NR_ptrace (TARGET_NR_Linux + 99) +#define TARGET_NR_getuid (TARGET_NR_Linux + 100) +#define TARGET_NR_syslog (TARGET_NR_Linux + 101) +#define TARGET_NR_getgid (TARGET_NR_Linux + 102) +#define TARGET_NR_setuid (TARGET_NR_Linux + 103) +#define TARGET_NR_setgid (TARGET_NR_Linux + 104) +#define TARGET_NR_geteuid (TARGET_NR_Linux + 105) +#define TARGET_NR_getegid (TARGET_NR_Linux + 106) +#define TARGET_NR_setpgid (TARGET_NR_Linux + 107) +#define TARGET_NR_getppid (TARGET_NR_Linux + 108) +#define TARGET_NR_getpgrp (TARGET_NR_Linux + 109) +#define TARGET_NR_setsid (TARGET_NR_Linux + 110) +#define TARGET_NR_setreuid (TARGET_NR_Linux + 111) +#define TARGET_NR_setregid (TARGET_NR_Linux + 112) +#define TARGET_NR_getgroups (TARGET_NR_Linux + 113) +#define TARGET_NR_setgroups (TARGET_NR_Linux + 114) +#define TARGET_NR_setresuid (TARGET_NR_Linux + 115) +#define TARGET_NR_getresuid (TARGET_NR_Linux + 116) +#define TARGET_NR_setresgid (TARGET_NR_Linux + 117) +#define TARGET_NR_getresgid (TARGET_NR_Linux + 118) +#define TARGET_NR_getpgid (TARGET_NR_Linux + 119) +#define TARGET_NR_setfsuid (TARGET_NR_Linux + 120) +#define TARGET_NR_setfsgid (TARGET_NR_Linux + 121) +#define TARGET_NR_getsid (TARGET_NR_Linux + 122) +#define TARGET_NR_capget (TARGET_NR_Linux + 123) +#define TARGET_NR_capset (TARGET_NR_Linux + 124) +#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 125) +#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 126) +#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 127) +#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 128) +#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 129) +#define TARGET_NR_utime (TARGET_NR_Linux + 130) +#define TARGET_NR_mknod (TARGET_NR_Linux + 131) +#define TARGET_NR_personality (TARGET_NR_Linux + 132) +#define TARGET_NR_ustat (TARGET_NR_Linux + 133) +#define TARGET_NR_statfs (TARGET_NR_Linux + 134) +#define TARGET_NR_fstatfs (TARGET_NR_Linux + 135) +#define TARGET_NR_sysfs (TARGET_NR_Linux + 136) +#define TARGET_NR_getpriority (TARGET_NR_Linux + 137) +#define TARGET_NR_setpriority (TARGET_NR_Linux + 138) +#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 139) +#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 140) +#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 141) +#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 142) +#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 143) +#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 144) +#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 145) +#define TARGET_NR_mlock (TARGET_NR_Linux + 146) +#define TARGET_NR_munlock (TARGET_NR_Linux + 147) +#define TARGET_NR_mlockall (TARGET_NR_Linux + 148) +#define TARGET_NR_munlockall (TARGET_NR_Linux + 149) +#define TARGET_NR_vhangup (TARGET_NR_Linux + 150) +#define TARGET_NR_pivot_root (TARGET_NR_Linux + 151) +#define TARGET_NR__sysctl (TARGET_NR_Linux + 152) +#define TARGET_NR_prctl (TARGET_NR_Linux + 153) +#define TARGET_NR_adjtimex (TARGET_NR_Linux + 154) +#define TARGET_NR_setrlimit (TARGET_NR_Linux + 155) +#define TARGET_NR_chroot (TARGET_NR_Linux + 156) +#define TARGET_NR_sync (TARGET_NR_Linux + 157) +#define TARGET_NR_acct (TARGET_NR_Linux + 158) +#define TARGET_NR_settimeofday (TARGET_NR_Linux + 159) +#define TARGET_NR_mount (TARGET_NR_Linux + 160) +#define TARGET_NR_umount2 (TARGET_NR_Linux + 161) +#define TARGET_NR_swapon (TARGET_NR_Linux + 162) +#define TARGET_NR_swapoff (TARGET_NR_Linux + 163) +#define TARGET_NR_reboot (TARGET_NR_Linux + 164) +#define TARGET_NR_sethostname (TARGET_NR_Linux + 165) +#define TARGET_NR_setdomainname (TARGET_NR_Linux + 166) +#define TARGET_NR_create_module (TARGET_NR_Linux + 167) +#define TARGET_NR_init_module (TARGET_NR_Linux + 168) +#define TARGET_NR_delete_module (TARGET_NR_Linux + 169) +#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 170) +#define TARGET_NR_query_module (TARGET_NR_Linux + 171) +#define TARGET_NR_quotactl (TARGET_NR_Linux + 172) +#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 173) +#define TARGET_NR_getpmsg (TARGET_NR_Linux + 174) +#define TARGET_NR_putpmsg (TARGET_NR_Linux + 175) +#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 176) +#define TARGET_NR_reserved177 (TARGET_NR_Linux + 177) +#define TARGET_NR_gettid (TARGET_NR_Linux + 178) +#define TARGET_NR_readahead (TARGET_NR_Linux + 179) +#define TARGET_NR_setxattr (TARGET_NR_Linux + 180) +#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 181) +#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 182) +#define TARGET_NR_getxattr (TARGET_NR_Linux + 183) +#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 184) +#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 185) +#define TARGET_NR_listxattr (TARGET_NR_Linux + 186) +#define TARGET_NR_llistxattr (TARGET_NR_Linux + 187) +#define TARGET_NR_flistxattr (TARGET_NR_Linux + 188) +#define TARGET_NR_removexattr (TARGET_NR_Linux + 189) +#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 190) +#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 191) +#define TARGET_NR_tkill (TARGET_NR_Linux + 192) +#define TARGET_NR_reserved193 (TARGET_NR_Linux + 193) +#define TARGET_NR_futex (TARGET_NR_Linux + 194) +#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 195) +#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 196) +#define TARGET_NR_cacheflush (TARGET_NR_Linux + 197) +#define TARGET_NR_cachectl (TARGET_NR_Linux + 198) +#define TARGET_NR_sysmips (TARGET_NR_Linux + 199) +#define TARGET_NR_io_setup (TARGET_NR_Linux + 200) +#define TARGET_NR_io_destroy (TARGET_NR_Linux + 201) +#define TARGET_NR_io_getevents (TARGET_NR_Linux + 202) +#define TARGET_NR_io_submit (TARGET_NR_Linux + 203) +#define TARGET_NR_io_cancel (TARGET_NR_Linux + 204) +#define TARGET_NR_exit_group (TARGET_NR_Linux + 205) +#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 206) +#define TARGET_NR_epoll_create (TARGET_NR_Linux + 207) +#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 208) +#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 209) +#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 210) +#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 211) +#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 212) +#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 213) +#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 214) +#define TARGET_NR_semtimedop (TARGET_NR_Linux + 215) +#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 216) +#define TARGET_NR_statfs64 (TARGET_NR_Linux + 217) +#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 218) +#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 219) +#define TARGET_NR_timer_create (TARGET_NR_Linux + 220) +#define TARGET_NR_timer_settime (TARGET_NR_Linux + 221) +#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 222) +#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 223) +#define TARGET_NR_timer_delete (TARGET_NR_Linux + 224) +#define TARGET_NR_clock_settime (TARGET_NR_Linux + 225) +#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 226) +#define TARGET_NR_clock_getres (TARGET_NR_Linux + 227) +#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 228) +#define TARGET_NR_tgkill (TARGET_NR_Linux + 229) +#define TARGET_NR_utimes (TARGET_NR_Linux + 230) +#define TARGET_NR_mbind (TARGET_NR_Linux + 231) +#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 232) +#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 233) +#define TARGET_NR_mq_open (TARGET_NR_Linux + 234) +#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 235) +#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 236) +#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 237) +#define TARGET_NR_mq_notify (TARGET_NR_Linux + 238) +#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 239) +#define TARGET_NR_vserver (TARGET_NR_Linux + 240) +#define TARGET_NR_waitid (TARGET_NR_Linux + 241) +/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 242) */ +#define TARGET_NR_add_key (TARGET_NR_Linux + 243) +#define TARGET_NR_request_key (TARGET_NR_Linux + 244) +#define TARGET_NR_keyctl (TARGET_NR_Linux + 245) +#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 246) +#define TARGET_NR_inotify_init (TARGET_NR_Linux + 247) +#define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 248) +#define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 249) +#define TARGET_NR_migrate_pages (TARGET_NR_Linux + 250) +#define TARGET_NR_openat (TARGET_NR_Linux + 251) +#define TARGET_NR_mkdirat (TARGET_NR_Linux + 252) +#define TARGET_NR_mknodat (TARGET_NR_Linux + 253) +#define TARGET_NR_fchownat (TARGET_NR_Linux + 254) +#define TARGET_NR_futimesat (TARGET_NR_Linux + 255) +#define TARGET_NR_newfstatat (TARGET_NR_Linux + 256) +#define TARGET_NR_unlinkat (TARGET_NR_Linux + 257) +#define TARGET_NR_renameat (TARGET_NR_Linux + 258) +#define TARGET_NR_linkat (TARGET_NR_Linux + 259) +#define TARGET_NR_symlinkat (TARGET_NR_Linux + 260) +#define TARGET_NR_readlinkat (TARGET_NR_Linux + 261) +#define TARGET_NR_fchmodat (TARGET_NR_Linux + 262) +#define TARGET_NR_faccessat (TARGET_NR_Linux + 263) +#define TARGET_NR_pselect6 (TARGET_NR_Linux + 264) +#define TARGET_NR_ppoll (TARGET_NR_Linux + 265) +#define TARGET_NR_unshare (TARGET_NR_Linux + 266) +#define TARGET_NR_splice (TARGET_NR_Linux + 267) +#define TARGET_NR_sync_file_range (TARGET_NR_Linux + 268) +#define TARGET_NR_tee (TARGET_NR_Linux + 269) +#define TARGET_NR_vmsplice (TARGET_NR_Linux + 270) +#define TARGET_NR_move_pages (TARGET_NR_Linux + 271) +#define TARGET_NR_set_robust_list (TARGET_NR_Linux + 272) +#define TARGET_NR_get_robust_list (TARGET_NR_Linux + 273) +#define TARGET_NR_kexec_load (TARGET_NR_Linux + 274) +#define TARGET_NR_getcpu (TARGET_NR_Linux + 275) +#define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 276) +#define TARGET_NR_ioprio_set (TARGET_NR_Linux + 277) +#define TARGET_NR_ioprio_get (TARGET_NR_Linux + 278) +#define TARGET_NR_utimensat (TARGET_NR_Linux + 279) +#define TARGET_NR_signalfd (TARGET_NR_Linux + 280) +#define TARGET_NR_timerfd (TARGET_NR_Linux + 281) +#define TARGET_NR_eventfd (TARGET_NR_Linux + 282) +#define TARGET_NR_fallocate (TARGET_NR_Linux + 283) +#define TARGET_NR_timerfd_create (TARGET_NR_Linux + 284) +#define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 285) +#define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 286) +#define TARGET_NR_signalfd4 (TARGET_NR_Linux + 287) +#define TARGET_NR_eventfd2 (TARGET_NR_Linux + 288) +#define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 289) +#define TARGET_NR_dup3 (TARGET_NR_Linux + 290) +#define TARGET_NR_pipe2 (TARGET_NR_Linux + 291) +#define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 292) +#define TARGET_NR_preadv (TARGET_NR_Linux + 293) +#define TARGET_NR_pwritev (TARGET_NR_Linux + 294) +#define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 295) +#define TARGET_NR_perf_event_open (TARGET_NR_Linux + 296) +#define TARGET_NR_accept4 (TARGET_NR_Linux + 297) +#define TARGET_NR_recvmmsg (TARGET_NR_Linux + 298) +#define TARGET_NR_getdents64 (TARGET_NR_Linux + 299) +#define TARGET_NR_fanotify_init (TARGET_NR_Linux + 300) +#define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 301) +#define TARGET_NR_prlimit64 (TARGET_NR_Linux + 302) +#define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 303) +#define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 304) +#define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 305) +#define TARGET_NR_syncfs (TARGET_NR_Linux + 306) +#else /* * Linux 64-bit syscalls are in the range from 5000 to 5999. */ -#define TARGET_NR_Linux 5000 -#define TARGET_NR_read (TARGET_NR_Linux + 0) -#define TARGET_NR_write (TARGET_NR_Linux + 1) -#define TARGET_NR_open (TARGET_NR_Linux + 2) -#define TARGET_NR_close (TARGET_NR_Linux + 3) -#define TARGET_NR_stat (TARGET_NR_Linux + 4) -#define TARGET_NR_fstat (TARGET_NR_Linux + 5) -#define TARGET_NR_lstat (TARGET_NR_Linux + 6) -#define TARGET_NR_poll (TARGET_NR_Linux + 7) -#define TARGET_NR_lseek (TARGET_NR_Linux + 8) -#define TARGET_NR_mmap (TARGET_NR_Linux + 9) -#define TARGET_NR_mprotect (TARGET_NR_Linux + 10) -#define TARGET_NR_munmap (TARGET_NR_Linux + 11) -#define TARGET_NR_brk (TARGET_NR_Linux + 12) -#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 13) -#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 14) -#define TARGET_NR_ioctl (TARGET_NR_Linux + 15) -#define TARGET_NR_pread64 (TARGET_NR_Linux + 16) -#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 17) -#define TARGET_NR_readv (TARGET_NR_Linux + 18) -#define TARGET_NR_writev (TARGET_NR_Linux + 19) -#define TARGET_NR_access (TARGET_NR_Linux + 20) -#define TARGET_NR_pipe (TARGET_NR_Linux + 21) -#define TARGET_NR__newselect (TARGET_NR_Linux + 22) -#define TARGET_NR_sched_yield (TARGET_NR_Linux + 23) -#define TARGET_NR_mremap (TARGET_NR_Linux + 24) -#define TARGET_NR_msync (TARGET_NR_Linux + 25) -#define TARGET_NR_mincore (TARGET_NR_Linux + 26) -#define TARGET_NR_madvise (TARGET_NR_Linux + 27) -#define TARGET_NR_shmget (TARGET_NR_Linux + 28) -#define TARGET_NR_shmat (TARGET_NR_Linux + 29) -#define TARGET_NR_shmctl (TARGET_NR_Linux + 30) -#define TARGET_NR_dup (TARGET_NR_Linux + 31) -#define TARGET_NR_dup2 (TARGET_NR_Linux + 32) -#define TARGET_NR_pause (TARGET_NR_Linux + 33) -#define TARGET_NR_nanosleep (TARGET_NR_Linux + 34) -#define TARGET_NR_getitimer (TARGET_NR_Linux + 35) -#define TARGET_NR_setitimer (TARGET_NR_Linux + 36) -#define TARGET_NR_alarm (TARGET_NR_Linux + 37) -#define TARGET_NR_getpid (TARGET_NR_Linux + 38) -#define TARGET_NR_sendfile (TARGET_NR_Linux + 39) -#define TARGET_NR_socket (TARGET_NR_Linux + 40) -#define TARGET_NR_connect (TARGET_NR_Linux + 41) -#define TARGET_NR_accept (TARGET_NR_Linux + 42) -#define TARGET_NR_sendto (TARGET_NR_Linux + 43) -#define TARGET_NR_recvfrom (TARGET_NR_Linux + 44) -#define TARGET_NR_sendmsg (TARGET_NR_Linux + 45) -#define TARGET_NR_recvmsg (TARGET_NR_Linux + 46) -#define TARGET_NR_shutdown (TARGET_NR_Linux + 47) -#define TARGET_NR_bind (TARGET_NR_Linux + 48) -#define TARGET_NR_listen (TARGET_NR_Linux + 49) -#define TARGET_NR_getsockname (TARGET_NR_Linux + 50) -#define TARGET_NR_getpeername (TARGET_NR_Linux + 51) -#define TARGET_NR_socketpair (TARGET_NR_Linux + 52) -#define TARGET_NR_setsockopt (TARGET_NR_Linux + 53) -#define TARGET_NR_getsockopt (TARGET_NR_Linux + 54) -#define TARGET_NR_clone (TARGET_NR_Linux + 55) -#define TARGET_NR_fork (TARGET_NR_Linux + 56) -#define TARGET_NR_execve (TARGET_NR_Linux + 57) -#define TARGET_NR_exit (TARGET_NR_Linux + 58) -#define TARGET_NR_wait4 (TARGET_NR_Linux + 59) -#define TARGET_NR_kill (TARGET_NR_Linux + 60) -#define TARGET_NR_uname (TARGET_NR_Linux + 61) -#define TARGET_NR_semget (TARGET_NR_Linux + 62) -#define TARGET_NR_semop (TARGET_NR_Linux + 63) -#define TARGET_NR_semctl (TARGET_NR_Linux + 64) -#define TARGET_NR_shmdt (TARGET_NR_Linux + 65) -#define TARGET_NR_msgget (TARGET_NR_Linux + 66) -#define TARGET_NR_msgsnd (TARGET_NR_Linux + 67) -#define TARGET_NR_msgrcv (TARGET_NR_Linux + 68) -#define TARGET_NR_msgctl (TARGET_NR_Linux + 69) -#define TARGET_NR_fcntl (TARGET_NR_Linux + 70) -#define TARGET_NR_flock (TARGET_NR_Linux + 71) -#define TARGET_NR_fsync (TARGET_NR_Linux + 72) -#define TARGET_NR_fdatasync (TARGET_NR_Linux + 73) -#define TARGET_NR_truncate (TARGET_NR_Linux + 74) -#define TARGET_NR_ftruncate (TARGET_NR_Linux + 75) -#define TARGET_NR_getdents (TARGET_NR_Linux + 76) -#define TARGET_NR_getcwd (TARGET_NR_Linux + 77) -#define TARGET_NR_chdir (TARGET_NR_Linux + 78) -#define TARGET_NR_fchdir (TARGET_NR_Linux + 79) -#define TARGET_NR_rename (TARGET_NR_Linux + 80) -#define TARGET_NR_mkdir (TARGET_NR_Linux + 81) -#define TARGET_NR_rmdir (TARGET_NR_Linux + 82) -#define TARGET_NR_creat (TARGET_NR_Linux + 83) -#define TARGET_NR_link (TARGET_NR_Linux + 84) -#define TARGET_NR_unlink (TARGET_NR_Linux + 85) -#define TARGET_NR_symlink (TARGET_NR_Linux + 86) -#define TARGET_NR_readlink (TARGET_NR_Linux + 87) -#define TARGET_NR_chmod (TARGET_NR_Linux + 88) -#define TARGET_NR_fchmod (TARGET_NR_Linux + 89) -#define TARGET_NR_chown (TARGET_NR_Linux + 90) -#define TARGET_NR_fchown (TARGET_NR_Linux + 91) -#define TARGET_NR_lchown (TARGET_NR_Linux + 92) -#define TARGET_NR_umask (TARGET_NR_Linux + 93) -#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 94) -#define TARGET_NR_getrlimit (TARGET_NR_Linux + 95) -#define TARGET_NR_getrusage (TARGET_NR_Linux + 96) -#define TARGET_NR_sysinfo (TARGET_NR_Linux + 97) -#define TARGET_NR_times (TARGET_NR_Linux + 98) -#define TARGET_NR_ptrace (TARGET_NR_Linux + 99) -#define TARGET_NR_getuid (TARGET_NR_Linux + 100) -#define TARGET_NR_syslog (TARGET_NR_Linux + 101) -#define TARGET_NR_getgid (TARGET_NR_Linux + 102) -#define TARGET_NR_setuid (TARGET_NR_Linux + 103) -#define TARGET_NR_setgid (TARGET_NR_Linux + 104) -#define TARGET_NR_geteuid (TARGET_NR_Linux + 105) -#define TARGET_NR_getegid (TARGET_NR_Linux + 106) -#define TARGET_NR_setpgid (TARGET_NR_Linux + 107) -#define TARGET_NR_getppid (TARGET_NR_Linux + 108) -#define TARGET_NR_getpgrp (TARGET_NR_Linux + 109) -#define TARGET_NR_setsid (TARGET_NR_Linux + 110) -#define TARGET_NR_setreuid (TARGET_NR_Linux + 111) -#define TARGET_NR_setregid (TARGET_NR_Linux + 112) -#define TARGET_NR_getgroups (TARGET_NR_Linux + 113) -#define TARGET_NR_setgroups (TARGET_NR_Linux + 114) -#define TARGET_NR_setresuid (TARGET_NR_Linux + 115) -#define TARGET_NR_getresuid (TARGET_NR_Linux + 116) -#define TARGET_NR_setresgid (TARGET_NR_Linux + 117) -#define TARGET_NR_getresgid (TARGET_NR_Linux + 118) -#define TARGET_NR_getpgid (TARGET_NR_Linux + 119) -#define TARGET_NR_setfsuid (TARGET_NR_Linux + 120) -#define TARGET_NR_setfsgid (TARGET_NR_Linux + 121) -#define TARGET_NR_getsid (TARGET_NR_Linux + 122) -#define TARGET_NR_capget (TARGET_NR_Linux + 123) -#define TARGET_NR_capset (TARGET_NR_Linux + 124) -#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 125) -#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 126) -#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 127) -#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 128) -#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 129) -#define TARGET_NR_utime (TARGET_NR_Linux + 130) -#define TARGET_NR_mknod (TARGET_NR_Linux + 131) -#define TARGET_NR_personality (TARGET_NR_Linux + 132) -#define TARGET_NR_ustat (TARGET_NR_Linux + 133) -#define TARGET_NR_statfs (TARGET_NR_Linux + 134) -#define TARGET_NR_fstatfs (TARGET_NR_Linux + 135) -#define TARGET_NR_sysfs (TARGET_NR_Linux + 136) -#define TARGET_NR_getpriority (TARGET_NR_Linux + 137) -#define TARGET_NR_setpriority (TARGET_NR_Linux + 138) -#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 139) -#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 140) -#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 141) -#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 142) -#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 143) -#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 144) -#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 145) -#define TARGET_NR_mlock (TARGET_NR_Linux + 146) -#define TARGET_NR_munlock (TARGET_NR_Linux + 147) -#define TARGET_NR_mlockall (TARGET_NR_Linux + 148) -#define TARGET_NR_munlockall (TARGET_NR_Linux + 149) -#define TARGET_NR_vhangup (TARGET_NR_Linux + 150) -#define TARGET_NR_pivot_root (TARGET_NR_Linux + 151) -#define TARGET_NR__sysctl (TARGET_NR_Linux + 152) -#define TARGET_NR_prctl (TARGET_NR_Linux + 153) -#define TARGET_NR_adjtimex (TARGET_NR_Linux + 154) -#define TARGET_NR_setrlimit (TARGET_NR_Linux + 155) -#define TARGET_NR_chroot (TARGET_NR_Linux + 156) -#define TARGET_NR_sync (TARGET_NR_Linux + 157) -#define TARGET_NR_acct (TARGET_NR_Linux + 158) -#define TARGET_NR_settimeofday (TARGET_NR_Linux + 159) -#define TARGET_NR_mount (TARGET_NR_Linux + 160) -#define TARGET_NR_umount2 (TARGET_NR_Linux + 161) -#define TARGET_NR_swapon (TARGET_NR_Linux + 162) -#define TARGET_NR_swapoff (TARGET_NR_Linux + 163) -#define TARGET_NR_reboot (TARGET_NR_Linux + 164) -#define TARGET_NR_sethostname (TARGET_NR_Linux + 165) -#define TARGET_NR_setdomainname (TARGET_NR_Linux + 166) -#define TARGET_NR_create_module (TARGET_NR_Linux + 167) -#define TARGET_NR_init_module (TARGET_NR_Linux + 168) -#define TARGET_NR_delete_module (TARGET_NR_Linux + 169) -#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 170) -#define TARGET_NR_query_module (TARGET_NR_Linux + 171) -#define TARGET_NR_quotactl (TARGET_NR_Linux + 172) -#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 173) -#define TARGET_NR_getpmsg (TARGET_NR_Linux + 174) -#define TARGET_NR_putpmsg (TARGET_NR_Linux + 175) -#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 176) -#define TARGET_NR_reserved177 (TARGET_NR_Linux + 177) -#define TARGET_NR_gettid (TARGET_NR_Linux + 178) -#define TARGET_NR_readahead (TARGET_NR_Linux + 179) -#define TARGET_NR_setxattr (TARGET_NR_Linux + 180) -#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 181) -#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 182) -#define TARGET_NR_getxattr (TARGET_NR_Linux + 183) -#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 184) -#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 185) -#define TARGET_NR_listxattr (TARGET_NR_Linux + 186) -#define TARGET_NR_llistxattr (TARGET_NR_Linux + 187) -#define TARGET_NR_flistxattr (TARGET_NR_Linux + 188) -#define TARGET_NR_removexattr (TARGET_NR_Linux + 189) -#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 190) -#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 191) -#define TARGET_NR_tkill (TARGET_NR_Linux + 192) -#define TARGET_NR_reserved193 (TARGET_NR_Linux + 193) -#define TARGET_NR_futex (TARGET_NR_Linux + 194) -#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 195) -#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 196) -#define TARGET_NR_cacheflush (TARGET_NR_Linux + 197) -#define TARGET_NR_cachectl (TARGET_NR_Linux + 198) -#define TARGET_NR_sysmips (TARGET_NR_Linux + 199) -#define TARGET_NR_io_setup (TARGET_NR_Linux + 200) -#define TARGET_NR_io_destroy (TARGET_NR_Linux + 201) -#define TARGET_NR_io_getevents (TARGET_NR_Linux + 202) -#define TARGET_NR_io_submit (TARGET_NR_Linux + 203) -#define TARGET_NR_io_cancel (TARGET_NR_Linux + 204) -#define TARGET_NR_exit_group (TARGET_NR_Linux + 205) -#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 206) -#define TARGET_NR_epoll_create (TARGET_NR_Linux + 207) -#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 208) -#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 209) -#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 210) -#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 211) -#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 212) -#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 213) -#define TARGET_NR_semtimedop (TARGET_NR_Linux + 214) -#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 215) -#define TARGET_NR_timer_create (TARGET_NR_Linux + 216) -#define TARGET_NR_timer_settime (TARGET_NR_Linux + 217) -#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 218) -#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 219) -#define TARGET_NR_timer_delete (TARGET_NR_Linux + 220) -#define TARGET_NR_clock_settime (TARGET_NR_Linux + 221) -#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 222) -#define TARGET_NR_clock_getres (TARGET_NR_Linux + 223) -#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 224) -#define TARGET_NR_tgkill (TARGET_NR_Linux + 225) -#define TARGET_NR_utimes (TARGET_NR_Linux + 226) -#define TARGET_NR_mbind (TARGET_NR_Linux + 227) -#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 228) -#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 229) -#define TARGET_NR_mq_open (TARGET_NR_Linux + 230) -#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 231) -#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 232) -#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 233) -#define TARGET_NR_mq_notify (TARGET_NR_Linux + 234) -#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 235) -#define TARGET_NR_vserver (TARGET_NR_Linux + 236) -#define TARGET_NR_waitid (TARGET_NR_Linux + 237) -/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 238) */ -#define TARGET_NR_add_key (TARGET_NR_Linux + 239) -#define TARGET_NR_request_key (TARGET_NR_Linux + 240) -#define TARGET_NR_keyctl (TARGET_NR_Linux + 241) -#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 242) -#define TARGET_NR_inotify_init (TARGET_NR_Linux + 243) -#define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 244) -#define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 245) -#define TARGET_NR_migrate_pages (TARGET_NR_Linux + 246) -#define TARGET_NR_openat (TARGET_NR_Linux + 247) -#define TARGET_NR_mkdirat (TARGET_NR_Linux + 248) -#define TARGET_NR_mknodat (TARGET_NR_Linux + 249) -#define TARGET_NR_fchownat (TARGET_NR_Linux + 250) -#define TARGET_NR_futimesat (TARGET_NR_Linux + 251) -#define TARGET_NR_newfstatat (TARGET_NR_Linux + 252) -#define TARGET_NR_unlinkat (TARGET_NR_Linux + 253) -#define TARGET_NR_renameat (TARGET_NR_Linux + 254) -#define TARGET_NR_linkat (TARGET_NR_Linux + 255) -#define TARGET_NR_symlinkat (TARGET_NR_Linux + 256) -#define TARGET_NR_readlinkat (TARGET_NR_Linux + 257) -#define TARGET_NR_fchmodat (TARGET_NR_Linux + 258) -#define TARGET_NR_faccessat (TARGET_NR_Linux + 259) -#define TARGET_NR_pselect6 (TARGET_NR_Linux + 260) -#define TARGET_NR_ppoll (TARGET_NR_Linux + 261) -#define TARGET_NR_unshare (TARGET_NR_Linux + 262) -#define TARGET_NR_splice (TARGET_NR_Linux + 263) -#define TARGET_NR_sync_file_range (TARGET_NR_Linux + 264) -#define TARGET_NR_tee (TARGET_NR_Linux + 265) -#define TARGET_NR_vmsplice (TARGET_NR_Linux + 266) -#define TARGET_NR_move_pages (TARGET_NR_Linux + 267) -#define TARGET_NR_set_robust_list (TARGET_NR_Linux + 268) -#define TARGET_NR_get_robust_list (TARGET_NR_Linux + 269) -#define TARGET_NR_kexec_load (TARGET_NR_Linux + 270) -#define TARGET_NR_getcpu (TARGET_NR_Linux + 271) -#define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 272) -#define TARGET_NR_ioprio_set (TARGET_NR_Linux + 273) -#define TARGET_NR_ioprio_get (TARGET_NR_Linux + 274) -#define TARGET_NR_utimensat (TARGET_NR_Linux + 275) -#define TARGET_NR_signalfd (TARGET_NR_Linux + 276) -#define TARGET_NR_timerfd (TARGET_NR_Linux + 277) -#define TARGET_NR_eventfd (TARGET_NR_Linux + 278) -#define TARGET_NR_fallocate (TARGET_NR_Linux + 279) -#define TARGET_NR_timerfd_create (TARGET_NR_Linux + 280) -#define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 281) -#define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 282) -#define TARGET_NR_signalfd4 (TARGET_NR_Linux + 283) -#define TARGET_NR_eventfd2 (TARGET_NR_Linux + 284) -#define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 285) -#define TARGET_NR_dup3 (TARGET_NR_Linux + 286) -#define TARGET_NR_pipe2 (TARGET_NR_Linux + 287) -#define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 288) -#define TARGET_NR_preadv (TARGET_NR_Linux + 289) -#define TARGET_NR_pwritev (TARGET_NR_Linux + 290) -#define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 291) -#define TARGET_NR_perf_event_open (TARGET_NR_Linux + 292) -#define TARGET_NR_accept4 (TARGET_NR_Linux + 293) -#define TARGET_NR_recvmmsg (TARGET_NR_Linux + 294) -#define TARGET_NR_fanotify_init (TARGET_NR_Linux + 295) -#define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 296) -#define TARGET_NR_prlimit64 (TARGET_NR_Linux + 297) -#define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 298) -#define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 299) -#define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 300) -#define TARGET_NR_syncfs (TARGET_NR_Linux + 301) +#define TARGET_NR_Linux 5000 +#define TARGET_NR_read (TARGET_NR_Linux + 0) +#define TARGET_NR_write (TARGET_NR_Linux + 1) +#define TARGET_NR_open (TARGET_NR_Linux + 2) +#define TARGET_NR_close (TARGET_NR_Linux + 3) +#define TARGET_NR_stat (TARGET_NR_Linux + 4) +#define TARGET_NR_fstat (TARGET_NR_Linux + 5) +#define TARGET_NR_lstat (TARGET_NR_Linux + 6) +#define TARGET_NR_poll (TARGET_NR_Linux + 7) +#define TARGET_NR_lseek (TARGET_NR_Linux + 8) +#define TARGET_NR_mmap (TARGET_NR_Linux + 9) +#define TARGET_NR_mprotect (TARGET_NR_Linux + 10) +#define TARGET_NR_munmap (TARGET_NR_Linux + 11) +#define TARGET_NR_brk (TARGET_NR_Linux + 12) +#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 13) +#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 14) +#define TARGET_NR_ioctl (TARGET_NR_Linux + 15) +#define TARGET_NR_pread64 (TARGET_NR_Linux + 16) +#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 17) +#define TARGET_NR_readv (TARGET_NR_Linux + 18) +#define TARGET_NR_writev (TARGET_NR_Linux + 19) +#define TARGET_NR_access (TARGET_NR_Linux + 20) +#define TARGET_NR_pipe (TARGET_NR_Linux + 21) +#define TARGET_NR__newselect (TARGET_NR_Linux + 22) +#define TARGET_NR_sched_yield (TARGET_NR_Linux + 23) +#define TARGET_NR_mremap (TARGET_NR_Linux + 24) +#define TARGET_NR_msync (TARGET_NR_Linux + 25) +#define TARGET_NR_mincore (TARGET_NR_Linux + 26) +#define TARGET_NR_madvise (TARGET_NR_Linux + 27) +#define TARGET_NR_shmget (TARGET_NR_Linux + 28) +#define TARGET_NR_shmat (TARGET_NR_Linux + 29) +#define TARGET_NR_shmctl (TARGET_NR_Linux + 30) +#define TARGET_NR_dup (TARGET_NR_Linux + 31) +#define TARGET_NR_dup2 (TARGET_NR_Linux + 32) +#define TARGET_NR_pause (TARGET_NR_Linux + 33) +#define TARGET_NR_nanosleep (TARGET_NR_Linux + 34) +#define TARGET_NR_getitimer (TARGET_NR_Linux + 35) +#define TARGET_NR_setitimer (TARGET_NR_Linux + 36) +#define TARGET_NR_alarm (TARGET_NR_Linux + 37) +#define TARGET_NR_getpid (TARGET_NR_Linux + 38) +#define TARGET_NR_sendfile (TARGET_NR_Linux + 39) +#define TARGET_NR_socket (TARGET_NR_Linux + 40) +#define TARGET_NR_connect (TARGET_NR_Linux + 41) +#define TARGET_NR_accept (TARGET_NR_Linux + 42) +#define TARGET_NR_sendto (TARGET_NR_Linux + 43) +#define TARGET_NR_recvfrom (TARGET_NR_Linux + 44) +#define TARGET_NR_sendmsg (TARGET_NR_Linux + 45) +#define TARGET_NR_recvmsg (TARGET_NR_Linux + 46) +#define TARGET_NR_shutdown (TARGET_NR_Linux + 47) +#define TARGET_NR_bind (TARGET_NR_Linux + 48) +#define TARGET_NR_listen (TARGET_NR_Linux + 49) +#define TARGET_NR_getsockname (TARGET_NR_Linux + 50) +#define TARGET_NR_getpeername (TARGET_NR_Linux + 51) +#define TARGET_NR_socketpair (TARGET_NR_Linux + 52) +#define TARGET_NR_setsockopt (TARGET_NR_Linux + 53) +#define TARGET_NR_getsockopt (TARGET_NR_Linux + 54) +#define TARGET_NR_clone (TARGET_NR_Linux + 55) +#define TARGET_NR_fork (TARGET_NR_Linux + 56) +#define TARGET_NR_execve (TARGET_NR_Linux + 57) +#define TARGET_NR_exit (TARGET_NR_Linux + 58) +#define TARGET_NR_wait4 (TARGET_NR_Linux + 59) +#define TARGET_NR_kill (TARGET_NR_Linux + 60) +#define TARGET_NR_uname (TARGET_NR_Linux + 61) +#define TARGET_NR_semget (TARGET_NR_Linux + 62) +#define TARGET_NR_semop (TARGET_NR_Linux + 63) +#define TARGET_NR_semctl (TARGET_NR_Linux + 64) +#define TARGET_NR_shmdt (TARGET_NR_Linux + 65) +#define TARGET_NR_msgget (TARGET_NR_Linux + 66) +#define TARGET_NR_msgsnd (TARGET_NR_Linux + 67) +#define TARGET_NR_msgrcv (TARGET_NR_Linux + 68) +#define TARGET_NR_msgctl (TARGET_NR_Linux + 69) +#define TARGET_NR_fcntl (TARGET_NR_Linux + 70) +#define TARGET_NR_flock (TARGET_NR_Linux + 71) +#define TARGET_NR_fsync (TARGET_NR_Linux + 72) +#define TARGET_NR_fdatasync (TARGET_NR_Linux + 73) +#define TARGET_NR_truncate (TARGET_NR_Linux + 74) +#define TARGET_NR_ftruncate (TARGET_NR_Linux + 75) +#define TARGET_NR_getdents (TARGET_NR_Linux + 76) +#define TARGET_NR_getcwd (TARGET_NR_Linux + 77) +#define TARGET_NR_chdir (TARGET_NR_Linux + 78) +#define TARGET_NR_fchdir (TARGET_NR_Linux + 79) +#define TARGET_NR_rename (TARGET_NR_Linux + 80) +#define TARGET_NR_mkdir (TARGET_NR_Linux + 81) +#define TARGET_NR_rmdir (TARGET_NR_Linux + 82) +#define TARGET_NR_creat (TARGET_NR_Linux + 83) +#define TARGET_NR_link (TARGET_NR_Linux + 84) +#define TARGET_NR_unlink (TARGET_NR_Linux + 85) +#define TARGET_NR_symlink (TARGET_NR_Linux + 86) +#define TARGET_NR_readlink (TARGET_NR_Linux + 87) +#define TARGET_NR_chmod (TARGET_NR_Linux + 88) +#define TARGET_NR_fchmod (TARGET_NR_Linux + 89) +#define TARGET_NR_chown (TARGET_NR_Linux + 90) +#define TARGET_NR_fchown (TARGET_NR_Linux + 91) +#define TARGET_NR_lchown (TARGET_NR_Linux + 92) +#define TARGET_NR_umask (TARGET_NR_Linux + 93) +#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 94) +#define TARGET_NR_getrlimit (TARGET_NR_Linux + 95) +#define TARGET_NR_getrusage (TARGET_NR_Linux + 96) +#define TARGET_NR_sysinfo (TARGET_NR_Linux + 97) +#define TARGET_NR_times (TARGET_NR_Linux + 98) +#define TARGET_NR_ptrace (TARGET_NR_Linux + 99) +#define TARGET_NR_getuid (TARGET_NR_Linux + 100) +#define TARGET_NR_syslog (TARGET_NR_Linux + 101) +#define TARGET_NR_getgid (TARGET_NR_Linux + 102) +#define TARGET_NR_setuid (TARGET_NR_Linux + 103) +#define TARGET_NR_setgid (TARGET_NR_Linux + 104) +#define TARGET_NR_geteuid (TARGET_NR_Linux + 105) +#define TARGET_NR_getegid (TARGET_NR_Linux + 106) +#define TARGET_NR_setpgid (TARGET_NR_Linux + 107) +#define TARGET_NR_getppid (TARGET_NR_Linux + 108) +#define TARGET_NR_getpgrp (TARGET_NR_Linux + 109) +#define TARGET_NR_setsid (TARGET_NR_Linux + 110) +#define TARGET_NR_setreuid (TARGET_NR_Linux + 111) +#define TARGET_NR_setregid (TARGET_NR_Linux + 112) +#define TARGET_NR_getgroups (TARGET_NR_Linux + 113) +#define TARGET_NR_setgroups (TARGET_NR_Linux + 114) +#define TARGET_NR_setresuid (TARGET_NR_Linux + 115) +#define TARGET_NR_getresuid (TARGET_NR_Linux + 116) +#define TARGET_NR_setresgid (TARGET_NR_Linux + 117) +#define TARGET_NR_getresgid (TARGET_NR_Linux + 118) +#define TARGET_NR_getpgid (TARGET_NR_Linux + 119) +#define TARGET_NR_setfsuid (TARGET_NR_Linux + 120) +#define TARGET_NR_setfsgid (TARGET_NR_Linux + 121) +#define TARGET_NR_getsid (TARGET_NR_Linux + 122) +#define TARGET_NR_capget (TARGET_NR_Linux + 123) +#define TARGET_NR_capset (TARGET_NR_Linux + 124) +#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 125) +#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 126) +#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 127) +#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 128) +#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 129) +#define TARGET_NR_utime (TARGET_NR_Linux + 130) +#define TARGET_NR_mknod (TARGET_NR_Linux + 131) +#define TARGET_NR_personality (TARGET_NR_Linux + 132) +#define TARGET_NR_ustat (TARGET_NR_Linux + 133) +#define TARGET_NR_statfs (TARGET_NR_Linux + 134) +#define TARGET_NR_fstatfs (TARGET_NR_Linux + 135) +#define TARGET_NR_sysfs (TARGET_NR_Linux + 136) +#define TARGET_NR_getpriority (TARGET_NR_Linux + 137) +#define TARGET_NR_setpriority (TARGET_NR_Linux + 138) +#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 139) +#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 140) +#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 141) +#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 142) +#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 143) +#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 144) +#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 145) +#define TARGET_NR_mlock (TARGET_NR_Linux + 146) +#define TARGET_NR_munlock (TARGET_NR_Linux + 147) +#define TARGET_NR_mlockall (TARGET_NR_Linux + 148) +#define TARGET_NR_munlockall (TARGET_NR_Linux + 149) +#define TARGET_NR_vhangup (TARGET_NR_Linux + 150) +#define TARGET_NR_pivot_root (TARGET_NR_Linux + 151) +#define TARGET_NR__sysctl (TARGET_NR_Linux + 152) +#define TARGET_NR_prctl (TARGET_NR_Linux + 153) +#define TARGET_NR_adjtimex (TARGET_NR_Linux + 154) +#define TARGET_NR_setrlimit (TARGET_NR_Linux + 155) +#define TARGET_NR_chroot (TARGET_NR_Linux + 156) +#define TARGET_NR_sync (TARGET_NR_Linux + 157) +#define TARGET_NR_acct (TARGET_NR_Linux + 158) +#define TARGET_NR_settimeofday (TARGET_NR_Linux + 159) +#define TARGET_NR_mount (TARGET_NR_Linux + 160) +#define TARGET_NR_umount2 (TARGET_NR_Linux + 161) +#define TARGET_NR_swapon (TARGET_NR_Linux + 162) +#define TARGET_NR_swapoff (TARGET_NR_Linux + 163) +#define TARGET_NR_reboot (TARGET_NR_Linux + 164) +#define TARGET_NR_sethostname (TARGET_NR_Linux + 165) +#define TARGET_NR_setdomainname (TARGET_NR_Linux + 166) +#define TARGET_NR_create_module (TARGET_NR_Linux + 167) +#define TARGET_NR_init_module (TARGET_NR_Linux + 168) +#define TARGET_NR_delete_module (TARGET_NR_Linux + 169) +#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 170) +#define TARGET_NR_query_module (TARGET_NR_Linux + 171) +#define TARGET_NR_quotactl (TARGET_NR_Linux + 172) +#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 173) +#define TARGET_NR_getpmsg (TARGET_NR_Linux + 174) +#define TARGET_NR_putpmsg (TARGET_NR_Linux + 175) +#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 176) +#define TARGET_NR_reserved177 (TARGET_NR_Linux + 177) +#define TARGET_NR_gettid (TARGET_NR_Linux + 178) +#define TARGET_NR_readahead (TARGET_NR_Linux + 179) +#define TARGET_NR_setxattr (TARGET_NR_Linux + 180) +#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 181) +#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 182) +#define TARGET_NR_getxattr (TARGET_NR_Linux + 183) +#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 184) +#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 185) +#define TARGET_NR_listxattr (TARGET_NR_Linux + 186) +#define TARGET_NR_llistxattr (TARGET_NR_Linux + 187) +#define TARGET_NR_flistxattr (TARGET_NR_Linux + 188) +#define TARGET_NR_removexattr (TARGET_NR_Linux + 189) +#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 190) +#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 191) +#define TARGET_NR_tkill (TARGET_NR_Linux + 192) +#define TARGET_NR_reserved193 (TARGET_NR_Linux + 193) +#define TARGET_NR_futex (TARGET_NR_Linux + 194) +#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 195) +#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 196) +#define TARGET_NR_cacheflush (TARGET_NR_Linux + 197) +#define TARGET_NR_cachectl (TARGET_NR_Linux + 198) +#define TARGET_NR_sysmips (TARGET_NR_Linux + 199) +#define TARGET_NR_io_setup (TARGET_NR_Linux + 200) +#define TARGET_NR_io_destroy (TARGET_NR_Linux + 201) +#define TARGET_NR_io_getevents (TARGET_NR_Linux + 202) +#define TARGET_NR_io_submit (TARGET_NR_Linux + 203) +#define TARGET_NR_io_cancel (TARGET_NR_Linux + 204) +#define TARGET_NR_exit_group (TARGET_NR_Linux + 205) +#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 206) +#define TARGET_NR_epoll_create (TARGET_NR_Linux + 207) +#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 208) +#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 209) +#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 210) +#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 211) +#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 212) +#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 213) +#define TARGET_NR_semtimedop (TARGET_NR_Linux + 214) +#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 215) +#define TARGET_NR_timer_create (TARGET_NR_Linux + 216) +#define TARGET_NR_timer_settime (TARGET_NR_Linux + 217) +#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 218) +#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 219) +#define TARGET_NR_timer_delete (TARGET_NR_Linux + 220) +#define TARGET_NR_clock_settime (TARGET_NR_Linux + 221) +#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 222) +#define TARGET_NR_clock_getres (TARGET_NR_Linux + 223) +#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 224) +#define TARGET_NR_tgkill (TARGET_NR_Linux + 225) +#define TARGET_NR_utimes (TARGET_NR_Linux + 226) +#define TARGET_NR_mbind (TARGET_NR_Linux + 227) +#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 228) +#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 229) +#define TARGET_NR_mq_open (TARGET_NR_Linux + 230) +#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 231) +#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 232) +#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 233) +#define TARGET_NR_mq_notify (TARGET_NR_Linux + 234) +#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 235) +#define TARGET_NR_vserver (TARGET_NR_Linux + 236) +#define TARGET_NR_waitid (TARGET_NR_Linux + 237) +/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 238) */ +#define TARGET_NR_add_key (TARGET_NR_Linux + 239) +#define TARGET_NR_request_key (TARGET_NR_Linux + 240) +#define TARGET_NR_keyctl (TARGET_NR_Linux + 241) +#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 242) +#define TARGET_NR_inotify_init (TARGET_NR_Linux + 243) +#define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 244) +#define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 245) +#define TARGET_NR_migrate_pages (TARGET_NR_Linux + 246) +#define TARGET_NR_openat (TARGET_NR_Linux + 247) +#define TARGET_NR_mkdirat (TARGET_NR_Linux + 248) +#define TARGET_NR_mknodat (TARGET_NR_Linux + 249) +#define TARGET_NR_fchownat (TARGET_NR_Linux + 250) +#define TARGET_NR_futimesat (TARGET_NR_Linux + 251) +#define TARGET_NR_newfstatat (TARGET_NR_Linux + 252) +#define TARGET_NR_unlinkat (TARGET_NR_Linux + 253) +#define TARGET_NR_renameat (TARGET_NR_Linux + 254) +#define TARGET_NR_linkat (TARGET_NR_Linux + 255) +#define TARGET_NR_symlinkat (TARGET_NR_Linux + 256) +#define TARGET_NR_readlinkat (TARGET_NR_Linux + 257) +#define TARGET_NR_fchmodat (TARGET_NR_Linux + 258) +#define TARGET_NR_faccessat (TARGET_NR_Linux + 259) +#define TARGET_NR_pselect6 (TARGET_NR_Linux + 260) +#define TARGET_NR_ppoll (TARGET_NR_Linux + 261) +#define TARGET_NR_unshare (TARGET_NR_Linux + 262) +#define TARGET_NR_splice (TARGET_NR_Linux + 263) +#define TARGET_NR_sync_file_range (TARGET_NR_Linux + 264) +#define TARGET_NR_tee (TARGET_NR_Linux + 265) +#define TARGET_NR_vmsplice (TARGET_NR_Linux + 266) +#define TARGET_NR_move_pages (TARGET_NR_Linux + 267) +#define TARGET_NR_set_robust_list (TARGET_NR_Linux + 268) +#define TARGET_NR_get_robust_list (TARGET_NR_Linux + 269) +#define TARGET_NR_kexec_load (TARGET_NR_Linux + 270) +#define TARGET_NR_getcpu (TARGET_NR_Linux + 271) +#define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 272) +#define TARGET_NR_ioprio_set (TARGET_NR_Linux + 273) +#define TARGET_NR_ioprio_get (TARGET_NR_Linux + 274) +#define TARGET_NR_utimensat (TARGET_NR_Linux + 275) +#define TARGET_NR_signalfd (TARGET_NR_Linux + 276) +#define TARGET_NR_timerfd (TARGET_NR_Linux + 277) +#define TARGET_NR_eventfd (TARGET_NR_Linux + 278) +#define TARGET_NR_fallocate (TARGET_NR_Linux + 279) +#define TARGET_NR_timerfd_create (TARGET_NR_Linux + 280) +#define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 281) +#define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 282) +#define TARGET_NR_signalfd4 (TARGET_NR_Linux + 283) +#define TARGET_NR_eventfd2 (TARGET_NR_Linux + 284) +#define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 285) +#define TARGET_NR_dup3 (TARGET_NR_Linux + 286) +#define TARGET_NR_pipe2 (TARGET_NR_Linux + 287) +#define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 288) +#define TARGET_NR_preadv (TARGET_NR_Linux + 289) +#define TARGET_NR_pwritev (TARGET_NR_Linux + 290) +#define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 291) +#define TARGET_NR_perf_event_open (TARGET_NR_Linux + 292) +#define TARGET_NR_accept4 (TARGET_NR_Linux + 293) +#define TARGET_NR_recvmmsg (TARGET_NR_Linux + 294) +#define TARGET_NR_fanotify_init (TARGET_NR_Linux + 295) +#define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 296) +#define TARGET_NR_prlimit64 (TARGET_NR_Linux + 297) +#define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 298) +#define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 299) +#define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 300) +#define TARGET_NR_syncfs (TARGET_NR_Linux + 301) +#endif diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h deleted file mode 100644 index ebe98f2070..0000000000 --- a/linux-user/mipsn32/syscall.h +++ /dev/null @@ -1,224 +0,0 @@ - -/* this struct defines the way the registers are stored on the - stack during a system call. */ - -struct target_pt_regs { - /* Saved main processor registers. */ - target_ulong regs[32]; - - /* Saved special registers. */ - target_ulong cp0_status; - target_ulong lo; - target_ulong hi; - target_ulong cp0_badvaddr; - target_ulong cp0_cause; - target_ulong cp0_epc; -}; - -/* Target errno definitions taken from asm-mips/errno.h */ -#undef TARGET_ENOMSG -#define TARGET_ENOMSG 35 /* Identifier removed */ -#undef TARGET_EIDRM -#define TARGET_EIDRM 36 /* Identifier removed */ -#undef TARGET_ECHRNG -#define TARGET_ECHRNG 37 /* Channel number out of range */ -#undef TARGET_EL2NSYNC -#define TARGET_EL2NSYNC 38 /* Level 2 not synchronized */ -#undef TARGET_EL3HLT -#define TARGET_EL3HLT 39 /* Level 3 halted */ -#undef TARGET_EL3RST -#define TARGET_EL3RST 40 /* Level 3 reset */ -#undef TARGET_ELNRNG -#define TARGET_ELNRNG 41 /* Link number out of range */ -#undef TARGET_EUNATCH -#define TARGET_EUNATCH 42 /* Protocol driver not attached */ -#undef TARGET_ENOCSI -#define TARGET_ENOCSI 43 /* No CSI structure available */ -#undef TARGET_EL2HLT -#define TARGET_EL2HLT 44 /* Level 2 halted */ -#undef TARGET_EDEADLK -#define TARGET_EDEADLK 45 /* Resource deadlock would occur */ -#undef TARGET_ENOLCK -#define TARGET_ENOLCK 46 /* No record locks available */ -#undef TARGET_EBADE -#define TARGET_EBADE 50 /* Invalid exchange */ -#undef TARGET_EBADR -#define TARGET_EBADR 51 /* Invalid request descriptor */ -#undef TARGET_EXFULL -#define TARGET_EXFULL 52 /* TARGET_Exchange full */ -#undef TARGET_ENOANO -#define TARGET_ENOANO 53 /* No anode */ -#undef TARGET_EBADRQC -#define TARGET_EBADRQC 54 /* Invalid request code */ -#undef TARGET_EBADSLT -#define TARGET_EBADSLT 55 /* Invalid slot */ -#undef TARGET_EDEADLOCK -#define TARGET_EDEADLOCK 56 /* File locking deadlock error */ -#undef TARGET_EBFONT -#define TARGET_EBFONT 59 /* Bad font file format */ -#undef TARGET_ENOSTR -#define TARGET_ENOSTR 60 /* Device not a stream */ -#undef TARGET_ENODATA -#define TARGET_ENODATA 61 /* No data available */ -#undef TARGET_ETIME -#define TARGET_ETIME 62 /* Timer expired */ -#undef TARGET_ENOSR -#define TARGET_ENOSR 63 /* Out of streams resources */ -#undef TARGET_ENONET -#define TARGET_ENONET 64 /* Machine is not on the network */ -#undef TARGET_ENOPKG -#define TARGET_ENOPKG 65 /* Package not installed */ -#undef TARGET_EREMOTE -#define TARGET_EREMOTE 66 /* Object is remote */ -#undef TARGET_ENOLINK -#define TARGET_ENOLINK 67 /* Link has been severed */ -#undef TARGET_EADV -#define TARGET_EADV 68 /* Advertise error */ -#undef TARGET_ESRMNT -#define TARGET_ESRMNT 69 /* Srmount error */ -#undef TARGET_ECOMM -#define TARGET_ECOMM 70 /* Communication error on send */ -#undef TARGET_EPROTO -#define TARGET_EPROTO 71 /* Protocol error */ -#undef TARGET_EDOTDOT -#define TARGET_EDOTDOT 73 /* RFS specific error */ -#undef TARGET_EMULTIHOP -#define TARGET_EMULTIHOP 74 /* Multihop attempted */ -#undef TARGET_EBADMSG -#define TARGET_EBADMSG 77 /* Not a data message */ -#undef TARGET_ENAMETOOLONG -#define TARGET_ENAMETOOLONG 78 /* File name too long */ -#undef TARGET_EOVERFLOW -#define TARGET_EOVERFLOW 79 /* Value too large for defined data type */ -#undef TARGET_ENOTUNIQ -#define TARGET_ENOTUNIQ 80 /* Name not unique on network */ -#undef TARGET_EBADFD -#define TARGET_EBADFD 81 /* File descriptor in bad state */ -#undef TARGET_EREMCHG -#define TARGET_EREMCHG 82 /* Remote address changed */ -#undef TARGET_ELIBACC -#define TARGET_ELIBACC 83 /* Can not access a needed shared library */ -#undef TARGET_ELIBBAD -#define TARGET_ELIBBAD 84 /* Accessing a corrupted shared library */ -#undef TARGET_ELIBSCN -#define TARGET_ELIBSCN 85 /* .lib section in a.out corrupted */ -#undef TARGET_ELIBMAX -#define TARGET_ELIBMAX 86 /* Attempting to link in too many shared libraries */ -#undef TARGET_ELIBEXEC -#define TARGET_ELIBEXEC 87 /* Cannot exec a shared library directly */ -#undef TARGET_EILSEQ -#define TARGET_EILSEQ 88 /* Illegal byte sequence */ -#undef TARGET_ENOSYS -#define TARGET_ENOSYS 89 /* Function not implemented */ -#undef TARGET_ELOOP -#define TARGET_ELOOP 90 /* Too many symbolic links encountered */ -#undef TARGET_ERESTART -#define TARGET_ERESTART 91 /* Interrupted system call should be restarted */ -#undef TARGET_ESTRPIPE -#define TARGET_ESTRPIPE 92 /* Streams pipe error */ -#undef TARGET_ENOTEMPTY -#define TARGET_ENOTEMPTY 93 /* Directory not empty */ -#undef TARGET_EUSERS -#define TARGET_EUSERS 94 /* Too many users */ -#undef TARGET_ENOTSOCK -#define TARGET_ENOTSOCK 95 /* Socket operation on non-socket */ -#undef TARGET_EDESTADDRREQ -#define TARGET_EDESTADDRREQ 96 /* Destination address required */ -#undef TARGET_EMSGSIZE -#define TARGET_EMSGSIZE 97 /* Message too long */ -#undef TARGET_EPROTOTYPE -#define TARGET_EPROTOTYPE 98 /* Protocol wrong type for socket */ -#undef TARGET_ENOPROTOOPT -#define TARGET_ENOPROTOOPT 99 /* Protocol not available */ -#undef TARGET_EPROTONOSUPPORT -#define TARGET_EPROTONOSUPPORT 120 /* Protocol not supported */ -#undef TARGET_ESOCKTNOSUPPORT -#define TARGET_ESOCKTNOSUPPORT 121 /* Socket type not supported */ -#undef TARGET_EOPNOTSUPP -#define TARGET_EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ -#undef TARGET_EPFNOSUPPORT -#define TARGET_EPFNOSUPPORT 123 /* Protocol family not supported */ -#undef TARGET_EAFNOSUPPORT -#define TARGET_EAFNOSUPPORT 124 /* Address family not supported by protocol */ -#undef TARGET_EADDRINUSE -#define TARGET_EADDRINUSE 125 /* Address already in use */ -#undef TARGET_EADDRNOTAVAIL -#define TARGET_EADDRNOTAVAIL 126 /* Cannot assign requested address */ -#undef TARGET_ENETDOWN -#define TARGET_ENETDOWN 127 /* Network is down */ -#undef TARGET_ENETUNREACH -#define TARGET_ENETUNREACH 128 /* Network is unreachable */ -#undef TARGET_ENETRESET -#define TARGET_ENETRESET 129 /* Network dropped connection because of reset */ -#undef TARGET_ECONNABORTED -#define TARGET_ECONNABORTED 130 /* Software caused connection abort */ -#undef TARGET_ECONNRESET -#define TARGET_ECONNRESET 131 /* Connection reset by peer */ -#undef TARGET_ENOBUFS -#define TARGET_ENOBUFS 132 /* No buffer space available */ -#undef TARGET_EISCONN -#define TARGET_EISCONN 133 /* Transport endpoint is already connected */ -#undef TARGET_ENOTCONN -#define TARGET_ENOTCONN 134 /* Transport endpoint is not connected */ -#undef TARGET_EUCLEAN -#define TARGET_EUCLEAN 135 /* Structure needs cleaning */ -#undef TARGET_ENOTNAM -#define TARGET_ENOTNAM 137 /* Not a XENIX named type file */ -#undef TARGET_ENAVAIL -#define TARGET_ENAVAIL 138 /* No XENIX semaphores available */ -#undef TARGET_EISNAM -#define TARGET_EISNAM 139 /* Is a named type file */ -#undef TARGET_EREMOTEIO -#define TARGET_EREMOTEIO 140 /* Remote I/O error */ -#undef TARGET_EINIT -#define TARGET_EINIT 141 /* Reserved */ -#undef TARGET_EREMDEV -#define TARGET_EREMDEV 142 /* TARGET_Error 142 */ -#undef TARGET_ESHUTDOWN -#define TARGET_ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ -#undef TARGET_ETOOMANYREFS -#define TARGET_ETOOMANYREFS 144 /* Too many references: cannot splice */ -#undef TARGET_ETIMEDOUT -#define TARGET_ETIMEDOUT 145 /* Connection timed out */ -#undef TARGET_ECONNREFUSED -#define TARGET_ECONNREFUSED 146 /* Connection refused */ -#undef TARGET_EHOSTDOWN -#define TARGET_EHOSTDOWN 147 /* Host is down */ -#undef TARGET_EHOSTUNREACH -#define TARGET_EHOSTUNREACH 148 /* No route to host */ -#undef TARGET_EALREADY -#define TARGET_EALREADY 149 /* Operation already in progress */ -#undef TARGET_EINPROGRESS -#define TARGET_EINPROGRESS 150 /* Operation now in progress */ -#undef TARGET_ESTALE -#define TARGET_ESTALE 151 /* Stale NFS file handle */ -#undef TARGET_ECANCELED -#define TARGET_ECANCELED 158 /* AIO operation canceled */ -/* - * These error are Linux extensions. - */ -#undef TARGET_ENOMEDIUM -#define TARGET_ENOMEDIUM 159 /* No medium found */ -#undef TARGET_EMEDIUMTYPE -#define TARGET_EMEDIUMTYPE 160 /* Wrong medium type */ -#undef TARGET_ENOKEY -#define TARGET_ENOKEY 161 /* Required key not available */ -#undef TARGET_EKEYEXPIRED -#define TARGET_EKEYEXPIRED 162 /* Key has expired */ -#undef TARGET_EKEYREVOKED -#define TARGET_EKEYREVOKED 163 /* Key has been revoked */ -#undef TARGET_EKEYREJECTED -#define TARGET_EKEYREJECTED 164 /* Key was rejected by service */ - -/* for robust mutexes */ -#undef TARGET_EOWNERDEAD -#define TARGET_EOWNERDEAD 165 /* Owner died */ -#undef TARGET_ENOTRECOVERABLE -#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ - - - -/* Nasty hack: define a fake errno value for use by sigreturn. */ -#define TARGET_QEMU_ESIGRETURN 255 - -#define UNAME_MACHINE "mips64" diff --git a/linux-user/mipsn32/syscall_nr.h b/linux-user/mipsn32/syscall_nr.h deleted file mode 100644 index 4e1aca3a9b..0000000000 --- a/linux-user/mipsn32/syscall_nr.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Linux N32 syscalls are in the range from 6000 to 6999. - */ -#define TARGET_NR_Linux 6000 -#define TARGET_NR_read (TARGET_NR_Linux + 0) -#define TARGET_NR_write (TARGET_NR_Linux + 1) -#define TARGET_NR_open (TARGET_NR_Linux + 2) -#define TARGET_NR_close (TARGET_NR_Linux + 3) -#define TARGET_NR_stat (TARGET_NR_Linux + 4) -#define TARGET_NR_fstat (TARGET_NR_Linux + 5) -#define TARGET_NR_lstat (TARGET_NR_Linux + 6) -#define TARGET_NR_poll (TARGET_NR_Linux + 7) -#define TARGET_NR_lseek (TARGET_NR_Linux + 8) -#define TARGET_NR_mmap (TARGET_NR_Linux + 9) -#define TARGET_NR_mprotect (TARGET_NR_Linux + 10) -#define TARGET_NR_munmap (TARGET_NR_Linux + 11) -#define TARGET_NR_brk (TARGET_NR_Linux + 12) -#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 13) -#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 14) -#define TARGET_NR_ioctl (TARGET_NR_Linux + 15) -#define TARGET_NR_pread64 (TARGET_NR_Linux + 16) -#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 17) -#define TARGET_NR_readv (TARGET_NR_Linux + 18) -#define TARGET_NR_writev (TARGET_NR_Linux + 19) -#define TARGET_NR_access (TARGET_NR_Linux + 20) -#define TARGET_NR_pipe (TARGET_NR_Linux + 21) -#define TARGET_NR__newselect (TARGET_NR_Linux + 22) -#define TARGET_NR_sched_yield (TARGET_NR_Linux + 23) -#define TARGET_NR_mremap (TARGET_NR_Linux + 24) -#define TARGET_NR_msync (TARGET_NR_Linux + 25) -#define TARGET_NR_mincore (TARGET_NR_Linux + 26) -#define TARGET_NR_madvise (TARGET_NR_Linux + 27) -#define TARGET_NR_shmget (TARGET_NR_Linux + 28) -#define TARGET_NR_shmat (TARGET_NR_Linux + 29) -#define TARGET_NR_shmctl (TARGET_NR_Linux + 30) -#define TARGET_NR_dup (TARGET_NR_Linux + 31) -#define TARGET_NR_dup2 (TARGET_NR_Linux + 32) -#define TARGET_NR_pause (TARGET_NR_Linux + 33) -#define TARGET_NR_nanosleep (TARGET_NR_Linux + 34) -#define TARGET_NR_getitimer (TARGET_NR_Linux + 35) -#define TARGET_NR_setitimer (TARGET_NR_Linux + 36) -#define TARGET_NR_alarm (TARGET_NR_Linux + 37) -#define TARGET_NR_getpid (TARGET_NR_Linux + 38) -#define TARGET_NR_sendfile (TARGET_NR_Linux + 39) -#define TARGET_NR_socket (TARGET_NR_Linux + 40) -#define TARGET_NR_connect (TARGET_NR_Linux + 41) -#define TARGET_NR_accept (TARGET_NR_Linux + 42) -#define TARGET_NR_sendto (TARGET_NR_Linux + 43) -#define TARGET_NR_recvfrom (TARGET_NR_Linux + 44) -#define TARGET_NR_sendmsg (TARGET_NR_Linux + 45) -#define TARGET_NR_recvmsg (TARGET_NR_Linux + 46) -#define TARGET_NR_shutdown (TARGET_NR_Linux + 47) -#define TARGET_NR_bind (TARGET_NR_Linux + 48) -#define TARGET_NR_listen (TARGET_NR_Linux + 49) -#define TARGET_NR_getsockname (TARGET_NR_Linux + 50) -#define TARGET_NR_getpeername (TARGET_NR_Linux + 51) -#define TARGET_NR_socketpair (TARGET_NR_Linux + 52) -#define TARGET_NR_setsockopt (TARGET_NR_Linux + 53) -#define TARGET_NR_getsockopt (TARGET_NR_Linux + 54) -#define TARGET_NR_clone (TARGET_NR_Linux + 55) -#define TARGET_NR_fork (TARGET_NR_Linux + 56) -#define TARGET_NR_execve (TARGET_NR_Linux + 57) -#define TARGET_NR_exit (TARGET_NR_Linux + 58) -#define TARGET_NR_wait4 (TARGET_NR_Linux + 59) -#define TARGET_NR_kill (TARGET_NR_Linux + 60) -#define TARGET_NR_uname (TARGET_NR_Linux + 61) -#define TARGET_NR_semget (TARGET_NR_Linux + 62) -#define TARGET_NR_semop (TARGET_NR_Linux + 63) -#define TARGET_NR_semctl (TARGET_NR_Linux + 64) -#define TARGET_NR_shmdt (TARGET_NR_Linux + 65) -#define TARGET_NR_msgget (TARGET_NR_Linux + 66) -#define TARGET_NR_msgsnd (TARGET_NR_Linux + 67) -#define TARGET_NR_msgrcv (TARGET_NR_Linux + 68) -#define TARGET_NR_msgctl (TARGET_NR_Linux + 69) -#define TARGET_NR_fcntl (TARGET_NR_Linux + 70) -#define TARGET_NR_flock (TARGET_NR_Linux + 71) -#define TARGET_NR_fsync (TARGET_NR_Linux + 72) -#define TARGET_NR_fdatasync (TARGET_NR_Linux + 73) -#define TARGET_NR_truncate (TARGET_NR_Linux + 74) -#define TARGET_NR_ftruncate (TARGET_NR_Linux + 75) -#define TARGET_NR_getdents (TARGET_NR_Linux + 76) -#define TARGET_NR_getcwd (TARGET_NR_Linux + 77) -#define TARGET_NR_chdir (TARGET_NR_Linux + 78) -#define TARGET_NR_fchdir (TARGET_NR_Linux + 79) -#define TARGET_NR_rename (TARGET_NR_Linux + 80) -#define TARGET_NR_mkdir (TARGET_NR_Linux + 81) -#define TARGET_NR_rmdir (TARGET_NR_Linux + 82) -#define TARGET_NR_creat (TARGET_NR_Linux + 83) -#define TARGET_NR_link (TARGET_NR_Linux + 84) -#define TARGET_NR_unlink (TARGET_NR_Linux + 85) -#define TARGET_NR_symlink (TARGET_NR_Linux + 86) -#define TARGET_NR_readlink (TARGET_NR_Linux + 87) -#define TARGET_NR_chmod (TARGET_NR_Linux + 88) -#define TARGET_NR_fchmod (TARGET_NR_Linux + 89) -#define TARGET_NR_chown (TARGET_NR_Linux + 90) -#define TARGET_NR_fchown (TARGET_NR_Linux + 91) -#define TARGET_NR_lchown (TARGET_NR_Linux + 92) -#define TARGET_NR_umask (TARGET_NR_Linux + 93) -#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 94) -#define TARGET_NR_getrlimit (TARGET_NR_Linux + 95) -#define TARGET_NR_getrusage (TARGET_NR_Linux + 96) -#define TARGET_NR_sysinfo (TARGET_NR_Linux + 97) -#define TARGET_NR_times (TARGET_NR_Linux + 98) -#define TARGET_NR_ptrace (TARGET_NR_Linux + 99) -#define TARGET_NR_getuid (TARGET_NR_Linux + 100) -#define TARGET_NR_syslog (TARGET_NR_Linux + 101) -#define TARGET_NR_getgid (TARGET_NR_Linux + 102) -#define TARGET_NR_setuid (TARGET_NR_Linux + 103) -#define TARGET_NR_setgid (TARGET_NR_Linux + 104) -#define TARGET_NR_geteuid (TARGET_NR_Linux + 105) -#define TARGET_NR_getegid (TARGET_NR_Linux + 106) -#define TARGET_NR_setpgid (TARGET_NR_Linux + 107) -#define TARGET_NR_getppid (TARGET_NR_Linux + 108) -#define TARGET_NR_getpgrp (TARGET_NR_Linux + 109) -#define TARGET_NR_setsid (TARGET_NR_Linux + 110) -#define TARGET_NR_setreuid (TARGET_NR_Linux + 111) -#define TARGET_NR_setregid (TARGET_NR_Linux + 112) -#define TARGET_NR_getgroups (TARGET_NR_Linux + 113) -#define TARGET_NR_setgroups (TARGET_NR_Linux + 114) -#define TARGET_NR_setresuid (TARGET_NR_Linux + 115) -#define TARGET_NR_getresuid (TARGET_NR_Linux + 116) -#define TARGET_NR_setresgid (TARGET_NR_Linux + 117) -#define TARGET_NR_getresgid (TARGET_NR_Linux + 118) -#define TARGET_NR_getpgid (TARGET_NR_Linux + 119) -#define TARGET_NR_setfsuid (TARGET_NR_Linux + 120) -#define TARGET_NR_setfsgid (TARGET_NR_Linux + 121) -#define TARGET_NR_getsid (TARGET_NR_Linux + 122) -#define TARGET_NR_capget (TARGET_NR_Linux + 123) -#define TARGET_NR_capset (TARGET_NR_Linux + 124) -#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 125) -#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 126) -#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 127) -#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 128) -#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 129) -#define TARGET_NR_utime (TARGET_NR_Linux + 130) -#define TARGET_NR_mknod (TARGET_NR_Linux + 131) -#define TARGET_NR_personality (TARGET_NR_Linux + 132) -#define TARGET_NR_ustat (TARGET_NR_Linux + 133) -#define TARGET_NR_statfs (TARGET_NR_Linux + 134) -#define TARGET_NR_fstatfs (TARGET_NR_Linux + 135) -#define TARGET_NR_sysfs (TARGET_NR_Linux + 136) -#define TARGET_NR_getpriority (TARGET_NR_Linux + 137) -#define TARGET_NR_setpriority (TARGET_NR_Linux + 138) -#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 139) -#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 140) -#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 141) -#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 142) -#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 143) -#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 144) -#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 145) -#define TARGET_NR_mlock (TARGET_NR_Linux + 146) -#define TARGET_NR_munlock (TARGET_NR_Linux + 147) -#define TARGET_NR_mlockall (TARGET_NR_Linux + 148) -#define TARGET_NR_munlockall (TARGET_NR_Linux + 149) -#define TARGET_NR_vhangup (TARGET_NR_Linux + 150) -#define TARGET_NR_pivot_root (TARGET_NR_Linux + 151) -#define TARGET_NR__sysctl (TARGET_NR_Linux + 152) -#define TARGET_NR_prctl (TARGET_NR_Linux + 153) -#define TARGET_NR_adjtimex (TARGET_NR_Linux + 154) -#define TARGET_NR_setrlimit (TARGET_NR_Linux + 155) -#define TARGET_NR_chroot (TARGET_NR_Linux + 156) -#define TARGET_NR_sync (TARGET_NR_Linux + 157) -#define TARGET_NR_acct (TARGET_NR_Linux + 158) -#define TARGET_NR_settimeofday (TARGET_NR_Linux + 159) -#define TARGET_NR_mount (TARGET_NR_Linux + 160) -#define TARGET_NR_umount2 (TARGET_NR_Linux + 161) -#define TARGET_NR_swapon (TARGET_NR_Linux + 162) -#define TARGET_NR_swapoff (TARGET_NR_Linux + 163) -#define TARGET_NR_reboot (TARGET_NR_Linux + 164) -#define TARGET_NR_sethostname (TARGET_NR_Linux + 165) -#define TARGET_NR_setdomainname (TARGET_NR_Linux + 166) -#define TARGET_NR_create_module (TARGET_NR_Linux + 167) -#define TARGET_NR_init_module (TARGET_NR_Linux + 168) -#define TARGET_NR_delete_module (TARGET_NR_Linux + 169) -#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 170) -#define TARGET_NR_query_module (TARGET_NR_Linux + 171) -#define TARGET_NR_quotactl (TARGET_NR_Linux + 172) -#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 173) -#define TARGET_NR_getpmsg (TARGET_NR_Linux + 174) -#define TARGET_NR_putpmsg (TARGET_NR_Linux + 175) -#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 176) -#define TARGET_NR_reserved177 (TARGET_NR_Linux + 177) -#define TARGET_NR_gettid (TARGET_NR_Linux + 178) -#define TARGET_NR_readahead (TARGET_NR_Linux + 179) -#define TARGET_NR_setxattr (TARGET_NR_Linux + 180) -#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 181) -#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 182) -#define TARGET_NR_getxattr (TARGET_NR_Linux + 183) -#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 184) -#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 185) -#define TARGET_NR_listxattr (TARGET_NR_Linux + 186) -#define TARGET_NR_llistxattr (TARGET_NR_Linux + 187) -#define TARGET_NR_flistxattr (TARGET_NR_Linux + 188) -#define TARGET_NR_removexattr (TARGET_NR_Linux + 189) -#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 190) -#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 191) -#define TARGET_NR_tkill (TARGET_NR_Linux + 192) -#define TARGET_NR_reserved193 (TARGET_NR_Linux + 193) -#define TARGET_NR_futex (TARGET_NR_Linux + 194) -#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 195) -#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 196) -#define TARGET_NR_cacheflush (TARGET_NR_Linux + 197) -#define TARGET_NR_cachectl (TARGET_NR_Linux + 198) -#define TARGET_NR_sysmips (TARGET_NR_Linux + 199) -#define TARGET_NR_io_setup (TARGET_NR_Linux + 200) -#define TARGET_NR_io_destroy (TARGET_NR_Linux + 201) -#define TARGET_NR_io_getevents (TARGET_NR_Linux + 202) -#define TARGET_NR_io_submit (TARGET_NR_Linux + 203) -#define TARGET_NR_io_cancel (TARGET_NR_Linux + 204) -#define TARGET_NR_exit_group (TARGET_NR_Linux + 205) -#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 206) -#define TARGET_NR_epoll_create (TARGET_NR_Linux + 207) -#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 208) -#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 209) -#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 210) -#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 211) -#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 212) -#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 213) -#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 214) -#define TARGET_NR_semtimedop (TARGET_NR_Linux + 215) -#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 216) -#define TARGET_NR_statfs64 (TARGET_NR_Linux + 217) -#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 218) -#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 219) -#define TARGET_NR_timer_create (TARGET_NR_Linux + 220) -#define TARGET_NR_timer_settime (TARGET_NR_Linux + 221) -#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 222) -#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 223) -#define TARGET_NR_timer_delete (TARGET_NR_Linux + 224) -#define TARGET_NR_clock_settime (TARGET_NR_Linux + 225) -#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 226) -#define TARGET_NR_clock_getres (TARGET_NR_Linux + 227) -#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 228) -#define TARGET_NR_tgkill (TARGET_NR_Linux + 229) -#define TARGET_NR_utimes (TARGET_NR_Linux + 230) -#define TARGET_NR_mbind (TARGET_NR_Linux + 231) -#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 232) -#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 233) -#define TARGET_NR_mq_open (TARGET_NR_Linux + 234) -#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 235) -#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 236) -#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 237) -#define TARGET_NR_mq_notify (TARGET_NR_Linux + 238) -#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 239) -#define TARGET_NR_vserver (TARGET_NR_Linux + 240) -#define TARGET_NR_waitid (TARGET_NR_Linux + 241) -/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 242) */ -#define TARGET_NR_add_key (TARGET_NR_Linux + 243) -#define TARGET_NR_request_key (TARGET_NR_Linux + 244) -#define TARGET_NR_keyctl (TARGET_NR_Linux + 245) -#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 246) -#define TARGET_NR_inotify_init (TARGET_NR_Linux + 247) -#define TARGET_NR_inotify_add_watch (TARGET_NR_Linux + 248) -#define TARGET_NR_inotify_rm_watch (TARGET_NR_Linux + 249) -#define TARGET_NR_migrate_pages (TARGET_NR_Linux + 250) -#define TARGET_NR_openat (TARGET_NR_Linux + 251) -#define TARGET_NR_mkdirat (TARGET_NR_Linux + 252) -#define TARGET_NR_mknodat (TARGET_NR_Linux + 253) -#define TARGET_NR_fchownat (TARGET_NR_Linux + 254) -#define TARGET_NR_futimesat (TARGET_NR_Linux + 255) -#define TARGET_NR_newfstatat (TARGET_NR_Linux + 256) -#define TARGET_NR_unlinkat (TARGET_NR_Linux + 257) -#define TARGET_NR_renameat (TARGET_NR_Linux + 258) -#define TARGET_NR_linkat (TARGET_NR_Linux + 259) -#define TARGET_NR_symlinkat (TARGET_NR_Linux + 260) -#define TARGET_NR_readlinkat (TARGET_NR_Linux + 261) -#define TARGET_NR_fchmodat (TARGET_NR_Linux + 262) -#define TARGET_NR_faccessat (TARGET_NR_Linux + 263) -#define TARGET_NR_pselect6 (TARGET_NR_Linux + 264) -#define TARGET_NR_ppoll (TARGET_NR_Linux + 265) -#define TARGET_NR_unshare (TARGET_NR_Linux + 266) -#define TARGET_NR_splice (TARGET_NR_Linux + 267) -#define TARGET_NR_sync_file_range (TARGET_NR_Linux + 268) -#define TARGET_NR_tee (TARGET_NR_Linux + 269) -#define TARGET_NR_vmsplice (TARGET_NR_Linux + 270) -#define TARGET_NR_move_pages (TARGET_NR_Linux + 271) -#define TARGET_NR_set_robust_list (TARGET_NR_Linux + 272) -#define TARGET_NR_get_robust_list (TARGET_NR_Linux + 273) -#define TARGET_NR_kexec_load (TARGET_NR_Linux + 274) -#define TARGET_NR_getcpu (TARGET_NR_Linux + 275) -#define TARGET_NR_epoll_pwait (TARGET_NR_Linux + 276) -#define TARGET_NR_ioprio_set (TARGET_NR_Linux + 277) -#define TARGET_NR_ioprio_get (TARGET_NR_Linux + 278) -#define TARGET_NR_utimensat (TARGET_NR_Linux + 279) -#define TARGET_NR_signalfd (TARGET_NR_Linux + 280) -#define TARGET_NR_timerfd (TARGET_NR_Linux + 281) -#define TARGET_NR_eventfd (TARGET_NR_Linux + 282) -#define TARGET_NR_fallocate (TARGET_NR_Linux + 283) -#define TARGET_NR_timerfd_create (TARGET_NR_Linux + 284) -#define TARGET_NR_timerfd_gettime (TARGET_NR_Linux + 285) -#define TARGET_NR_timerfd_settime (TARGET_NR_Linux + 286) -#define TARGET_NR_signalfd4 (TARGET_NR_Linux + 287) -#define TARGET_NR_eventfd2 (TARGET_NR_Linux + 288) -#define TARGET_NR_epoll_create1 (TARGET_NR_Linux + 289) -#define TARGET_NR_dup3 (TARGET_NR_Linux + 290) -#define TARGET_NR_pipe2 (TARGET_NR_Linux + 291) -#define TARGET_NR_inotify_init1 (TARGET_NR_Linux + 292) -#define TARGET_NR_preadv (TARGET_NR_Linux + 293) -#define TARGET_NR_pwritev (TARGET_NR_Linux + 294) -#define TARGET_NR_rt_tgsigqueueinfo (TARGET_NR_Linux + 295) -#define TARGET_NR_perf_event_open (TARGET_NR_Linux + 296) -#define TARGET_NR_accept4 (TARGET_NR_Linux + 297) -#define TARGET_NR_recvmmsg (TARGET_NR_Linux + 298) -#define TARGET_NR_getdents64 (TARGET_NR_Linux + 299) -#define TARGET_NR_fanotify_init (TARGET_NR_Linux + 300) -#define TARGET_NR_fanotify_mark (TARGET_NR_Linux + 301) -#define TARGET_NR_prlimit64 (TARGET_NR_Linux + 302) -#define TARGET_NR_name_to_handle_at (TARGET_NR_Linux + 303) -#define TARGET_NR_open_by_handle_at (TARGET_NR_Linux + 304) -#define TARGET_NR_clock_adjtime (TARGET_NR_Linux + 305) -#define TARGET_NR_syncfs (TARGET_NR_Linux + 306) diff --git a/linux-user/mipsn32/target_signal.h b/linux-user/mipsn32/target_signal.h deleted file mode 100644 index ff20d9e33e..0000000000 --- a/linux-user/mipsn32/target_signal.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - int32_t ss_sp; - uint32_t ss_size; - int32_t ss_flags; -} target_stack_t; - - -/* - * sigaltstack controls - */ -#define TARGET_SS_ONSTACK 1 -#define TARGET_SS_DISABLE 2 - -#define TARGET_MINSIGSTKSZ 2048 -#define TARGET_SIGSTKSZ 8192 - -static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state) -{ - return state->active_tc.gpr[29]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/mipsn32/termbits.h b/linux-user/mipsn32/termbits.h deleted file mode 100644 index d3a6cf8f91..0000000000 --- a/linux-user/mipsn32/termbits.h +++ /dev/null @@ -1,245 +0,0 @@ -/* from asm/termbits.h */ - -#define TARGET_NCCS 23 - -struct target_termios { - unsigned int c_iflag; /* input mode flags */ - unsigned int c_oflag; /* output mode flags */ - unsigned int c_cflag; /* control mode flags */ - unsigned int c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[TARGET_NCCS]; /* control characters */ -}; - -/* c_iflag bits */ -#define TARGET_IGNBRK 0000001 -#define TARGET_BRKINT 0000002 -#define TARGET_IGNPAR 0000004 -#define TARGET_PARMRK 0000010 -#define TARGET_INPCK 0000020 -#define TARGET_ISTRIP 0000040 -#define TARGET_INLCR 0000100 -#define TARGET_IGNCR 0000200 -#define TARGET_ICRNL 0000400 -#define TARGET_IUCLC 0001000 -#define TARGET_IXON 0002000 -#define TARGET_IXANY 0004000 -#define TARGET_IXOFF 0010000 -#define TARGET_IMAXBEL 0020000 -#define TARGET_IUTF8 0040000 - -/* c_oflag bits */ -#define TARGET_OPOST 0000001 -#define TARGET_OLCUC 0000002 -#define TARGET_ONLCR 0000004 -#define TARGET_OCRNL 0000010 -#define TARGET_ONOCR 0000020 -#define TARGET_ONLRET 0000040 -#define TARGET_OFILL 0000100 -#define TARGET_OFDEL 0000200 -#define TARGET_NLDLY 0000400 -#define TARGET_NL0 0000000 -#define TARGET_NL1 0000400 -#define TARGET_CRDLY 0003000 -#define TARGET_CR0 0000000 -#define TARGET_CR1 0001000 -#define TARGET_CR2 0002000 -#define TARGET_CR3 0003000 -#define TARGET_TABDLY 0014000 -#define TARGET_TAB0 0000000 -#define TARGET_TAB1 0004000 -#define TARGET_TAB2 0010000 -#define TARGET_TAB3 0014000 -#define TARGET_XTABS 0014000 -#define TARGET_BSDLY 0020000 -#define TARGET_BS0 0000000 -#define TARGET_BS1 0020000 -#define TARGET_VTDLY 0040000 -#define TARGET_VT0 0000000 -#define TARGET_VT1 0040000 -#define TARGET_FFDLY 0100000 -#define TARGET_FF0 0000000 -#define TARGET_FF1 0100000 - -/* c_cflag bit meaning */ -#define TARGET_CBAUD 0010017 -#define TARGET_B0 0000000 /* hang up */ -#define TARGET_B50 0000001 -#define TARGET_B75 0000002 -#define TARGET_B110 0000003 -#define TARGET_B134 0000004 -#define TARGET_B150 0000005 -#define TARGET_B200 0000006 -#define TARGET_B300 0000007 -#define TARGET_B600 0000010 -#define TARGET_B1200 0000011 -#define TARGET_B1800 0000012 -#define TARGET_B2400 0000013 -#define TARGET_B4800 0000014 -#define TARGET_B9600 0000015 -#define TARGET_B19200 0000016 -#define TARGET_B38400 0000017 -#define TARGET_EXTA B19200 -#define TARGET_EXTB B38400 -#define TARGET_CSIZE 0000060 -#define TARGET_CS5 0000000 -#define TARGET_CS6 0000020 -#define TARGET_CS7 0000040 -#define TARGET_CS8 0000060 -#define TARGET_CSTOPB 0000100 -#define TARGET_CREAD 0000200 -#define TARGET_PARENB 0000400 -#define TARGET_PARODD 0001000 -#define TARGET_HUPCL 0002000 -#define TARGET_CLOCAL 0004000 -#define TARGET_CBAUDEX 0010000 -#define TARGET_BOTHER 0010000 -#define TARGET_B57600 0010001 -#define TARGET_B115200 0010002 -#define TARGET_B230400 0010003 -#define TARGET_B460800 0010004 -#define TARGET_B500000 0010005 -#define TARGET_B576000 0010006 -#define TARGET_B921600 0010007 -#define TARGET_B1000000 0010010 -#define TARGET_B1152000 0010011 -#define TARGET_B1500000 0010012 -#define TARGET_B2000000 0010013 -#define TARGET_B2500000 0010014 -#define TARGET_B3000000 0010015 -#define TARGET_B3500000 0010016 -#define TARGET_B4000000 0010017 -#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ -#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ -#define TARGET_CRTSCTS 020000000000 /* flow control */ - -/* c_lflag bits */ -#define TARGET_ISIG 0000001 -#define TARGET_ICANON 0000002 -#define TARGET_XCASE 0000004 -#define TARGET_ECHO 0000010 -#define TARGET_ECHOE 0000020 -#define TARGET_ECHOK 0000040 -#define TARGET_ECHONL 0000100 -#define TARGET_NOFLSH 0000200 -#define TARGET_IEXTEN 0000400 -#define TARGET_ECHOCTL 0001000 -#define TARGET_ECHOPRT 0002000 -#define TARGET_ECHOKE 0004000 -#define TARGET_FLUSHO 0010000 -#define TARGET_PENDIN 0040000 -#define TARGET_TOSTOP 0100000 -#define TARGET_ITOSTOP TARGET_TOSTOP - -/* c_cc character offsets */ -#define TARGET_VINTR 0 -#define TARGET_VQUIT 1 -#define TARGET_VERASE 2 -#define TARGET_VKILL 3 -#define TARGET_VMIN 4 -#define TARGET_VTIME 5 -#define TARGET_VEOL2 6 -#define TARGET_VSWTC 7 -#define TARGET_VSTART 8 -#define TARGET_VSTOP 9 -#define TARGET_VSUSP 10 -/* VDSUSP not supported */ -#define TARGET_VREPRINT 12 -#define TARGET_VDISCARD 13 -#define TARGET_VWERASE 14 -#define TARGET_VLNEXT 15 -#define TARGET_VEOF 16 -#define TARGET_VEOL 17 - -/* ioctls */ - -#define TARGET_TCGETA 0x5401 -#define TARGET_TCSETA 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ -#define TARGET_TCSETAW 0x5403 -#define TARGET_TCSETAF 0x5404 - -#define TARGET_TCSBRK 0x5405 -#define TARGET_TCXONC 0x5406 -#define TARGET_TCFLSH 0x5407 - -#define TARGET_TCGETS 0x540d -#define TARGET_TCSETS 0x540e -#define TARGET_TCSETSW 0x540f -#define TARGET_TCSETSF 0x5410 - -#define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */ -#define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */ -#define TARGET_TIOCOUTQ 0x7472 /* output queue size */ -#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */ -#define TARGET_TIOCMGET 0x741d /* get all modem bits */ -#define TARGET_TIOCMBIS 0x741b /* bis modem bits */ -#define TARGET_TIOCMBIC 0x741c /* bic modem bits */ -#define TARGET_TIOCMSET 0x741a /* set all modem bits */ -#define TARGET_TIOCPKT 0x5470 /* pty: set/clear packet mode */ -#define TARGET_TIOCPKT_DATA 0x00 /* data packet */ -#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */ -#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */ -#define TARGET_TIOCPKT_STOP 0x04 /* stop output */ -#define TARGET_TIOCPKT_START 0x08 /* start output */ -#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */ -#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */ -/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */ -#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) /* set window size */ -#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) /* get window size */ -#define TARGET_TIOCNOTTY 0x5471 /* void tty association */ -#define TARGET_TIOCSETD 0x7401 -#define TARGET_TIOCGETD 0x7400 - -#define TARGET_FIOCLEX 0x6601 -#define TARGET_FIONCLEX 0x6602 -#define TARGET_FIOASYNC 0x667d -#define TARGET_FIONBIO 0x667e -#define TARGET_FIOQSIZE 0x667f - -#define TARGET_TIOCGLTC 0x7474 /* get special local chars */ -#define TARGET_TIOCSLTC 0x7475 /* set special local chars */ -#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */ -#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */ -#define TARGET_TIOCCONS TARGET_IOW('t', 120, int) /* become virtual console */ - -#define TARGET_FIONREAD 0x467f -#define TARGET_TIOCINQ TARGET_FIONREAD - -#define TARGET_TIOCGETP 0x7408 -#define TARGET_TIOCSETP 0x7409 -#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */ - -/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */ -/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */ -/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */ -/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */ -/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */ - /* 127-124 compat */ - -#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ -#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ -#define TARGET_TIOCGSID 0x7416 /* Return the session ID of FD */ -#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ - -/* I hope the range from 0x5480 on is free ... */ -#define TARGET_TIOCSCTTY 0x5480 /* become controlling tty */ -#define TARGET_TIOCGSOFTCAR 0x5481 -#define TARGET_TIOCSSOFTCAR 0x5482 -#define TARGET_TIOCLINUX 0x5483 -#define TARGET_TIOCGSERIAL 0x5484 -#define TARGET_TIOCSSERIAL 0x5485 -#define TARGET_TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */ -#define TARGET_TIOCSERCONFIG 0x5488 -#define TARGET_TIOCSERGWILD 0x5489 -#define TARGET_TIOCSERSWILD 0x548a -#define TARGET_TIOCGLCKTRMIOS 0x548b -#define TARGET_TIOCSLCKTRMIOS 0x548c -#define TARGET_TIOCSERGSTRUCT 0x548d /* For debugging only */ -#define TARGET_TIOCSERGETLSR 0x548e /* Get line status register */ -#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config */ -#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */ -#define TARGET_TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */ -#define TARGET_TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */ -#define TARGET_TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */ -#define TARGET_TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */ From 1dde716ed6719c341c1bfa427781f0715af90cbc Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 21 Feb 2013 16:15:54 +0100 Subject: [PATCH 1377/1634] iscsi: retry read, write, flush and unmap on unit attention check conditions the storage might return a check condition status for various reasons. (e.g. bus reset, capacity change, thin-provisioning info etc.) currently all these informative status responses lead to an I/O error which is populated to the guest. this patch introduces a retry mechanism to avoid this. Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini --- block/iscsi.c | 291 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 203 insertions(+), 88 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index deb3b68890..439af6f217 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -60,8 +60,11 @@ typedef struct IscsiAIOCB { uint8_t *buf; int status; int canceled; + int retries; size_t read_size; size_t read_offset; + int64_t sector_num; + int nb_sectors; #ifdef __linux__ sg_io_hdr_t *ioh; #endif @@ -69,6 +72,7 @@ typedef struct IscsiAIOCB { #define NOP_INTERVAL 5000 #define MAX_NOP_FAILURES 3 +#define ISCSI_CMD_RETRIES 5 static void iscsi_bh_cb(void *p) @@ -191,6 +195,8 @@ iscsi_process_write(void *arg) iscsi_set_events(iscsilun); } +static int +iscsi_aio_writev_acb(IscsiAIOCB *acb); static void iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status, @@ -208,7 +214,19 @@ iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status, } acb->status = 0; - if (status < 0) { + if (status != 0) { + if (status == SCSI_STATUS_CHECK_CONDITION + && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION + && acb->retries-- > 0) { + if (acb->task != NULL) { + scsi_free_scsi_task(acb->task); + acb->task = NULL; + } + if (iscsi_aio_writev_acb(acb) == 0) { + iscsi_set_events(acb->iscsilun); + return; + } + } error_report("Failed to write16 data to iSCSI lun. %s", iscsi_get_error(iscsi)); acb->status = -EIO; @@ -222,15 +240,10 @@ static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun) return sector * BDRV_SECTOR_SIZE / iscsilun->block_size; } -static BlockDriverAIOCB * -iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, - QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, - void *opaque) +static int +iscsi_aio_writev_acb(IscsiAIOCB *acb) { - IscsiLun *iscsilun = bs->opaque; - struct iscsi_context *iscsi = iscsilun->iscsi; - IscsiAIOCB *acb; + struct iscsi_context *iscsi = acb->iscsilun->iscsi; size_t size; uint32_t num_sectors; uint64_t lba; @@ -239,19 +252,13 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, #endif int ret; - acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); - trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb); - - acb->iscsilun = iscsilun; - acb->qiov = qiov; - acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; acb->buf = NULL; /* this will allow us to get rid of 'buf' completely */ - size = nb_sectors * BDRV_SECTOR_SIZE; + size = acb->nb_sectors * BDRV_SECTOR_SIZE; #if !defined(LIBISCSI_FEATURE_IOVECTOR) data.size = MIN(size, acb->qiov->size); @@ -270,48 +277,76 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, if (acb->task == NULL) { error_report("iSCSI: Failed to allocate task for scsi WRITE16 " "command. %s", iscsi_get_error(iscsi)); - qemu_aio_release(acb); - return NULL; + return -1; } memset(acb->task, 0, sizeof(struct scsi_task)); acb->task->xfer_dir = SCSI_XFER_WRITE; acb->task->cdb_size = 16; acb->task->cdb[0] = 0x8a; - lba = sector_qemu2lun(sector_num, iscsilun); + lba = sector_qemu2lun(acb->sector_num, acb->iscsilun); *(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32); *(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff); - num_sectors = size / iscsilun->block_size; + num_sectors = size / acb->iscsilun->block_size; *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors); acb->task->expxferlen = size; #if defined(LIBISCSI_FEATURE_IOVECTOR) - ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task, iscsi_aio_write16_cb, NULL, acb); #else - ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task, iscsi_aio_write16_cb, &data, acb); #endif if (ret != 0) { - scsi_free_scsi_task(acb->task); g_free(acb->buf); - qemu_aio_release(acb); - return NULL; + return -1; } #if defined(LIBISCSI_FEATURE_IOVECTOR) scsi_task_set_iov_out(acb->task, (struct scsi_iovec*) acb->qiov->iov, acb->qiov->niov); #endif - iscsi_set_events(iscsilun); + return 0; +} +static BlockDriverAIOCB * +iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num, + QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque) +{ + IscsiLun *iscsilun = bs->opaque; + IscsiAIOCB *acb; + + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); + trace_iscsi_aio_writev(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb); + + acb->iscsilun = iscsilun; + acb->qiov = qiov; + acb->nb_sectors = nb_sectors; + acb->sector_num = sector_num; + acb->retries = ISCSI_CMD_RETRIES; + + if (iscsi_aio_writev_acb(acb) != 0) { + if (acb->task) { + scsi_free_scsi_task(acb->task); + } + qemu_aio_release(acb); + return NULL; + } + + iscsi_set_events(iscsilun); return &acb->common; } +static int +iscsi_aio_readv_acb(IscsiAIOCB *acb); + static void iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status, void *command_data, void *opaque) @@ -326,6 +361,18 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status, acb->status = 0; if (status != 0) { + if (status == SCSI_STATUS_CHECK_CONDITION + && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION + && acb->retries-- > 0) { + if (acb->task != NULL) { + scsi_free_scsi_task(acb->task); + acb->task = NULL; + } + if (iscsi_aio_readv_acb(acb) == 0) { + iscsi_set_events(acb->iscsilun); + return; + } + } error_report("Failed to read16 data from iSCSI lun. %s", iscsi_get_error(iscsi)); acb->status = -EIO; @@ -334,35 +381,20 @@ iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status, iscsi_schedule_bh(acb); } -static BlockDriverAIOCB * -iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, - QEMUIOVector *qiov, int nb_sectors, - BlockDriverCompletionFunc *cb, - void *opaque) +static int +iscsi_aio_readv_acb(IscsiAIOCB *acb) { - IscsiLun *iscsilun = bs->opaque; - struct iscsi_context *iscsi = iscsilun->iscsi; - IscsiAIOCB *acb; - size_t qemu_read_size; + struct iscsi_context *iscsi = acb->iscsilun->iscsi; + uint64_t lba; + uint32_t num_sectors; + int ret; #if !defined(LIBISCSI_FEATURE_IOVECTOR) int i; #endif - int ret; - uint64_t lba; - uint32_t num_sectors; - - qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors; - - acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); - trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb); - - acb->iscsilun = iscsilun; - acb->qiov = qiov; acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; - acb->read_size = qemu_read_size; acb->buf = NULL; /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU @@ -370,30 +402,29 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, * data. */ acb->read_offset = 0; - if (iscsilun->block_size > BDRV_SECTOR_SIZE) { - uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num; + if (acb->iscsilun->block_size > BDRV_SECTOR_SIZE) { + uint64_t bdrv_offset = BDRV_SECTOR_SIZE * acb->sector_num; - acb->read_offset = bdrv_offset % iscsilun->block_size; + acb->read_offset = bdrv_offset % acb->iscsilun->block_size; } - num_sectors = (qemu_read_size + iscsilun->block_size + num_sectors = (acb->read_size + acb->iscsilun->block_size + acb->read_offset - 1) - / iscsilun->block_size; + / acb->iscsilun->block_size; acb->task = malloc(sizeof(struct scsi_task)); if (acb->task == NULL) { error_report("iSCSI: Failed to allocate task for scsi READ16 " "command. %s", iscsi_get_error(iscsi)); - qemu_aio_release(acb); - return NULL; + return -1; } memset(acb->task, 0, sizeof(struct scsi_task)); acb->task->xfer_dir = SCSI_XFER_READ; - lba = sector_qemu2lun(sector_num, iscsilun); - acb->task->expxferlen = qemu_read_size; + lba = sector_qemu2lun(acb->sector_num, acb->iscsilun); + acb->task->expxferlen = acb->read_size; - switch (iscsilun->type) { + switch (acb->iscsilun->type) { case TYPE_DISK: acb->task->cdb_size = 16; acb->task->cdb[0] = 0x88; @@ -409,14 +440,12 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, break; } - ret = iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, + ret = iscsi_scsi_command_async(iscsi, acb->iscsilun->lun, acb->task, iscsi_aio_read16_cb, NULL, acb); if (ret != 0) { - scsi_free_scsi_task(acb->task); - qemu_aio_release(acb); - return NULL; + return -1; } #if defined(LIBISCSI_FEATURE_IOVECTOR) @@ -428,12 +457,42 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, acb->qiov->iov[i].iov_base); } #endif + return 0; +} + +static BlockDriverAIOCB * +iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num, + QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, + void *opaque) +{ + IscsiLun *iscsilun = bs->opaque; + IscsiAIOCB *acb; + + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); + trace_iscsi_aio_readv(iscsilun->iscsi, sector_num, nb_sectors, opaque, acb); + + acb->nb_sectors = nb_sectors; + acb->sector_num = sector_num; + acb->iscsilun = iscsilun; + acb->qiov = qiov; + acb->read_size = BDRV_SECTOR_SIZE * (size_t)acb->nb_sectors; + acb->retries = ISCSI_CMD_RETRIES; + + if (iscsi_aio_readv_acb(acb) != 0) { + if (acb->task) { + scsi_free_scsi_task(acb->task); + } + qemu_aio_release(acb); + return NULL; + } iscsi_set_events(iscsilun); - return &acb->common; } +static int +iscsi_aio_flush_acb(IscsiAIOCB *acb); static void iscsi_synccache10_cb(struct iscsi_context *iscsi, int status, @@ -446,7 +505,19 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status, } acb->status = 0; - if (status < 0) { + if (status != 0) { + if (status == SCSI_STATUS_CHECK_CONDITION + && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION + && acb->retries-- > 0) { + if (acb->task != NULL) { + scsi_free_scsi_task(acb->task); + acb->task = NULL; + } + if (iscsi_aio_flush_acb(acb) == 0) { + iscsi_set_events(acb->iscsilun); + return; + } + } error_report("Failed to sync10 data on iSCSI lun. %s", iscsi_get_error(iscsi)); acb->status = -EIO; @@ -455,29 +526,43 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status, iscsi_schedule_bh(acb); } -static BlockDriverAIOCB * -iscsi_aio_flush(BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque) +static int +iscsi_aio_flush_acb(IscsiAIOCB *acb) { - IscsiLun *iscsilun = bs->opaque; - struct iscsi_context *iscsi = iscsilun->iscsi; - IscsiAIOCB *acb; + struct iscsi_context *iscsi = acb->iscsilun->iscsi; - acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); - - acb->iscsilun = iscsilun; acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; acb->buf = NULL; - acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun, + acb->task = iscsi_synchronizecache10_task(iscsi, acb->iscsilun->lun, 0, 0, 0, 0, iscsi_synccache10_cb, acb); if (acb->task == NULL) { error_report("iSCSI: Failed to send synchronizecache10 command. %s", iscsi_get_error(iscsi)); + return -1; + } + + return 0; +} + +static BlockDriverAIOCB * +iscsi_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) +{ + IscsiLun *iscsilun = bs->opaque; + + IscsiAIOCB *acb; + + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); + + acb->iscsilun = iscsilun; + acb->retries = ISCSI_CMD_RETRIES; + + if (iscsi_aio_flush_acb(acb) != 0) { qemu_aio_release(acb); return NULL; } @@ -487,6 +572,8 @@ iscsi_aio_flush(BlockDriverState *bs, return &acb->common; } +static int iscsi_aio_discard_acb(IscsiAIOCB *acb); + static void iscsi_unmap_cb(struct iscsi_context *iscsi, int status, void *command_data, void *opaque) @@ -498,7 +585,19 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status, } acb->status = 0; - if (status < 0) { + if (status != 0) { + if (status == SCSI_STATUS_CHECK_CONDITION + && acb->task->sense.key == SCSI_SENSE_UNIT_ATTENTION + && acb->retries-- > 0) { + if (acb->task != NULL) { + scsi_free_scsi_task(acb->task); + acb->task = NULL; + } + if (iscsi_aio_discard_acb(acb) == 0) { + iscsi_set_events(acb->iscsilun); + return; + } + } error_report("Failed to unmap data on iSCSI lun. %s", iscsi_get_error(iscsi)); acb->status = -EIO; @@ -507,34 +606,50 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status, iscsi_schedule_bh(acb); } -static BlockDriverAIOCB * -iscsi_aio_discard(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, - BlockDriverCompletionFunc *cb, void *opaque) -{ - IscsiLun *iscsilun = bs->opaque; - struct iscsi_context *iscsi = iscsilun->iscsi; - IscsiAIOCB *acb; +static int iscsi_aio_discard_acb(IscsiAIOCB *acb) { + struct iscsi_context *iscsi = acb->iscsilun->iscsi; struct unmap_list list[1]; - acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); - - acb->iscsilun = iscsilun; acb->canceled = 0; acb->bh = NULL; acb->status = -EINPROGRESS; acb->buf = NULL; - list[0].lba = sector_qemu2lun(sector_num, iscsilun); - list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size; + list[0].lba = sector_qemu2lun(acb->sector_num, acb->iscsilun); + list[0].num = acb->nb_sectors * BDRV_SECTOR_SIZE / acb->iscsilun->block_size; - acb->task = iscsi_unmap_task(iscsi, iscsilun->lun, + acb->task = iscsi_unmap_task(iscsi, acb->iscsilun->lun, 0, 0, &list[0], 1, iscsi_unmap_cb, acb); if (acb->task == NULL) { error_report("iSCSI: Failed to send unmap command. %s", iscsi_get_error(iscsi)); + return -1; + } + + return 0; +} + +static BlockDriverAIOCB * +iscsi_aio_discard(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + IscsiLun *iscsilun = bs->opaque; + IscsiAIOCB *acb; + + acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); + + acb->iscsilun = iscsilun; + acb->nb_sectors = nb_sectors; + acb->sector_num = sector_num; + acb->retries = ISCSI_CMD_RETRIES; + + if (iscsi_aio_discard_acb(acb) != 0) { + if (acb->task) { + scsi_free_scsi_task(acb->task); + } qemu_aio_release(acb); return NULL; } From cb1b83e740384b4e0d950f3d7c81c02b8ce86c2e Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Mon, 18 Feb 2013 14:50:46 +0100 Subject: [PATCH 1378/1634] iscsi: add iscsi_truncate support this patch adds iscsi_truncate which effectively allows for online resizing of iscsi volumes. for this to work you have to resize the volume on your storage and then call block_resize command in qemu which will issue a readcapacity16 to update the capacity. v4: - factor out complete readcapacity logic into a separate function - handle capacity change check condition in readcapacity function (this happens if the block_resize cmd is the first iscsi task executed after a resize on the storage) v3: - remove switch statement in iscsi_open - create separate patch for brdv_drain_all() in bdrv_truncate() v2: - add a general bdrv_drain_all() before bdrv_truncate() to avoid in-flight AIOs while the device is truncated - since no AIOs are in flight we can use a sync libiscsi call to re-read the capacity - factor out the readcapacity16 logic as it is redundant to iscsi_open() and iscsi_truncate(). Signed-off-by: Peter Lieven [allow any type of unit attention check condition in iscsi_readcapacity_sync(), as in Message-ID: <51263A2A.6070304@dlhnet.de> - Paolo] Signed-off-by: Paolo Bonzini --- block/iscsi.c | 135 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 88 insertions(+), 47 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 439af6f217..3d529213ff 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -938,6 +938,71 @@ static void iscsi_nop_timed_event(void *opaque) } #endif +static int iscsi_readcapacity_sync(IscsiLun *iscsilun) +{ + struct scsi_task *task = NULL; + struct scsi_readcapacity10 *rc10 = NULL; + struct scsi_readcapacity16 *rc16 = NULL; + int ret = 0; + int retries = ISCSI_CMD_RETRIES; + +try_again: + switch (iscsilun->type) { + case TYPE_DISK: + task = iscsi_readcapacity16_sync(iscsilun->iscsi, iscsilun->lun); + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + if (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION + && task->sense.key == SCSI_SENSE_UNIT_ATTENTION + && retries-- > 0) { + scsi_free_scsi_task(task); + goto try_again; + } + error_report("iSCSI: failed to send readcapacity16 command."); + ret = -EINVAL; + goto out; + } + rc16 = scsi_datain_unmarshall(task); + if (rc16 == NULL) { + error_report("iSCSI: Failed to unmarshall readcapacity16 data."); + ret = -EINVAL; + goto out; + } + iscsilun->block_size = rc16->block_length; + iscsilun->num_blocks = rc16->returned_lba + 1; + break; + case TYPE_ROM: + task = iscsi_readcapacity10_sync(iscsilun->iscsi, iscsilun->lun, 0, 0); + if (task == NULL || task->status != SCSI_STATUS_GOOD) { + error_report("iSCSI: failed to send readcapacity10 command."); + ret = -EINVAL; + goto out; + } + rc10 = scsi_datain_unmarshall(task); + if (rc10 == NULL) { + error_report("iSCSI: Failed to unmarshall readcapacity10 data."); + ret = -EINVAL; + goto out; + } + iscsilun->block_size = rc10->block_size; + if (rc10->lba == 0) { + /* blank disk loaded */ + iscsilun->num_blocks = 0; + } else { + iscsilun->num_blocks = rc10->lba + 1; + } + break; + default: + break; + } + +out: + if (task) { + scsi_free_scsi_task(task); + } + + return ret; +} + /* * We support iscsi url's on the form * iscsi://[%@][:]// @@ -949,8 +1014,6 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) struct iscsi_url *iscsi_url = NULL; struct scsi_task *task = NULL; struct scsi_inquiry_standard *inq = NULL; - struct scsi_readcapacity10 *rc10 = NULL; - struct scsi_readcapacity16 *rc16 = NULL; char *initiator_name = NULL; int ret; @@ -1040,50 +1103,9 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) iscsilun->type = inq->periperal_device_type; - scsi_free_scsi_task(task); - - switch (iscsilun->type) { - case TYPE_DISK: - task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun); - if (task == NULL || task->status != SCSI_STATUS_GOOD) { - error_report("iSCSI: failed to send readcapacity16 command."); - ret = -EINVAL; - goto out; - } - rc16 = scsi_datain_unmarshall(task); - if (rc16 == NULL) { - error_report("iSCSI: Failed to unmarshall readcapacity16 data."); - ret = -EINVAL; - goto out; - } - iscsilun->block_size = rc16->block_length; - iscsilun->num_blocks = rc16->returned_lba + 1; - break; - case TYPE_ROM: - task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0); - if (task == NULL || task->status != SCSI_STATUS_GOOD) { - error_report("iSCSI: failed to send readcapacity10 command."); - ret = -EINVAL; - goto out; - } - rc10 = scsi_datain_unmarshall(task); - if (rc10 == NULL) { - error_report("iSCSI: Failed to unmarshall readcapacity10 data."); - ret = -EINVAL; - goto out; - } - iscsilun->block_size = rc10->block_size; - if (rc10->lba == 0) { - /* blank disk loaded */ - iscsilun->num_blocks = 0; - } else { - iscsilun->num_blocks = rc10->lba + 1; - } - break; - default: - break; + if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) { + goto out; } - bs->total_sectors = iscsilun->num_blocks * iscsilun->block_size / BDRV_SECTOR_SIZE ; @@ -1096,8 +1118,6 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags) bs->sg = 1; } - ret = 0; - #if defined(LIBISCSI_FEATURE_NOP_COUNTER) /* Set up a timer for sending out iSCSI NOPs */ iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event, iscsilun); @@ -1138,6 +1158,26 @@ static void iscsi_close(BlockDriverState *bs) memset(iscsilun, 0, sizeof(IscsiLun)); } +static int iscsi_truncate(BlockDriverState *bs, int64_t offset) +{ + IscsiLun *iscsilun = bs->opaque; + int ret = 0; + + if (iscsilun->type != TYPE_DISK) { + return -ENOTSUP; + } + + if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) { + return ret; + } + + if (offset > iscsi_getlength(bs)) { + return -EINVAL; + } + + return 0; +} + static int iscsi_has_zero_init(BlockDriverState *bs) { return 0; @@ -1208,6 +1248,7 @@ static BlockDriver bdrv_iscsi = { .create_options = iscsi_create_options, .bdrv_getlength = iscsi_getlength, + .bdrv_truncate = iscsi_truncate, .bdrv_aio_readv = iscsi_aio_readv, .bdrv_aio_writev = iscsi_aio_writev, From 3c33ea9640758bb625e110a77673e5abfd184e54 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 18:14:28 +0100 Subject: [PATCH 1379/1634] iscsi: look for pkg-config file too Due to library conflicts, Fedora will have to put libiscsi in /usr/lib/iscsi. Simplify configuration by using a pkg-config file. The Fedora package will distribute one, and the patch to add it has been sent to upstream libiscsi as well. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- configure | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 2f98c5a242..a9a7c9971b 100755 --- a/configure +++ b/configure @@ -2803,7 +2803,13 @@ if test "$libiscsi" != "no" ; then #include int main(void) { iscsi_unmap_sync(NULL,0,0,0,NULL,0); return 0; } EOF - if compile_prog "" "-liscsi" ; then + if $pkg_config --atleast-version=1.7.0 libiscsi --modversion >/dev/null 2>&1; then + libiscsi="yes" + libiscsi_cflags=$($pkg_config --cflags libiscsi 2>/dev/null) + libiscsi_libs=$($pkg_config --libs libiscsi 2>/dev/null) + CFLAGS="$CFLAGS $libiscsi_cflags" + LIBS="$LIBS $libiscsi_libs" + elif compile_prog "" "-liscsi" ; then libiscsi="yes" LIBS="$LIBS -liscsi" else From 6f6710aa99ac53b59ff0f14380830cb9ab6bdc14 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 Feb 2013 12:12:58 +0100 Subject: [PATCH 1380/1634] scsi: do not call scsi_read_data/scsi_write_data for a canceled request Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/scsi-bus.c | 4 ++++ trace-events | 1 + 2 files changed, 5 insertions(+) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index a97f1cdc1c..01e1dec4ca 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -1508,6 +1508,10 @@ void scsi_req_unref(SCSIRequest *req) will start the next chunk or complete the command. */ void scsi_req_continue(SCSIRequest *req) { + if (req->io_canceled) { + trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag); + return; + } trace_scsi_req_continue(req->dev->id, req->lun, req->tag); if (req->cmd.mode == SCSI_XFER_TO_DEV) { req->ops->write_data(req); diff --git a/trace-events b/trace-events index a27ae43032..3064fc7767 100644 --- a/trace-events +++ b/trace-events @@ -460,6 +460,7 @@ scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d le scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d" scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d" scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d" +scsi_req_continue_canceled(int target, int lun, int tag) "target %d lun %d tag %d" scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d" scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64 scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d" From d0242eadc5bba4f3abe34bc5d536bbfb81aa9891 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 Feb 2013 12:14:34 +0100 Subject: [PATCH 1381/1634] scsi-disk: do not complete canceled UNMAP requests Canceled requests should never be completed, and doing that could cause accesses to a NULL hba_private field. Cc: qemu-stable@nongnu.org Reported-by: Stefan Priebe Tested-by: Stefan Priebe Signed-off-by: Paolo Bonzini --- hw/scsi-disk.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index d41158693e..6c0ddff2fb 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1478,13 +1478,17 @@ static void scsi_unmap_complete(void *opaque, int ret) uint32_t nb_sectors; r->req.aiocb = NULL; + if (r->req.io_canceled) { + goto done; + } + if (ret < 0) { if (scsi_handle_rw_error(r, -ret)) { goto done; } } - if (data->count > 0 && !r->req.io_canceled) { + if (data->count > 0) { sector_num = ldq_be_p(&data->inbuf[0]); nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; if (!check_lba_range(s, sector_num, nb_sectors)) { @@ -1501,10 +1505,9 @@ static void scsi_unmap_complete(void *opaque, int ret) return; } + scsi_req_complete(&r->req, GOOD); + done: - if (data->count == 0) { - scsi_req_complete(&r->req, GOOD); - } if (!r->req.io_canceled) { scsi_req_unref(&r->req); } From 0c92e0e6b64c9061f7365a2712b9055ea35b52f9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 Feb 2013 12:16:05 +0100 Subject: [PATCH 1382/1634] scsi-disk: handle io_canceled uniformly and correctly Always check it immediately after calling bdrv_acct_done, and always do a "goto done" in case the "done" label has to free some memory---as is the case for scsi_unmap_complete in the previous patch. This patch could fix problems that happen when a request is split into multiple parts, and one of them is canceled. Then the next part is fired, but the HBA's cancellation callbacks have fired already. Whether this happens or not, depends on how the block/ driver implements AIO cancellation. It it does a simple bdrv_drain_all() or similar, then it will not have a problem. If it only cancels the given AIOCB, this scenario could happen. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/scsi-disk.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 6c0ddff2fb..4a0673c0bf 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -178,6 +178,9 @@ static void scsi_aio_complete(void *opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; bdrv_acct_done(s->qdev.conf.bs, &r->acct); + if (r->req.io_canceled) { + goto done; + } if (ret < 0) { if (scsi_handle_rw_error(r, -ret)) { @@ -223,6 +226,10 @@ static void scsi_write_do_fua(SCSIDiskReq *r) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + if (r->req.io_canceled) { + goto done; + } + if (scsi_is_cmd_fua(&r->req.cmd)) { bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH); r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r); @@ -230,6 +237,8 @@ static void scsi_write_do_fua(SCSIDiskReq *r) } scsi_req_complete(&r->req, GOOD); + +done: if (!r->req.io_canceled) { scsi_req_unref(&r->req); } @@ -243,6 +252,9 @@ static void scsi_dma_complete(void *opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; bdrv_acct_done(s->qdev.conf.bs, &r->acct); + if (r->req.io_canceled) { + goto done; + } if (ret < 0) { if (scsi_handle_rw_error(r, -ret)) { @@ -274,6 +286,9 @@ static void scsi_read_complete(void * opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; bdrv_acct_done(s->qdev.conf.bs, &r->acct); + if (r->req.io_canceled) { + goto done; + } if (ret < 0) { if (scsi_handle_rw_error(r, -ret)) { @@ -305,6 +320,9 @@ static void scsi_do_read(void *opaque, int ret) r->req.aiocb = NULL; bdrv_acct_done(s->qdev.conf.bs, &r->acct); } + if (r->req.io_canceled) { + goto done; + } if (ret < 0) { if (scsi_handle_rw_error(r, -ret)) { @@ -312,10 +330,6 @@ static void scsi_do_read(void *opaque, int ret) } } - if (r->req.io_canceled) { - return; - } - /* The request is used as the AIO opaque value, so add a ref. */ scsi_req_ref(&r->req); @@ -423,6 +437,9 @@ static void scsi_write_complete(void * opaque, int ret) r->req.aiocb = NULL; bdrv_acct_done(s->qdev.conf.bs, &r->acct); } + if (r->req.io_canceled) { + goto done; + } if (ret < 0) { if (scsi_handle_rw_error(r, -ret)) { From 0bc472a9d6b80567c212023c5eae413f4dfb53ad Mon Sep 17 00:00:00 2001 From: Kuo-Jung Su Date: Tue, 5 Mar 2013 21:27:24 +0000 Subject: [PATCH 1383/1634] hw/nand.c: correct the sense of the BUSY/READY status bit The BIT6 of Status Register(SR): SR[6] behaves the same as R/B# pin SR[6] = 0 indicates the device is busy; SR[6] = 1 means the device is ready Some NAND flash controller (i.e. ftnandc021) relies on the SR[6] to determine if the NAND flash erase/program is success or error timeout. P.S: The exmaple NAND flash datasheet could be found at following link: http://www.mxic.com.tw/QuickPlace/hq/PageLibrary4825740B00298A3B.nsf/h_Index/8FEA549237D2F7674825795800104C26/$File/MX30LF1G08AA,%203V,%201Gb,%20v1.1.pdf Signed-off-by: Kuo-Jung Su Reviewed-by: Peter Crosthwaite Signed-off-by: Edgar E. Iglesias --- hw/nand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/nand.c b/hw/nand.c index 4a71265ed3..61e918fa83 100644 --- a/hw/nand.c +++ b/hw/nand.c @@ -46,7 +46,7 @@ # define NAND_IOSTATUS_PLANE1 (1 << 2) # define NAND_IOSTATUS_PLANE2 (1 << 3) # define NAND_IOSTATUS_PLANE3 (1 << 4) -# define NAND_IOSTATUS_BUSY (1 << 6) +# define NAND_IOSTATUS_READY (1 << 6) # define NAND_IOSTATUS_UNPROTCT (1 << 7) # define MAX_PAGE 0x800 @@ -231,6 +231,7 @@ static void nand_reset(DeviceState *dev) s->iolen = 0; s->offset = 0; s->status &= NAND_IOSTATUS_UNPROTCT; + s->status |= NAND_IOSTATUS_READY; } static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value) From 4652b792f01b559e005186b703ed9b1a11cbf8e3 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 22 Feb 2013 21:05:01 +0100 Subject: [PATCH 1384/1634] configure: Create link to icon bitmap for out-of-tree builds This allows to pick up the icon when starting QEMU directly from an out-of-tree build directory. Signed-off-by: Jan Kiszka Reviewed-by: Stefan Weil Signed-off-by: Stefan Hajnoczi --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 2f98c5a242..87b2e73b9e 100755 --- a/configure +++ b/configure @@ -4369,6 +4369,7 @@ FILES="$FILES tests/tcg/lm32/Makefile po/Makefile" FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" FILES="$FILES pc-bios/spapr-rtas/Makefile" FILES="$FILES roms/seabios/Makefile roms/vgabios/Makefile" +FILES="$FILES pc-bios/qemu-icon.bmp" for bios_file in \ $source_path/pc-bios/*.bin \ $source_path/pc-bios/*.aml \ From eeb29fb9aa733f97d85857c210d6580a92a1b532 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Tue, 26 Feb 2013 19:31:32 -0500 Subject: [PATCH 1385/1634] rtc-test: Fix test failures with recent glib As of glib 2.35.4, glib changed its logic for ordering test cases: https://bugzilla.gnome.org/show_bug.cgi?id=694487 This was causing failures in rtc-test. Group the reordered test cases into their own suite, which maintains the original ordering. CC: qemu-stable@nongnu.org Signed-off-by: Cole Robinson Signed-off-by: Stefan Hajnoczi --- tests/rtc-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rtc-test.c b/tests/rtc-test.c index c5fd042610..9ab583b860 100644 --- a/tests/rtc-test.c +++ b/tests/rtc-test.c @@ -565,8 +565,8 @@ int main(int argc, char **argv) qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd); qtest_add_func("/rtc/set-year/20xx", set_year_20xx); qtest_add_func("/rtc/set-year/1980", set_year_1980); - qtest_add_func("/rtc/register_b_set_flag", register_b_set_flag); - qtest_add_func("/rtc/fuzz-registers", fuzz_registers); + qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag); + qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers); ret = g_test_run(); if (s) { From 58427a0f42679c875b077b7adc5db36897973865 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 4 Mar 2013 18:11:47 +0100 Subject: [PATCH 1386/1634] lm32: remove unused function The milkymist-minimac device in fact does not exist at all. Signed-off-by: Paolo Bonzini Acked-by: Michael Walle Signed-off-by: Stefan Hajnoczi --- hw/milkymist-hw.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h index c8bd7e93dd..5def311eea 100644 --- a/hw/milkymist-hw.h +++ b/hw/milkymist-hw.h @@ -170,22 +170,6 @@ static inline DeviceState *milkymist_ac97_create(hwaddr base, return dev; } -static inline DeviceState *milkymist_minimac_create(hwaddr base, - qemu_irq rx_irq, qemu_irq tx_irq) -{ - DeviceState *dev; - - qemu_check_nic_model(&nd_table[0], "minimac"); - dev = qdev_create(NULL, "milkymist-minimac"); - qdev_set_nic_properties(dev, &nd_table[0]); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq); - - return dev; -} - static inline DeviceState *milkymist_minimac2_create(hwaddr base, hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq) { From 4bd1afbdb3a228683dafa77a9fb3093f0dfab1de Mon Sep 17 00:00:00 2001 From: Lei Li Date: Wed, 6 Mar 2013 22:29:16 +0800 Subject: [PATCH 1387/1634] osdep: replace setsockopt by qemu_setsockopt Fix the compiler warning when cross build qemu-ga for windows by using qemu_setsockopt() instead of setsockopt(). util/osdep.c: In function 'socket_set_nodelay': util/osdep.c:69:5: warning: passing argument 4 of 'setsockopt' from incompatible pointer type [enabled by default] In file included from /home/lei/qemu_b/include/sysemu/os-win32.h:30:0, from /home/lei/qemu_b/include/qemu-common.h:46, from util/osdep.c:48: /usr/i686-w64-mingw32/sys-root/mingw/include/winsock2.h:990:63: note: expected 'const char *' but argument is of type 'int *' Signed-off-by: Lei Li Signed-off-by: Stefan Hajnoczi --- util/osdep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/osdep.c b/util/osdep.c index c4082610df..bd59ac90c1 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -57,7 +57,7 @@ static const char *qemu_version = QEMU_VERSION; int socket_set_cork(int fd, int v) { #if defined(SOL_TCP) && defined(TCP_CORK) - return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v)); + return qemu_setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v)); #else return 0; #endif @@ -66,7 +66,7 @@ int socket_set_cork(int fd, int v) int socket_set_nodelay(int fd) { int v = 1; - return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); + return qemu_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); } int qemu_madvise(void *addr, size_t len, int advice) From 358689fe299c306f1d81bea57a5067d0abb56699 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Fri, 1 Mar 2013 08:43:18 +0100 Subject: [PATCH 1388/1634] configure: Require at least spice-protocol-0.12.3 As of 5a49d3e9 we assume SPICE_PORT_EVENT_BREAK to be defined. However, it is defined not in 0.12.2 what we require now, but in 0.12.3. Therefore in order to prevent build failure we must adjust our minimal requirements. Signed-off-by: Stefan Hajnoczi --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 87b2e73b9e..f2c46b2e41 100755 --- a/configure +++ b/configure @@ -2871,7 +2871,7 @@ EOF spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null) spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null) if $pkg_config --atleast-version=0.12.0 spice-server >/dev/null 2>&1 && \ - $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1 && \ + $pkg_config --atleast-version=0.12.3 spice-protocol > /dev/null 2>&1 && \ compile_prog "$spice_cflags" "$spice_libs" ; then spice="yes" libs_softmmu="$libs_softmmu $spice_libs" From 7f9c9d12856e65e272297a619705864d9e6346f8 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 1 Mar 2013 07:53:55 -0500 Subject: [PATCH 1389/1634] rng-random: Use qemu_open / qemu_close In the rng backend use qemu_open and qemu_close rather than POSIX open/close. Signed-off-by: Stefan Berger Reviewed-by: Eric Blake Signed-off-by: Stefan Hajnoczi --- backends/rng-random.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/rng-random.c b/backends/rng-random.c index 0d1108811d..acd20afad2 100644 --- a/backends/rng-random.c +++ b/backends/rng-random.c @@ -74,7 +74,7 @@ static void rng_random_opened(RngBackend *b, Error **errp) error_set(errp, QERR_INVALID_PARAMETER_VALUE, "filename", "a valid filename"); } else { - s->fd = open(s->filename, O_RDONLY | O_NONBLOCK); + s->fd = qemu_open(s->filename, O_RDONLY | O_NONBLOCK); if (s->fd == -1) { error_set(errp, QERR_OPEN_FILE_FAILED, s->filename); @@ -130,7 +130,7 @@ static void rng_random_finalize(Object *obj) qemu_set_fd_handler(s->fd, NULL, NULL, NULL); if (s->fd != -1) { - close(s->fd); + qemu_close(s->fd); } g_free(s->filename); From d37e12a07c06b13610b7fabb6b8e009d7a759bc8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 1 Mar 2013 16:57:41 +0000 Subject: [PATCH 1390/1634] pci_host: Drop write-only address_space field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The address_space field of PCIHostState was only ever written, never used. Drop it completely. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber Signed-off-by: Stefan Hajnoczi --- hw/pci/pci_host.h | 1 - hw/piix_pci.c | 1 - hw/ppc/prep.c | 1 - 3 files changed, 3 deletions(-) diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h index 1845d4dfd5..236cd0f75c 100644 --- a/hw/pci/pci_host.h +++ b/hw/pci/pci_host.h @@ -40,7 +40,6 @@ struct PCIHostState { MemoryRegion conf_mem; MemoryRegion data_mem; MemoryRegion mmcfg; - MemoryRegion *address_space; uint32_t config_reg; PCIBus *bus; }; diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 6c77e493e4..9246983c55 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -244,7 +244,6 @@ static PCIBus *i440fx_common_init(const char *device_name, dev = qdev_create(NULL, "i440FX-pcihost"); s = PCI_HOST_BRIDGE(dev); - s->address_space = address_space_mem; b = pci_bus_new(dev, NULL, pci_address_space, address_space_io, 0); s->bus = b; diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index e06dded003..292091180d 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -567,7 +567,6 @@ static void ppc_prep_init(QEMUMachineInitArgs *args) dev = qdev_create(NULL, "raven-pcihost"); pcihost = PCI_HOST_BRIDGE(dev); - pcihost->address_space = get_system_memory(); object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL); qdev_init_nofail(dev); pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); From db2d5eba652ecb7420ac4ef79fc747ef391ad0d9 Mon Sep 17 00:00:00 2001 From: Lei Li Date: Thu, 7 Mar 2013 15:50:26 +0800 Subject: [PATCH 1391/1634] Fix the wrong description in qemu manual Fix LP#1151450 the wrong description in qemu manual: 'qemu-system-x86_84' should be 'qemu-system-x86_64'. Signed-off-by: Lei Li Signed-off-by: Stefan Hajnoczi --- qemu-options.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index 6f9334a97f..cd76f2a00c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2132,7 +2132,7 @@ gluster[+transport]://[server[:port]]/volname/image[?socket=...] Example @example -qemu-system-x86_84 --drive file=gluster://192.0.2.1/testvol/a.img +qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img @end example See also @url{http://www.gluster.org}. From baca6f183d78a0c864a5ccc0ec64e26ba960e604 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:16 +0530 Subject: [PATCH 1392/1634] char-socket: fix error reporting Right now the inet connect code tries all available addresses but until one doesn't fail. It passes local_err each time without clearing it from the previous failure. This can trigger an assert since the inet connect code tries to set an error on an object != NULL. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 16c806d60aa5e9660ed7751bb4e37dcd278f97f0.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- util/qemu-sockets.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 1350cccce3..3f122965ad 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -373,6 +373,10 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, } for (e = res; e != NULL; e = e->ai_next) { + if (error_is_set(errp)) { + error_free(*errp); + *errp = NULL; + } if (connect_state != NULL) { connect_state->current_addr = e; } From ed7a154063266a30a31752d3b18d484ddc7f5aa9 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:17 +0530 Subject: [PATCH 1393/1634] qemu-char: remove dead/confusing logic with nb_stdio_clients This code is very old dating back to 2007. What is puzzling is that STDIO_MAX_CLIENTS was always #define to 1 meaning that all of the code to deal with more than one client was unreachable. Just remove the whole mess of it. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: d276bccdbf4e7463020c5f539f61ae3bfbc88d1d.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 134 ++++++++++++---------------------------------------- 1 file changed, 29 insertions(+), 105 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 36295b1bcd..0a74c10df7 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -539,9 +539,6 @@ int send_all(int fd, const void *_buf, int len1) } #endif /* !_WIN32 */ -#define STDIO_MAX_CLIENTS 1 -static int stdio_nb_clients; - #ifndef _WIN32 typedef struct { @@ -594,11 +591,8 @@ static void fd_chr_update_read_handler(CharDriverState *chr) FDCharDriver *s = chr->opaque; if (s->fd_in >= 0) { - if (display_type == DT_NOGRAPHIC && s->fd_in == 0) { - } else { - qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, - fd_chr_read, NULL, chr); - } + qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, + fd_chr_read, NULL, chr); } } @@ -607,10 +601,7 @@ static void fd_chr_close(struct CharDriverState *chr) FDCharDriver *s = chr->opaque; if (s->fd_in >= 0) { - if (display_type == DT_NOGRAPHIC && s->fd_in == 0) { - } else { - qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); - } + qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); } g_free(s); @@ -677,53 +668,6 @@ static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) return qemu_chr_open_fd(fd_in, fd_out); } - -/* for STDIO, we handle the case where several clients use it - (nographic mode) */ - -#define TERM_FIFO_MAX_SIZE 1 - -static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; -static int term_fifo_size; - -static int stdio_read_poll(void *opaque) -{ - CharDriverState *chr = opaque; - - /* try to flush the queue if needed */ - if (term_fifo_size != 0 && qemu_chr_be_can_write(chr) > 0) { - qemu_chr_be_write(chr, term_fifo, 1); - term_fifo_size = 0; - } - /* see if we can absorb more chars */ - if (term_fifo_size == 0) - return 1; - else - return 0; -} - -static void stdio_read(void *opaque) -{ - int size; - uint8_t buf[1]; - CharDriverState *chr = opaque; - - size = read(0, buf, 1); - if (size == 0) { - /* stdin has been closed. Remove it from the active list. */ - qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); - qemu_chr_be_event(chr, CHR_EVENT_CLOSED); - return; - } - if (size > 0) { - if (qemu_chr_be_can_write(chr) > 0) { - qemu_chr_be_write(chr, buf, 1); - } else if (term_fifo_size == 0) { - term_fifo[term_fifo_size++] = buf[0]; - } - } -} - /* init terminal so that we can grab keys */ static struct termios oldtty; static int old_fd0_flags; @@ -760,8 +704,6 @@ static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo) static void qemu_chr_close_stdio(struct CharDriverState *chr) { term_exit(); - stdio_nb_clients--; - qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL); fd_chr_close(chr); } @@ -769,25 +711,18 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) { CharDriverState *chr; - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) { - return NULL; - } if (is_daemonized()) { error_report("cannot use stdio with -daemonize"); return NULL; } - if (stdio_nb_clients == 0) { - old_fd0_flags = fcntl(0, F_GETFL); - tcgetattr (0, &oldtty); - fcntl(0, F_SETFL, O_NONBLOCK); - atexit(term_exit); - } + old_fd0_flags = fcntl(0, F_GETFL); + tcgetattr (0, &oldtty); + fcntl(0, F_SETFL, O_NONBLOCK); + atexit(term_exit); chr = qemu_chr_open_fd(0, 1); chr->chr_close = qemu_chr_close_stdio; chr->chr_set_echo = qemu_chr_set_echo_stdio; - qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); - stdio_nb_clients++; stdio_allow_signal = qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC); qemu_chr_fe_set_echo(chr, false); @@ -1448,8 +1383,6 @@ static CharDriverState *qemu_chr_open_pp_fd(int fd) #else /* _WIN32 */ -static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; - typedef struct { int max_size; HANDLE hcom, hrecv, hsend; @@ -1951,7 +1884,6 @@ static void win_stdio_close(CharDriverState *chr) g_free(chr->opaque); g_free(chr); - stdio_nb_clients--; } static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) @@ -1961,11 +1893,6 @@ static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) DWORD dwMode; int is_console = 0; - if (stdio_nb_clients >= STDIO_MAX_CLIENTS - || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { - return NULL; - } - chr = g_malloc0(sizeof(CharDriverState)); stdio = g_malloc0(sizeof(WinStdioCharState)); @@ -1981,37 +1908,34 @@ static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) chr->chr_write = win_stdio_write; chr->chr_close = win_stdio_close; - if (stdio_nb_clients == 0) { - if (is_console) { - if (qemu_add_wait_object(stdio->hStdIn, - win_stdio_wait_func, chr)) { - fprintf(stderr, "qemu_add_wait_object: failed\n"); - } - } else { - DWORD dwId; + if (is_console) { + if (qemu_add_wait_object(stdio->hStdIn, + win_stdio_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); + } + } else { + DWORD dwId; + + stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, + chr, 0, &dwId); - stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, - chr, 0, &dwId); - - if (stdio->hInputThread == INVALID_HANDLE_VALUE - || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE - || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { - fprintf(stderr, "cannot create stdio thread or event\n"); - exit(1); - } - if (qemu_add_wait_object(stdio->hInputReadyEvent, - win_stdio_thread_wait_func, chr)) { - fprintf(stderr, "qemu_add_wait_object: failed\n"); - } + if (stdio->hInputThread == INVALID_HANDLE_VALUE + || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE + || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { + fprintf(stderr, "cannot create stdio thread or event\n"); + exit(1); + } + if (qemu_add_wait_object(stdio->hInputReadyEvent, + win_stdio_thread_wait_func, chr)) { + fprintf(stderr, "qemu_add_wait_object: failed\n"); } } dwMode |= ENABLE_LINE_INPUT; - stdio_clients[stdio_nb_clients++] = chr; - if (stdio_nb_clients == 1 && is_console) { + if (is_console) { /* set the terminal in raw mode */ /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ dwMode |= ENABLE_PROCESSED_INPUT; From 96c6384776d631839a9c8fe02bf135f9ba22586c Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:18 +0530 Subject: [PATCH 1394/1634] char: add IOWatchPoll support This is a special GSource that supports CharDriverState style poll callbacks. For reviewability and bisectability, this code is #if 0'd out in this patch to avoid unused warnings since all of the functions are static. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 9b59ac17b9d0bb3972a73fed04d415f07b391936.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 0a74c10df7..8aa0b41954 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -541,6 +541,146 @@ int send_all(int fd, const void *_buf, int len1) #ifndef _WIN32 +#if 0 +typedef struct IOWatchPoll +{ + GSource *src; + int max_size; + + IOCanReadHandler *fd_can_read; + void *opaque; + + QTAILQ_ENTRY(IOWatchPoll) node; +} IOWatchPoll; + +static QTAILQ_HEAD(, IOWatchPoll) io_watch_poll_list = + QTAILQ_HEAD_INITIALIZER(io_watch_poll_list); + +static IOWatchPoll *io_watch_poll_from_source(GSource *source) +{ + IOWatchPoll *i; + + QTAILQ_FOREACH(i, &io_watch_poll_list, node) { + if (i->src == source) { + return i; + } + } + + return NULL; +} + +static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_) +{ + IOWatchPoll *iwp = io_watch_poll_from_source(source); + + iwp->max_size = iwp->fd_can_read(iwp->opaque); + if (iwp->max_size == 0) { + return FALSE; + } + + return g_io_watch_funcs.prepare(source, timeout_); +} + +static gboolean io_watch_poll_check(GSource *source) +{ + IOWatchPoll *iwp = io_watch_poll_from_source(source); + + if (iwp->max_size == 0) { + return FALSE; + } + + return g_io_watch_funcs.check(source); +} + +static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback, + gpointer user_data) +{ + return g_io_watch_funcs.dispatch(source, callback, user_data); +} + +static void io_watch_poll_finalize(GSource *source) +{ + IOWatchPoll *iwp = io_watch_poll_from_source(source); + QTAILQ_REMOVE(&io_watch_poll_list, iwp, node); + g_io_watch_funcs.finalize(source); +} + +static GSourceFuncs io_watch_poll_funcs = { + .prepare = io_watch_poll_prepare, + .check = io_watch_poll_check, + .dispatch = io_watch_poll_dispatch, + .finalize = io_watch_poll_finalize, +}; + +/* Can only be used for read */ +static guint io_add_watch_poll(GIOChannel *channel, + IOCanReadHandler *fd_can_read, + GIOFunc fd_read, + gpointer user_data) +{ + IOWatchPoll *iwp; + GSource *src; + guint tag; + + src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP); + g_source_set_funcs(src, &io_watch_poll_funcs); + g_source_set_callback(src, (GSourceFunc)fd_read, user_data, NULL); + tag = g_source_attach(src, NULL); + g_source_unref(src); + + iwp = g_malloc0(sizeof(*iwp)); + iwp->src = src; + iwp->max_size = 0; + iwp->fd_can_read = fd_can_read; + iwp->opaque = user_data; + + QTAILQ_INSERT_HEAD(&io_watch_poll_list, iwp, node); + + return tag; +} + +static GIOChannel *io_channel_from_fd(int fd) +{ + GIOChannel *chan; + + if (fd == -1) { + return NULL; + } + + chan = g_io_channel_unix_new(fd); + + g_io_channel_set_encoding(chan, NULL, NULL); + g_io_channel_set_buffered(chan, FALSE); + + return chan; +} + +static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1) +{ + GIOStatus status; + gsize bytes_written; + int len; + const uint8_t *buf = _buf; + + len = len1; + while (len > 0) { + status = g_io_channel_write_chars(fd, (const gchar *)buf, len, + &bytes_written, NULL); + if (status != G_IO_STATUS_NORMAL) { + if (status != G_IO_STATUS_AGAIN) { + return -1; + } + } else if (status == G_IO_STATUS_EOF) { + break; + } else { + buf += bytes_written; + len -= bytes_written; + } + } + return len1 - len; +} +#endif + typedef struct { int fd_in, fd_out; int max_size; From a29753f8aa79a34a324afebe340182a51a5aef11 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:19 +0530 Subject: [PATCH 1395/1634] qemu-char: convert fd_chr to use a GIOChannel This uses the newly introduced IOWatchPoll source. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 0cb5d14510ee835a0ebc23676d10a2cce9280da5.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 109 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 8aa0b41954..4c63ccbd78 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -541,7 +541,6 @@ int send_all(int fd, const void *_buf, int len1) #ifndef _WIN32 -#if 0 typedef struct IOWatchPoll { GSource *src; @@ -679,18 +678,50 @@ static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1) } return len1 - len; } -#endif -typedef struct { - int fd_in, fd_out; +typedef struct FDCharDriver { + CharDriverState *chr; + GIOChannel *fd_in, *fd_out; + guint fd_in_tag; int max_size; + QTAILQ_ENTRY(FDCharDriver) node; } FDCharDriver; - static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { FDCharDriver *s = chr->opaque; - return send_all(s->fd_out, buf, len); + + return io_channel_send_all(s->fd_out, buf, len); +} + +static gboolean fd_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) +{ + CharDriverState *chr = opaque; + FDCharDriver *s = chr->opaque; + int len; + uint8_t buf[READ_BUF_LEN]; + GIOStatus status; + gsize bytes_read; + + len = sizeof(buf); + if (len > s->max_size) { + len = s->max_size; + } + if (len == 0) { + return FALSE; + } + + status = g_io_channel_read_chars(chan, (gchar *)buf, + len, &bytes_read, NULL); + if (status == G_IO_STATUS_EOF) { + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); + return FALSE; + } + if (status == G_IO_STATUS_NORMAL) { + qemu_chr_be_write(chr, buf, bytes_read); + } + + return TRUE; } static int fd_chr_read_poll(void *opaque) @@ -702,37 +733,16 @@ static int fd_chr_read_poll(void *opaque) return s->max_size; } -static void fd_chr_read(void *opaque) -{ - CharDriverState *chr = opaque; - FDCharDriver *s = chr->opaque; - int size, len; - uint8_t buf[READ_BUF_LEN]; - - len = sizeof(buf); - if (len > s->max_size) - len = s->max_size; - if (len == 0) - return; - size = read(s->fd_in, buf, len); - if (size == 0) { - /* FD has been closed. Remove it from the active list. */ - qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); - qemu_chr_be_event(chr, CHR_EVENT_CLOSED); - return; - } - if (size > 0) { - qemu_chr_be_write(chr, buf, size); - } -} - static void fd_chr_update_read_handler(CharDriverState *chr) { FDCharDriver *s = chr->opaque; - if (s->fd_in >= 0) { - qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, - fd_chr_read, NULL, chr); + if (s->fd_in_tag) { + g_source_remove(s->fd_in_tag); + } + + if (s->fd_in) { + s->fd_in_tag = io_add_watch_poll(s->fd_in, fd_chr_read_poll, fd_chr_read, chr); } } @@ -740,8 +750,16 @@ static void fd_chr_close(struct CharDriverState *chr) { FDCharDriver *s = chr->opaque; - if (s->fd_in >= 0) { - qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL); + if (s->fd_in_tag) { + g_source_remove(s->fd_in_tag); + s->fd_in_tag = 0; + } + + if (s->fd_in) { + g_io_channel_unref(s->fd_in); + } + if (s->fd_out) { + g_io_channel_unref(s->fd_out); } g_free(s); @@ -756,8 +774,9 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) chr = g_malloc0(sizeof(CharDriverState)); s = g_malloc0(sizeof(FDCharDriver)); - s->fd_in = fd_in; - s->fd_out = fd_out; + s->fd_in = io_channel_from_fd(fd_in); + s->fd_out = io_channel_from_fd(fd_out); + s->chr = chr; chr->opaque = s; chr->chr_write = fd_chr_write; chr->chr_update_read_handler = fd_chr_update_read_handler; @@ -1230,22 +1249,24 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) case CHR_IOCTL_SERIAL_SET_PARAMS: { QEMUSerialSetParams *ssp = arg; - tty_serial_init(s->fd_in, ssp->speed, ssp->parity, + tty_serial_init(g_io_channel_unix_get_fd(s->fd_in), + ssp->speed, ssp->parity, ssp->data_bits, ssp->stop_bits); } break; case CHR_IOCTL_SERIAL_SET_BREAK: { int enable = *(int *)arg; - if (enable) - tcsendbreak(s->fd_in, 1); + if (enable) { + tcsendbreak(g_io_channel_unix_get_fd(s->fd_in), 1); + } } break; case CHR_IOCTL_SERIAL_GET_TIOCM: { int sarg = 0; int *targ = (int *)arg; - ioctl(s->fd_in, TIOCMGET, &sarg); + ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMGET, &sarg); *targ = 0; if (sarg & TIOCM_CTS) *targ |= CHR_TIOCM_CTS; @@ -1265,7 +1286,7 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) { int sarg = *(int *)arg; int targ = 0; - ioctl(s->fd_in, TIOCMGET, &targ); + ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMGET, &targ); targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS); if (sarg & CHR_TIOCM_CTS) @@ -1280,7 +1301,7 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) targ |= TIOCM_DTR; if (sarg & CHR_TIOCM_RTS) targ |= TIOCM_RTS; - ioctl(s->fd_in, TIOCMSET, &targ); + ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMSET, &targ); } break; default: @@ -1295,7 +1316,7 @@ static void qemu_chr_close_tty(CharDriverState *chr) int fd = -1; if (s) { - fd = s->fd_in; + fd = g_io_channel_unix_get_fd(s->fd_in); } fd_chr_close(chr); From 093d3a20055282e282ba056addbe59b79e13a32f Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:20 +0530 Subject: [PATCH 1396/1634] qemu-char: convert pty to GIOChannel Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 339eebf3c59a450b0354056e9ac4b41f67230831.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 4c63ccbd78..64b95d7a06 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -953,7 +953,8 @@ static void cfmakeraw (struct termios *termios_p) #define HAVE_CHARDEV_TTY 1 typedef struct { - int fd; + GIOChannel *fd; + guint fd_tag; int connected; int polling; int read_bytes; @@ -972,7 +973,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) pty_chr_update_read_handler(chr); return 0; } - return send_all(s->fd, buf, len); + return io_channel_send_all(s->fd, buf, len); } static int pty_chr_read_poll(void *opaque) @@ -984,36 +985,39 @@ static int pty_chr_read_poll(void *opaque) return s->read_bytes; } -static void pty_chr_read(void *opaque) +static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) { CharDriverState *chr = opaque; PtyCharDriver *s = chr->opaque; - int size, len; + gsize size, len; uint8_t buf[READ_BUF_LEN]; + GIOStatus status; len = sizeof(buf); if (len > s->read_bytes) len = s->read_bytes; if (len == 0) - return; - size = read(s->fd, buf, len); - if ((size == -1 && errno == EIO) || - (size == 0)) { + return FALSE; + status = g_io_channel_read_chars(s->fd, (gchar *)buf, len, &size, NULL); + if (status != G_IO_STATUS_NORMAL) { pty_chr_state(chr, 0); - return; - } - if (size > 0) { + return FALSE; + } else { pty_chr_state(chr, 1); qemu_chr_be_write(chr, buf, size); } + return TRUE; } static void pty_chr_update_read_handler(CharDriverState *chr) { PtyCharDriver *s = chr->opaque; - qemu_set_fd_handler2(s->fd, pty_chr_read_poll, - pty_chr_read, NULL, chr); + if (s->fd_tag) { + g_source_remove(s->fd_tag); + } + + s->fd_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, pty_chr_read, chr); s->polling = 1; /* * Short timeout here: just need wait long enougth that qemu makes @@ -1031,7 +1035,8 @@ static void pty_chr_state(CharDriverState *chr, int connected) PtyCharDriver *s = chr->opaque; if (!connected) { - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + g_source_remove(s->fd_tag); + s->fd_tag = 0; s->connected = 0; s->polling = 0; /* (re-)connect poll interval for idle guests: once per second. @@ -1066,9 +1071,14 @@ static void pty_chr_timer(void *opaque) static void pty_chr_close(struct CharDriverState *chr) { PtyCharDriver *s = chr->opaque; + int fd; - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); - close(s->fd); + if (s->fd_tag) { + g_source_remove(s->fd_tag); + } + fd = g_io_channel_unix_get_fd(s->fd); + g_io_channel_unref(s->fd); + close(fd); qemu_del_timer(s->timer); qemu_free_timer(s->timer); g_free(s); @@ -1120,7 +1130,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) chr->chr_update_read_handler = pty_chr_update_read_handler; chr->chr_close = pty_chr_close; - s->fd = master_fd; + s->fd = io_channel_from_fd(master_fd); s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr); return chr; From 76a9644b711541472d9fb3a9b418acd55d9464a1 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:21 +0530 Subject: [PATCH 1397/1634] qemu-char: convert UDP to GIOChannel Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 775a2bd666a3d1fa008656bf97191b7573c6ffb5.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 68 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 64b95d7a06..94ff33212a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -654,6 +654,26 @@ static GIOChannel *io_channel_from_fd(int fd) return chan; } +static GIOChannel *io_channel_from_socket(int fd) +{ + GIOChannel *chan; + + if (fd == -1) { + return NULL; + } + +#ifdef _WIN32 + chan = g_io_channel_win32_new_socket(fd); +#else + chan = g_io_channel_unix_new(fd); +#endif + + g_io_channel_set_encoding(chan, NULL, NULL); + g_io_channel_set_buffered(chan, FALSE); + + return chan; +} + static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1) { GIOStatus status; @@ -2126,6 +2146,8 @@ static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) typedef struct { int fd; + GIOChannel *chan; + guint tag; uint8_t buf[READ_BUF_LEN]; int bufcnt; int bufptr; @@ -2135,8 +2157,17 @@ typedef struct { static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { NetCharDriver *s = chr->opaque; + gsize bytes_written; + GIOStatus status; - return send(s->fd, (const void *)buf, len, 0); + status = g_io_channel_write_chars(s->chan, (const gchar *)buf, len, &bytes_written, NULL); + if (status == G_IO_STATUS_EOF) { + return 0; + } else if (status != G_IO_STATUS_NORMAL) { + return -1; + } + + return bytes_written; } static int udp_chr_read_poll(void *opaque) @@ -2157,17 +2188,22 @@ static int udp_chr_read_poll(void *opaque) return s->max_size; } -static void udp_chr_read(void *opaque) +static gboolean udp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) { CharDriverState *chr = opaque; NetCharDriver *s = chr->opaque; + gsize bytes_read = 0; + GIOStatus status; if (s->max_size == 0) - return; - s->bufcnt = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0); + return FALSE; + status = g_io_channel_read_chars(s->chan, (gchar *)s->buf, sizeof(s->buf), + &bytes_read, NULL); + s->bufcnt = bytes_read; s->bufptr = s->bufcnt; - if (s->bufcnt <= 0) - return; + if (status != G_IO_STATUS_NORMAL) { + return FALSE; + } s->bufptr = 0; while (s->max_size > 0 && s->bufptr < s->bufcnt) { @@ -2175,23 +2211,32 @@ static void udp_chr_read(void *opaque) s->bufptr++; s->max_size = qemu_chr_be_can_write(chr); } + + return TRUE; } static void udp_chr_update_read_handler(CharDriverState *chr) { NetCharDriver *s = chr->opaque; - if (s->fd >= 0) { - qemu_set_fd_handler2(s->fd, udp_chr_read_poll, - udp_chr_read, NULL, chr); + if (s->tag) { + g_source_remove(s->tag); + s->tag = 0; + } + + if (s->chan) { + s->tag = io_add_watch_poll(s->chan, udp_chr_read_poll, udp_chr_read, chr); } } static void udp_chr_close(CharDriverState *chr) { NetCharDriver *s = chr->opaque; - if (s->fd >= 0) { - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + if (s->tag) { + g_source_remove(s->tag); + } + if (s->chan) { + g_io_channel_unref(s->chan); closesocket(s->fd); } g_free(s); @@ -2214,6 +2259,7 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) } s->fd = fd; + s->chan = io_channel_from_socket(s->fd); s->bufcnt = 0; s->bufptr = 0; chr->opaque = s; From 2ea5a7af7bfa576a5936400ccca4144caca9640b Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:22 +0530 Subject: [PATCH 1398/1634] qemu-char: tcp: make use GIOChannel I didn't bother switching to g_io_channel_read/write because we need to use sendmsg on Unix. No problem though since we're using an unbuffered channel. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 002f726576dfb51bca4854aa257b74d77c1cd4e8.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 60 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 94ff33212a..5a5349111c 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2285,6 +2285,9 @@ return_err: /* TCP Net console */ typedef struct { + + GIOChannel *chan, *listen_chan; + guint tag, listen_tag; int fd, listen_fd; int connected; int max_size; @@ -2294,13 +2297,13 @@ typedef struct { int msgfd; } TCPCharDriver; -static void tcp_chr_accept(void *opaque); +static gboolean tcp_chr_accept(GIOChannel *chan, GIOCondition cond, void *opaque); static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { TCPCharDriver *s = chr->opaque; if (s->connected) { - return send_all(s->fd, buf, len); + return io_channel_send_all(s->chan, buf, len); } else { /* XXX: indicate an error ? */ return len; @@ -2440,15 +2443,16 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) } #endif -static void tcp_chr_read(void *opaque) +static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; uint8_t buf[READ_BUF_LEN]; int len, size; - if (!s->connected || s->max_size <= 0) - return; + if (!s->connected || s->max_size <= 0) { + return FALSE; + } len = sizeof(buf); if (len > s->max_size) len = s->max_size; @@ -2456,10 +2460,13 @@ static void tcp_chr_read(void *opaque) if (size == 0) { /* connection closed */ s->connected = 0; - if (s->listen_fd >= 0) { - qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); + if (s->listen_chan) { + s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr); } - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + g_source_remove(s->tag); + s->tag = 0; + g_io_channel_unref(s->chan); + s->chan = NULL; closesocket(s->fd); s->fd = -1; qemu_chr_be_event(chr, CHR_EVENT_CLOSED); @@ -2469,6 +2476,8 @@ static void tcp_chr_read(void *opaque) if (size > 0) qemu_chr_be_write(chr, buf, size); } + + return TRUE; } #ifndef _WIN32 @@ -2484,9 +2493,8 @@ static void tcp_chr_connect(void *opaque) TCPCharDriver *s = chr->opaque; s->connected = 1; - if (s->fd >= 0) { - qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, - tcp_chr_read, NULL, chr); + if (s->chan) { + s->tag = io_add_watch_poll(s->chan, tcp_chr_read_poll, tcp_chr_read, chr); } qemu_chr_generic_open(chr); } @@ -2516,13 +2524,15 @@ static int tcp_chr_add_client(CharDriverState *chr, int fd) if (s->do_nodelay) socket_set_nodelay(fd); s->fd = fd; - qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL); + s->chan = io_channel_from_socket(fd); + g_source_remove(s->listen_tag); + s->listen_tag = 0; tcp_chr_connect(chr); return 0; } -static void tcp_chr_accept(void *opaque) +static gboolean tcp_chr_accept(GIOChannel *channel, GIOCondition cond, void *opaque) { CharDriverState *chr = opaque; TCPCharDriver *s = chr->opaque; @@ -2547,7 +2557,7 @@ static void tcp_chr_accept(void *opaque) } fd = qemu_accept(s->listen_fd, addr, &len); if (fd < 0 && errno != EINTR) { - return; + return FALSE; } else if (fd >= 0) { if (s->do_telnetopt) tcp_chr_telnet_init(fd); @@ -2556,17 +2566,29 @@ static void tcp_chr_accept(void *opaque) } if (tcp_chr_add_client(chr, fd) < 0) close(fd); + + return TRUE; } static void tcp_chr_close(CharDriverState *chr) { TCPCharDriver *s = chr->opaque; if (s->fd >= 0) { - qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + if (s->tag) { + g_source_remove(s->tag); + } + if (s->chan) { + g_io_channel_unref(s->chan); + } closesocket(s->fd); } if (s->listen_fd >= 0) { - qemu_set_fd_handler2(s->listen_fd, NULL, NULL, NULL, NULL); + if (s->listen_tag) { + g_source_remove(s->listen_tag); + } + if (s->listen_chan) { + g_io_channel_unref(s->listen_chan); + } closesocket(s->listen_fd); } g_free(s); @@ -2632,7 +2654,8 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, if (is_listen) { s->listen_fd = fd; - qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); + s->listen_chan = io_channel_from_socket(s->listen_fd); + s->listen_tag = g_io_add_watch(s->listen_chan, G_IO_IN, tcp_chr_accept, chr); if (is_telnet) { s->do_telnetopt = 1; } @@ -2640,13 +2663,14 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, s->connected = 1; s->fd = fd; socket_set_nodelay(fd); + s->chan = io_channel_from_socket(s->fd); tcp_chr_connect(chr); } if (is_listen && is_waitconnect) { printf("QEMU waiting for connection on: %s\n", chr->filename); - tcp_chr_accept(chr); + tcp_chr_accept(s->listen_chan, G_IO_IN, chr); socket_set_nonblock(s->listen_fd); } return chr; From 23673ca740e0eda66901ca801a5a901df378b063 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:23 +0530 Subject: [PATCH 1399/1634] qemu-char: add watch support This allows a front-end to request for a callback when the backend is writable again. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 96f93c0f741064604bbb6389ce962191120af8b7.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- include/char/char.h | 4 ++++ qemu-char.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/char/char.h b/include/char/char.h index c91ce3c98a..09ac4014dd 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -56,6 +56,7 @@ typedef void IOEventHandler(void *opaque, int event); struct CharDriverState { void (*init)(struct CharDriverState *s); int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len); + GSource *(*chr_add_watch)(struct CharDriverState *s, GIOCondition cond); void (*chr_update_read_handler)(struct CharDriverState *s); int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg); int (*get_msgfd)(struct CharDriverState *s); @@ -152,6 +153,9 @@ void qemu_chr_fe_close(struct CharDriverState *chr); void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) GCC_FMT_ATTR(2, 3); +guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, + GIOFunc func, void *user_data); + /** * @qemu_chr_fe_write: * diff --git a/qemu-char.c b/qemu-char.c index 5a5349111c..70917438d3 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -686,7 +686,11 @@ static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1) status = g_io_channel_write_chars(fd, (const gchar *)buf, len, &bytes_written, NULL); if (status != G_IO_STATUS_NORMAL) { - if (status != G_IO_STATUS_AGAIN) { + if (status == G_IO_STATUS_AGAIN) { + errno = EAGAIN; + return -1; + } else { + errno = EINVAL; return -1; } } else if (status == G_IO_STATUS_EOF) { @@ -753,6 +757,12 @@ static int fd_chr_read_poll(void *opaque) return s->max_size; } +static GSource *fd_chr_add_watch(CharDriverState *chr, GIOCondition cond) +{ + FDCharDriver *s = chr->opaque; + return g_io_create_watch(s->fd_out, cond); +} + static void fd_chr_update_read_handler(CharDriverState *chr) { FDCharDriver *s = chr->opaque; @@ -796,8 +806,10 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) s = g_malloc0(sizeof(FDCharDriver)); s->fd_in = io_channel_from_fd(fd_in); s->fd_out = io_channel_from_fd(fd_out); + fcntl(fd_out, F_SETFL, O_NONBLOCK); s->chr = chr; chr->opaque = s; + chr->chr_add_watch = fd_chr_add_watch; chr->chr_write = fd_chr_write; chr->chr_update_read_handler = fd_chr_update_read_handler; chr->chr_close = fd_chr_close; @@ -3279,6 +3291,24 @@ void qemu_chr_fe_close(struct CharDriverState *chr) } } +guint qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond, + GIOFunc func, void *user_data) +{ + GSource *src; + guint tag; + + if (s->chr_add_watch == NULL) { + return -ENOSYS; + } + + src = s->chr_add_watch(s, cond); + g_source_set_callback(src, (GSourceFunc)func, user_data, NULL); + tag = g_source_attach(src, NULL); + g_source_unref(src); + + return tag; +} + void qemu_chr_delete(CharDriverState *chr) { QTAILQ_REMOVE(&chardevs, chr, next); From e6a87ed837b52aea903c25693b1e3703824b9ef7 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:24 +0530 Subject: [PATCH 1400/1634] qemu-char: add pty watch This lets ptys support adding front end watchs. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 23380f37b22d407ba0b9e080f6ea0d66b279f2d2.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 70917438d3..f1d089ffdd 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1008,6 +1008,12 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) return io_channel_send_all(s->fd, buf, len); } +static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond) +{ + PtyCharDriver *s = chr->opaque; + return g_io_create_watch(s->fd, cond); +} + static int pty_chr_read_poll(void *opaque) { CharDriverState *chr = opaque; @@ -1161,6 +1167,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) chr->chr_write = pty_chr_write; chr->chr_update_read_handler = pty_chr_update_read_handler; chr->chr_close = pty_chr_close; + chr->chr_add_watch = pty_chr_add_watch; s->fd = io_channel_from_fd(master_fd); s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr); From d3cc5bc416cdf25bae0f3f6de58830be8ac5b648 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Tue, 5 Mar 2013 23:21:25 +0530 Subject: [PATCH 1401/1634] char: add gio watch fn for tcp backends Signed-off-by: Amit Shah Message-id: b50e668c4f4146a654c5d4412440eb9e589f2c02.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index f1d089ffdd..eb0ac811a3 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2462,6 +2462,12 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) } #endif +static GSource *tcp_chr_add_watch(CharDriverState *chr, GIOCondition cond) +{ + TCPCharDriver *s = chr->opaque; + return g_io_create_watch(s->chan, cond); +} + static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) { CharDriverState *chr = opaque; @@ -2670,6 +2676,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, chr->chr_close = tcp_chr_close; chr->get_msgfd = tcp_get_msgfd; chr->chr_add_client = tcp_chr_add_client; + chr->chr_add_watch = tcp_chr_add_watch; if (is_listen) { s->listen_fd = fd; From 8aa33cafc41a0fe8549d1dbcc65b75c31112dea8 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:26 +0530 Subject: [PATCH 1402/1634] qemu-char: use a glib timeout instead of qemu-timer Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 05a883ce5a98275b976bf0124610599859c2b7da.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 68 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index eb0ac811a3..6dba943667 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -990,12 +990,50 @@ typedef struct { int connected; int polling; int read_bytes; - QEMUTimer *timer; + guint timer_tag; } PtyCharDriver; static void pty_chr_update_read_handler(CharDriverState *chr); static void pty_chr_state(CharDriverState *chr, int connected); +static gboolean pty_chr_timer(gpointer opaque) +{ + struct CharDriverState *chr = opaque; + PtyCharDriver *s = chr->opaque; + + if (s->connected) { + goto out; + } + if (s->polling) { + /* If we arrive here without polling being cleared due + * read returning -EIO, then we are (re-)connected */ + pty_chr_state(chr, 1); + goto out; + } + + /* Next poll ... */ + pty_chr_update_read_handler(chr); + +out: + return FALSE; +} + +static void pty_chr_rearm_timer(CharDriverState *chr, int ms) +{ + PtyCharDriver *s = chr->opaque; + + if (s->timer_tag) { + g_source_remove(s->timer_tag); + s->timer_tag = 0; + } + + if (ms == 1000) { + s->timer_tag = g_timeout_add_seconds(1, pty_chr_timer, chr); + } else { + s->timer_tag = g_timeout_add(ms, pty_chr_timer, chr); + } +} + static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { PtyCharDriver *s = chr->opaque; @@ -1065,7 +1103,7 @@ static void pty_chr_update_read_handler(CharDriverState *chr) * timeout to the normal (much longer) poll interval before the * timer triggers. */ - qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 10); + pty_chr_rearm_timer(chr, 10); } static void pty_chr_state(CharDriverState *chr, int connected) @@ -1080,7 +1118,7 @@ static void pty_chr_state(CharDriverState *chr, int connected) /* (re-)connect poll interval for idle guests: once per second. * We check more frequently in case the guests sends data to * the virtual device linked to our pty. */ - qemu_mod_timer(s->timer, qemu_get_clock_ms(rt_clock) + 1000); + pty_chr_rearm_timer(chr, 1000); } else { if (!s->connected) qemu_chr_generic_open(chr); @@ -1088,23 +1126,6 @@ static void pty_chr_state(CharDriverState *chr, int connected) } } -static void pty_chr_timer(void *opaque) -{ - struct CharDriverState *chr = opaque; - PtyCharDriver *s = chr->opaque; - - if (s->connected) - return; - if (s->polling) { - /* If we arrive here without polling being cleared due - * read returning -EIO, then we are (re-)connected */ - pty_chr_state(chr, 1); - return; - } - - /* Next poll ... */ - pty_chr_update_read_handler(chr); -} static void pty_chr_close(struct CharDriverState *chr) { @@ -1117,8 +1138,9 @@ static void pty_chr_close(struct CharDriverState *chr) fd = g_io_channel_unix_get_fd(s->fd); g_io_channel_unref(s->fd); close(fd); - qemu_del_timer(s->timer); - qemu_free_timer(s->timer); + if (s->timer_tag) { + g_source_remove(s->timer_tag); + } g_free(s); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } @@ -1170,7 +1192,7 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) chr->chr_add_watch = pty_chr_add_watch; s->fd = io_channel_from_fd(master_fd); - s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr); + s->timer_tag = 0; return chr; } From 9f939df955a4152aad69a19a77e0898631bb2c18 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:27 +0530 Subject: [PATCH 1403/1634] qemu-char: remove use of QEMUTimer in favor of glib idle function qemu-char is now independent of the QEMU main loop. Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 3cda0bbcfb94912df8a767983a52bb71a4a3231d.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- include/char/char.h | 2 +- qemu-char.c | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/char/char.h b/include/char/char.h index 09ac4014dd..e8b781cd5e 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -71,7 +71,7 @@ struct CharDriverState { void (*chr_guest_open)(struct CharDriverState *chr); void (*chr_guest_close)(struct CharDriverState *chr); void *opaque; - QEMUTimer *open_timer; + int idle_tag; char *label; char *filename; int opened; diff --git a/qemu-char.c b/qemu-char.c index 6dba943667..2c7c929085 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -122,20 +122,18 @@ void qemu_chr_be_event(CharDriverState *s, int event) s->chr_event(s->handler_opaque, event); } -static void qemu_chr_fire_open_event(void *opaque) +static gboolean qemu_chr_generic_open_bh(gpointer opaque) { CharDriverState *s = opaque; qemu_chr_be_event(s, CHR_EVENT_OPENED); - qemu_free_timer(s->open_timer); - s->open_timer = NULL; + s->idle_tag = 0; + return FALSE; } void qemu_chr_generic_open(CharDriverState *s) { - if (s->open_timer == NULL) { - s->open_timer = qemu_new_timer_ms(rt_clock, - qemu_chr_fire_open_event, s); - qemu_mod_timer(s->open_timer, qemu_get_clock_ms(rt_clock) - 1); + if (s->idle_tag == 0) { + s->idle_tag = g_idle_add(qemu_chr_generic_open_bh, s); } } From d654f34ec8bf006f9b57a067e0f272ab94ee8e06 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:28 +0530 Subject: [PATCH 1404/1634] qemu-char: make char drivers dynamically registerable Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 0ff4f5f2b8b7afdb85a0c241403ad73f472f0b81.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- include/char/char.h | 2 + qemu-char.c | 110 ++++++++++++++++++++++++++------------------ 2 files changed, 68 insertions(+), 44 deletions(-) diff --git a/include/char/char.h b/include/char/char.h index e8b781cd5e..2e24270895 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -244,6 +244,8 @@ CharDriverState *qemu_chr_find(const char *name); QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); +void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *)); + /* add an eventfd to the qemu devices that are polled */ CharDriverState *qemu_chr_open_eventfd(int eventfd); diff --git a/qemu-char.c b/qemu-char.c index 2c7c929085..9bcdf737cc 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3177,53 +3177,31 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) #endif -static const struct { +typedef struct CharDriver { const char *name; CharDriverState *(*open)(QemuOpts *opts); -} backend_table[] = { - { .name = "null", .open = qemu_chr_open_null }, - { .name = "socket", .open = qemu_chr_open_socket }, - { .name = "udp", .open = qemu_chr_open_udp }, - { .name = "msmouse", .open = qemu_chr_open_msmouse }, - { .name = "vc", .open = vc_init }, - { .name = "memory", .open = qemu_chr_open_ringbuf }, -#ifdef _WIN32 - { .name = "file", .open = qemu_chr_open_win_file_out }, - { .name = "pipe", .open = qemu_chr_open_win_pipe }, - { .name = "console", .open = qemu_chr_open_win_con }, - { .name = "serial", .open = qemu_chr_open_win }, - { .name = "stdio", .open = qemu_chr_open_win_stdio }, -#else - { .name = "file", .open = qemu_chr_open_file_out }, - { .name = "pipe", .open = qemu_chr_open_pipe }, - { .name = "stdio", .open = qemu_chr_open_stdio }, -#endif -#ifdef CONFIG_BRLAPI - { .name = "braille", .open = chr_baum_init }, -#endif -#ifdef HAVE_CHARDEV_TTY - { .name = "tty", .open = qemu_chr_open_tty }, - { .name = "serial", .open = qemu_chr_open_tty }, - { .name = "pty", .open = qemu_chr_open_pty }, -#endif -#ifdef HAVE_CHARDEV_PARPORT - { .name = "parallel", .open = qemu_chr_open_pp }, - { .name = "parport", .open = qemu_chr_open_pp }, -#endif -#ifdef CONFIG_SPICE - { .name = "spicevmc", .open = qemu_chr_open_spice }, -#if SPICE_SERVER_VERSION >= 0x000c02 - { .name = "spiceport", .open = qemu_chr_open_spice_port }, -#endif -#endif -}; +} CharDriver; + +static GSList *backends; + +void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *)) +{ + CharDriver *s; + + s = g_malloc0(sizeof(*s)); + s->name = g_strdup(name); + s->open = open; + + backends = g_slist_append(backends, s); +} CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s), Error **errp) { + CharDriver *cd; CharDriverState *chr; - int i; + GSList *i; if (qemu_opts_id(opts) == NULL) { error_setg(errp, "chardev: no id specified"); @@ -3235,17 +3213,20 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, qemu_opts_id(opts)); goto err; } - for (i = 0; i < ARRAY_SIZE(backend_table); i++) { - if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0) + for (i = backends; i; i = i->next) { + cd = i->data; + + if (strcmp(cd->name, qemu_opt_get(opts, "backend")) == 0) { break; + } } - if (i == ARRAY_SIZE(backend_table)) { + if (i == NULL) { error_setg(errp, "chardev: backend \"%s\" not found", qemu_opt_get(opts, "backend")); - goto err; + return NULL; } - chr = backend_table[i].open(opts); + chr = cd->open(opts); if (!chr) { error_setg(errp, "chardev: opening backend \"%s\" failed", qemu_opt_get(opts, "backend")); @@ -3677,3 +3658,44 @@ void qmp_chardev_remove(const char *id, Error **errp) } qemu_chr_delete(chr); } + +static void register_types(void) +{ + register_char_driver("null", qemu_chr_open_null); + register_char_driver("socket", qemu_chr_open_socket); + register_char_driver("udp", qemu_chr_open_udp); + register_char_driver("msmouse", qemu_chr_open_msmouse); + register_char_driver("vc", vc_init); + register_char_driver("memory", qemu_chr_open_ringbuf); +#ifdef _WIN32 + register_char_driver("file", qemu_chr_open_win_file_out); + register_char_driver("pipe", qemu_chr_open_win_pipe); + register_char_driver("console", qemu_chr_open_win_con); + register_char_driver("serial", qemu_chr_open_win); + register_char_driver("stdio", qemu_chr_open_win_stdio); +#else + register_char_driver("file", qemu_chr_open_file_out); + register_char_driver("pipe", qemu_chr_open_pipe); + register_char_driver("stdio", qemu_chr_open_stdio); +#endif +#ifdef CONFIG_BRLAPI + register_char_driver("braille", chr_baum_init); +#endif +#ifdef HAVE_CHARDEV_TTY + register_char_driver("tty", qemu_chr_open_tty); + register_char_driver("serial", qemu_chr_open_tty); + register_char_driver("pty", qemu_chr_open_pty); +#endif +#ifdef HAVE_CHARDEV_PARPORT + register_char_driver("parallel", qemu_chr_open_pp); + register_char_driver("parport", qemu_chr_open_pp); +#endif +#ifdef CONFIG_SPICE + register_char_driver("spicevmc", qemu_chr_open_spice); +#if SPICE_SERVER_VERSION >= 0x000c02 + register_char_driver("spiceport", qemu_chr_open_spice_port); +#endif +#endif +} + +type_init(register_types); From 26c60614524f41bc9016cbe27eaefe59473d3461 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:29 +0530 Subject: [PATCH 1405/1634] qemu-char: move spice registration to spice-qemu-char.c Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 49a8d12eeb117e5530b2fab02af7681b54f9245c.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 6 ------ spice-qemu-char.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 9bcdf737cc..2e9f92e355 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3690,12 +3690,6 @@ static void register_types(void) register_char_driver("parallel", qemu_chr_open_pp); register_char_driver("parport", qemu_chr_open_pp); #endif -#ifdef CONFIG_SPICE - register_char_driver("spicevmc", qemu_chr_open_spice); -#if SPICE_SERVER_VERSION >= 0x000c02 - register_char_driver("spiceport", qemu_chr_open_spice_port); -#endif -#endif } type_init(register_types); diff --git a/spice-qemu-char.c b/spice-qemu-char.c index a4d7de8c4f..aea3d24e7d 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -307,3 +307,13 @@ void qemu_spice_register_ports(void) } } #endif + +static void register_types(void) +{ + register_char_driver("spicevmc", qemu_chr_open_spice); +#if SPICE_SERVER_VERSION >= 0x000c02 + register_char_driver("spiceport", qemu_chr_open_spice_port); +#endif +} + +type_init(register_types); From 08744c98115cfa144ed3493556024e400b2e2573 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:30 +0530 Subject: [PATCH 1406/1634] qemu-char: move baum registration to baum.c Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 1b24baa1ec3a174d5cad31e079d829904b53077b.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- hw/baum.c | 9 ++++++++- hw/baum.h | 30 ------------------------------ qemu-char.c | 4 ---- vl.c | 1 - 4 files changed, 8 insertions(+), 36 deletions(-) delete mode 100644 hw/baum.h diff --git a/hw/baum.c b/hw/baum.c index 09dcb9cc74..d75b15007d 100644 --- a/hw/baum.c +++ b/hw/baum.c @@ -562,7 +562,7 @@ static void baum_close(struct CharDriverState *chr) g_free(baum); } -CharDriverState *chr_baum_init(QemuOpts *opts) +static CharDriverState *chr_baum_init(QemuOpts *opts) { BaumDriverState *baum; CharDriverState *chr; @@ -625,3 +625,10 @@ fail_handle: g_free(baum); return NULL; } + +static void register_types(void) +{ + register_char_driver("braille", chr_baum_init); +} + +type_init(register_types); diff --git a/hw/baum.h b/hw/baum.h deleted file mode 100644 index 763588422a..0000000000 --- a/hw/baum.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * QEMU Baum - * - * Copyright (c) 2008 Samuel Thibault - * - * 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. - */ -#ifndef HW_BAUM_H -#define HW_BAUM_H 1 - -/* char device */ -CharDriverState *chr_baum_init(QemuOpts *opts); - -#endif diff --git a/qemu-char.c b/qemu-char.c index 2e9f92e355..6fcd2da984 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -28,7 +28,6 @@ #include "qemu/timer.h" #include "char/char.h" #include "hw/usb.h" -#include "hw/baum.h" #include "hw/msmouse.h" #include "qmp-commands.h" @@ -3678,9 +3677,6 @@ static void register_types(void) register_char_driver("pipe", qemu_chr_open_pipe); register_char_driver("stdio", qemu_chr_open_stdio); #endif -#ifdef CONFIG_BRLAPI - register_char_driver("braille", chr_baum_init); -#endif #ifdef HAVE_CHARDEV_TTY register_char_driver("tty", qemu_chr_open_tty); register_char_driver("serial", qemu_chr_open_tty); diff --git a/vl.c b/vl.c index c03edf1bfb..5dc05581f5 100644 --- a/vl.c +++ b/vl.c @@ -119,7 +119,6 @@ int main(int argc, char **argv) #include "hw/pcmcia.h" #include "hw/pc.h" #include "hw/isa.h" -#include "hw/baum.h" #include "hw/bt.h" #include "hw/watchdog.h" #include "hw/smbios.h" From 5ab8211b9e1215ed136164c6d9622f2c928f7a8d Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:31 +0530 Subject: [PATCH 1407/1634] qemu-char: move msmouse registeration to msmouse.c Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: b47d1153b0d7669743c9a6bb98ce30f4cf7f876b.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- hw/msmouse.c | 10 ++++++++-- hw/msmouse.h | 7 ------- qemu-char.c | 3 +-- 3 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 hw/msmouse.h diff --git a/hw/msmouse.c b/hw/msmouse.c index ef47aed4e9..407ec87784 100644 --- a/hw/msmouse.c +++ b/hw/msmouse.c @@ -25,7 +25,6 @@ #include "qemu-common.h" #include "char/char.h" #include "ui/console.h" -#include "msmouse.h" #define MSMOUSE_LO6(n) ((n) & 0x3f) #define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) @@ -64,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr) g_free (chr); } -CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) +static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) { CharDriverState *chr; @@ -76,3 +75,10 @@ CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) return chr; } + +static void register_types(void) +{ + register_char_driver("msmouse", qemu_chr_open_msmouse); +} + +type_init(register_types); diff --git a/hw/msmouse.h b/hw/msmouse.h deleted file mode 100644 index 8cff3a71c3..0000000000 --- a/hw/msmouse.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef HW_MSMOUSE_H -#define HW_MSMOUSE_H 1 - -/* msmouse.c */ -CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts); - -#endif diff --git a/qemu-char.c b/qemu-char.c index 6fcd2da984..cf02cabba2 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -28,7 +28,6 @@ #include "qemu/timer.h" #include "char/char.h" #include "hw/usb.h" -#include "hw/msmouse.h" #include "qmp-commands.h" #include @@ -2179,6 +2178,7 @@ static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) } #endif /* !_WIN32 */ + /***********************************************************/ /* UDP Net console */ @@ -3663,7 +3663,6 @@ static void register_types(void) register_char_driver("null", qemu_chr_open_null); register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); - register_char_driver("msmouse", qemu_chr_open_msmouse); register_char_driver("vc", vc_init); register_char_driver("memory", qemu_chr_open_ringbuf); #ifdef _WIN32 From 01f45d986fb0b7c2d4f0466efe3cde9708f325be Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:32 +0530 Subject: [PATCH 1408/1634] qemu-char: move text console init to console.c Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 17cefde0a8d7807294bab95e93c3328a20d3f2ed.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- qemu-char.c | 1 - ui/console.c | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index cf02cabba2..b82d6433d2 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3663,7 +3663,6 @@ static void register_types(void) register_char_driver("null", qemu_chr_open_null); register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); - register_char_driver("vc", vc_init); register_char_driver("memory", qemu_chr_open_ringbuf); #ifdef _WIN32 register_char_driver("file", qemu_chr_open_win_file_out); diff --git a/ui/console.c b/ui/console.c index 0d95f32123..83a6fa3969 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1739,3 +1739,10 @@ PixelFormat qemu_default_pixelformat(int bpp) } return pf; } + +static void register_types(void) +{ + register_char_driver("vc", text_console_init); +} + +type_init(register_types); From fcfb4d6aae611d1f804d486d3c998000912c4c81 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 5 Mar 2013 23:21:33 +0530 Subject: [PATCH 1409/1634] serial: add flow control to transmit Signed-off-by: Anthony Liguori Signed-off-by: Amit Shah Message-id: 2976f10d4e66ed4a34011f6f0d6937026d22be5f.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- hw/serial.c | 28 +++++++++++----------------- hw/serial.h | 2 -- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/hw/serial.c b/hw/serial.c index f0ce9b0c15..eb38f2231d 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -256,16 +256,17 @@ static void serial_update_msl(SerialState *s) qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100); } -static void serial_xmit(void *opaque) +static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) { SerialState *s = opaque; - uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock); if (s->tsr_retry <= 0) { if (s->fcr & UART_FCR_FE) { s->tsr = fifo_get(s,XMIT_FIFO); if (!s->xmit_fifo.count) s->lsr |= UART_LSR_THRE; + } else if ((s->lsr & UART_LSR_THRE)) { + return FALSE; } else { s->tsr = s->thr; s->lsr |= UART_LSR_THRE; @@ -277,30 +278,25 @@ static void serial_xmit(void *opaque) /* in loopback mode, say that we just received a char */ serial_receive1(s, &s->tsr, 1); } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { - if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { + if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && + qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) { s->tsr_retry++; - qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); - return; - } else if (s->poll_msl < 0) { - /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then - drop any further failed writes instantly, until we get one that goes through. - This is to prevent guests that log to unconnected pipes or pty's from stalling. */ - s->tsr_retry = -1; + return FALSE; } - } - else { + s->tsr_retry = 0; + } else { s->tsr_retry = 0; } s->last_xmit_ts = qemu_get_clock_ns(vm_clock); - if (!(s->lsr & UART_LSR_THRE)) - qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time); if (s->lsr & UART_LSR_THRE) { s->lsr |= UART_LSR_TEMT; s->thr_ipending = 1; serial_update_irq(s); } + + return FALSE; } @@ -330,7 +326,7 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); } - serial_xmit(s); + serial_xmit(NULL, G_IO_OUT, s); } break; case 1: @@ -684,8 +680,6 @@ void serial_init_core(SerialState *s) s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s); s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); - s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s); - qemu_register_reset(serial_reset, s); qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, diff --git a/hw/serial.h b/hw/serial.h index 98ee4241be..e57375d03c 100644 --- a/hw/serial.h +++ b/hw/serial.h @@ -72,8 +72,6 @@ struct SerialState { struct QEMUTimer *fifo_timeout_timer; int timeout_ipending; /* timeout interrupt pending state */ - struct QEMUTimer *transmit_timer; - uint64_t char_transmit_time; /* time to transmit a char in ticks */ int poll_msl; From 7df4d4578f70b565870f353ba0b72f2f23781a09 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Tue, 5 Mar 2013 23:21:34 +0530 Subject: [PATCH 1410/1634] virtio: console: add flow control The virtio-serial-bus already has the logic to make flow control work properly. Hook into the char layer's new ability to signal a backend is writable again. Signed-off-by: Amit Shah Message-id: abffa02235d55ca6e2489068c58971c8897e976c.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- hw/virtio-console.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 46072a086f..b3ee074a87 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -20,6 +20,18 @@ typedef struct VirtConsole { CharDriverState *chr; } VirtConsole; +/* + * Callback function that's called from chardevs when backend becomes + * writable. + */ +static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond, + void *opaque) +{ + VirtConsole *vcon = opaque; + + virtio_serial_throttle_port(&vcon->port, false); + return FALSE; +} /* Callback function that's called when the guest sends us data */ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) @@ -48,6 +60,7 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) * do_flush_queued_data(). */ ret = 0; + qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked, vcon); } return ret; } From d6258c93a7133bb2bf2ab4e91476bc0b631ba7f1 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Tue, 5 Mar 2013 23:21:35 +0530 Subject: [PATCH 1411/1634] virtio-serial: make flow control explicit in virtio-console virtio-console.c used to return a value less than the number of bytes asked to be written out to a chardev backend in case the backend is not writable. virtio-serial-bus.c then implicitly enabled flow control for that port. Make this explicit instead. Signed-off-by: Amit Shah Message-id: f5ec50b068c25422256e499cf4adc06d353bf394.1362505276.git.amit.shah@redhat.com Signed-off-by: Anthony Liguori --- hw/virtio-console.c | 17 +++++++++-------- hw/virtio-serial-bus.c | 19 +------------------ 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/hw/virtio-console.c b/hw/virtio-console.c index b3ee074a87..194de6431e 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -47,20 +47,21 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) ret = qemu_chr_fe_write(vcon->chr, buf, len); trace_virtio_console_flush_buf(port->id, len, ret); - if (ret < 0) { + if (ret <= 0) { + VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); + /* * Ideally we'd get a better error code than just -1, but * that's what the chardev interface gives us right now. If * we had a finer-grained message, like -EPIPE, we could close - * this connection. Absent such error messages, the most we - * can do is to return 0 here. - * - * This will prevent stray -1 values to go to - * virtio-serial-bus.c and cause abort()s in - * do_flush_queued_data(). + * this connection. */ ret = 0; - qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked, vcon); + if (!k->is_console) { + virtio_serial_throttle_port(port, true); + qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked, + vcon); + } } return ret; } diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index aa7d0d7fc7..f76c5058ba 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -172,24 +172,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, port->elem.out_sg[i].iov_base + port->iov_offset, buf_size); - if (ret < 0 && ret != -EAGAIN) { - /* We don't handle any other type of errors here */ - abort(); - } - if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) { - /* - * this is a temporary check until chardevs can signal to - * frontends that they are writable again. This prevents - * the console from going into throttled mode (forever) - * if virtio-console is connected to a pty without a - * listener. Otherwise the guest spins forever. - * We can revert this if - * 1: chardevs can notify frondends - * 2: the guest driver does not spin in these cases - */ - if (!vsc->is_console) { - virtio_serial_throttle_port(port, true); - } + if (port->throttled) { port->iov_idx = i; if (ret > 0) { port->iov_offset += ret; From 156dfaded87d718a9ea798083e1c3e5ea7526713 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 10 Feb 2013 18:59:02 +0000 Subject: [PATCH 1412/1634] pseries: Add cleanup hook for PAPR virtual LAN device Currently the spapr-vlan device does not supply a cleanup call for its NetClientInfo structure. With current qemu versions, that leads to a SEGV on exit, when net_cleanup() attempts to call the cleanup handlers on all net clients. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_llan.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 6ef29362f5..0ace2eb1f3 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -175,11 +175,19 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, return size; } +static void spapr_vlan_cleanup(NetClientState *nc) +{ + VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc); + + dev->nic = NULL; +} + static NetClientInfo net_spapr_vlan_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = spapr_vlan_can_receive, .receive = spapr_vlan_receive, + .cleanup = spapr_vlan_cleanup, }; static void spapr_vlan_reset(VIOsPAPRDevice *sdev) From 0136d715ad985fccb8fed4bb5081d5bd20bfe88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 11 Feb 2013 10:53:11 +0000 Subject: [PATCH 1413/1634] target-ppc: Fix CPU_POWERPC_MPC8547E MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was defined to ..._MPC8545E_v21 rather than ..._MPC8547E_v21. Due to both resolving to CPU_POWERPC_e500v2_v21 this did not show. Fixing this nontheless helps with QOM'ifying CPU aliases. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f5fc9b18f0..a2e1fc9a09 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7282,7 +7282,7 @@ enum { #define CPU_POWERPC_MPC8545E_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8545E_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8545E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8547E CPU_POWERPC_MPC8545E_v21 +#define CPU_POWERPC_MPC8547E CPU_POWERPC_MPC8547E_v21 #define CPU_POWERPC_MPC8547E_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8547E_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8547E_v21 CPU_POWERPC_e500v2_v21 From bfe6d5b0daf9fdafeb0dbb7c26774dbb1bbb4507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:00 +0000 Subject: [PATCH 1414/1634] target-ppc: Fix "G2leGP3" PVR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike derived PVR constants mapped to CPU_POWERPC_G2LEgp3, the "G2leGP3" model definition itself used the CPU_POWERPC_G2LEgp1 PVR. Fixing this will allow to alias CPU_POWERPC_G2LEgp3-using types to "G2leGP3". Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index a2e1fc9a09..d2706f76e8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8243,7 +8243,7 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC G2LE GP1 core */ POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE), /* PowerPC G2LE GP3 core */ - POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp1, G2LE), + POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE), /* PowerPC MPC603 microcontrollers */ /* MPC8240 */ POWERPC_DEF("MPC8240", CPU_POWERPC_MPC8240, 603E), From 5e95acc8ff2a068b09494f2522744f89f662a515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:01 +0000 Subject: [PATCH 1415/1634] target-ppc: Update error handling in ppc_cpu_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit fe828a4d4b7a5617cda7b24e95e327bfb71d790e added a new fatal error message while QOM realize'ification was in flight. Convert it to return an Error instead of exit()ing. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- 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 d2706f76e8..d00c737ee5 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10043,9 +10043,9 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) #if !defined(CONFIG_USER_ONLY) if (smp_threads > max_smt) { - fprintf(stderr, "Cannot support more than %d threads on PPC with %s\n", - max_smt, kvm_enabled() ? "KVM" : "TCG"); - exit(1); + error_setg(errp, "Cannot support more than %d threads on PPC with %s", + max_smt, kvm_enabled() ? "KVM" : "TCG"); + return; } #endif From 9a1350539a69f465c14109605d6648572794ceda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:02 +0000 Subject: [PATCH 1416/1634] target-ppc: Drop nested TARGET_PPC64 guard for POWER7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is within a large TARGET_PPC64 section from 970 to 620, so an #endif /* TARGET_PPC64 */ is confusing. Clean this up. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d00c737ee5..98a64e1b77 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6671,7 +6671,6 @@ static void init_proc_970MP (CPUPPCState *env) vscr_init(env, 0x00010000); } -#if defined(TARGET_PPC64) /* POWER7 */ #define POWERPC_INSNS_POWER7 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6755,7 +6754,6 @@ static void init_proc_POWER7 (CPUPPCState *env) * value is the one used by 74xx processors. */ vscr_init(env, 0x00010000); } -#endif /* TARGET_PPC64 */ /* PowerPC 620 */ #define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ From c4d0a36c3630ad30058406747d3cd4cc6a6eae3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:03 +0000 Subject: [PATCH 1417/1634] target-ppc: Inline comma into POWERPC_DEF_SVR() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To repurpose the POWERPC_DEF_SVR() macro outside of an array, move the comma into the macro. No functional change. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 1206 +++++++++++++++++------------------ 1 file changed, 603 insertions(+), 603 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 98a64e1b77..3f75bef971 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7714,7 +7714,7 @@ enum { .flags = glue(POWERPC_FLAG_,_type), \ .init_proc = &glue(init_proc_,_type), \ .check_pow = &glue(check_pow_,_type), \ - } + }, #define POWERPC_DEF(_name, _pvr, _type) \ POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type) @@ -7722,1621 +7722,1621 @@ static const ppc_def_t ppc_defs[] = { /* Embedded PowerPC */ /* PowerPC 401 family */ /* Generic PowerPC 401 */ - POWERPC_DEF("401", CPU_POWERPC_401, 401), + POWERPC_DEF("401", CPU_POWERPC_401, 401) /* PowerPC 401 cores */ /* PowerPC 401A1 */ - POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401), + POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401) /* PowerPC 401B2 */ - POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2), + POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2) #if defined (TODO) /* PowerPC 401B3 */ - POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3), + POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3) #endif /* PowerPC 401C2 */ - POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2), + POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2) /* PowerPC 401D2 */ - POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2), + POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2) /* PowerPC 401E2 */ - POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2), + POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2) /* PowerPC 401F2 */ - POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2), + POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2) /* PowerPC 401G2 */ /* XXX: to be checked */ - POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2), + POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2) /* PowerPC 401 microcontrolers */ #if defined (TODO) /* PowerPC 401GF */ - POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401), + POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401) #endif /* IOP480 (401 microcontroler) */ - POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480), + POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480) /* IBM Processor for Network Resources */ - POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401), + POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401) #if defined (TODO) - POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401), + POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401) #endif /* PowerPC 403 family */ /* Generic PowerPC 403 */ - POWERPC_DEF("403", CPU_POWERPC_403, 403), + POWERPC_DEF("403", CPU_POWERPC_403, 403) /* PowerPC 403 microcontrolers */ /* PowerPC 403 GA */ - POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403), + POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403) /* PowerPC 403 GB */ - POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403), + POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403) /* PowerPC 403 GC */ - POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403), + POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403) /* PowerPC 403 GCX */ - POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX), + POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX) #if defined (TODO) /* PowerPC 403 GP */ - POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403), + POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403) #endif /* PowerPC 405 family */ /* Generic PowerPC 405 */ - POWERPC_DEF("405", CPU_POWERPC_405, 405), + POWERPC_DEF("405", CPU_POWERPC_405, 405) /* PowerPC 405 cores */ #if defined (TODO) /* PowerPC 405 A3 */ - POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405), + POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405) #endif #if defined (TODO) /* PowerPC 405 A4 */ - POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405), + POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405) #endif #if defined (TODO) /* PowerPC 405 B3 */ - POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405), + POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405) #endif #if defined (TODO) /* PowerPC 405 B4 */ - POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405), + POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405) #endif #if defined (TODO) /* PowerPC 405 C3 */ - POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405), + POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405) #endif #if defined (TODO) /* PowerPC 405 C4 */ - POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405), + POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405) #endif /* PowerPC 405 D2 */ - POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405), + POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405) #if defined (TODO) /* PowerPC 405 D3 */ - POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405), + POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405) #endif /* PowerPC 405 D4 */ - POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405), + POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405) #if defined (TODO) /* PowerPC 405 D5 */ - POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405), + POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405) #endif #if defined (TODO) /* PowerPC 405 E4 */ - POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405), + POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405) #endif #if defined (TODO) /* PowerPC 405 F4 */ - POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405), + POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405) #endif #if defined (TODO) /* PowerPC 405 F5 */ - POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405), + POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405) #endif #if defined (TODO) /* PowerPC 405 F6 */ - POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405), + POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405) #endif /* PowerPC 405 microcontrolers */ /* PowerPC 405 CR */ - POWERPC_DEF("405CR", CPU_POWERPC_405CR, 405), + POWERPC_DEF("405CR", CPU_POWERPC_405CR, 405) /* PowerPC 405 CRa */ - POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405), + POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405) /* PowerPC 405 CRb */ - POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405), + POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405) /* PowerPC 405 CRc */ - POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405), + POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405) /* PowerPC 405 EP */ - POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405), + POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405) #if defined(TODO) /* PowerPC 405 EXr */ - POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405), + POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405) #endif /* PowerPC 405 EZ */ - POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405), + POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405) #if defined(TODO) /* PowerPC 405 FX */ - POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405), + POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405) #endif /* PowerPC 405 GP */ - POWERPC_DEF("405GP", CPU_POWERPC_405GP, 405), + POWERPC_DEF("405GP", CPU_POWERPC_405GP, 405) /* PowerPC 405 GPa */ - POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405), + POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405) /* PowerPC 405 GPb */ - POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405), + POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405) /* PowerPC 405 GPc */ - POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405), + POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405) /* PowerPC 405 GPd */ - POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405), + POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405) /* PowerPC 405 GPe */ - POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 405), + POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 405) /* PowerPC 405 GPR */ - POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405), + POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405) #if defined(TODO) /* PowerPC 405 H */ - POWERPC_DEF("405H", CPU_POWERPC_405H, 405), + POWERPC_DEF("405H", CPU_POWERPC_405H, 405) #endif #if defined(TODO) /* PowerPC 405 L */ - POWERPC_DEF("405L", CPU_POWERPC_405L, 405), + POWERPC_DEF("405L", CPU_POWERPC_405L, 405) #endif /* PowerPC 405 LP */ - POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405), + POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405) #if defined(TODO) /* PowerPC 405 PM */ - POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405), + POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405) #endif #if defined(TODO) /* PowerPC 405 PS */ - POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405), + POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405) #endif #if defined(TODO) /* PowerPC 405 S */ - POWERPC_DEF("405S", CPU_POWERPC_405S, 405), + POWERPC_DEF("405S", CPU_POWERPC_405S, 405) #endif /* Npe405 H */ - POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405), + POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405) /* Npe405 H2 */ - POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405), + POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405) /* Npe405 L */ - POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405), + POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405) /* Npe4GS3 */ - POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405), + POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405) #if defined (TODO) - POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405), + POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405) #endif #if defined (TODO) - POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405), + POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405) #endif #if defined (TODO) /* PowerPC LC77700 (Sanyo) */ - POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405), + POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405) #endif /* PowerPC 401/403/405 based set-top-box microcontrolers */ #if defined (TODO) /* STB010000 */ - POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2), + POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2) #endif #if defined (TODO) /* STB01010 */ - POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2), + POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2) #endif #if defined (TODO) /* STB0210 */ - POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3), + POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3) #endif /* STB03xx */ - POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405), + POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405) #if defined (TODO) /* STB043x */ - POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405), + POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405) #endif #if defined (TODO) /* STB045x */ - POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405), + POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405) #endif /* STB04xx */ - POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405), + POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405) /* STB25xx */ - POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405), + POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405) #if defined (TODO) /* STB130 */ - POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405), + POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405) #endif /* Xilinx PowerPC 405 cores */ - POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405), - POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 405), - POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405), - POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 405), + POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405) + POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 405) + POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405) + POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 405) #if defined (TODO) /* Zarlink ZL10310 */ - POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405), + POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405) #endif #if defined (TODO) /* Zarlink ZL10311 */ - POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405), + POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405) #endif #if defined (TODO) /* Zarlink ZL10320 */ - POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405), + POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405) #endif #if defined (TODO) /* Zarlink ZL10321 */ - POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405), + POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405) #endif /* PowerPC 440 family */ #if defined(TODO_USER_ONLY) /* Generic PowerPC 440 */ - POWERPC_DEF("440", CPU_POWERPC_440, 440GP), + POWERPC_DEF("440", CPU_POWERPC_440, 440GP) #endif /* PowerPC 440 cores */ #if defined (TODO) /* PowerPC 440 A4 */ - POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4), + POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4) #endif /* PowerPC 440 Xilinx 5 */ - POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5), + POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5) #if defined (TODO) /* PowerPC 440 A5 */ - POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5), + POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5) #endif #if defined (TODO) /* PowerPC 440 B4 */ - POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4), + POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4) #endif #if defined (TODO) /* PowerPC 440 G4 */ - POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4), + POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4) #endif #if defined (TODO) /* PowerPC 440 F5 */ - POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5), + POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5) #endif #if defined (TODO) /* PowerPC 440 G5 */ - POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5), + POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5) #endif #if defined (TODO) /* PowerPC 440H4 */ - POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4), + POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4) #endif #if defined (TODO) /* PowerPC 440H6 */ - POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5), + POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5) #endif /* PowerPC 440 microcontrolers */ /* PowerPC 440 EP */ - POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP), + POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP) /* PowerPC 440 EPa */ - POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP), + POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP) /* PowerPC 440 EPb */ - POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP), + POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP) /* PowerPC 440 EPX */ - POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP), + POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP) #if defined(TODO_USER_ONLY) /* PowerPC 440 GP */ - POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP), + POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GPb */ - POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP), + POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GPc */ - POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP), + POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GR */ - POWERPC_DEF("440GR", CPU_POWERPC_440GR, 440x5), + POWERPC_DEF("440GR", CPU_POWERPC_440GR, 440x5) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GRa */ - POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5), + POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GRX */ - POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5), + POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GX */ - POWERPC_DEF("440GX", CPU_POWERPC_440GX, 440EP), + POWERPC_DEF("440GX", CPU_POWERPC_440GX, 440EP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GXa */ - POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP), + POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GXb */ - POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP), + POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GXc */ - POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP), + POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GXf */ - POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP), + POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP) #endif #if defined(TODO) /* PowerPC 440 S */ - POWERPC_DEF("440S", CPU_POWERPC_440S, 440), + POWERPC_DEF("440S", CPU_POWERPC_440S, 440) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 SP */ - POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP), + POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 SP2 */ - POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP), + POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP) #endif #if defined(TODO_USER_ONLY) /* PowerPC 440 SPE */ - POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP), + POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP) #endif /* PowerPC 460 family */ #if defined (TODO) /* Generic PowerPC 464 */ - POWERPC_DEF("464", CPU_POWERPC_464, 460), + POWERPC_DEF("464", CPU_POWERPC_464, 460) #endif /* PowerPC 464 microcontrolers */ #if defined (TODO) /* PowerPC 464H90 */ - POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460), + POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460) #endif #if defined (TODO) /* PowerPC 464H90F */ - POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F), + POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F) #endif /* Freescale embedded PowerPC cores */ /* MPC5xx family (aka RCPU) */ #if defined(TODO_USER_ONLY) /* Generic MPC5xx core */ - POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx), + POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* Codename for MPC5xx core */ - POWERPC_DEF("RCPU", CPU_POWERPC_MPC5xx, MPC5xx), + POWERPC_DEF("RCPU", CPU_POWERPC_MPC5xx, MPC5xx) #endif /* MPC5xx microcontrollers */ #if defined(TODO_USER_ONLY) /* MGT560 */ - POWERPC_DEF("MGT560", CPU_POWERPC_MGT560, MPC5xx), + POWERPC_DEF("MGT560", CPU_POWERPC_MGT560, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC509 */ - POWERPC_DEF("MPC509", CPU_POWERPC_MPC509, MPC5xx), + POWERPC_DEF("MPC509", CPU_POWERPC_MPC509, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC533 */ - POWERPC_DEF("MPC533", CPU_POWERPC_MPC533, MPC5xx), + POWERPC_DEF("MPC533", CPU_POWERPC_MPC533, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC534 */ - POWERPC_DEF("MPC534", CPU_POWERPC_MPC534, MPC5xx), + POWERPC_DEF("MPC534", CPU_POWERPC_MPC534, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC555 */ - POWERPC_DEF("MPC555", CPU_POWERPC_MPC555, MPC5xx), + POWERPC_DEF("MPC555", CPU_POWERPC_MPC555, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC556 */ - POWERPC_DEF("MPC556", CPU_POWERPC_MPC556, MPC5xx), + POWERPC_DEF("MPC556", CPU_POWERPC_MPC556, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC560 */ - POWERPC_DEF("MPC560", CPU_POWERPC_MPC560, MPC5xx), + POWERPC_DEF("MPC560", CPU_POWERPC_MPC560, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC561 */ - POWERPC_DEF("MPC561", CPU_POWERPC_MPC561, MPC5xx), + POWERPC_DEF("MPC561", CPU_POWERPC_MPC561, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC562 */ - POWERPC_DEF("MPC562", CPU_POWERPC_MPC562, MPC5xx), + POWERPC_DEF("MPC562", CPU_POWERPC_MPC562, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC563 */ - POWERPC_DEF("MPC563", CPU_POWERPC_MPC563, MPC5xx), + POWERPC_DEF("MPC563", CPU_POWERPC_MPC563, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC564 */ - POWERPC_DEF("MPC564", CPU_POWERPC_MPC564, MPC5xx), + POWERPC_DEF("MPC564", CPU_POWERPC_MPC564, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC565 */ - POWERPC_DEF("MPC565", CPU_POWERPC_MPC565, MPC5xx), + POWERPC_DEF("MPC565", CPU_POWERPC_MPC565, MPC5xx) #endif #if defined(TODO_USER_ONLY) /* MPC566 */ - POWERPC_DEF("MPC566", CPU_POWERPC_MPC566, MPC5xx), + POWERPC_DEF("MPC566", CPU_POWERPC_MPC566, MPC5xx) #endif /* MPC8xx family (aka PowerQUICC) */ #if defined(TODO_USER_ONLY) /* Generic MPC8xx core */ - POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx), + POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* Codename for MPC8xx core */ - POWERPC_DEF("PowerQUICC", CPU_POWERPC_MPC8xx, MPC8xx), + POWERPC_DEF("PowerQUICC", CPU_POWERPC_MPC8xx, MPC8xx) #endif /* MPC8xx microcontrollers */ #if defined(TODO_USER_ONLY) /* MGT823 */ - POWERPC_DEF("MGT823", CPU_POWERPC_MGT823, MPC8xx), + POWERPC_DEF("MGT823", CPU_POWERPC_MGT823, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC821 */ - POWERPC_DEF("MPC821", CPU_POWERPC_MPC821, MPC8xx), + POWERPC_DEF("MPC821", CPU_POWERPC_MPC821, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC823 */ - POWERPC_DEF("MPC823", CPU_POWERPC_MPC823, MPC8xx), + POWERPC_DEF("MPC823", CPU_POWERPC_MPC823, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC850 */ - POWERPC_DEF("MPC850", CPU_POWERPC_MPC850, MPC8xx), + POWERPC_DEF("MPC850", CPU_POWERPC_MPC850, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC852T */ - POWERPC_DEF("MPC852T", CPU_POWERPC_MPC852T, MPC8xx), + POWERPC_DEF("MPC852T", CPU_POWERPC_MPC852T, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC855T */ - POWERPC_DEF("MPC855T", CPU_POWERPC_MPC855T, MPC8xx), + POWERPC_DEF("MPC855T", CPU_POWERPC_MPC855T, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC857 */ - POWERPC_DEF("MPC857", CPU_POWERPC_MPC857, MPC8xx), + POWERPC_DEF("MPC857", CPU_POWERPC_MPC857, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC859 */ - POWERPC_DEF("MPC859", CPU_POWERPC_MPC859, MPC8xx), + POWERPC_DEF("MPC859", CPU_POWERPC_MPC859, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC860 */ - POWERPC_DEF("MPC860", CPU_POWERPC_MPC860, MPC8xx), + POWERPC_DEF("MPC860", CPU_POWERPC_MPC860, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC862 */ - POWERPC_DEF("MPC862", CPU_POWERPC_MPC862, MPC8xx), + POWERPC_DEF("MPC862", CPU_POWERPC_MPC862, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC866 */ - POWERPC_DEF("MPC866", CPU_POWERPC_MPC866, MPC8xx), + POWERPC_DEF("MPC866", CPU_POWERPC_MPC866, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC870 */ - POWERPC_DEF("MPC870", CPU_POWERPC_MPC870, MPC8xx), + POWERPC_DEF("MPC870", CPU_POWERPC_MPC870, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC875 */ - POWERPC_DEF("MPC875", CPU_POWERPC_MPC875, MPC8xx), + POWERPC_DEF("MPC875", CPU_POWERPC_MPC875, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC880 */ - POWERPC_DEF("MPC880", CPU_POWERPC_MPC880, MPC8xx), + POWERPC_DEF("MPC880", CPU_POWERPC_MPC880, MPC8xx) #endif #if defined(TODO_USER_ONLY) /* MPC885 */ - POWERPC_DEF("MPC885", CPU_POWERPC_MPC885, MPC8xx), + POWERPC_DEF("MPC885", CPU_POWERPC_MPC885, MPC8xx) #endif /* MPC82xx family (aka PowerQUICC-II) */ /* Generic MPC52xx core */ POWERPC_DEF_SVR("MPC52xx", - CPU_POWERPC_MPC52xx, POWERPC_SVR_52xx, G2LE), + CPU_POWERPC_MPC52xx, POWERPC_SVR_52xx, G2LE) /* Generic MPC82xx core */ - POWERPC_DEF("MPC82xx", CPU_POWERPC_MPC82xx, G2), + POWERPC_DEF("MPC82xx", CPU_POWERPC_MPC82xx, G2) /* Codename for MPC82xx */ - POWERPC_DEF("PowerQUICC-II", CPU_POWERPC_MPC82xx, G2), + POWERPC_DEF("PowerQUICC-II", CPU_POWERPC_MPC82xx, G2) /* PowerPC G2 core */ - POWERPC_DEF("G2", CPU_POWERPC_G2, G2), + POWERPC_DEF("G2", CPU_POWERPC_G2, G2) /* PowerPC G2 H4 core */ - POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2), + POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2) /* PowerPC G2 GP core */ - POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2), + POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2) /* PowerPC G2 LS core */ - POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2), + POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2) /* PowerPC G2 HiP3 core */ - POWERPC_DEF("G2HiP3", CPU_POWERPC_G2_HIP3, G2), + POWERPC_DEF("G2HiP3", CPU_POWERPC_G2_HIP3, G2) /* PowerPC G2 HiP4 core */ - POWERPC_DEF("G2HiP4", CPU_POWERPC_G2_HIP4, G2), + POWERPC_DEF("G2HiP4", CPU_POWERPC_G2_HIP4, G2) /* PowerPC MPC603 core */ - POWERPC_DEF("MPC603", CPU_POWERPC_MPC603, 603E), + POWERPC_DEF("MPC603", CPU_POWERPC_MPC603, 603E) /* PowerPC G2le core (same as G2 plus little-endian mode support) */ - POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE), + POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE) /* PowerPC G2LE GP core */ - POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE), + POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE) /* PowerPC G2LE LS core */ - POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE), + POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE) /* PowerPC G2LE GP1 core */ - POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE), + POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE) /* PowerPC G2LE GP3 core */ - POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE), + POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE) /* PowerPC MPC603 microcontrollers */ /* MPC8240 */ - POWERPC_DEF("MPC8240", CPU_POWERPC_MPC8240, 603E), + POWERPC_DEF("MPC8240", CPU_POWERPC_MPC8240, 603E) /* PowerPC G2 microcontrollers */ #if defined(TODO) /* MPC5121 */ POWERPC_DEF_SVR("MPC5121", - CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE), + CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE) #endif /* MPC5200 */ POWERPC_DEF_SVR("MPC5200", - CPU_POWERPC_MPC5200, POWERPC_SVR_5200, G2LE), + CPU_POWERPC_MPC5200, POWERPC_SVR_5200, G2LE) /* MPC5200 v1.0 */ POWERPC_DEF_SVR("MPC5200_v10", - CPU_POWERPC_MPC5200_v10, POWERPC_SVR_5200_v10, G2LE), + CPU_POWERPC_MPC5200_v10, POWERPC_SVR_5200_v10, G2LE) /* MPC5200 v1.1 */ POWERPC_DEF_SVR("MPC5200_v11", - CPU_POWERPC_MPC5200_v11, POWERPC_SVR_5200_v11, G2LE), + CPU_POWERPC_MPC5200_v11, POWERPC_SVR_5200_v11, G2LE) /* MPC5200 v1.2 */ POWERPC_DEF_SVR("MPC5200_v12", - CPU_POWERPC_MPC5200_v12, POWERPC_SVR_5200_v12, G2LE), + CPU_POWERPC_MPC5200_v12, POWERPC_SVR_5200_v12, G2LE) /* MPC5200B */ POWERPC_DEF_SVR("MPC5200B", - CPU_POWERPC_MPC5200B, POWERPC_SVR_5200B, G2LE), + CPU_POWERPC_MPC5200B, POWERPC_SVR_5200B, G2LE) /* MPC5200B v2.0 */ POWERPC_DEF_SVR("MPC5200B_v20", - CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE), + CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE) /* MPC5200B v2.1 */ POWERPC_DEF_SVR("MPC5200B_v21", - CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE), + CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE) /* MPC8241 */ - POWERPC_DEF("MPC8241", CPU_POWERPC_MPC8241, G2), + POWERPC_DEF("MPC8241", CPU_POWERPC_MPC8241, G2) /* MPC8245 */ - POWERPC_DEF("MPC8245", CPU_POWERPC_MPC8245, G2), + POWERPC_DEF("MPC8245", CPU_POWERPC_MPC8245, G2) /* MPC8247 */ - POWERPC_DEF("MPC8247", CPU_POWERPC_MPC8247, G2LE), + POWERPC_DEF("MPC8247", CPU_POWERPC_MPC8247, G2LE) /* MPC8248 */ - POWERPC_DEF("MPC8248", CPU_POWERPC_MPC8248, G2LE), + POWERPC_DEF("MPC8248", CPU_POWERPC_MPC8248, G2LE) /* MPC8250 */ - POWERPC_DEF("MPC8250", CPU_POWERPC_MPC8250, G2), + POWERPC_DEF("MPC8250", CPU_POWERPC_MPC8250, G2) /* MPC8250 HiP3 */ - POWERPC_DEF("MPC8250_HiP3", CPU_POWERPC_MPC8250_HiP3, G2), + POWERPC_DEF("MPC8250_HiP3", CPU_POWERPC_MPC8250_HiP3, G2) /* MPC8250 HiP4 */ - POWERPC_DEF("MPC8250_HiP4", CPU_POWERPC_MPC8250_HiP4, G2), + POWERPC_DEF("MPC8250_HiP4", CPU_POWERPC_MPC8250_HiP4, G2) /* MPC8255 */ - POWERPC_DEF("MPC8255", CPU_POWERPC_MPC8255, G2), + POWERPC_DEF("MPC8255", CPU_POWERPC_MPC8255, G2) /* MPC8255 HiP3 */ - POWERPC_DEF("MPC8255_HiP3", CPU_POWERPC_MPC8255_HiP3, G2), + POWERPC_DEF("MPC8255_HiP3", CPU_POWERPC_MPC8255_HiP3, G2) /* MPC8255 HiP4 */ - POWERPC_DEF("MPC8255_HiP4", CPU_POWERPC_MPC8255_HiP4, G2), + POWERPC_DEF("MPC8255_HiP4", CPU_POWERPC_MPC8255_HiP4, G2) /* MPC8260 */ - POWERPC_DEF("MPC8260", CPU_POWERPC_MPC8260, G2), + POWERPC_DEF("MPC8260", CPU_POWERPC_MPC8260, G2) /* MPC8260 HiP3 */ - POWERPC_DEF("MPC8260_HiP3", CPU_POWERPC_MPC8260_HiP3, G2), + POWERPC_DEF("MPC8260_HiP3", CPU_POWERPC_MPC8260_HiP3, G2) /* MPC8260 HiP4 */ - POWERPC_DEF("MPC8260_HiP4", CPU_POWERPC_MPC8260_HiP4, G2), + POWERPC_DEF("MPC8260_HiP4", CPU_POWERPC_MPC8260_HiP4, G2) /* MPC8264 */ - POWERPC_DEF("MPC8264", CPU_POWERPC_MPC8264, G2), + POWERPC_DEF("MPC8264", CPU_POWERPC_MPC8264, G2) /* MPC8264 HiP3 */ - POWERPC_DEF("MPC8264_HiP3", CPU_POWERPC_MPC8264_HiP3, G2), + POWERPC_DEF("MPC8264_HiP3", CPU_POWERPC_MPC8264_HiP3, G2) /* MPC8264 HiP4 */ - POWERPC_DEF("MPC8264_HiP4", CPU_POWERPC_MPC8264_HiP4, G2), + POWERPC_DEF("MPC8264_HiP4", CPU_POWERPC_MPC8264_HiP4, G2) /* MPC8265 */ - POWERPC_DEF("MPC8265", CPU_POWERPC_MPC8265, G2), + POWERPC_DEF("MPC8265", CPU_POWERPC_MPC8265, G2) /* MPC8265 HiP3 */ - POWERPC_DEF("MPC8265_HiP3", CPU_POWERPC_MPC8265_HiP3, G2), + POWERPC_DEF("MPC8265_HiP3", CPU_POWERPC_MPC8265_HiP3, G2) /* MPC8265 HiP4 */ - POWERPC_DEF("MPC8265_HiP4", CPU_POWERPC_MPC8265_HiP4, G2), + POWERPC_DEF("MPC8265_HiP4", CPU_POWERPC_MPC8265_HiP4, G2) /* MPC8266 */ - POWERPC_DEF("MPC8266", CPU_POWERPC_MPC8266, G2), + POWERPC_DEF("MPC8266", CPU_POWERPC_MPC8266, G2) /* MPC8266 HiP3 */ - POWERPC_DEF("MPC8266_HiP3", CPU_POWERPC_MPC8266_HiP3, G2), + POWERPC_DEF("MPC8266_HiP3", CPU_POWERPC_MPC8266_HiP3, G2) /* MPC8266 HiP4 */ - POWERPC_DEF("MPC8266_HiP4", CPU_POWERPC_MPC8266_HiP4, G2), + POWERPC_DEF("MPC8266_HiP4", CPU_POWERPC_MPC8266_HiP4, G2) /* MPC8270 */ - POWERPC_DEF("MPC8270", CPU_POWERPC_MPC8270, G2LE), + POWERPC_DEF("MPC8270", CPU_POWERPC_MPC8270, G2LE) /* MPC8271 */ - POWERPC_DEF("MPC8271", CPU_POWERPC_MPC8271, G2LE), + POWERPC_DEF("MPC8271", CPU_POWERPC_MPC8271, G2LE) /* MPC8272 */ - POWERPC_DEF("MPC8272", CPU_POWERPC_MPC8272, G2LE), + POWERPC_DEF("MPC8272", CPU_POWERPC_MPC8272, G2LE) /* MPC8275 */ - POWERPC_DEF("MPC8275", CPU_POWERPC_MPC8275, G2LE), + POWERPC_DEF("MPC8275", CPU_POWERPC_MPC8275, G2LE) /* MPC8280 */ - POWERPC_DEF("MPC8280", CPU_POWERPC_MPC8280, G2LE), + POWERPC_DEF("MPC8280", CPU_POWERPC_MPC8280, G2LE) /* e200 family */ /* Generic PowerPC e200 core */ - POWERPC_DEF("e200", CPU_POWERPC_e200, e200), + POWERPC_DEF("e200", CPU_POWERPC_e200, e200) /* Generic MPC55xx core */ #if defined (TODO) POWERPC_DEF_SVR("MPC55xx", - CPU_POWERPC_MPC55xx, POWERPC_SVR_55xx, e200), + CPU_POWERPC_MPC55xx, POWERPC_SVR_55xx, e200) #endif #if defined (TODO) /* PowerPC e200z0 core */ - POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200), + POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200) #endif #if defined (TODO) /* PowerPC e200z1 core */ - POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200), + POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200) #endif #if defined (TODO) /* PowerPC e200z3 core */ - POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200), + POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200) #endif /* PowerPC e200z5 core */ - POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200), + POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200) /* PowerPC e200z6 core */ - POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200), + POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200) /* PowerPC e200 microcontrollers */ #if defined (TODO) /* MPC5514E */ POWERPC_DEF_SVR("MPC5514E", - CPU_POWERPC_MPC5514E, POWERPC_SVR_5514E, e200), + CPU_POWERPC_MPC5514E, POWERPC_SVR_5514E, e200) #endif #if defined (TODO) /* MPC5514E v0 */ POWERPC_DEF_SVR("MPC5514E_v0", - CPU_POWERPC_MPC5514E_v0, POWERPC_SVR_5514E_v0, e200), + CPU_POWERPC_MPC5514E_v0, POWERPC_SVR_5514E_v0, e200) #endif #if defined (TODO) /* MPC5514E v1 */ POWERPC_DEF_SVR("MPC5514E_v1", - CPU_POWERPC_MPC5514E_v1, POWERPC_SVR_5514E_v1, e200), + CPU_POWERPC_MPC5514E_v1, POWERPC_SVR_5514E_v1, e200) #endif #if defined (TODO) /* MPC5514G */ POWERPC_DEF_SVR("MPC5514G", - CPU_POWERPC_MPC5514G, POWERPC_SVR_5514G, e200), + CPU_POWERPC_MPC5514G, POWERPC_SVR_5514G, e200) #endif #if defined (TODO) /* MPC5514G v0 */ POWERPC_DEF_SVR("MPC5514G_v0", - CPU_POWERPC_MPC5514G_v0, POWERPC_SVR_5514G_v0, e200), + CPU_POWERPC_MPC5514G_v0, POWERPC_SVR_5514G_v0, e200) #endif #if defined (TODO) /* MPC5514G v1 */ POWERPC_DEF_SVR("MPC5514G_v1", - CPU_POWERPC_MPC5514G_v1, POWERPC_SVR_5514G_v1, e200), + CPU_POWERPC_MPC5514G_v1, POWERPC_SVR_5514G_v1, e200) #endif #if defined (TODO) /* MPC5515S */ POWERPC_DEF_SVR("MPC5515S", - CPU_POWERPC_MPC5515S, POWERPC_SVR_5515S, e200), + CPU_POWERPC_MPC5515S, POWERPC_SVR_5515S, e200) #endif #if defined (TODO) /* MPC5516E */ POWERPC_DEF_SVR("MPC5516E", - CPU_POWERPC_MPC5516E, POWERPC_SVR_5516E, e200), + CPU_POWERPC_MPC5516E, POWERPC_SVR_5516E, e200) #endif #if defined (TODO) /* MPC5516E v0 */ POWERPC_DEF_SVR("MPC5516E_v0", - CPU_POWERPC_MPC5516E_v0, POWERPC_SVR_5516E_v0, e200), + CPU_POWERPC_MPC5516E_v0, POWERPC_SVR_5516E_v0, e200) #endif #if defined (TODO) /* MPC5516E v1 */ POWERPC_DEF_SVR("MPC5516E_v1", - CPU_POWERPC_MPC5516E_v1, POWERPC_SVR_5516E_v1, e200), + CPU_POWERPC_MPC5516E_v1, POWERPC_SVR_5516E_v1, e200) #endif #if defined (TODO) /* MPC5516G */ POWERPC_DEF_SVR("MPC5516G", - CPU_POWERPC_MPC5516G, POWERPC_SVR_5516G, e200), + CPU_POWERPC_MPC5516G, POWERPC_SVR_5516G, e200) #endif #if defined (TODO) /* MPC5516G v0 */ POWERPC_DEF_SVR("MPC5516G_v0", - CPU_POWERPC_MPC5516G_v0, POWERPC_SVR_5516G_v0, e200), + CPU_POWERPC_MPC5516G_v0, POWERPC_SVR_5516G_v0, e200) #endif #if defined (TODO) /* MPC5516G v1 */ POWERPC_DEF_SVR("MPC5516G_v1", - CPU_POWERPC_MPC5516G_v1, POWERPC_SVR_5516G_v1, e200), + CPU_POWERPC_MPC5516G_v1, POWERPC_SVR_5516G_v1, e200) #endif #if defined (TODO) /* MPC5516S */ POWERPC_DEF_SVR("MPC5516S", - CPU_POWERPC_MPC5516S, POWERPC_SVR_5516S, e200), + CPU_POWERPC_MPC5516S, POWERPC_SVR_5516S, e200) #endif #if defined (TODO) /* MPC5533 */ POWERPC_DEF_SVR("MPC5533", - CPU_POWERPC_MPC5533, POWERPC_SVR_5533, e200), + CPU_POWERPC_MPC5533, POWERPC_SVR_5533, e200) #endif #if defined (TODO) /* MPC5534 */ POWERPC_DEF_SVR("MPC5534", - CPU_POWERPC_MPC5534, POWERPC_SVR_5534, e200), + CPU_POWERPC_MPC5534, POWERPC_SVR_5534, e200) #endif #if defined (TODO) /* MPC5553 */ POWERPC_DEF_SVR("MPC5553", - CPU_POWERPC_MPC5553, POWERPC_SVR_5553, e200), + CPU_POWERPC_MPC5553, POWERPC_SVR_5553, e200) #endif #if defined (TODO) /* MPC5554 */ POWERPC_DEF_SVR("MPC5554", - CPU_POWERPC_MPC5554, POWERPC_SVR_5554, e200), + CPU_POWERPC_MPC5554, POWERPC_SVR_5554, e200) #endif #if defined (TODO) /* MPC5561 */ POWERPC_DEF_SVR("MPC5561", - CPU_POWERPC_MPC5561, POWERPC_SVR_5561, e200), + CPU_POWERPC_MPC5561, POWERPC_SVR_5561, e200) #endif #if defined (TODO) /* MPC5565 */ POWERPC_DEF_SVR("MPC5565", - CPU_POWERPC_MPC5565, POWERPC_SVR_5565, e200), + CPU_POWERPC_MPC5565, POWERPC_SVR_5565, e200) #endif #if defined (TODO) /* MPC5566 */ POWERPC_DEF_SVR("MPC5566", - CPU_POWERPC_MPC5566, POWERPC_SVR_5566, e200), + CPU_POWERPC_MPC5566, POWERPC_SVR_5566, e200) #endif #if defined (TODO) /* MPC5567 */ POWERPC_DEF_SVR("MPC5567", - CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200), + CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200) #endif /* e300 family */ /* Generic PowerPC e300 core */ - POWERPC_DEF("e300", CPU_POWERPC_e300, e300), + POWERPC_DEF("e300", CPU_POWERPC_e300, e300) /* PowerPC e300c1 core */ - POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300), + POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300) /* PowerPC e300c2 core */ - POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300), + POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300) /* PowerPC e300c3 core */ - POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300), + POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300) /* PowerPC e300c4 core */ - POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300), + POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300) /* PowerPC e300 microcontrollers */ #if defined (TODO) /* MPC8313 */ POWERPC_DEF_SVR("MPC8313", - CPU_POWERPC_MPC831x, POWERPC_SVR_8313, e300), + CPU_POWERPC_MPC831x, POWERPC_SVR_8313, e300) #endif #if defined (TODO) /* MPC8313E */ POWERPC_DEF_SVR("MPC8313E", - CPU_POWERPC_MPC831x, POWERPC_SVR_8313E, e300), + CPU_POWERPC_MPC831x, POWERPC_SVR_8313E, e300) #endif #if defined (TODO) /* MPC8314 */ POWERPC_DEF_SVR("MPC8314", - CPU_POWERPC_MPC831x, POWERPC_SVR_8314, e300), + CPU_POWERPC_MPC831x, POWERPC_SVR_8314, e300) #endif #if defined (TODO) /* MPC8314E */ POWERPC_DEF_SVR("MPC8314E", - CPU_POWERPC_MPC831x, POWERPC_SVR_8314E, e300), + CPU_POWERPC_MPC831x, POWERPC_SVR_8314E, e300) #endif #if defined (TODO) /* MPC8315 */ POWERPC_DEF_SVR("MPC8315", - CPU_POWERPC_MPC831x, POWERPC_SVR_8315, e300), + CPU_POWERPC_MPC831x, POWERPC_SVR_8315, e300) #endif #if defined (TODO) /* MPC8315E */ POWERPC_DEF_SVR("MPC8315E", - CPU_POWERPC_MPC831x, POWERPC_SVR_8315E, e300), + CPU_POWERPC_MPC831x, POWERPC_SVR_8315E, e300) #endif #if defined (TODO) /* MPC8321 */ POWERPC_DEF_SVR("MPC8321", - CPU_POWERPC_MPC832x, POWERPC_SVR_8321, e300), + CPU_POWERPC_MPC832x, POWERPC_SVR_8321, e300) #endif #if defined (TODO) /* MPC8321E */ POWERPC_DEF_SVR("MPC8321E", - CPU_POWERPC_MPC832x, POWERPC_SVR_8321E, e300), + CPU_POWERPC_MPC832x, POWERPC_SVR_8321E, e300) #endif #if defined (TODO) /* MPC8323 */ POWERPC_DEF_SVR("MPC8323", - CPU_POWERPC_MPC832x, POWERPC_SVR_8323, e300), + CPU_POWERPC_MPC832x, POWERPC_SVR_8323, e300) #endif #if defined (TODO) /* MPC8323E */ POWERPC_DEF_SVR("MPC8323E", - CPU_POWERPC_MPC832x, POWERPC_SVR_8323E, e300), + CPU_POWERPC_MPC832x, POWERPC_SVR_8323E, e300) #endif /* MPC8343 */ POWERPC_DEF_SVR("MPC8343", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8343, e300) /* MPC8343A */ POWERPC_DEF_SVR("MPC8343A", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343A, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8343A, e300) /* MPC8343E */ POWERPC_DEF_SVR("MPC8343E", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343E, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8343E, e300) /* MPC8343EA */ POWERPC_DEF_SVR("MPC8343EA", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343EA, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8343EA, e300) /* MPC8347 */ POWERPC_DEF_SVR("MPC8347", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347, e300) /* MPC8347T */ POWERPC_DEF_SVR("MPC8347T", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347T, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347T, e300) /* MPC8347P */ POWERPC_DEF_SVR("MPC8347P", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347P, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347P, e300) /* MPC8347A */ POWERPC_DEF_SVR("MPC8347A", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347A, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347A, e300) /* MPC8347AT */ POWERPC_DEF_SVR("MPC8347AT", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347AT, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347AT, e300) /* MPC8347AP */ POWERPC_DEF_SVR("MPC8347AP", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347AP, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347AP, e300) /* MPC8347E */ POWERPC_DEF_SVR("MPC8347E", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347E, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347E, e300) /* MPC8347ET */ POWERPC_DEF_SVR("MPC8347ET", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347ET, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347ET, e300) /* MPC8343EP */ POWERPC_DEF_SVR("MPC8347EP", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EP, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347EP, e300) /* MPC8347EA */ POWERPC_DEF_SVR("MPC8347EA", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EA, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347EA, e300) /* MPC8347EAT */ POWERPC_DEF_SVR("MPC8347EAT", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAT, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAT, e300) /* MPC8343EAP */ POWERPC_DEF_SVR("MPC8347EAP", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAP, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAP, e300) /* MPC8349 */ POWERPC_DEF_SVR("MPC8349", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8349, e300) /* MPC8349A */ POWERPC_DEF_SVR("MPC8349A", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349A, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8349A, e300) /* MPC8349E */ POWERPC_DEF_SVR("MPC8349E", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349E, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8349E, e300) /* MPC8349EA */ POWERPC_DEF_SVR("MPC8349EA", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349EA, e300), + CPU_POWERPC_MPC834x, POWERPC_SVR_8349EA, e300) #if defined (TODO) /* MPC8358E */ POWERPC_DEF_SVR("MPC8358E", - CPU_POWERPC_MPC835x, POWERPC_SVR_8358E, e300), + CPU_POWERPC_MPC835x, POWERPC_SVR_8358E, e300) #endif #if defined (TODO) /* MPC8360E */ POWERPC_DEF_SVR("MPC8360E", - CPU_POWERPC_MPC836x, POWERPC_SVR_8360E, e300), + CPU_POWERPC_MPC836x, POWERPC_SVR_8360E, e300) #endif /* MPC8377 */ POWERPC_DEF_SVR("MPC8377", - CPU_POWERPC_MPC837x, POWERPC_SVR_8377, e300), + CPU_POWERPC_MPC837x, POWERPC_SVR_8377, e300) /* MPC8377E */ POWERPC_DEF_SVR("MPC8377E", - CPU_POWERPC_MPC837x, POWERPC_SVR_8377E, e300), + CPU_POWERPC_MPC837x, POWERPC_SVR_8377E, e300) /* MPC8378 */ POWERPC_DEF_SVR("MPC8378", - CPU_POWERPC_MPC837x, POWERPC_SVR_8378, e300), + CPU_POWERPC_MPC837x, POWERPC_SVR_8378, e300) /* MPC8378E */ POWERPC_DEF_SVR("MPC8378E", - CPU_POWERPC_MPC837x, POWERPC_SVR_8378E, e300), + CPU_POWERPC_MPC837x, POWERPC_SVR_8378E, e300) /* MPC8379 */ POWERPC_DEF_SVR("MPC8379", - CPU_POWERPC_MPC837x, POWERPC_SVR_8379, e300), + CPU_POWERPC_MPC837x, POWERPC_SVR_8379, e300) /* MPC8379E */ POWERPC_DEF_SVR("MPC8379E", - CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300), + CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300) /* e500 family */ /* PowerPC e500 core */ - POWERPC_DEF("e500", CPU_POWERPC_e500v2_v22, e500v2), + POWERPC_DEF("e500", CPU_POWERPC_e500v2_v22, e500v2) /* PowerPC e500v1 core */ - POWERPC_DEF("e500v1", CPU_POWERPC_e500v1, e500v1), + POWERPC_DEF("e500v1", CPU_POWERPC_e500v1, e500v1) /* PowerPC e500 v1.0 core */ - POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1), + POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1) /* PowerPC e500 v2.0 core */ - POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1), + POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1) /* PowerPC e500v2 core */ - POWERPC_DEF("e500v2", CPU_POWERPC_e500v2, e500v2), + POWERPC_DEF("e500v2", CPU_POWERPC_e500v2, e500v2) /* PowerPC e500v2 v1.0 core */ - POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2), + POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2) /* PowerPC e500v2 v2.0 core */ - POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2), + POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2) /* PowerPC e500v2 v2.1 core */ - POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2), + POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2) /* PowerPC e500v2 v2.2 core */ - POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2), + POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2) /* PowerPC e500v2 v3.0 core */ - POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2), - POWERPC_DEF_SVR("e500mc", CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc), + POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2) + POWERPC_DEF_SVR("e500mc", CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc) #ifdef TARGET_PPC64 - POWERPC_DEF_SVR("e5500", CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500), + POWERPC_DEF_SVR("e5500", CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500) #endif /* PowerPC e500 microcontrollers */ /* MPC8533 */ POWERPC_DEF_SVR("MPC8533", - CPU_POWERPC_MPC8533, POWERPC_SVR_8533, e500v2), + CPU_POWERPC_MPC8533, POWERPC_SVR_8533, e500v2) /* MPC8533 v1.0 */ POWERPC_DEF_SVR("MPC8533_v10", - CPU_POWERPC_MPC8533_v10, POWERPC_SVR_8533_v10, e500v2), + CPU_POWERPC_MPC8533_v10, POWERPC_SVR_8533_v10, e500v2) /* MPC8533 v1.1 */ POWERPC_DEF_SVR("MPC8533_v11", - CPU_POWERPC_MPC8533_v11, POWERPC_SVR_8533_v11, e500v2), + CPU_POWERPC_MPC8533_v11, POWERPC_SVR_8533_v11, e500v2) /* MPC8533E */ POWERPC_DEF_SVR("MPC8533E", - CPU_POWERPC_MPC8533E, POWERPC_SVR_8533E, e500v2), + CPU_POWERPC_MPC8533E, POWERPC_SVR_8533E, e500v2) /* MPC8533E v1.0 */ POWERPC_DEF_SVR("MPC8533E_v10", - CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500v2), + CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500v2) POWERPC_DEF_SVR("MPC8533E_v11", - CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500v2), + CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500v2) /* MPC8540 */ POWERPC_DEF_SVR("MPC8540", - CPU_POWERPC_MPC8540, POWERPC_SVR_8540, e500v1), + CPU_POWERPC_MPC8540, POWERPC_SVR_8540, e500v1) /* MPC8540 v1.0 */ POWERPC_DEF_SVR("MPC8540_v10", - CPU_POWERPC_MPC8540_v10, POWERPC_SVR_8540_v10, e500v1), + CPU_POWERPC_MPC8540_v10, POWERPC_SVR_8540_v10, e500v1) /* MPC8540 v2.0 */ POWERPC_DEF_SVR("MPC8540_v20", - CPU_POWERPC_MPC8540_v20, POWERPC_SVR_8540_v20, e500v1), + CPU_POWERPC_MPC8540_v20, POWERPC_SVR_8540_v20, e500v1) /* MPC8540 v2.1 */ POWERPC_DEF_SVR("MPC8540_v21", - CPU_POWERPC_MPC8540_v21, POWERPC_SVR_8540_v21, e500v1), + CPU_POWERPC_MPC8540_v21, POWERPC_SVR_8540_v21, e500v1) /* MPC8541 */ POWERPC_DEF_SVR("MPC8541", - CPU_POWERPC_MPC8541, POWERPC_SVR_8541, e500v1), + CPU_POWERPC_MPC8541, POWERPC_SVR_8541, e500v1) /* MPC8541 v1.0 */ POWERPC_DEF_SVR("MPC8541_v10", - CPU_POWERPC_MPC8541_v10, POWERPC_SVR_8541_v10, e500v1), + CPU_POWERPC_MPC8541_v10, POWERPC_SVR_8541_v10, e500v1) /* MPC8541 v1.1 */ POWERPC_DEF_SVR("MPC8541_v11", - CPU_POWERPC_MPC8541_v11, POWERPC_SVR_8541_v11, e500v1), + CPU_POWERPC_MPC8541_v11, POWERPC_SVR_8541_v11, e500v1) /* MPC8541E */ POWERPC_DEF_SVR("MPC8541E", - CPU_POWERPC_MPC8541E, POWERPC_SVR_8541E, e500v1), + CPU_POWERPC_MPC8541E, POWERPC_SVR_8541E, e500v1) /* MPC8541E v1.0 */ POWERPC_DEF_SVR("MPC8541E_v10", - CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500v1), + CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500v1) /* MPC8541E v1.1 */ POWERPC_DEF_SVR("MPC8541E_v11", - CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500v1), + CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500v1) /* MPC8543 */ POWERPC_DEF_SVR("MPC8543", - CPU_POWERPC_MPC8543, POWERPC_SVR_8543, e500v2), + CPU_POWERPC_MPC8543, POWERPC_SVR_8543, e500v2) /* MPC8543 v1.0 */ POWERPC_DEF_SVR("MPC8543_v10", - CPU_POWERPC_MPC8543_v10, POWERPC_SVR_8543_v10, e500v2), + CPU_POWERPC_MPC8543_v10, POWERPC_SVR_8543_v10, e500v2) /* MPC8543 v1.1 */ POWERPC_DEF_SVR("MPC8543_v11", - CPU_POWERPC_MPC8543_v11, POWERPC_SVR_8543_v11, e500v2), + CPU_POWERPC_MPC8543_v11, POWERPC_SVR_8543_v11, e500v2) /* MPC8543 v2.0 */ POWERPC_DEF_SVR("MPC8543_v20", - CPU_POWERPC_MPC8543_v20, POWERPC_SVR_8543_v20, e500v2), + CPU_POWERPC_MPC8543_v20, POWERPC_SVR_8543_v20, e500v2) /* MPC8543 v2.1 */ POWERPC_DEF_SVR("MPC8543_v21", - CPU_POWERPC_MPC8543_v21, POWERPC_SVR_8543_v21, e500v2), + CPU_POWERPC_MPC8543_v21, POWERPC_SVR_8543_v21, e500v2) /* MPC8543E */ POWERPC_DEF_SVR("MPC8543E", - CPU_POWERPC_MPC8543E, POWERPC_SVR_8543E, e500v2), + CPU_POWERPC_MPC8543E, POWERPC_SVR_8543E, e500v2) /* MPC8543E v1.0 */ POWERPC_DEF_SVR("MPC8543E_v10", - CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500v2), + CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500v2) /* MPC8543E v1.1 */ POWERPC_DEF_SVR("MPC8543E_v11", - CPU_POWERPC_MPC8543E_v11, POWERPC_SVR_8543E_v11, e500v2), + CPU_POWERPC_MPC8543E_v11, POWERPC_SVR_8543E_v11, e500v2) /* MPC8543E v2.0 */ POWERPC_DEF_SVR("MPC8543E_v20", - CPU_POWERPC_MPC8543E_v20, POWERPC_SVR_8543E_v20, e500v2), + CPU_POWERPC_MPC8543E_v20, POWERPC_SVR_8543E_v20, e500v2) /* MPC8543E v2.1 */ POWERPC_DEF_SVR("MPC8543E_v21", - CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500v2), + CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500v2) /* MPC8544 */ POWERPC_DEF_SVR("MPC8544", - CPU_POWERPC_MPC8544, POWERPC_SVR_8544, e500v2), + CPU_POWERPC_MPC8544, POWERPC_SVR_8544, e500v2) /* MPC8544 v1.0 */ POWERPC_DEF_SVR("MPC8544_v10", - CPU_POWERPC_MPC8544_v10, POWERPC_SVR_8544_v10, e500v2), + CPU_POWERPC_MPC8544_v10, POWERPC_SVR_8544_v10, e500v2) /* MPC8544 v1.1 */ POWERPC_DEF_SVR("MPC8544_v11", - CPU_POWERPC_MPC8544_v11, POWERPC_SVR_8544_v11, e500v2), + CPU_POWERPC_MPC8544_v11, POWERPC_SVR_8544_v11, e500v2) /* MPC8544E */ POWERPC_DEF_SVR("MPC8544E", - CPU_POWERPC_MPC8544E, POWERPC_SVR_8544E, e500v2), + CPU_POWERPC_MPC8544E, POWERPC_SVR_8544E, e500v2) /* MPC8544E v1.0 */ POWERPC_DEF_SVR("MPC8544E_v10", - CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500v2), + CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500v2) /* MPC8544E v1.1 */ POWERPC_DEF_SVR("MPC8544E_v11", - CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500v2), + CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500v2) /* MPC8545 */ POWERPC_DEF_SVR("MPC8545", - CPU_POWERPC_MPC8545, POWERPC_SVR_8545, e500v2), + CPU_POWERPC_MPC8545, POWERPC_SVR_8545, e500v2) /* MPC8545 v2.0 */ POWERPC_DEF_SVR("MPC8545_v20", - CPU_POWERPC_MPC8545_v20, POWERPC_SVR_8545_v20, e500v2), + CPU_POWERPC_MPC8545_v20, POWERPC_SVR_8545_v20, e500v2) /* MPC8545 v2.1 */ POWERPC_DEF_SVR("MPC8545_v21", - CPU_POWERPC_MPC8545_v21, POWERPC_SVR_8545_v21, e500v2), + CPU_POWERPC_MPC8545_v21, POWERPC_SVR_8545_v21, e500v2) /* MPC8545E */ POWERPC_DEF_SVR("MPC8545E", - CPU_POWERPC_MPC8545E, POWERPC_SVR_8545E, e500v2), + CPU_POWERPC_MPC8545E, POWERPC_SVR_8545E, e500v2) /* MPC8545E v2.0 */ POWERPC_DEF_SVR("MPC8545E_v20", - CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500v2), + CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500v2) /* MPC8545E v2.1 */ POWERPC_DEF_SVR("MPC8545E_v21", - CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500v2), + CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500v2) /* MPC8547E */ POWERPC_DEF_SVR("MPC8547E", - CPU_POWERPC_MPC8547E, POWERPC_SVR_8547E, e500v2), + CPU_POWERPC_MPC8547E, POWERPC_SVR_8547E, e500v2) /* MPC8547E v2.0 */ POWERPC_DEF_SVR("MPC8547E_v20", - CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500v2), + CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500v2) /* MPC8547E v2.1 */ POWERPC_DEF_SVR("MPC8547E_v21", - CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500v2), + CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500v2) /* MPC8548 */ POWERPC_DEF_SVR("MPC8548", - CPU_POWERPC_MPC8548, POWERPC_SVR_8548, e500v2), + CPU_POWERPC_MPC8548, POWERPC_SVR_8548, e500v2) /* MPC8548 v1.0 */ POWERPC_DEF_SVR("MPC8548_v10", - CPU_POWERPC_MPC8548_v10, POWERPC_SVR_8548_v10, e500v2), + CPU_POWERPC_MPC8548_v10, POWERPC_SVR_8548_v10, e500v2) /* MPC8548 v1.1 */ POWERPC_DEF_SVR("MPC8548_v11", - CPU_POWERPC_MPC8548_v11, POWERPC_SVR_8548_v11, e500v2), + CPU_POWERPC_MPC8548_v11, POWERPC_SVR_8548_v11, e500v2) /* MPC8548 v2.0 */ POWERPC_DEF_SVR("MPC8548_v20", - CPU_POWERPC_MPC8548_v20, POWERPC_SVR_8548_v20, e500v2), + CPU_POWERPC_MPC8548_v20, POWERPC_SVR_8548_v20, e500v2) /* MPC8548 v2.1 */ POWERPC_DEF_SVR("MPC8548_v21", - CPU_POWERPC_MPC8548_v21, POWERPC_SVR_8548_v21, e500v2), + CPU_POWERPC_MPC8548_v21, POWERPC_SVR_8548_v21, e500v2) /* MPC8548E */ POWERPC_DEF_SVR("MPC8548E", - CPU_POWERPC_MPC8548E, POWERPC_SVR_8548E, e500v2), + CPU_POWERPC_MPC8548E, POWERPC_SVR_8548E, e500v2) /* MPC8548E v1.0 */ POWERPC_DEF_SVR("MPC8548E_v10", - CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500v2), + CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500v2) /* MPC8548E v1.1 */ POWERPC_DEF_SVR("MPC8548E_v11", - CPU_POWERPC_MPC8548E_v11, POWERPC_SVR_8548E_v11, e500v2), + CPU_POWERPC_MPC8548E_v11, POWERPC_SVR_8548E_v11, e500v2) /* MPC8548E v2.0 */ POWERPC_DEF_SVR("MPC8548E_v20", - CPU_POWERPC_MPC8548E_v20, POWERPC_SVR_8548E_v20, e500v2), + CPU_POWERPC_MPC8548E_v20, POWERPC_SVR_8548E_v20, e500v2) /* MPC8548E v2.1 */ POWERPC_DEF_SVR("MPC8548E_v21", - CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2), + CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2) /* MPC8555 */ POWERPC_DEF_SVR("MPC8555", - CPU_POWERPC_MPC8555, POWERPC_SVR_8555, e500v2), + CPU_POWERPC_MPC8555, POWERPC_SVR_8555, e500v2) /* MPC8555 v1.0 */ POWERPC_DEF_SVR("MPC8555_v10", - CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2), + CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2) /* MPC8555 v1.1 */ POWERPC_DEF_SVR("MPC8555_v11", - CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2), + CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2) /* MPC8555E */ POWERPC_DEF_SVR("MPC8555E", - CPU_POWERPC_MPC8555E, POWERPC_SVR_8555E, e500v2), + CPU_POWERPC_MPC8555E, POWERPC_SVR_8555E, e500v2) /* MPC8555E v1.0 */ POWERPC_DEF_SVR("MPC8555E_v10", - CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2), + CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2) /* MPC8555E v1.1 */ POWERPC_DEF_SVR("MPC8555E_v11", - CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2), + CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2) /* MPC8560 */ POWERPC_DEF_SVR("MPC8560", - CPU_POWERPC_MPC8560, POWERPC_SVR_8560, e500v2), + CPU_POWERPC_MPC8560, POWERPC_SVR_8560, e500v2) /* MPC8560 v1.0 */ POWERPC_DEF_SVR("MPC8560_v10", - CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2), + CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2) /* MPC8560 v2.0 */ POWERPC_DEF_SVR("MPC8560_v20", - CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v2), + CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v2) /* MPC8560 v2.1 */ POWERPC_DEF_SVR("MPC8560_v21", - CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v2), + CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v2) /* MPC8567 */ POWERPC_DEF_SVR("MPC8567", - CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500v2), + CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500v2) /* MPC8567E */ POWERPC_DEF_SVR("MPC8567E", - CPU_POWERPC_MPC8567E, POWERPC_SVR_8567E, e500v2), + CPU_POWERPC_MPC8567E, POWERPC_SVR_8567E, e500v2) /* MPC8568 */ POWERPC_DEF_SVR("MPC8568", - CPU_POWERPC_MPC8568, POWERPC_SVR_8568, e500v2), + CPU_POWERPC_MPC8568, POWERPC_SVR_8568, e500v2) /* MPC8568E */ POWERPC_DEF_SVR("MPC8568E", - CPU_POWERPC_MPC8568E, POWERPC_SVR_8568E, e500v2), + CPU_POWERPC_MPC8568E, POWERPC_SVR_8568E, e500v2) /* MPC8572 */ POWERPC_DEF_SVR("MPC8572", - CPU_POWERPC_MPC8572, POWERPC_SVR_8572, e500v2), + CPU_POWERPC_MPC8572, POWERPC_SVR_8572, e500v2) /* MPC8572E */ POWERPC_DEF_SVR("MPC8572E", - CPU_POWERPC_MPC8572E, POWERPC_SVR_8572E, e500v2), + CPU_POWERPC_MPC8572E, POWERPC_SVR_8572E, e500v2) /* e600 family */ /* PowerPC e600 core */ - POWERPC_DEF("e600", CPU_POWERPC_e600, 7400), + POWERPC_DEF("e600", CPU_POWERPC_e600, 7400) /* PowerPC e600 microcontrollers */ #if defined (TODO) /* MPC8610 */ POWERPC_DEF_SVR("MPC8610", - CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400), + CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400) #endif /* MPC8641 */ POWERPC_DEF_SVR("MPC8641", - CPU_POWERPC_MPC8641, POWERPC_SVR_8641, 7400), + CPU_POWERPC_MPC8641, POWERPC_SVR_8641, 7400) /* MPC8641D */ POWERPC_DEF_SVR("MPC8641D", - CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400), + CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400) /* 32 bits "classic" PowerPC */ /* PowerPC 6xx family */ /* PowerPC 601 */ - POWERPC_DEF("601", CPU_POWERPC_601, 601v), + POWERPC_DEF("601", CPU_POWERPC_601, 601v) /* PowerPC 601v0 */ - POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601), + POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601) /* PowerPC 601v1 */ - POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601), + POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601) /* PowerPC 601v */ - POWERPC_DEF("601v", CPU_POWERPC_601v, 601v), + POWERPC_DEF("601v", CPU_POWERPC_601v, 601v) /* PowerPC 601v2 */ - POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v), + POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v) /* PowerPC 602 */ - POWERPC_DEF("602", CPU_POWERPC_602, 602), + POWERPC_DEF("602", CPU_POWERPC_602, 602) /* PowerPC 603 */ - POWERPC_DEF("603", CPU_POWERPC_603, 603), + POWERPC_DEF("603", CPU_POWERPC_603, 603) /* Code name for PowerPC 603 */ - POWERPC_DEF("Vanilla", CPU_POWERPC_603, 603), + POWERPC_DEF("Vanilla", CPU_POWERPC_603, 603) /* PowerPC 603e (aka PID6) */ - POWERPC_DEF("603e", CPU_POWERPC_603E, 603E), + POWERPC_DEF("603e", CPU_POWERPC_603E, 603E) /* Code name for PowerPC 603e */ - POWERPC_DEF("Stretch", CPU_POWERPC_603E, 603E), + POWERPC_DEF("Stretch", CPU_POWERPC_603E, 603E) /* PowerPC 603e v1.1 */ - POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E), + POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E) /* PowerPC 603e v1.2 */ - POWERPC_DEF("603e_v1.2", CPU_POWERPC_603E_v12, 603E), + POWERPC_DEF("603e_v1.2", CPU_POWERPC_603E_v12, 603E) /* PowerPC 603e v1.3 */ - POWERPC_DEF("603e_v1.3", CPU_POWERPC_603E_v13, 603E), + POWERPC_DEF("603e_v1.3", CPU_POWERPC_603E_v13, 603E) /* PowerPC 603e v1.4 */ - POWERPC_DEF("603e_v1.4", CPU_POWERPC_603E_v14, 603E), + POWERPC_DEF("603e_v1.4", CPU_POWERPC_603E_v14, 603E) /* PowerPC 603e v2.2 */ - POWERPC_DEF("603e_v2.2", CPU_POWERPC_603E_v22, 603E), + POWERPC_DEF("603e_v2.2", CPU_POWERPC_603E_v22, 603E) /* PowerPC 603e v3 */ - POWERPC_DEF("603e_v3", CPU_POWERPC_603E_v3, 603E), + POWERPC_DEF("603e_v3", CPU_POWERPC_603E_v3, 603E) /* PowerPC 603e v4 */ - POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E), + POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E) /* PowerPC 603e v4.1 */ - POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E), + POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E) /* PowerPC 603e (aka PID7) */ - POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E), + POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E) /* PowerPC 603e7t */ - POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E), + POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E) /* PowerPC 603e7v */ - POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E), + POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E) /* Code name for PowerPC 603ev */ - POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 603E), + POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 603E) /* PowerPC 603e7v1 */ - POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E), + POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E) /* PowerPC 603e7v2 */ - POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E), + POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E) /* PowerPC 603p (aka PID7v) */ - POWERPC_DEF("603p", CPU_POWERPC_603P, 603E), + POWERPC_DEF("603p", CPU_POWERPC_603P, 603E) /* PowerPC 603r (aka PID7t) */ - POWERPC_DEF("603r", CPU_POWERPC_603R, 603E), + POWERPC_DEF("603r", CPU_POWERPC_603R, 603E) /* Code name for PowerPC 603r */ - POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 603E), + POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 603E) /* PowerPC 604 */ - POWERPC_DEF("604", CPU_POWERPC_604, 604), + POWERPC_DEF("604", CPU_POWERPC_604, 604) /* PowerPC 604e (aka PID9) */ - POWERPC_DEF("604e", CPU_POWERPC_604E, 604E), + POWERPC_DEF("604e", CPU_POWERPC_604E, 604E) /* Code name for PowerPC 604e */ - POWERPC_DEF("Sirocco", CPU_POWERPC_604E, 604E), + POWERPC_DEF("Sirocco", CPU_POWERPC_604E, 604E) /* PowerPC 604e v1.0 */ - POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E), + POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E) /* PowerPC 604e v2.2 */ - POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604E), + POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604E) /* PowerPC 604e v2.4 */ - POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E), + POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E) /* PowerPC 604r (aka PIDA) */ - POWERPC_DEF("604r", CPU_POWERPC_604R, 604E), + POWERPC_DEF("604r", CPU_POWERPC_604R, 604E) /* Code name for PowerPC 604r */ - POWERPC_DEF("Mach5", CPU_POWERPC_604R, 604E), + POWERPC_DEF("Mach5", CPU_POWERPC_604R, 604E) #if defined(TODO) /* PowerPC 604ev */ - POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E), + POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E) #endif /* PowerPC 7xx family */ /* Generic PowerPC 740 (G3) */ - POWERPC_DEF("740", CPU_POWERPC_7x0, 740), + POWERPC_DEF("740", CPU_POWERPC_7x0, 740) /* Code name for PowerPC 740 */ - POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 740), + POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 740) /* Generic PowerPC 750 (G3) */ - POWERPC_DEF("750", CPU_POWERPC_7x0, 750), + POWERPC_DEF("750", CPU_POWERPC_7x0, 750) /* Code name for PowerPC 750 */ - POWERPC_DEF("Typhoon", CPU_POWERPC_7x0, 750), + POWERPC_DEF("Typhoon", CPU_POWERPC_7x0, 750) /* PowerPC 740/750 is also known as G3 */ - POWERPC_DEF("G3", CPU_POWERPC_7x0, 750), + POWERPC_DEF("G3", CPU_POWERPC_7x0, 750) /* PowerPC 740 v1.0 (G3) */ - POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740), + POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740) /* PowerPC 750 v1.0 (G3) */ - POWERPC_DEF("750_v1.0", CPU_POWERPC_7x0_v10, 750), + POWERPC_DEF("750_v1.0", CPU_POWERPC_7x0_v10, 750) /* PowerPC 740 v2.0 (G3) */ - POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 740), + POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 740) /* PowerPC 750 v2.0 (G3) */ - POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 750), + POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 750) /* PowerPC 740 v2.1 (G3) */ - POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 740), + POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 740) /* PowerPC 750 v2.1 (G3) */ - POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 750), + POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 750) /* PowerPC 740 v2.2 (G3) */ - POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 740), + POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 740) /* PowerPC 750 v2.2 (G3) */ - POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 750), + POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 750) /* PowerPC 740 v3.0 (G3) */ - POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 740), + POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 740) /* PowerPC 750 v3.0 (G3) */ - POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 750), + POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 750) /* PowerPC 740 v3.1 (G3) */ - POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 740), + POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 740) /* PowerPC 750 v3.1 (G3) */ - POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 750), + POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 750) /* PowerPC 740E (G3) */ - POWERPC_DEF("740e", CPU_POWERPC_740E, 740), + POWERPC_DEF("740e", CPU_POWERPC_740E, 740) /* PowerPC 750E (G3) */ - POWERPC_DEF("750e", CPU_POWERPC_750E, 750), + POWERPC_DEF("750e", CPU_POWERPC_750E, 750) /* PowerPC 740P (G3) */ - POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740), + POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740) /* PowerPC 750P (G3) */ - POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750), + POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750) /* Code name for PowerPC 740P/750P (G3) */ - POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 750), + POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 750) /* PowerPC 750CL (G3 embedded) */ - POWERPC_DEF("750cl", CPU_POWERPC_750CL, 750cl), + POWERPC_DEF("750cl", CPU_POWERPC_750CL, 750cl) /* PowerPC 750CL v1.0 */ - POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl), + POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl) /* PowerPC 750CL v2.0 */ - POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl), + POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl) /* PowerPC 750CX (G3 embedded) */ - POWERPC_DEF("750cx", CPU_POWERPC_750CX, 750cx), + POWERPC_DEF("750cx", CPU_POWERPC_750CX, 750cx) /* PowerPC 750CX v1.0 (G3 embedded) */ - POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx), + POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx) /* PowerPC 750CX v2.1 (G3 embedded) */ - POWERPC_DEF("750cx_v2.0", CPU_POWERPC_750CX_v20, 750cx), + POWERPC_DEF("750cx_v2.0", CPU_POWERPC_750CX_v20, 750cx) /* PowerPC 750CX v2.1 (G3 embedded) */ - POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx), + POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx) /* PowerPC 750CX v2.2 (G3 embedded) */ - POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx), + POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx) /* PowerPC 750CXe (G3 embedded) */ - POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 750cx), + POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 750cx) /* PowerPC 750CXe v2.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx), + POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx) /* PowerPC 750CXe v2.2 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 750cx), + POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 750cx) /* PowerPC 750CXe v2.3 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 750cx), + POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 750cx) /* PowerPC 750CXe v2.4 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 750cx), + POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 750cx) /* PowerPC 750CXe v2.4b (G3 embedded) */ - POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 750cx), + POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 750cx) /* PowerPC 750CXe v3.0 (G3 embedded) */ - POWERPC_DEF("750cxe_v3.0", CPU_POWERPC_750CXE_v30, 750cx), + POWERPC_DEF("750cxe_v3.0", CPU_POWERPC_750CXE_v30, 750cx) /* PowerPC 750CXe v3.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 750cx), + POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 750cx) /* PowerPC 750CXe v3.1b (G3 embedded) */ - POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 750cx), + POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 750cx) /* PowerPC 750CXr (G3 embedded) */ - POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx), + POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx) /* PowerPC 750FL (G3 embedded) */ - POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx), + POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx) /* PowerPC 750FX (G3 embedded) */ - POWERPC_DEF("750fx", CPU_POWERPC_750FX, 750fx), + POWERPC_DEF("750fx", CPU_POWERPC_750FX, 750fx) /* PowerPC 750FX v1.0 (G3 embedded) */ - POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx), + POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx) /* PowerPC 750FX v2.0 (G3 embedded) */ - POWERPC_DEF("750fx_v2.0", CPU_POWERPC_750FX_v20, 750fx), + POWERPC_DEF("750fx_v2.0", CPU_POWERPC_750FX_v20, 750fx) /* PowerPC 750FX v2.1 (G3 embedded) */ - POWERPC_DEF("750fx_v2.1", CPU_POWERPC_750FX_v21, 750fx), + POWERPC_DEF("750fx_v2.1", CPU_POWERPC_750FX_v21, 750fx) /* PowerPC 750FX v2.2 (G3 embedded) */ - POWERPC_DEF("750fx_v2.2", CPU_POWERPC_750FX_v22, 750fx), + POWERPC_DEF("750fx_v2.2", CPU_POWERPC_750FX_v22, 750fx) /* PowerPC 750FX v2.3 (G3 embedded) */ - POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx), + POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx) /* PowerPC 750GL (G3 embedded) */ - POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx), + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx) /* PowerPC 750GX (G3 embedded) */ - POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750gx), + POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750gx) /* PowerPC 750GX v1.0 (G3 embedded) */ - POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx), + POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx) /* PowerPC 750GX v1.1 (G3 embedded) */ - POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx), + POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx) /* PowerPC 750GX v1.2 (G3 embedded) */ - POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx), + POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx) /* PowerPC 750L (G3 embedded) */ - POWERPC_DEF("750l", CPU_POWERPC_750L, 750), + POWERPC_DEF("750l", CPU_POWERPC_750L, 750) /* Code name for PowerPC 750L (G3 embedded) */ - POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 750), + POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 750) /* PowerPC 750L v2.0 (G3 embedded) */ - POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750), + POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750) /* PowerPC 750L v2.1 (G3 embedded) */ - POWERPC_DEF("750l_v2.1", CPU_POWERPC_750L_v21, 750), + POWERPC_DEF("750l_v2.1", CPU_POWERPC_750L_v21, 750) /* PowerPC 750L v2.2 (G3 embedded) */ - POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 750), + POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 750) /* PowerPC 750L v3.0 (G3 embedded) */ - POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750), + POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750) /* PowerPC 750L v3.2 (G3 embedded) */ - POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750), + POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750) /* Generic PowerPC 745 */ - POWERPC_DEF("745", CPU_POWERPC_7x5, 745), + POWERPC_DEF("745", CPU_POWERPC_7x5, 745) /* Generic PowerPC 755 */ - POWERPC_DEF("755", CPU_POWERPC_7x5, 755), + POWERPC_DEF("755", CPU_POWERPC_7x5, 755) /* Code name for PowerPC 745/755 */ - POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 755), + POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 755) /* PowerPC 745 v1.0 */ - POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745), + POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745) /* PowerPC 755 v1.0 */ - POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 755), + POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 755) /* PowerPC 745 v1.1 */ - POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 745), + POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 745) /* PowerPC 755 v1.1 */ - POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 755), + POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 755) /* PowerPC 745 v2.0 */ - POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 745), + POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 745) /* PowerPC 755 v2.0 */ - POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 755), + POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 755) /* PowerPC 745 v2.1 */ - POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 745), + POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 745) /* PowerPC 755 v2.1 */ - POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 755), + POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 755) /* PowerPC 745 v2.2 */ - POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 745), + POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 745) /* PowerPC 755 v2.2 */ - POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 755), + POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 755) /* PowerPC 745 v2.3 */ - POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 745), + POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 745) /* PowerPC 755 v2.3 */ - POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 755), + POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 755) /* PowerPC 745 v2.4 */ - POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 745), + POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 745) /* PowerPC 755 v2.4 */ - POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 755), + POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 755) /* PowerPC 745 v2.5 */ - POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 745), + POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 745) /* PowerPC 755 v2.5 */ - POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 755), + POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 755) /* PowerPC 745 v2.6 */ - POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 745), + POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 745) /* PowerPC 755 v2.6 */ - POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 755), + POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 755) /* PowerPC 745 v2.7 */ - POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 745), + POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 745) /* PowerPC 755 v2.7 */ - POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 755), + POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 755) /* PowerPC 745 v2.8 */ - POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 745), + POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 745) /* PowerPC 755 v2.8 */ - POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755), + POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755) #if defined (TODO) /* PowerPC 745P (G3) */ - POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745), + POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745) /* PowerPC 755P (G3) */ - POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755), + POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755) #endif /* PowerPC 74xx family */ /* PowerPC 7400 (G4) */ - POWERPC_DEF("7400", CPU_POWERPC_7400, 7400), + POWERPC_DEF("7400", CPU_POWERPC_7400, 7400) /* Code name for PowerPC 7400 */ - POWERPC_DEF("Max", CPU_POWERPC_7400, 7400), + POWERPC_DEF("Max", CPU_POWERPC_7400, 7400) /* PowerPC 74xx is also well known as G4 */ - POWERPC_DEF("G4", CPU_POWERPC_7400, 7400), + POWERPC_DEF("G4", CPU_POWERPC_7400, 7400) /* PowerPC 7400 v1.0 (G4) */ - POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400), + POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400) /* PowerPC 7400 v1.1 (G4) */ - POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400), + POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400) /* PowerPC 7400 v2.0 (G4) */ - POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400), + POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400) /* PowerPC 7400 v2.1 (G4) */ - POWERPC_DEF("7400_v2.1", CPU_POWERPC_7400_v21, 7400), + POWERPC_DEF("7400_v2.1", CPU_POWERPC_7400_v21, 7400) /* PowerPC 7400 v2.2 (G4) */ - POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400), + POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400) /* PowerPC 7400 v2.6 (G4) */ - POWERPC_DEF("7400_v2.6", CPU_POWERPC_7400_v26, 7400), + POWERPC_DEF("7400_v2.6", CPU_POWERPC_7400_v26, 7400) /* PowerPC 7400 v2.7 (G4) */ - POWERPC_DEF("7400_v2.7", CPU_POWERPC_7400_v27, 7400), + POWERPC_DEF("7400_v2.7", CPU_POWERPC_7400_v27, 7400) /* PowerPC 7400 v2.8 (G4) */ - POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400), + POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400) /* PowerPC 7400 v2.9 (G4) */ - POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400), + POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400) /* PowerPC 7410 (G4) */ - POWERPC_DEF("7410", CPU_POWERPC_7410, 7410), + POWERPC_DEF("7410", CPU_POWERPC_7410, 7410) /* Code name for PowerPC 7410 */ - POWERPC_DEF("Nitro", CPU_POWERPC_7410, 7410), + POWERPC_DEF("Nitro", CPU_POWERPC_7410, 7410) /* PowerPC 7410 v1.0 (G4) */ - POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410), + POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410) /* PowerPC 7410 v1.1 (G4) */ - POWERPC_DEF("7410_v1.1", CPU_POWERPC_7410_v11, 7410), + POWERPC_DEF("7410_v1.1", CPU_POWERPC_7410_v11, 7410) /* PowerPC 7410 v1.2 (G4) */ - POWERPC_DEF("7410_v1.2", CPU_POWERPC_7410_v12, 7410), + POWERPC_DEF("7410_v1.2", CPU_POWERPC_7410_v12, 7410) /* PowerPC 7410 v1.3 (G4) */ - POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410), + POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410) /* PowerPC 7410 v1.4 (G4) */ - POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410), + POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410) /* PowerPC 7448 (G4) */ - POWERPC_DEF("7448", CPU_POWERPC_7448, 7400), + POWERPC_DEF("7448", CPU_POWERPC_7448, 7400) /* PowerPC 7448 v1.0 (G4) */ - POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400), + POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400) /* PowerPC 7448 v1.1 (G4) */ - POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400), + POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400) /* PowerPC 7448 v2.0 (G4) */ - POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400), + POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400) /* PowerPC 7448 v2.1 (G4) */ - POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400), + POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400) /* PowerPC 7450 (G4) */ - POWERPC_DEF("7450", CPU_POWERPC_7450, 7450), + POWERPC_DEF("7450", CPU_POWERPC_7450, 7450) /* Code name for PowerPC 7450 */ - POWERPC_DEF("Vger", CPU_POWERPC_7450, 7450), + POWERPC_DEF("Vger", CPU_POWERPC_7450, 7450) /* PowerPC 7450 v1.0 (G4) */ - POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450), + POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450) /* PowerPC 7450 v1.1 (G4) */ - POWERPC_DEF("7450_v1.1", CPU_POWERPC_7450_v11, 7450), + POWERPC_DEF("7450_v1.1", CPU_POWERPC_7450_v11, 7450) /* PowerPC 7450 v1.2 (G4) */ - POWERPC_DEF("7450_v1.2", CPU_POWERPC_7450_v12, 7450), + POWERPC_DEF("7450_v1.2", CPU_POWERPC_7450_v12, 7450) /* PowerPC 7450 v2.0 (G4) */ - POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450), + POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450) /* PowerPC 7450 v2.1 (G4) */ - POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450), + POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450) /* PowerPC 7441 (G4) */ - POWERPC_DEF("7441", CPU_POWERPC_74x1, 7440), + POWERPC_DEF("7441", CPU_POWERPC_74x1, 7440) /* PowerPC 7451 (G4) */ - POWERPC_DEF("7451", CPU_POWERPC_74x1, 7450), + POWERPC_DEF("7451", CPU_POWERPC_74x1, 7450) /* PowerPC 7441 v2.1 (G4) */ - POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440), + POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440) /* PowerPC 7441 v2.3 (G4) */ - POWERPC_DEF("7441_v2.3", CPU_POWERPC_74x1_v23, 7440), + POWERPC_DEF("7441_v2.3", CPU_POWERPC_74x1_v23, 7440) /* PowerPC 7451 v2.3 (G4) */ - POWERPC_DEF("7451_v2.3", CPU_POWERPC_74x1_v23, 7450), + POWERPC_DEF("7451_v2.3", CPU_POWERPC_74x1_v23, 7450) /* PowerPC 7441 v2.10 (G4) */ - POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440), + POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440) /* PowerPC 7451 v2.10 (G4) */ - POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450), + POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450) /* PowerPC 7445 (G4) */ - POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445), + POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445) /* PowerPC 7455 (G4) */ - POWERPC_DEF("7455", CPU_POWERPC_74x5, 7455), + POWERPC_DEF("7455", CPU_POWERPC_74x5, 7455) /* Code name for PowerPC 7445/7455 */ - POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 7455), + POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 7455) /* PowerPC 7445 v1.0 (G4) */ - POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445), + POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445) /* PowerPC 7455 v1.0 (G4) */ - POWERPC_DEF("7455_v1.0", CPU_POWERPC_74x5_v10, 7455), + POWERPC_DEF("7455_v1.0", CPU_POWERPC_74x5_v10, 7455) /* PowerPC 7445 v2.1 (G4) */ - POWERPC_DEF("7445_v2.1", CPU_POWERPC_74x5_v21, 7445), + POWERPC_DEF("7445_v2.1", CPU_POWERPC_74x5_v21, 7445) /* PowerPC 7455 v2.1 (G4) */ - POWERPC_DEF("7455_v2.1", CPU_POWERPC_74x5_v21, 7455), + POWERPC_DEF("7455_v2.1", CPU_POWERPC_74x5_v21, 7455) /* PowerPC 7445 v3.2 (G4) */ - POWERPC_DEF("7445_v3.2", CPU_POWERPC_74x5_v32, 7445), + POWERPC_DEF("7445_v3.2", CPU_POWERPC_74x5_v32, 7445) /* PowerPC 7455 v3.2 (G4) */ - POWERPC_DEF("7455_v3.2", CPU_POWERPC_74x5_v32, 7455), + POWERPC_DEF("7455_v3.2", CPU_POWERPC_74x5_v32, 7455) /* PowerPC 7445 v3.3 (G4) */ - POWERPC_DEF("7445_v3.3", CPU_POWERPC_74x5_v33, 7445), + POWERPC_DEF("7445_v3.3", CPU_POWERPC_74x5_v33, 7445) /* PowerPC 7455 v3.3 (G4) */ - POWERPC_DEF("7455_v3.3", CPU_POWERPC_74x5_v33, 7455), + POWERPC_DEF("7455_v3.3", CPU_POWERPC_74x5_v33, 7455) /* PowerPC 7445 v3.4 (G4) */ - POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445), + POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445) /* PowerPC 7455 v3.4 (G4) */ - POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455), + POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455) /* PowerPC 7447 (G4) */ - POWERPC_DEF("7447", CPU_POWERPC_74x7, 7445), + POWERPC_DEF("7447", CPU_POWERPC_74x7, 7445) /* PowerPC 7457 (G4) */ - POWERPC_DEF("7457", CPU_POWERPC_74x7, 7455), + POWERPC_DEF("7457", CPU_POWERPC_74x7, 7455) /* Code name for PowerPC 7447/7457 */ - POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 7455), + POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 7455) /* PowerPC 7447 v1.0 (G4) */ - POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445), + POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445) /* PowerPC 7457 v1.0 (G4) */ - POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455), + POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455) /* PowerPC 7447 v1.1 (G4) */ - POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445), + POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445) /* PowerPC 7457 v1.1 (G4) */ - POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455), + POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455) /* PowerPC 7457 v1.2 (G4) */ - POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455), + POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455) /* PowerPC 7447A (G4) */ - POWERPC_DEF("7447A", CPU_POWERPC_74x7A, 7445), + POWERPC_DEF("7447A", CPU_POWERPC_74x7A, 7445) /* PowerPC 7457A (G4) */ - POWERPC_DEF("7457A", CPU_POWERPC_74x7A, 7455), + POWERPC_DEF("7457A", CPU_POWERPC_74x7A, 7455) /* PowerPC 7447A v1.0 (G4) */ - POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445), + POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445) /* PowerPC 7457A v1.0 (G4) */ - POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455), + POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455) /* Code name for PowerPC 7447A/7457A */ - POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7A_v10, 7455), + POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7A_v10, 7455) /* PowerPC 7447A v1.1 (G4) */ - POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445), + POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445) /* PowerPC 7457A v1.1 (G4) */ - POWERPC_DEF("7457A_v1.1", CPU_POWERPC_74x7A_v11, 7455), + POWERPC_DEF("7457A_v1.1", CPU_POWERPC_74x7A_v11, 7455) /* PowerPC 7447A v1.2 (G4) */ - POWERPC_DEF("7447A_v1.2", CPU_POWERPC_74x7A_v12, 7445), + POWERPC_DEF("7447A_v1.2", CPU_POWERPC_74x7A_v12, 7445) /* PowerPC 7457A v1.2 (G4) */ - POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455), + POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455) /* 64 bits PowerPC */ #if defined (TARGET_PPC64) /* PowerPC 620 */ - POWERPC_DEF("620", CPU_POWERPC_620, 620), + POWERPC_DEF("620", CPU_POWERPC_620, 620) /* Code name for PowerPC 620 */ - POWERPC_DEF("Trident", CPU_POWERPC_620, 620), + POWERPC_DEF("Trident", CPU_POWERPC_620, 620) #if defined (TODO) /* PowerPC 630 (POWER3) */ - POWERPC_DEF("630", CPU_POWERPC_630, 630), - POWERPC_DEF("POWER3", CPU_POWERPC_630, 630), + POWERPC_DEF("630", CPU_POWERPC_630, 630) + POWERPC_DEF("POWER3", CPU_POWERPC_630, 630) /* Code names for POWER3 */ - POWERPC_DEF("Boxer", CPU_POWERPC_630, 630), - POWERPC_DEF("Dino", CPU_POWERPC_630, 630), + POWERPC_DEF("Boxer", CPU_POWERPC_630, 630) + POWERPC_DEF("Dino", CPU_POWERPC_630, 630) #endif #if defined (TODO) /* PowerPC 631 (Power 3+) */ - POWERPC_DEF("631", CPU_POWERPC_631, 631), - POWERPC_DEF("POWER3+", CPU_POWERPC_631, 631), + POWERPC_DEF("631", CPU_POWERPC_631, 631) + POWERPC_DEF("POWER3+", CPU_POWERPC_631, 631) #endif #if defined (TODO) /* POWER4 */ - POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4), + POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4) #endif #if defined (TODO) /* POWER4p */ - POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P), + POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P) #endif #if defined (TODO) /* POWER5 */ - POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5), + POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5) /* POWER5GR */ - POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5), + POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5) #endif #if defined (TODO) /* POWER5+ */ - POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P), + POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P) /* POWER5GS */ - POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P), + POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P) #endif #if defined (TODO) /* POWER6 */ - POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6), + POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6) /* POWER6 running in POWER5 mode */ - POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5), + POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5) /* POWER6A */ - POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6), + POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6) #endif /* POWER7 */ - POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7), - POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7), - POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7), - POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7), + POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7) + POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7) + POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7) + POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7) /* PowerPC 970 */ - POWERPC_DEF("970", CPU_POWERPC_970, 970), + POWERPC_DEF("970", CPU_POWERPC_970, 970) /* PowerPC 970FX (G5) */ - POWERPC_DEF("970fx", CPU_POWERPC_970FX, 970FX), + POWERPC_DEF("970fx", CPU_POWERPC_970FX, 970FX) /* PowerPC 970FX v1.0 (G5) */ - POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX), + POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX) /* PowerPC 970FX v2.0 (G5) */ - POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX), + POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX) /* PowerPC 970FX v2.1 (G5) */ - POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX), + POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX) /* PowerPC 970FX v3.0 (G5) */ - POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX), + POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX) /* PowerPC 970FX v3.1 (G5) */ - POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX), + POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX) /* PowerPC 970GX (G5) */ - POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX), + POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX) /* PowerPC 970MP */ - POWERPC_DEF("970mp", CPU_POWERPC_970MP, 970MP), + POWERPC_DEF("970mp", CPU_POWERPC_970MP, 970MP) /* PowerPC 970MP v1.0 */ - POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP), + POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP) /* PowerPC 970MP v1.1 */ - POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP), + POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP) #if defined (TODO) /* PowerPC Cell */ - POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970), + POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970) #endif #if defined (TODO) /* PowerPC Cell v1.0 */ - POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970), + POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970) #endif #if defined (TODO) /* PowerPC Cell v2.0 */ - POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970), + POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970) #endif #if defined (TODO) /* PowerPC Cell v3.0 */ - POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970), + POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970) #endif #if defined (TODO) /* PowerPC Cell v3.1 */ - POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970), + POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970) #endif #if defined (TODO) /* PowerPC Cell v3.2 */ - POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970), + POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970) #endif #if defined (TODO) /* RS64 (Apache/A35) */ @@ -9344,57 +9344,57 @@ static const ppc_def_t ppc_defs[] = { * and the PowerPC 64 one. */ /* What about A10 & A30 ? */ - POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64), - POWERPC_DEF("Apache", CPU_POWERPC_RS64, RS64), - POWERPC_DEF("A35", CPU_POWERPC_RS64, RS64), + POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64) + POWERPC_DEF("Apache", CPU_POWERPC_RS64, RS64) + POWERPC_DEF("A35", CPU_POWERPC_RS64, RS64) #endif #if defined (TODO) /* RS64-II (NorthStar/A50) */ - POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64), - POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, RS64), - POWERPC_DEF("A50", CPU_POWERPC_RS64II, RS64), + POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64) + POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, RS64) + POWERPC_DEF("A50", CPU_POWERPC_RS64II, RS64) #endif #if defined (TODO) /* RS64-III (Pulsar) */ - POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64), - POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, RS64), + POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64) + POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, RS64) #endif #if defined (TODO) /* RS64-IV (IceStar/IStar/SStar) */ - POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64), - POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, RS64), - POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, RS64), - POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, RS64), + POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64) + POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, RS64) + POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, RS64) + POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, RS64) #endif #endif /* defined (TARGET_PPC64) */ /* POWER */ #if defined (TODO) /* Original POWER */ - POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RIOS", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RSC", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, POWER), - POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, POWER), + POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER) + POWERPC_DEF("RIOS", CPU_POWERPC_POWER, POWER) + POWERPC_DEF("RSC", CPU_POWERPC_POWER, POWER) + POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, POWER) + POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, POWER) #endif #if defined (TODO) /* POWER2 */ - POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER), - POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, POWER), - POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, POWER), + POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER) + POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, POWER) + POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, POWER) #endif /* PA semi cores */ #if defined (TODO) /* PA PA6T */ - POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T), + POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T) #endif /* Generic PowerPCs */ #if defined (TARGET_PPC64) - POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, PPC64), + POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, PPC64) #endif - POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32), - POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, DEFAULT), + POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32) + POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, DEFAULT) /* Fallback */ - POWERPC_DEF("default", CPU_POWERPC_DEFAULT, DEFAULT), + POWERPC_DEF("default", CPU_POWERPC_DEFAULT, DEFAULT) }; /*****************************************************************************/ From fd5ed418c7703bb7403f89f1474b0fe633f989cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:04 +0000 Subject: [PATCH 1418/1634] target-ppc: Extract aliases from definitions list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move definitions that were 100% identical except for the name into a list of aliases so that we don't register duplicate CPU types. Drop the accompanying comments since they don't really add value. We need to support recursive lookup due to code names referencing a generic name referencing a specific model revision. List aliases separately for -cpu ?. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 145 ++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 73 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3f75bef971..862f40ae23 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8082,10 +8082,6 @@ static const ppc_def_t ppc_defs[] = { #if defined(TODO_USER_ONLY) /* Generic MPC5xx core */ POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* Codename for MPC5xx core */ - POWERPC_DEF("RCPU", CPU_POWERPC_MPC5xx, MPC5xx) #endif /* MPC5xx microcontrollers */ #if defined(TODO_USER_ONLY) @@ -8144,10 +8140,6 @@ static const ppc_def_t ppc_defs[] = { #if defined(TODO_USER_ONLY) /* Generic MPC8xx core */ POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* Codename for MPC8xx core */ - POWERPC_DEF("PowerQUICC", CPU_POWERPC_MPC8xx, MPC8xx) #endif /* MPC8xx microcontrollers */ #if defined(TODO_USER_ONLY) @@ -8216,8 +8208,6 @@ static const ppc_def_t ppc_defs[] = { CPU_POWERPC_MPC52xx, POWERPC_SVR_52xx, G2LE) /* Generic MPC82xx core */ POWERPC_DEF("MPC82xx", CPU_POWERPC_MPC82xx, G2) - /* Codename for MPC82xx */ - POWERPC_DEF("PowerQUICC-II", CPU_POWERPC_MPC82xx, G2) /* PowerPC G2 core */ POWERPC_DEF("G2", CPU_POWERPC_G2, G2) /* PowerPC G2 H4 core */ @@ -8612,8 +8602,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF_SVR("MPC8379E", CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300) /* e500 family */ - /* PowerPC e500 core */ - POWERPC_DEF("e500", CPU_POWERPC_e500v2_v22, e500v2) /* PowerPC e500v1 core */ POWERPC_DEF("e500v1", CPU_POWERPC_e500v1, e500v1) /* PowerPC e500 v1.0 core */ @@ -8868,12 +8856,8 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("602", CPU_POWERPC_602, 602) /* PowerPC 603 */ POWERPC_DEF("603", CPU_POWERPC_603, 603) - /* Code name for PowerPC 603 */ - POWERPC_DEF("Vanilla", CPU_POWERPC_603, 603) /* PowerPC 603e (aka PID6) */ POWERPC_DEF("603e", CPU_POWERPC_603E, 603E) - /* Code name for PowerPC 603e */ - POWERPC_DEF("Stretch", CPU_POWERPC_603E, 603E) /* PowerPC 603e v1.1 */ POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E) /* PowerPC 603e v1.2 */ @@ -8896,8 +8880,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E) /* PowerPC 603e7v */ POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E) - /* Code name for PowerPC 603ev */ - POWERPC_DEF("Vaillant", CPU_POWERPC_603E7v, 603E) /* PowerPC 603e7v1 */ POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E) /* PowerPC 603e7v2 */ @@ -8906,14 +8888,10 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("603p", CPU_POWERPC_603P, 603E) /* PowerPC 603r (aka PID7t) */ POWERPC_DEF("603r", CPU_POWERPC_603R, 603E) - /* Code name for PowerPC 603r */ - POWERPC_DEF("Goldeneye", CPU_POWERPC_603R, 603E) /* PowerPC 604 */ POWERPC_DEF("604", CPU_POWERPC_604, 604) /* PowerPC 604e (aka PID9) */ POWERPC_DEF("604e", CPU_POWERPC_604E, 604E) - /* Code name for PowerPC 604e */ - POWERPC_DEF("Sirocco", CPU_POWERPC_604E, 604E) /* PowerPC 604e v1.0 */ POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E) /* PowerPC 604e v2.2 */ @@ -8922,8 +8900,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E) /* PowerPC 604r (aka PIDA) */ POWERPC_DEF("604r", CPU_POWERPC_604R, 604E) - /* Code name for PowerPC 604r */ - POWERPC_DEF("Mach5", CPU_POWERPC_604R, 604E) #if defined(TODO) /* PowerPC 604ev */ POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E) @@ -8931,14 +8907,8 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 7xx family */ /* Generic PowerPC 740 (G3) */ POWERPC_DEF("740", CPU_POWERPC_7x0, 740) - /* Code name for PowerPC 740 */ - POWERPC_DEF("Arthur", CPU_POWERPC_7x0, 740) /* Generic PowerPC 750 (G3) */ POWERPC_DEF("750", CPU_POWERPC_7x0, 750) - /* Code name for PowerPC 750 */ - POWERPC_DEF("Typhoon", CPU_POWERPC_7x0, 750) - /* PowerPC 740/750 is also known as G3 */ - POWERPC_DEF("G3", CPU_POWERPC_7x0, 750) /* PowerPC 740 v1.0 (G3) */ POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740) /* PowerPC 750 v1.0 (G3) */ @@ -8971,8 +8941,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740) /* PowerPC 750P (G3) */ POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750) - /* Code name for PowerPC 740P/750P (G3) */ - POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P, 750) /* PowerPC 750CL (G3 embedded) */ POWERPC_DEF("750cl", CPU_POWERPC_750CL, 750cl) /* PowerPC 750CL v1.0 */ @@ -9035,8 +9003,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx) /* PowerPC 750L (G3 embedded) */ POWERPC_DEF("750l", CPU_POWERPC_750L, 750) - /* Code name for PowerPC 750L (G3 embedded) */ - POWERPC_DEF("LoneStar", CPU_POWERPC_750L, 750) /* PowerPC 750L v2.0 (G3 embedded) */ POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750) /* PowerPC 750L v2.1 (G3 embedded) */ @@ -9051,8 +9017,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("745", CPU_POWERPC_7x5, 745) /* Generic PowerPC 755 */ POWERPC_DEF("755", CPU_POWERPC_7x5, 755) - /* Code name for PowerPC 745/755 */ - POWERPC_DEF("Goldfinger", CPU_POWERPC_7x5, 755) /* PowerPC 745 v1.0 */ POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745) /* PowerPC 755 v1.0 */ @@ -9106,10 +9070,6 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 74xx family */ /* PowerPC 7400 (G4) */ POWERPC_DEF("7400", CPU_POWERPC_7400, 7400) - /* Code name for PowerPC 7400 */ - POWERPC_DEF("Max", CPU_POWERPC_7400, 7400) - /* PowerPC 74xx is also well known as G4 */ - POWERPC_DEF("G4", CPU_POWERPC_7400, 7400) /* PowerPC 7400 v1.0 (G4) */ POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400) /* PowerPC 7400 v1.1 (G4) */ @@ -9130,8 +9090,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400) /* PowerPC 7410 (G4) */ POWERPC_DEF("7410", CPU_POWERPC_7410, 7410) - /* Code name for PowerPC 7410 */ - POWERPC_DEF("Nitro", CPU_POWERPC_7410, 7410) /* PowerPC 7410 v1.0 (G4) */ POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410) /* PowerPC 7410 v1.1 (G4) */ @@ -9154,8 +9112,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400) /* PowerPC 7450 (G4) */ POWERPC_DEF("7450", CPU_POWERPC_7450, 7450) - /* Code name for PowerPC 7450 */ - POWERPC_DEF("Vger", CPU_POWERPC_7450, 7450) /* PowerPC 7450 v1.0 (G4) */ POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450) /* PowerPC 7450 v1.1 (G4) */ @@ -9184,8 +9140,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445) /* PowerPC 7455 (G4) */ POWERPC_DEF("7455", CPU_POWERPC_74x5, 7455) - /* Code name for PowerPC 7445/7455 */ - POWERPC_DEF("Apollo6", CPU_POWERPC_74x5, 7455) /* PowerPC 7445 v1.0 (G4) */ POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445) /* PowerPC 7455 v1.0 (G4) */ @@ -9210,8 +9164,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7447", CPU_POWERPC_74x7, 7445) /* PowerPC 7457 (G4) */ POWERPC_DEF("7457", CPU_POWERPC_74x7, 7455) - /* Code name for PowerPC 7447/7457 */ - POWERPC_DEF("Apollo7", CPU_POWERPC_74x7, 7455) /* PowerPC 7447 v1.0 (G4) */ POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445) /* PowerPC 7457 v1.0 (G4) */ @@ -9230,8 +9182,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445) /* PowerPC 7457A v1.0 (G4) */ POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455) - /* Code name for PowerPC 7447A/7457A */ - POWERPC_DEF("Apollo7PM", CPU_POWERPC_74x7A_v10, 7455) /* PowerPC 7447A v1.1 (G4) */ POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445) /* PowerPC 7457A v1.1 (G4) */ @@ -9244,20 +9194,13 @@ static const ppc_def_t ppc_defs[] = { #if defined (TARGET_PPC64) /* PowerPC 620 */ POWERPC_DEF("620", CPU_POWERPC_620, 620) - /* Code name for PowerPC 620 */ - POWERPC_DEF("Trident", CPU_POWERPC_620, 620) #if defined (TODO) /* PowerPC 630 (POWER3) */ POWERPC_DEF("630", CPU_POWERPC_630, 630) - POWERPC_DEF("POWER3", CPU_POWERPC_630, 630) - /* Code names for POWER3 */ - POWERPC_DEF("Boxer", CPU_POWERPC_630, 630) - POWERPC_DEF("Dino", CPU_POWERPC_630, 630) #endif #if defined (TODO) /* PowerPC 631 (Power 3+) */ POWERPC_DEF("631", CPU_POWERPC_631, 631) - POWERPC_DEF("POWER3+", CPU_POWERPC_631, 631) #endif #if defined (TODO) /* POWER4 */ @@ -9345,42 +9288,28 @@ static const ppc_def_t ppc_defs[] = { */ /* What about A10 & A30 ? */ POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64) - POWERPC_DEF("Apache", CPU_POWERPC_RS64, RS64) - POWERPC_DEF("A35", CPU_POWERPC_RS64, RS64) #endif #if defined (TODO) /* RS64-II (NorthStar/A50) */ POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64) - POWERPC_DEF("NorthStar", CPU_POWERPC_RS64II, RS64) - POWERPC_DEF("A50", CPU_POWERPC_RS64II, RS64) #endif #if defined (TODO) /* RS64-III (Pulsar) */ POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64) - POWERPC_DEF("Pulsar", CPU_POWERPC_RS64III, RS64) #endif #if defined (TODO) /* RS64-IV (IceStar/IStar/SStar) */ POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64) - POWERPC_DEF("IceStar", CPU_POWERPC_RS64IV, RS64) - POWERPC_DEF("IStar", CPU_POWERPC_RS64IV, RS64) - POWERPC_DEF("SStar", CPU_POWERPC_RS64IV, RS64) #endif #endif /* defined (TARGET_PPC64) */ /* POWER */ #if defined (TODO) /* Original POWER */ POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER) - POWERPC_DEF("RIOS", CPU_POWERPC_POWER, POWER) - POWERPC_DEF("RSC", CPU_POWERPC_POWER, POWER) - POWERPC_DEF("RSC3308", CPU_POWERPC_POWER, POWER) - POWERPC_DEF("RSC4608", CPU_POWERPC_POWER, POWER) #endif #if defined (TODO) /* POWER2 */ POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER) - POWERPC_DEF("RSC2", CPU_POWERPC_POWER2, POWER) - POWERPC_DEF("P2SC", CPU_POWERPC_POWER2, POWER) #endif /* PA semi cores */ #if defined (TODO) @@ -9393,8 +9322,60 @@ static const ppc_def_t ppc_defs[] = { #endif POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32) POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, DEFAULT) - /* Fallback */ - POWERPC_DEF("default", CPU_POWERPC_DEFAULT, DEFAULT) +}; + +typedef struct PowerPCCPUAlias { + const char *alias; + const char *model; +} PowerPCCPUAlias; + +static const PowerPCCPUAlias ppc_cpu_aliases[] = { + { "RCPU", "MPC5xx" }, + { "PowerQUICC", "MPC8xx" }, + { "PowerQUICC-II", "MPC82xx" }, + { "e500", "e500v2_v22" }, + { "Vanilla", "603" }, + { "Stretch", "603e" }, + { "Vaillant", "603e7v" }, + { "Goldeneye", "603r" }, + { "Sirocco", "604e" }, + { "Mach5", "604r" }, + { "Arthur", "740" }, + { "Typhoon", "750" }, + { "G3", "750" }, + { "Conan/Doyle", "750p" }, + { "LoneStar", "750l" }, + { "Goldfinger", "755" }, + { "Max", "7400" }, + { "G4", "7400" }, + { "Nitro", "7410" }, + { "Vger", "7450" }, + { "Apollo6", "7455" }, + { "Apollo7", "7457" }, + { "Apollo7PM", "7457A_v1.0" }, +#if defined(TARGET_PPC64) + { "Trident", "620" }, + { "POWER3", "630" }, + { "Boxer", "POWER3" }, + { "Dino", "POWER3" }, + { "POWER3+", "631" }, + { "Apache", "RS64" }, + { "A35", "RS64" }, + { "NorthStar", "RS64-II" }, + { "A50", "RS64-II" }, + { "Pulsar", "RS64-III" }, + { "IceStar", "RS64-IV" }, + { "IStar", "RS64-IV" }, + { "SStar", "RS64-IV" }, +#endif + { "RIOS", "POWER" }, + { "RSC", "POWER" }, + { "RSC3308", "POWER" }, + { "RSC4608", "POWER" }, + { "RSC2", "POWER2" }, + { "P2SC", "POWER2" }, + + { "default", "ppc" }, }; /*****************************************************************************/ @@ -10323,6 +10304,12 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) } } + for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { + if (strcmp(ppc_cpu_aliases[i].alias, name) == 0) { + return ppc_cpu_class_by_name(ppc_cpu_aliases[i].model); + } + } + list = object_class_get_list(TYPE_POWERPC_CPU, false); item = g_slist_find_custom(list, name, ppc_cpu_compare_class_name); if (item != NULL) { @@ -10403,11 +10390,23 @@ void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) .cpu_fprintf = cpu_fprintf, }; GSList *list; + int i; list = object_class_get_list(TYPE_POWERPC_CPU, false); list = g_slist_sort(list, ppc_cpu_list_compare); g_slist_foreach(list, ppc_cpu_list_entry, &s); g_slist_free(list); + + cpu_fprintf(f, "\n"); + for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { + ObjectClass *oc = ppc_cpu_class_by_name(ppc_cpu_aliases[i].model); + if (oc == NULL) { + /* Hide aliases that point to a TODO or TODO_USER_ONLY model */ + continue; + } + cpu_fprintf(f, "PowerPC %-16s\n", + ppc_cpu_aliases[i].alias); + } } static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) From f7851859d2af38bbdf953269a7e2a9b4681b4253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:05 +0000 Subject: [PATCH 1419/1634] target-ppc: Make -cpu "ppc" an alias to "ppc32" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the #if 0'ed alternative to make it "ppc64" for TARGET_PPC64. If we ever want to change it, we can more easily do so now. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 862f40ae23..892310580d 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6824,33 +6824,6 @@ static void init_proc_620 (CPUPPCState *env) #define check_pow_PPC64 check_pow_970FX #define init_proc_PPC64 init_proc_970FX -/* Default PowerPC target will be PowerPC 32 */ -#if defined (TARGET_PPC64) && 0 // XXX: TODO -#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC64 -#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64 -#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS2_PPC64 -#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC64 -#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC64 -#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC64 -#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64 -#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC64 -#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC64 -#define check_pow_DEFAULT check_pow_PPC64 -#define init_proc_DEFAULT init_proc_PPC64 -#else -#define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32 -#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32 -#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS2_PPC32 -#define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC32 -#define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC32 -#define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC32 -#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32 -#define POWERPC_BFDM_DEFAULT POWERPC_BFDM_PPC32 -#define POWERPC_FLAG_DEFAULT POWERPC_FLAG_PPC32 -#define check_pow_DEFAULT check_pow_PPC32 -#define init_proc_DEFAULT init_proc_PPC32 -#endif - /*****************************************************************************/ /* PVR definitions for most known PowerPC */ enum { @@ -9321,7 +9294,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, PPC64) #endif POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32) - POWERPC_DEF("ppc", CPU_POWERPC_DEFAULT, DEFAULT) }; typedef struct PowerPCCPUAlias { @@ -9375,6 +9347,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "RSC2", "POWER2" }, { "P2SC", "POWER2" }, + { "ppc", "ppc32" }, { "default", "ppc" }, }; From e0b9a74e53c012953c54f4bd5a09e20cf1cc48a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:06 +0000 Subject: [PATCH 1420/1634] target-ppc: Extract MPC5xx aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Their PVR differed but was defined to MPC5xx. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 81 +++++++------------------------------ 1 file changed, 15 insertions(+), 66 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 892310580d..6a5f7e8475 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7057,19 +7057,6 @@ enum { /* Freescale embedded PowerPC cores */ /* PowerPC MPC 5xx cores (aka RCPU) */ CPU_POWERPC_MPC5xx = 0x00020020, -#define CPU_POWERPC_MGT560 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC509 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC533 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC534 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC555 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC556 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC560 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC561 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC562 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC563 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC564 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC565 CPU_POWERPC_MPC5xx -#define CPU_POWERPC_MPC566 CPU_POWERPC_MPC5xx /* PowerPC MPC 8xx cores (aka PowerQUICC) */ CPU_POWERPC_MPC8xx = 0x00500000, #define CPU_POWERPC_MGT823 CPU_POWERPC_MPC8xx @@ -8055,59 +8042,6 @@ static const ppc_def_t ppc_defs[] = { #if defined(TODO_USER_ONLY) /* Generic MPC5xx core */ POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx) -#endif - /* MPC5xx microcontrollers */ -#if defined(TODO_USER_ONLY) - /* MGT560 */ - POWERPC_DEF("MGT560", CPU_POWERPC_MGT560, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC509 */ - POWERPC_DEF("MPC509", CPU_POWERPC_MPC509, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC533 */ - POWERPC_DEF("MPC533", CPU_POWERPC_MPC533, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC534 */ - POWERPC_DEF("MPC534", CPU_POWERPC_MPC534, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC555 */ - POWERPC_DEF("MPC555", CPU_POWERPC_MPC555, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC556 */ - POWERPC_DEF("MPC556", CPU_POWERPC_MPC556, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC560 */ - POWERPC_DEF("MPC560", CPU_POWERPC_MPC560, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC561 */ - POWERPC_DEF("MPC561", CPU_POWERPC_MPC561, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC562 */ - POWERPC_DEF("MPC562", CPU_POWERPC_MPC562, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC563 */ - POWERPC_DEF("MPC563", CPU_POWERPC_MPC563, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC564 */ - POWERPC_DEF("MPC564", CPU_POWERPC_MPC564, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC565 */ - POWERPC_DEF("MPC565", CPU_POWERPC_MPC565, MPC5xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC566 */ - POWERPC_DEF("MPC566", CPU_POWERPC_MPC566, MPC5xx) #endif /* MPC8xx family (aka PowerQUICC) */ #if defined(TODO_USER_ONLY) @@ -9303,6 +9237,21 @@ typedef struct PowerPCCPUAlias { static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "RCPU", "MPC5xx" }, + /* MPC5xx microcontrollers */ + { "MGT560", "MPC5xx" }, + { "MPC509", "MPC5xx" }, + { "MPC533", "MPC5xx" }, + { "MPC534", "MPC5xx" }, + { "MPC555", "MPC5xx" }, + { "MPC556", "MPC5xx" }, + { "MPC560", "MPC5xx" }, + { "MPC561", "MPC5xx" }, + { "MPC562", "MPC5xx" }, + { "MPC563", "MPC5xx" }, + { "MPC564", "MPC5xx" }, + { "MPC565", "MPC5xx" }, + { "MPC566", "MPC5xx" }, + { "PowerQUICC", "MPC8xx" }, { "PowerQUICC-II", "MPC82xx" }, { "e500", "e500v2_v22" }, From 20267b6f327ed2d7c54451034d234d67b1b410e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:07 +0000 Subject: [PATCH 1421/1634] target-ppc: Extract MGT823/MPC8xx as aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They used different PVRs but were defined to MPC8xx. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 93 +++++++------------------------------ 1 file changed, 17 insertions(+), 76 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6a5f7e8475..6a86e10408 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7059,21 +7059,6 @@ enum { CPU_POWERPC_MPC5xx = 0x00020020, /* PowerPC MPC 8xx cores (aka PowerQUICC) */ CPU_POWERPC_MPC8xx = 0x00500000, -#define CPU_POWERPC_MGT823 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC821 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC823 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC850 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC852T CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC855T CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC857 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC859 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC860 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC862 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC866 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC870 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC875 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC880 CPU_POWERPC_MPC8xx -#define CPU_POWERPC_MPC885 CPU_POWERPC_MPC8xx /* G2 cores (aka PowerQUICC-II) */ CPU_POWERPC_G2 = 0x00810011, CPU_POWERPC_G2H4 = 0x80811010, @@ -8047,67 +8032,6 @@ static const ppc_def_t ppc_defs[] = { #if defined(TODO_USER_ONLY) /* Generic MPC8xx core */ POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx) -#endif - /* MPC8xx microcontrollers */ -#if defined(TODO_USER_ONLY) - /* MGT823 */ - POWERPC_DEF("MGT823", CPU_POWERPC_MGT823, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC821 */ - POWERPC_DEF("MPC821", CPU_POWERPC_MPC821, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC823 */ - POWERPC_DEF("MPC823", CPU_POWERPC_MPC823, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC850 */ - POWERPC_DEF("MPC850", CPU_POWERPC_MPC850, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC852T */ - POWERPC_DEF("MPC852T", CPU_POWERPC_MPC852T, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC855T */ - POWERPC_DEF("MPC855T", CPU_POWERPC_MPC855T, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC857 */ - POWERPC_DEF("MPC857", CPU_POWERPC_MPC857, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC859 */ - POWERPC_DEF("MPC859", CPU_POWERPC_MPC859, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC860 */ - POWERPC_DEF("MPC860", CPU_POWERPC_MPC860, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC862 */ - POWERPC_DEF("MPC862", CPU_POWERPC_MPC862, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC866 */ - POWERPC_DEF("MPC866", CPU_POWERPC_MPC866, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC870 */ - POWERPC_DEF("MPC870", CPU_POWERPC_MPC870, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC875 */ - POWERPC_DEF("MPC875", CPU_POWERPC_MPC875, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC880 */ - POWERPC_DEF("MPC880", CPU_POWERPC_MPC880, MPC8xx) -#endif -#if defined(TODO_USER_ONLY) - /* MPC885 */ - POWERPC_DEF("MPC885", CPU_POWERPC_MPC885, MPC8xx) #endif /* MPC82xx family (aka PowerQUICC-II) */ /* Generic MPC52xx core */ @@ -9253,6 +9177,23 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC566", "MPC5xx" }, { "PowerQUICC", "MPC8xx" }, + /* MPC8xx microcontrollers */ + { "MGT823", "MPC8xx" }, + { "MPC821", "MPC8xx" }, + { "MPC823", "MPC8xx" }, + { "MPC850", "MPC8xx" }, + { "MPC852T", "MPC8xx" }, + { "MPC855T", "MPC8xx" }, + { "MPC857", "MPC8xx" }, + { "MPC859", "MPC8xx" }, + { "MPC860", "MPC8xx" }, + { "MPC862", "MPC8xx" }, + { "MPC866", "MPC8xx" }, + { "MPC870", "MPC8xx" }, + { "MPC875", "MPC8xx" }, + { "MPC880", "MPC8xx" }, + { "MPC885", "MPC8xx" }, + { "PowerQUICC-II", "MPC82xx" }, { "e500", "e500v2_v22" }, { "Vanilla", "603" }, From 8f43bc789c7ddd1a0f5b3cbc55cf67a1c6ae44e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:08 +0000 Subject: [PATCH 1422/1634] target-ppc: Extract 40x aliases 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 --- target-ppc/translate_init.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6a86e10408..8a3cf9f91c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6852,8 +6852,6 @@ enum { CPU_POWERPC_XIPCHIP = xxx, #endif /* PowerPC 403 family */ - /* Generic PowerPC 403 */ -#define CPU_POWERPC_403 CPU_POWERPC_403GC /* PowerPC 403 microcontrollers */ CPU_POWERPC_403GA = 0x00200011, CPU_POWERPC_403GB = 0x00200100, @@ -6863,8 +6861,6 @@ enum { CPU_POWERPC_403GP = xxx, #endif /* PowerPC 405 family */ - /* Generic PowerPC 405 */ -#define CPU_POWERPC_405 CPU_POWERPC_405D4 /* PowerPC 405 cores */ #if 0 CPU_POWERPC_405A3 = xxx, @@ -6906,7 +6902,6 @@ enum { #endif /* PowerPC 405 microcontrolers */ /* XXX: missing 0x200108a0 */ -#define CPU_POWERPC_405CR CPU_POWERPC_405CRc CPU_POWERPC_405CRa = 0x40110041, CPU_POWERPC_405CRb = 0x401100C5, CPU_POWERPC_405CRc = 0x40110145, @@ -6918,7 +6913,6 @@ enum { #if 0 CPU_POWERPC_405FX = xxx, #endif -#define CPU_POWERPC_405GP CPU_POWERPC_405GPd CPU_POWERPC_405GPa = 0x40110000, CPU_POWERPC_405GPb = 0x40110040, CPU_POWERPC_405GPc = 0x40110082, @@ -6979,9 +6973,7 @@ enum { #endif /* Xilinx cores */ CPU_POWERPC_X2VP4 = 0x20010820, -#define CPU_POWERPC_X2VP7 CPU_POWERPC_X2VP4 CPU_POWERPC_X2VP20 = 0x20010860, -#define CPU_POWERPC_X2VP50 CPU_POWERPC_X2VP20 #if 0 CPU_POWERPC_ZL10310 = xxx, #endif @@ -7701,8 +7693,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401) #endif /* PowerPC 403 family */ - /* Generic PowerPC 403 */ - POWERPC_DEF("403", CPU_POWERPC_403, 403) /* PowerPC 403 microcontrolers */ /* PowerPC 403 GA */ POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403) @@ -7717,8 +7707,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403) #endif /* PowerPC 405 family */ - /* Generic PowerPC 405 */ - POWERPC_DEF("405", CPU_POWERPC_405, 405) /* PowerPC 405 cores */ #if defined (TODO) /* PowerPC 405 A3 */ @@ -7773,8 +7761,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405) #endif /* PowerPC 405 microcontrolers */ - /* PowerPC 405 CR */ - POWERPC_DEF("405CR", CPU_POWERPC_405CR, 405) /* PowerPC 405 CRa */ POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405) /* PowerPC 405 CRb */ @@ -7793,8 +7779,6 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 405 FX */ POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405) #endif - /* PowerPC 405 GP */ - POWERPC_DEF("405GP", CPU_POWERPC_405GP, 405) /* PowerPC 405 GPa */ POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405) /* PowerPC 405 GPb */ @@ -7880,9 +7864,7 @@ static const ppc_def_t ppc_defs[] = { #endif /* Xilinx PowerPC 405 cores */ POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405) - POWERPC_DEF("x2vp7", CPU_POWERPC_X2VP7, 405) POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405) - POWERPC_DEF("x2vp50", CPU_POWERPC_X2VP50, 405) #if defined (TODO) /* Zarlink ZL10310 */ POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405) @@ -9160,6 +9142,13 @@ typedef struct PowerPCCPUAlias { } PowerPCCPUAlias; static const PowerPCCPUAlias ppc_cpu_aliases[] = { + { "403", "403GC" }, + { "405", "405D4" }, + { "405CR", "405CRc" }, + { "405GP", "405GPd" }, + { "x2vp7", "x2vp4" }, + { "x2vp50", "x2vp20" }, + { "RCPU", "MPC5xx" }, /* MPC5xx microcontrollers */ { "MGT560", "MPC5xx" }, From 8c00a9991ae759048c444a6836ce2206e4b0d372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:09 +0000 Subject: [PATCH 1423/1634] target-ppc: Extract 440 aliases 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 --- target-ppc/translate_init.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8a3cf9f91c..fb0a36663e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7013,17 +7013,13 @@ enum { CPU_POWERPC_440H6 = xxx, #endif /* PowerPC 440 microcontrolers */ -#define CPU_POWERPC_440EP CPU_POWERPC_440EPb CPU_POWERPC_440EPa = 0x42221850, CPU_POWERPC_440EPb = 0x422218D3, -#define CPU_POWERPC_440GP CPU_POWERPC_440GPc CPU_POWERPC_440GPb = 0x40120440, CPU_POWERPC_440GPc = 0x40120481, -#define CPU_POWERPC_440GR CPU_POWERPC_440GRa #define CPU_POWERPC_440GRa CPU_POWERPC_440EPb CPU_POWERPC_440GRX = 0x200008D0, #define CPU_POWERPC_440EPX CPU_POWERPC_440GRX -#define CPU_POWERPC_440GX CPU_POWERPC_440GXf CPU_POWERPC_440GXa = 0x51B21850, CPU_POWERPC_440GXb = 0x51B21851, CPU_POWERPC_440GXc = 0x51B21892, @@ -7922,18 +7918,12 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5) #endif /* PowerPC 440 microcontrolers */ - /* PowerPC 440 EP */ - POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP) /* PowerPC 440 EPa */ POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP) /* PowerPC 440 EPb */ POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP) /* PowerPC 440 EPX */ POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP) -#if defined(TODO_USER_ONLY) - /* PowerPC 440 GP */ - POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP) -#endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GPb */ POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP) @@ -7942,10 +7932,6 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 440 GPc */ POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP) #endif -#if defined(TODO_USER_ONLY) - /* PowerPC 440 GR */ - POWERPC_DEF("440GR", CPU_POWERPC_440GR, 440x5) -#endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GRa */ POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5) @@ -7954,10 +7940,6 @@ static const ppc_def_t ppc_defs[] = { /* PowerPC 440 GRX */ POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5) #endif -#if defined(TODO_USER_ONLY) - /* PowerPC 440 GX */ - POWERPC_DEF("440GX", CPU_POWERPC_440GX, 440EP) -#endif #if defined(TODO_USER_ONLY) /* PowerPC 440 GXa */ POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP) @@ -9149,6 +9131,11 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "x2vp7", "x2vp4" }, { "x2vp50", "x2vp20" }, + { "440EP", "440EPb" }, + { "440GP", "440GPc" }, + { "440GR", "440GRa" }, + { "440GX", "440GXf" }, + { "RCPU", "MPC5xx" }, /* MPC5xx microcontrollers */ { "MGT560", "MPC5xx" }, From a7de06e17ecdd3b2cd57c2b6f01913e663365f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:10 +0000 Subject: [PATCH 1424/1634] target-ppc: Turn "ppc32" and "ppc64" CPUs into aliases 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 --- target-ppc/translate_init.c | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index fb0a36663e..86b5c910e8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6798,32 +6798,6 @@ static void init_proc_620 (CPUPPCState *env) } #endif /* defined (TARGET_PPC64) */ -/* Default 32 bits PowerPC target will be 604 */ -#define CPU_POWERPC_PPC32 CPU_POWERPC_604 -#define POWERPC_INSNS_PPC32 POWERPC_INSNS_604 -#define POWERPC_INSNS2_PPC32 POWERPC_INSNS2_604 -#define POWERPC_MSRM_PPC32 POWERPC_MSRM_604 -#define POWERPC_MMU_PPC32 POWERPC_MMU_604 -#define POWERPC_EXCP_PPC32 POWERPC_EXCP_604 -#define POWERPC_INPUT_PPC32 POWERPC_INPUT_604 -#define POWERPC_BFDM_PPC32 POWERPC_BFDM_604 -#define POWERPC_FLAG_PPC32 POWERPC_FLAG_604 -#define check_pow_PPC32 check_pow_604 -#define init_proc_PPC32 init_proc_604 - -/* Default 64 bits PowerPC target will be 970 FX */ -#define CPU_POWERPC_PPC64 CPU_POWERPC_970FX -#define POWERPC_INSNS_PPC64 POWERPC_INSNS_970FX -#define POWERPC_INSNS2_PPC64 POWERPC_INSNS2_970FX -#define POWERPC_MSRM_PPC64 POWERPC_MSRM_970FX -#define POWERPC_MMU_PPC64 POWERPC_MMU_970FX -#define POWERPC_EXCP_PPC64 POWERPC_EXCP_970FX -#define POWERPC_INPUT_PPC64 POWERPC_INPUT_970FX -#define POWERPC_BFDM_PPC64 POWERPC_BFDM_970FX -#define POWERPC_FLAG_PPC64 POWERPC_FLAG_970FX -#define check_pow_PPC64 check_pow_970FX -#define init_proc_PPC64 init_proc_970FX - /*****************************************************************************/ /* PVR definitions for most known PowerPC */ enum { @@ -9111,11 +9085,6 @@ static const ppc_def_t ppc_defs[] = { /* PA PA6T */ POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T) #endif - /* Generic PowerPCs */ -#if defined (TARGET_PPC64) - POWERPC_DEF("ppc64", CPU_POWERPC_PPC64, PPC64) -#endif - POWERPC_DEF("ppc32", CPU_POWERPC_PPC32, PPC32) }; typedef struct PowerPCCPUAlias { @@ -9213,6 +9182,11 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "RSC2", "POWER2" }, { "P2SC", "POWER2" }, + /* Generic PowerPCs */ +#if defined(TARGET_PPC64) + { "ppc64", "970fx" }, +#endif + { "ppc32", "604" }, { "ppc", "ppc32" }, { "default", "ppc" }, }; From 4c739207ddaa2d4da96f887b802536117a49e6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:11 +0000 Subject: [PATCH 1425/1634] target-ppc: Extract 74x7[A] aliases 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 --- target-ppc/translate_init.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 86b5c910e8..27e625e2b1 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7368,11 +7368,9 @@ enum { CPU_POWERPC_74x5_v32 = 0x80010302, CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ -#define CPU_POWERPC_74x7 CPU_POWERPC_74x7_v12 CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ CPU_POWERPC_74x7_v11 = 0x80020101, /* aka B: 1.1 */ CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ -#define CPU_POWERPC_74x7A CPU_POWERPC_74x7A_v12 CPU_POWERPC_74x7A_v10 = 0x80030100, /* aka A: 1.0 */ CPU_POWERPC_74x7A_v11 = 0x80030101, /* aka B: 1.1 */ CPU_POWERPC_74x7A_v12 = 0x80030102, /* aka C: 1.2 */ @@ -8929,10 +8927,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445) /* PowerPC 7455 v3.4 (G4) */ POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455) - /* PowerPC 7447 (G4) */ - POWERPC_DEF("7447", CPU_POWERPC_74x7, 7445) - /* PowerPC 7457 (G4) */ - POWERPC_DEF("7457", CPU_POWERPC_74x7, 7455) /* PowerPC 7447 v1.0 (G4) */ POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445) /* PowerPC 7457 v1.0 (G4) */ @@ -8943,10 +8937,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455) /* PowerPC 7457 v1.2 (G4) */ POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455) - /* PowerPC 7447A (G4) */ - POWERPC_DEF("7447A", CPU_POWERPC_74x7A, 7445) - /* PowerPC 7457A (G4) */ - POWERPC_DEF("7457A", CPU_POWERPC_74x7A, 7455) /* PowerPC 7447A v1.0 (G4) */ POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445) /* PowerPC 7457A v1.0 (G4) */ @@ -9158,7 +9148,11 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Nitro", "7410" }, { "Vger", "7450" }, { "Apollo6", "7455" }, + { "7447", "7447_v1.2" }, + { "7457", "7457_v1.2" }, { "Apollo7", "7457" }, + { "7447A", "7447A_v1.2" }, + { "7457A", "7457A_v1.2" }, { "Apollo7PM", "7457A_v1.0" }, #if defined(TARGET_PPC64) { "Trident", "620" }, From d96c8a2344eea5d15556d86f986c4911fb875831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:12 +0000 Subject: [PATCH 1426/1634] target-ppc: Extract 74x5 as aliases 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 --- target-ppc/translate_init.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 27e625e2b1..b7c9781c7a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7361,7 +7361,6 @@ enum { CPU_POWERPC_74x1_v23 = 0x80000203, /* aka G: 2.3 */ /* XXX: this entry might be a bug in some documentation */ CPU_POWERPC_74x1_v210 = 0x80000210, /* aka G: 2.3 ? */ -#define CPU_POWERPC_74x5 CPU_POWERPC_74x5_v32 CPU_POWERPC_74x5_v10 = 0x80010100, /* XXX: missing 0x80010200 */ CPU_POWERPC_74x5_v21 = 0x80010201, /* aka C: 2.1 */ @@ -8903,10 +8902,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440) /* PowerPC 7451 v2.10 (G4) */ POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450) - /* PowerPC 7445 (G4) */ - POWERPC_DEF("7445", CPU_POWERPC_74x5, 7445) - /* PowerPC 7455 (G4) */ - POWERPC_DEF("7455", CPU_POWERPC_74x5, 7455) /* PowerPC 7445 v1.0 (G4) */ POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445) /* PowerPC 7455 v1.0 (G4) */ @@ -9147,6 +9142,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "G4", "7400" }, { "Nitro", "7410" }, { "Vger", "7450" }, + { "7445", "7445_v3.2" }, + { "7455", "7455_v3.2" }, { "Apollo6", "7455" }, { "7447", "7447_v1.2" }, { "7457", "7457_v1.2" }, From 078840e1bc1e21964fbf91548a9430a1a61195de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:13 +0000 Subject: [PATCH 1427/1634] target-ppc: Extract 74x1 aliases 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 --- target-ppc/translate_init.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b7c9781c7a..bd3076cc0e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7357,7 +7357,6 @@ enum { CPU_POWERPC_7450_v12 = 0x80000102, CPU_POWERPC_7450_v20 = 0x80000200, /* aka A, B, C, D: 2.04 */ CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ -#define CPU_POWERPC_74x1 CPU_POWERPC_74x1_v23 CPU_POWERPC_74x1_v23 = 0x80000203, /* aka G: 2.3 */ /* XXX: this entry might be a bug in some documentation */ CPU_POWERPC_74x1_v210 = 0x80000210, /* aka G: 2.3 ? */ @@ -8888,10 +8887,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450) /* PowerPC 7450 v2.1 (G4) */ POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450) - /* PowerPC 7441 (G4) */ - POWERPC_DEF("7441", CPU_POWERPC_74x1, 7440) - /* PowerPC 7451 (G4) */ - POWERPC_DEF("7451", CPU_POWERPC_74x1, 7450) /* PowerPC 7441 v2.1 (G4) */ POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440) /* PowerPC 7441 v2.3 (G4) */ @@ -9142,6 +9137,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "G4", "7400" }, { "Nitro", "7410" }, { "Vger", "7450" }, + { "7441", "7441_v2.3" }, + { "7451", "7451_v2.3" }, { "7445", "7445_v3.2" }, { "7455", "7455_v3.2" }, { "Apollo6", "7455" }, From e9a7cf3bb386ce4b425e4dd154fa660e59939ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:14 +0000 Subject: [PATCH 1428/1634] target-ppc: Extract 7450 alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index bd3076cc0e..7bc401ba90 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7351,7 +7351,6 @@ enum { CPU_POWERPC_7448_v11 = 0x80040101, CPU_POWERPC_7448_v20 = 0x80040200, CPU_POWERPC_7448_v21 = 0x80040201, -#define CPU_POWERPC_7450 CPU_POWERPC_7450_v21 CPU_POWERPC_7450_v10 = 0x80000100, CPU_POWERPC_7450_v11 = 0x80000101, CPU_POWERPC_7450_v12 = 0x80000102, @@ -8875,8 +8874,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400) /* PowerPC 7448 v2.1 (G4) */ POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400) - /* PowerPC 7450 (G4) */ - POWERPC_DEF("7450", CPU_POWERPC_7450, 7450) /* PowerPC 7450 v1.0 (G4) */ POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450) /* PowerPC 7450 v1.1 (G4) */ @@ -9136,6 +9133,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Max", "7400" }, { "G4", "7400" }, { "Nitro", "7410" }, + { "7450", "7450_v2.1" }, { "Vger", "7450" }, { "7441", "7441_v2.3" }, { "7451", "7451_v2.3" }, From df502ce84527fc55544c66c2bd9a920480036cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:15 +0000 Subject: [PATCH 1429/1634] target-ppc: Extract 7448 alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7bc401ba90..4a4444f8c8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7346,7 +7346,6 @@ enum { CPU_POWERPC_7410_v12 = 0x800C1102, /* aka C */ CPU_POWERPC_7410_v13 = 0x800C1103, /* aka D */ CPU_POWERPC_7410_v14 = 0x800C1104, /* aka E */ -#define CPU_POWERPC_7448 CPU_POWERPC_7448_v21 CPU_POWERPC_7448_v10 = 0x80040100, CPU_POWERPC_7448_v11 = 0x80040101, CPU_POWERPC_7448_v20 = 0x80040200, @@ -8864,8 +8863,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410) /* PowerPC 7410 v1.4 (G4) */ POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410) - /* PowerPC 7448 (G4) */ - POWERPC_DEF("7448", CPU_POWERPC_7448, 7400) /* PowerPC 7448 v1.0 (G4) */ POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400) /* PowerPC 7448 v1.1 (G4) */ @@ -9133,6 +9130,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Max", "7400" }, { "G4", "7400" }, { "Nitro", "7410" }, + { "7448", "7448_v2.1" }, { "7450", "7450_v2.1" }, { "Vger", "7450" }, { "7441", "7441_v2.3" }, From 08546b912cc5f2940ef9e6d2d83abb43d295bbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:16 +0000 Subject: [PATCH 1430/1634] target-ppc: Extract 7410 alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4a4444f8c8..3fd8fd76f0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7340,7 +7340,6 @@ enum { CPU_POWERPC_7400_v27 = 0x000C0207, CPU_POWERPC_7400_v28 = 0x000C0208, CPU_POWERPC_7400_v29 = 0x000C0209, -#define CPU_POWERPC_7410 CPU_POWERPC_7410_v14 CPU_POWERPC_7410_v10 = 0x800C1100, CPU_POWERPC_7410_v11 = 0x800C1101, CPU_POWERPC_7410_v12 = 0x800C1102, /* aka C */ @@ -8851,8 +8850,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400) /* PowerPC 7400 v2.9 (G4) */ POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400) - /* PowerPC 7410 (G4) */ - POWERPC_DEF("7410", CPU_POWERPC_7410, 7410) /* PowerPC 7410 v1.0 (G4) */ POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410) /* PowerPC 7410 v1.1 (G4) */ @@ -9129,6 +9126,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Goldfinger", "755" }, { "Max", "7400" }, { "G4", "7400" }, + { "7410", "7410_v1.4" }, { "Nitro", "7410" }, { "7448", "7448_v2.1" }, { "7450", "7450_v2.1" }, From 06704e9ceb85916537c8398735aa18e24ebdad86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:17 +0000 Subject: [PATCH 1431/1634] target-ppc: Extract 7400 alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3fd8fd76f0..a97dfb73c5 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7330,7 +7330,6 @@ enum { #endif /* PowerPC 74xx cores (aka G4) */ /* XXX: missing 0x000C1101 */ -#define CPU_POWERPC_7400 CPU_POWERPC_7400_v29 CPU_POWERPC_7400_v10 = 0x000C0100, CPU_POWERPC_7400_v11 = 0x000C0101, CPU_POWERPC_7400_v20 = 0x000C0200, @@ -8830,8 +8829,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755) #endif /* PowerPC 74xx family */ - /* PowerPC 7400 (G4) */ - POWERPC_DEF("7400", CPU_POWERPC_7400, 7400) /* PowerPC 7400 v1.0 (G4) */ POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400) /* PowerPC 7400 v1.1 (G4) */ @@ -9124,6 +9121,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Conan/Doyle", "750p" }, { "LoneStar", "750l" }, { "Goldfinger", "755" }, + { "7400", "7400_v2.9" }, { "Max", "7400" }, { "G4", "7400" }, { "7410", "7410_v1.4" }, From 80c7abd3171c2939020f01d5310c3bd066ccad19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:18 +0000 Subject: [PATCH 1432/1634] target-ppc: Extract 7x5 aliases 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 --- target-ppc/translate_init.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index a97dfb73c5..5981d98d9b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7313,7 +7313,6 @@ enum { CPU_POWERPC_750L_v30 = 0x00088300, CPU_POWERPC_750L_v32 = 0x00088302, /* PowerPC 745/755 cores */ -#define CPU_POWERPC_7x5 CPU_POWERPC_7x5_v28 CPU_POWERPC_7x5_v10 = 0x00083100, CPU_POWERPC_7x5_v11 = 0x00083101, CPU_POWERPC_7x5_v20 = 0x00083200, @@ -8774,10 +8773,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750) /* PowerPC 750L v3.2 (G3 embedded) */ POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750) - /* Generic PowerPC 745 */ - POWERPC_DEF("745", CPU_POWERPC_7x5, 745) - /* Generic PowerPC 755 */ - POWERPC_DEF("755", CPU_POWERPC_7x5, 755) /* PowerPC 745 v1.0 */ POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745) /* PowerPC 755 v1.0 */ @@ -9120,6 +9115,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "G3", "750" }, { "Conan/Doyle", "750p" }, { "LoneStar", "750l" }, + { "745", "745_v2.8" }, + { "755", "755_v2.8" }, { "Goldfinger", "755" }, { "7400", "7400_v2.9" }, { "Max", "7400" }, From 8fc82f9e0d93b6d827a874a25dce6f6a226cef5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:19 +0000 Subject: [PATCH 1433/1634] target-ppc: Extract 750 aliases 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 --- target-ppc/translate_init.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5981d98d9b..86db9a58cf 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7276,15 +7276,12 @@ enum { CPU_POWERPC_750E = 0x00080200, CPU_POWERPC_7x0P = 0x10080000, /* XXX: missing 0x00087010 (CL ?) */ -#define CPU_POWERPC_750CL CPU_POWERPC_750CL_v20 CPU_POWERPC_750CL_v10 = 0x00087200, CPU_POWERPC_750CL_v20 = 0x00087210, /* aka rev E */ -#define CPU_POWERPC_750CX CPU_POWERPC_750CX_v22 CPU_POWERPC_750CX_v10 = 0x00082100, CPU_POWERPC_750CX_v20 = 0x00082200, CPU_POWERPC_750CX_v21 = 0x00082201, CPU_POWERPC_750CX_v22 = 0x00082202, -#define CPU_POWERPC_750CXE CPU_POWERPC_750CXE_v31b CPU_POWERPC_750CXE_v21 = 0x00082211, CPU_POWERPC_750CXE_v22 = 0x00082212, CPU_POWERPC_750CXE_v23 = 0x00082213, @@ -7295,18 +7292,15 @@ enum { CPU_POWERPC_750CXE_v31b = 0x00083311, CPU_POWERPC_750CXR = 0x00083410, CPU_POWERPC_750FL = 0x70000203, -#define CPU_POWERPC_750FX CPU_POWERPC_750FX_v23 CPU_POWERPC_750FX_v10 = 0x70000100, CPU_POWERPC_750FX_v20 = 0x70000200, CPU_POWERPC_750FX_v21 = 0x70000201, CPU_POWERPC_750FX_v22 = 0x70000202, CPU_POWERPC_750FX_v23 = 0x70000203, CPU_POWERPC_750GL = 0x70020102, -#define CPU_POWERPC_750GX CPU_POWERPC_750GX_v12 CPU_POWERPC_750GX_v10 = 0x70020100, CPU_POWERPC_750GX_v11 = 0x70020101, CPU_POWERPC_750GX_v12 = 0x70020102, -#define CPU_POWERPC_750L CPU_POWERPC_750L_v32 /* Aka LoneStar */ CPU_POWERPC_750L_v20 = 0x00088200, CPU_POWERPC_750L_v21 = 0x00088201, CPU_POWERPC_750L_v22 = 0x00088202, @@ -8701,14 +8695,10 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740) /* PowerPC 750P (G3) */ POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750) - /* PowerPC 750CL (G3 embedded) */ - POWERPC_DEF("750cl", CPU_POWERPC_750CL, 750cl) /* PowerPC 750CL v1.0 */ POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl) /* PowerPC 750CL v2.0 */ POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl) - /* PowerPC 750CX (G3 embedded) */ - POWERPC_DEF("750cx", CPU_POWERPC_750CX, 750cx) /* PowerPC 750CX v1.0 (G3 embedded) */ POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx) /* PowerPC 750CX v2.1 (G3 embedded) */ @@ -8717,8 +8707,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx) /* PowerPC 750CX v2.2 (G3 embedded) */ POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx) - /* PowerPC 750CXe (G3 embedded) */ - POWERPC_DEF("750cxe", CPU_POWERPC_750CXE, 750cx) /* PowerPC 750CXe v2.1 (G3 embedded) */ POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx) /* PowerPC 750CXe v2.2 (G3 embedded) */ @@ -8739,8 +8727,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx) /* PowerPC 750FL (G3 embedded) */ POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx) - /* PowerPC 750FX (G3 embedded) */ - POWERPC_DEF("750fx", CPU_POWERPC_750FX, 750fx) /* PowerPC 750FX v1.0 (G3 embedded) */ POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx) /* PowerPC 750FX v2.0 (G3 embedded) */ @@ -8753,16 +8739,12 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx) /* PowerPC 750GL (G3 embedded) */ POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx) - /* PowerPC 750GX (G3 embedded) */ - POWERPC_DEF("750gx", CPU_POWERPC_750GX, 750gx) /* PowerPC 750GX v1.0 (G3 embedded) */ POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx) /* PowerPC 750GX v1.1 (G3 embedded) */ POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx) /* PowerPC 750GX v1.2 (G3 embedded) */ POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx) - /* PowerPC 750L (G3 embedded) */ - POWERPC_DEF("750l", CPU_POWERPC_750L, 750) /* PowerPC 750L v2.0 (G3 embedded) */ POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750) /* PowerPC 750L v2.1 (G3 embedded) */ @@ -9114,6 +9096,12 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Typhoon", "750" }, { "G3", "750" }, { "Conan/Doyle", "750p" }, + { "750cl", "750cl_v2.0" }, + { "750cx", "750cx_v2.2" }, + { "750cxe", "750cxe_v3.1b" }, + { "750fx", "750fx_v2.3" }, + { "750gx", "750gx_v1.2" }, + { "750l", "750l_v3.2" }, { "LoneStar", "750l" }, { "745", "745_v2.8" }, { "755", "755_v2.8" }, From 0446aecd56739760a2fa4b1dec342e3a4d5ebe9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:20 +0000 Subject: [PATCH 1434/1634] target-ppc: Extract 740/750 aliases 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 --- target-ppc/translate_init.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 86db9a58cf..e6be35ce0e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7265,7 +7265,6 @@ enum { #endif /* PowerPC 740/750 cores (aka G3) */ /* XXX: missing 0x00084202 */ -#define CPU_POWERPC_7x0 CPU_POWERPC_7x0_v31 CPU_POWERPC_7x0_v10 = 0x00080100, CPU_POWERPC_7x0_v20 = 0x00080200, CPU_POWERPC_7x0_v21 = 0x00080201, @@ -8659,10 +8658,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E) #endif /* PowerPC 7xx family */ - /* Generic PowerPC 740 (G3) */ - POWERPC_DEF("740", CPU_POWERPC_7x0, 740) - /* Generic PowerPC 750 (G3) */ - POWERPC_DEF("750", CPU_POWERPC_7x0, 750) /* PowerPC 740 v1.0 (G3) */ POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740) /* PowerPC 750 v1.0 (G3) */ @@ -9092,7 +9087,9 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Goldeneye", "603r" }, { "Sirocco", "604e" }, { "Mach5", "604r" }, + { "740", "740_v3.1" }, { "Arthur", "740" }, + { "750", "750_v3.1" }, { "Typhoon", "750" }, { "G3", "750" }, { "Conan/Doyle", "750p" }, From 16a177333eaa041104f8eeb37d7bbc33d6753695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:22 +0000 Subject: [PATCH 1435/1634] target-ppc: Extract 603e alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index e6be35ce0e..59a16449d5 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7232,7 +7232,6 @@ enum { CPU_POWERPC_601_v2 = 0x00010002, CPU_POWERPC_602 = 0x00050100, CPU_POWERPC_603 = 0x00030100, -#define CPU_POWERPC_603E CPU_POWERPC_603E_v41 CPU_POWERPC_603E_v11 = 0x00060101, CPU_POWERPC_603E_v12 = 0x00060102, CPU_POWERPC_603E_v13 = 0x00060103, @@ -8609,8 +8608,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("602", CPU_POWERPC_602, 602) /* PowerPC 603 */ POWERPC_DEF("603", CPU_POWERPC_603, 603) - /* PowerPC 603e (aka PID6) */ - POWERPC_DEF("603e", CPU_POWERPC_603E, 603E) /* PowerPC 603e v1.1 */ POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E) /* PowerPC 603e v1.2 */ @@ -9082,6 +9079,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "PowerQUICC-II", "MPC82xx" }, { "e500", "e500v2_v22" }, { "Vanilla", "603" }, + { "603e", "603e_v4.1" }, { "Stretch", "603e" }, { "Vaillant", "603e7v" }, { "Goldeneye", "603r" }, From 4ae0e9d870f0e588a459529d9cc660e20f2ac5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:23 +0000 Subject: [PATCH 1436/1634] target-ppc: Extract 603r alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 59a16449d5..69455c4e44 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7246,7 +7246,6 @@ enum { CPU_POWERPC_603E7v2 = 0x00070201, CPU_POWERPC_603E7 = 0x00070200, CPU_POWERPC_603P = 0x00070000, -#define CPU_POWERPC_603R CPU_POWERPC_603E7t /* XXX: missing 0x00040303 (604) */ CPU_POWERPC_604 = 0x00040103, #define CPU_POWERPC_604E CPU_POWERPC_604E_v24 @@ -8636,8 +8635,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E) /* PowerPC 603p (aka PID7v) */ POWERPC_DEF("603p", CPU_POWERPC_603P, 603E) - /* PowerPC 603r (aka PID7t) */ - POWERPC_DEF("603r", CPU_POWERPC_603R, 603E) /* PowerPC 604 */ POWERPC_DEF("604", CPU_POWERPC_604, 604) /* PowerPC 604e (aka PID9) */ @@ -9082,6 +9079,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "603e", "603e_v4.1" }, { "Stretch", "603e" }, { "Vaillant", "603e7v" }, + { "603r", "603e7t" }, { "Goldeneye", "603r" }, { "Sirocco", "604e" }, { "Mach5", "604r" }, From 336c86322d67dd3eb2e6d571b9d94c761b6988ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:24 +0000 Subject: [PATCH 1437/1634] target-ppc: Extract 601/601v aliases 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 --- target-ppc/translate_init.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 69455c4e44..03284c7c74 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7225,10 +7225,8 @@ enum { #define CPU_POWERPC_MPC8641 CPU_POWERPC_e600 #define CPU_POWERPC_MPC8641D CPU_POWERPC_e600 /* PowerPC 6xx cores */ -#define CPU_POWERPC_601 CPU_POWERPC_601_v2 CPU_POWERPC_601_v0 = 0x00010001, CPU_POWERPC_601_v1 = 0x00010001, -#define CPU_POWERPC_601v CPU_POWERPC_601_v2 CPU_POWERPC_601_v2 = 0x00010002, CPU_POWERPC_602 = 0x00050100, CPU_POWERPC_603 = 0x00030100, @@ -8593,14 +8591,10 @@ static const ppc_def_t ppc_defs[] = { CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400) /* 32 bits "classic" PowerPC */ /* PowerPC 6xx family */ - /* PowerPC 601 */ - POWERPC_DEF("601", CPU_POWERPC_601, 601v) /* PowerPC 601v0 */ POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601) /* PowerPC 601v1 */ POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601) - /* PowerPC 601v */ - POWERPC_DEF("601v", CPU_POWERPC_601v, 601v) /* PowerPC 601v2 */ POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v) /* PowerPC 602 */ @@ -9075,6 +9069,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "PowerQUICC-II", "MPC82xx" }, { "e500", "e500v2_v22" }, + { "601", "601_v2" }, + { "601v", "601_v2" }, { "Vanilla", "603" }, { "603e", "603e_v4.1" }, { "Stretch", "603e" }, From 91b5d028786b22bc4fe89b439ea55276ad09ec8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:21 +0000 Subject: [PATCH 1438/1634] target-ppc: Extract 604e alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 03284c7c74..c9094103f6 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7246,7 +7246,6 @@ enum { CPU_POWERPC_603P = 0x00070000, /* XXX: missing 0x00040303 (604) */ CPU_POWERPC_604 = 0x00040103, -#define CPU_POWERPC_604E CPU_POWERPC_604E_v24 /* XXX: missing 0x00091203 */ /* XXX: missing 0x00092110 */ /* XXX: missing 0x00092120 */ @@ -8631,8 +8630,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("603p", CPU_POWERPC_603P, 603E) /* PowerPC 604 */ POWERPC_DEF("604", CPU_POWERPC_604, 604) - /* PowerPC 604e (aka PID9) */ - POWERPC_DEF("604e", CPU_POWERPC_604E, 604E) /* PowerPC 604e v1.0 */ POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E) /* PowerPC 604e v2.2 */ @@ -9077,6 +9074,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Vaillant", "603e7v" }, { "603r", "603e7t" }, { "Goldeneye", "603r" }, + { "604e", "604e_v2.4" }, { "Sirocco", "604e" }, { "Mach5", "604r" }, { "740", "740_v3.1" }, From 52d80768dba6876919bb4e7f4fc00641431ef2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:25 +0000 Subject: [PATCH 1439/1634] target-ppc: Extract MPC85xx aliases 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 --- target-ppc/translate_init.c | 102 ++++++------------------------------ 1 file changed, 17 insertions(+), 85 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index c9094103f6..9939af5bc8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7147,67 +7147,50 @@ enum { CPU_POWERPC_e500mc = 0x80230020, CPU_POWERPC_e5500 = 0x80240020, /* MPC85xx microcontrollers */ -#define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11 #define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 #define CPU_POWERPC_MPC8533_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8533E CPU_POWERPC_MPC8533E_v11 #define CPU_POWERPC_MPC8533E_v10 CPU_POWERPC_e500v2_v21 #define CPU_POWERPC_MPC8533E_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8540 CPU_POWERPC_MPC8540_v21 #define CPU_POWERPC_MPC8540_v10 CPU_POWERPC_e500v1_v10 #define CPU_POWERPC_MPC8540_v20 CPU_POWERPC_e500v1_v20 #define CPU_POWERPC_MPC8540_v21 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8541 CPU_POWERPC_MPC8541_v11 #define CPU_POWERPC_MPC8541_v10 CPU_POWERPC_e500v1_v20 #define CPU_POWERPC_MPC8541_v11 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8541E CPU_POWERPC_MPC8541E_v11 #define CPU_POWERPC_MPC8541E_v10 CPU_POWERPC_e500v1_v20 #define CPU_POWERPC_MPC8541E_v11 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8543 CPU_POWERPC_MPC8543_v21 #define CPU_POWERPC_MPC8543_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8543_v11 CPU_POWERPC_e500v2_v11 #define CPU_POWERPC_MPC8543_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8543_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8543E CPU_POWERPC_MPC8543E_v21 #define CPU_POWERPC_MPC8543E_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8543E_v11 CPU_POWERPC_e500v2_v11 #define CPU_POWERPC_MPC8543E_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8543E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8544 CPU_POWERPC_MPC8544_v11 #define CPU_POWERPC_MPC8544_v10 CPU_POWERPC_e500v2_v21 #define CPU_POWERPC_MPC8544_v11 CPU_POWERPC_e500v2_v22 #define CPU_POWERPC_MPC8544E_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8544E CPU_POWERPC_MPC8544E_v11 #define CPU_POWERPC_MPC8544E_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8545 CPU_POWERPC_MPC8545_v21 #define CPU_POWERPC_MPC8545_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8545_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8545_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8545E CPU_POWERPC_MPC8545E_v21 #define CPU_POWERPC_MPC8545E_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8545E_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8545E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8547E CPU_POWERPC_MPC8547E_v21 #define CPU_POWERPC_MPC8547E_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8547E_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8547E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8548 CPU_POWERPC_MPC8548_v21 #define CPU_POWERPC_MPC8548_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8548_v11 CPU_POWERPC_e500v2_v11 #define CPU_POWERPC_MPC8548_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8548_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8548E CPU_POWERPC_MPC8548E_v21 #define CPU_POWERPC_MPC8548E_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8548E_v11 CPU_POWERPC_e500v2_v11 #define CPU_POWERPC_MPC8548E_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8548E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8555 CPU_POWERPC_MPC8555_v11 #define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8555E CPU_POWERPC_MPC8555E_v11 #define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8560 CPU_POWERPC_MPC8560_v21 #define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v2_v10 #define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v2_v20 #define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v2_v21 @@ -7509,64 +7492,47 @@ enum { POWERPC_SVR_8378E = 0x80C40010 | POWERPC_SVR_E500, POWERPC_SVR_8379 = 0x80C30010 | POWERPC_SVR_E500, POWERPC_SVR_8379E = 0x80C00010 | POWERPC_SVR_E500, -#define POWERPC_SVR_8533 POWERPC_SVR_8533_v11 POWERPC_SVR_8533_v10 = 0x80340010 | POWERPC_SVR_E500, POWERPC_SVR_8533_v11 = 0x80340011 | POWERPC_SVR_E500, -#define POWERPC_SVR_8533E POWERPC_SVR_8533E_v11 POWERPC_SVR_8533E_v10 = 0x803C0010 | POWERPC_SVR_E500, POWERPC_SVR_8533E_v11 = 0x803C0011 | POWERPC_SVR_E500, -#define POWERPC_SVR_8540 POWERPC_SVR_8540_v21 POWERPC_SVR_8540_v10 = 0x80300010 | POWERPC_SVR_E500, POWERPC_SVR_8540_v20 = 0x80300020 | POWERPC_SVR_E500, POWERPC_SVR_8540_v21 = 0x80300021 | POWERPC_SVR_E500, -#define POWERPC_SVR_8541 POWERPC_SVR_8541_v11 POWERPC_SVR_8541_v10 = 0x80720010 | POWERPC_SVR_E500, POWERPC_SVR_8541_v11 = 0x80720011 | POWERPC_SVR_E500, -#define POWERPC_SVR_8541E POWERPC_SVR_8541E_v11 POWERPC_SVR_8541E_v10 = 0x807A0010 | POWERPC_SVR_E500, POWERPC_SVR_8541E_v11 = 0x807A0011 | POWERPC_SVR_E500, -#define POWERPC_SVR_8543 POWERPC_SVR_8543_v21 POWERPC_SVR_8543_v10 = 0x80320010 | POWERPC_SVR_E500, POWERPC_SVR_8543_v11 = 0x80320011 | POWERPC_SVR_E500, POWERPC_SVR_8543_v20 = 0x80320020 | POWERPC_SVR_E500, POWERPC_SVR_8543_v21 = 0x80320021 | POWERPC_SVR_E500, -#define POWERPC_SVR_8543E POWERPC_SVR_8543E_v21 POWERPC_SVR_8543E_v10 = 0x803A0010 | POWERPC_SVR_E500, POWERPC_SVR_8543E_v11 = 0x803A0011 | POWERPC_SVR_E500, POWERPC_SVR_8543E_v20 = 0x803A0020 | POWERPC_SVR_E500, POWERPC_SVR_8543E_v21 = 0x803A0021 | POWERPC_SVR_E500, -#define POWERPC_SVR_8544 POWERPC_SVR_8544_v11 POWERPC_SVR_8544_v10 = 0x80340110 | POWERPC_SVR_E500, POWERPC_SVR_8544_v11 = 0x80340111 | POWERPC_SVR_E500, -#define POWERPC_SVR_8544E POWERPC_SVR_8544E_v11 POWERPC_SVR_8544E_v10 = 0x803C0110 | POWERPC_SVR_E500, POWERPC_SVR_8544E_v11 = 0x803C0111 | POWERPC_SVR_E500, -#define POWERPC_SVR_8545 POWERPC_SVR_8545_v21 POWERPC_SVR_8545_v20 = 0x80310220 | POWERPC_SVR_E500, POWERPC_SVR_8545_v21 = 0x80310221 | POWERPC_SVR_E500, -#define POWERPC_SVR_8545E POWERPC_SVR_8545E_v21 POWERPC_SVR_8545E_v20 = 0x80390220 | POWERPC_SVR_E500, POWERPC_SVR_8545E_v21 = 0x80390221 | POWERPC_SVR_E500, -#define POWERPC_SVR_8547E POWERPC_SVR_8547E_v21 POWERPC_SVR_8547E_v20 = 0x80390120 | POWERPC_SVR_E500, POWERPC_SVR_8547E_v21 = 0x80390121 | POWERPC_SVR_E500, -#define POWERPC_SVR_8548 POWERPC_SVR_8548_v21 POWERPC_SVR_8548_v10 = 0x80310010 | POWERPC_SVR_E500, POWERPC_SVR_8548_v11 = 0x80310011 | POWERPC_SVR_E500, POWERPC_SVR_8548_v20 = 0x80310020 | POWERPC_SVR_E500, POWERPC_SVR_8548_v21 = 0x80310021 | POWERPC_SVR_E500, -#define POWERPC_SVR_8548E POWERPC_SVR_8548E_v21 POWERPC_SVR_8548E_v10 = 0x80390010 | POWERPC_SVR_E500, POWERPC_SVR_8548E_v11 = 0x80390011 | POWERPC_SVR_E500, POWERPC_SVR_8548E_v20 = 0x80390020 | POWERPC_SVR_E500, POWERPC_SVR_8548E_v21 = 0x80390021 | POWERPC_SVR_E500, -#define POWERPC_SVR_8555 POWERPC_SVR_8555_v11 POWERPC_SVR_8555_v10 = 0x80710010 | POWERPC_SVR_E500, POWERPC_SVR_8555_v11 = 0x80710011 | POWERPC_SVR_E500, -#define POWERPC_SVR_8555E POWERPC_SVR_8555_v11 POWERPC_SVR_8555E_v10 = 0x80790010 | POWERPC_SVR_E500, POWERPC_SVR_8555E_v11 = 0x80790011 | POWERPC_SVR_E500, -#define POWERPC_SVR_8560 POWERPC_SVR_8560_v21 POWERPC_SVR_8560_v10 = 0x80700010 | POWERPC_SVR_E500, POWERPC_SVR_8560_v20 = 0x80700020 | POWERPC_SVR_E500, POWERPC_SVR_8560_v21 = 0x80700021 | POWERPC_SVR_E500, @@ -8373,26 +8339,17 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF_SVR("e5500", CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500) #endif /* PowerPC e500 microcontrollers */ - /* MPC8533 */ - POWERPC_DEF_SVR("MPC8533", - CPU_POWERPC_MPC8533, POWERPC_SVR_8533, e500v2) /* MPC8533 v1.0 */ POWERPC_DEF_SVR("MPC8533_v10", CPU_POWERPC_MPC8533_v10, POWERPC_SVR_8533_v10, e500v2) /* MPC8533 v1.1 */ POWERPC_DEF_SVR("MPC8533_v11", CPU_POWERPC_MPC8533_v11, POWERPC_SVR_8533_v11, e500v2) - /* MPC8533E */ - POWERPC_DEF_SVR("MPC8533E", - CPU_POWERPC_MPC8533E, POWERPC_SVR_8533E, e500v2) /* MPC8533E v1.0 */ POWERPC_DEF_SVR("MPC8533E_v10", CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500v2) POWERPC_DEF_SVR("MPC8533E_v11", CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500v2) - /* MPC8540 */ - POWERPC_DEF_SVR("MPC8540", - CPU_POWERPC_MPC8540, POWERPC_SVR_8540, e500v1) /* MPC8540 v1.0 */ POWERPC_DEF_SVR("MPC8540_v10", CPU_POWERPC_MPC8540_v10, POWERPC_SVR_8540_v10, e500v1) @@ -8402,27 +8359,18 @@ static const ppc_def_t ppc_defs[] = { /* MPC8540 v2.1 */ POWERPC_DEF_SVR("MPC8540_v21", CPU_POWERPC_MPC8540_v21, POWERPC_SVR_8540_v21, e500v1) - /* MPC8541 */ - POWERPC_DEF_SVR("MPC8541", - CPU_POWERPC_MPC8541, POWERPC_SVR_8541, e500v1) /* MPC8541 v1.0 */ POWERPC_DEF_SVR("MPC8541_v10", CPU_POWERPC_MPC8541_v10, POWERPC_SVR_8541_v10, e500v1) /* MPC8541 v1.1 */ POWERPC_DEF_SVR("MPC8541_v11", CPU_POWERPC_MPC8541_v11, POWERPC_SVR_8541_v11, e500v1) - /* MPC8541E */ - POWERPC_DEF_SVR("MPC8541E", - CPU_POWERPC_MPC8541E, POWERPC_SVR_8541E, e500v1) /* MPC8541E v1.0 */ POWERPC_DEF_SVR("MPC8541E_v10", CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500v1) /* MPC8541E v1.1 */ POWERPC_DEF_SVR("MPC8541E_v11", CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500v1) - /* MPC8543 */ - POWERPC_DEF_SVR("MPC8543", - CPU_POWERPC_MPC8543, POWERPC_SVR_8543, e500v2) /* MPC8543 v1.0 */ POWERPC_DEF_SVR("MPC8543_v10", CPU_POWERPC_MPC8543_v10, POWERPC_SVR_8543_v10, e500v2) @@ -8435,9 +8383,6 @@ static const ppc_def_t ppc_defs[] = { /* MPC8543 v2.1 */ POWERPC_DEF_SVR("MPC8543_v21", CPU_POWERPC_MPC8543_v21, POWERPC_SVR_8543_v21, e500v2) - /* MPC8543E */ - POWERPC_DEF_SVR("MPC8543E", - CPU_POWERPC_MPC8543E, POWERPC_SVR_8543E, e500v2) /* MPC8543E v1.0 */ POWERPC_DEF_SVR("MPC8543E_v10", CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500v2) @@ -8450,54 +8395,36 @@ static const ppc_def_t ppc_defs[] = { /* MPC8543E v2.1 */ POWERPC_DEF_SVR("MPC8543E_v21", CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500v2) - /* MPC8544 */ - POWERPC_DEF_SVR("MPC8544", - CPU_POWERPC_MPC8544, POWERPC_SVR_8544, e500v2) /* MPC8544 v1.0 */ POWERPC_DEF_SVR("MPC8544_v10", CPU_POWERPC_MPC8544_v10, POWERPC_SVR_8544_v10, e500v2) /* MPC8544 v1.1 */ POWERPC_DEF_SVR("MPC8544_v11", CPU_POWERPC_MPC8544_v11, POWERPC_SVR_8544_v11, e500v2) - /* MPC8544E */ - POWERPC_DEF_SVR("MPC8544E", - CPU_POWERPC_MPC8544E, POWERPC_SVR_8544E, e500v2) /* MPC8544E v1.0 */ POWERPC_DEF_SVR("MPC8544E_v10", CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500v2) /* MPC8544E v1.1 */ POWERPC_DEF_SVR("MPC8544E_v11", CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500v2) - /* MPC8545 */ - POWERPC_DEF_SVR("MPC8545", - CPU_POWERPC_MPC8545, POWERPC_SVR_8545, e500v2) /* MPC8545 v2.0 */ POWERPC_DEF_SVR("MPC8545_v20", CPU_POWERPC_MPC8545_v20, POWERPC_SVR_8545_v20, e500v2) /* MPC8545 v2.1 */ POWERPC_DEF_SVR("MPC8545_v21", CPU_POWERPC_MPC8545_v21, POWERPC_SVR_8545_v21, e500v2) - /* MPC8545E */ - POWERPC_DEF_SVR("MPC8545E", - CPU_POWERPC_MPC8545E, POWERPC_SVR_8545E, e500v2) /* MPC8545E v2.0 */ POWERPC_DEF_SVR("MPC8545E_v20", CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500v2) /* MPC8545E v2.1 */ POWERPC_DEF_SVR("MPC8545E_v21", CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500v2) - /* MPC8547E */ - POWERPC_DEF_SVR("MPC8547E", - CPU_POWERPC_MPC8547E, POWERPC_SVR_8547E, e500v2) /* MPC8547E v2.0 */ POWERPC_DEF_SVR("MPC8547E_v20", CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500v2) /* MPC8547E v2.1 */ POWERPC_DEF_SVR("MPC8547E_v21", CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500v2) - /* MPC8548 */ - POWERPC_DEF_SVR("MPC8548", - CPU_POWERPC_MPC8548, POWERPC_SVR_8548, e500v2) /* MPC8548 v1.0 */ POWERPC_DEF_SVR("MPC8548_v10", CPU_POWERPC_MPC8548_v10, POWERPC_SVR_8548_v10, e500v2) @@ -8510,9 +8437,6 @@ static const ppc_def_t ppc_defs[] = { /* MPC8548 v2.1 */ POWERPC_DEF_SVR("MPC8548_v21", CPU_POWERPC_MPC8548_v21, POWERPC_SVR_8548_v21, e500v2) - /* MPC8548E */ - POWERPC_DEF_SVR("MPC8548E", - CPU_POWERPC_MPC8548E, POWERPC_SVR_8548E, e500v2) /* MPC8548E v1.0 */ POWERPC_DEF_SVR("MPC8548E_v10", CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500v2) @@ -8525,27 +8449,18 @@ static const ppc_def_t ppc_defs[] = { /* MPC8548E v2.1 */ POWERPC_DEF_SVR("MPC8548E_v21", CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2) - /* MPC8555 */ - POWERPC_DEF_SVR("MPC8555", - CPU_POWERPC_MPC8555, POWERPC_SVR_8555, e500v2) /* MPC8555 v1.0 */ POWERPC_DEF_SVR("MPC8555_v10", CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2) /* MPC8555 v1.1 */ POWERPC_DEF_SVR("MPC8555_v11", CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2) - /* MPC8555E */ - POWERPC_DEF_SVR("MPC8555E", - CPU_POWERPC_MPC8555E, POWERPC_SVR_8555E, e500v2) /* MPC8555E v1.0 */ POWERPC_DEF_SVR("MPC8555E_v10", CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2) /* MPC8555E v1.1 */ POWERPC_DEF_SVR("MPC8555E_v11", CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2) - /* MPC8560 */ - POWERPC_DEF_SVR("MPC8560", - CPU_POWERPC_MPC8560, POWERPC_SVR_8560, e500v2) /* MPC8560 v1.0 */ POWERPC_DEF_SVR("MPC8560_v10", CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2) @@ -9066,6 +8981,23 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "PowerQUICC-II", "MPC82xx" }, { "e500", "e500v2_v22" }, + { "MPC8533", "MPC8533_v11" }, + { "MPC8533E", "MPC8533E_v11" }, + { "MPC8540", "MPC8540_v21" }, + { "MPC8541", "MPC8541_v11" }, + { "MPC8541E", "MPC8541E_v11" }, + { "MPC8543", "MPC8543_v21" }, + { "MPC8543E", "MPC8543E_v21" }, + { "MPC8544", "MPC8544_v11" }, + { "MPC8544E", "MPC8544E_v11" }, + { "MPC8545", "MPC8545_v21" }, + { "MPC8545E", "MPC8545E_v21" }, + { "MPC8547E", "MPC8547E_v21" }, + { "MPC8548", "MPC8548_v21" }, + { "MPC8548E", "MPC8548E_v21" }, + { "MPC8555", "MPC8555_v11" }, + { "MPC8555E", "MPC8555E_v11" }, + { "MPC8560", "MPC8560_v21" }, { "601", "601_v2" }, { "601v", "601_v2" }, { "Vanilla", "603" }, From 6d4decb484b5cc31a9a4a069eff21c89f8d288b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:26 +0000 Subject: [PATCH 1440/1634] target-ppc: Extract e500v1/e500v2 aliases 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 --- target-ppc/translate_init.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 9939af5bc8..91473dcf40 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7134,8 +7134,6 @@ enum { /* e500 family */ /* e500 cores */ #define CPU_POWERPC_e500 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_e500v1 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_e500v2 CPU_POWERPC_e500v2_v22 CPU_POWERPC_e500v1_v10 = 0x80200010, CPU_POWERPC_e500v1_v20 = 0x80200020, CPU_POWERPC_e500v2_v10 = 0x80210010, @@ -8316,14 +8314,10 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF_SVR("MPC8379E", CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300) /* e500 family */ - /* PowerPC e500v1 core */ - POWERPC_DEF("e500v1", CPU_POWERPC_e500v1, e500v1) /* PowerPC e500 v1.0 core */ POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1) /* PowerPC e500 v2.0 core */ POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1) - /* PowerPC e500v2 core */ - POWERPC_DEF("e500v2", CPU_POWERPC_e500v2, e500v2) /* PowerPC e500v2 v1.0 core */ POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2) /* PowerPC e500v2 v2.0 core */ @@ -8981,6 +8975,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "PowerQUICC-II", "MPC82xx" }, { "e500", "e500v2_v22" }, + { "e500v1", "e500_v20" }, + { "e500v2", "e500v2_v22" }, { "MPC8533", "MPC8533_v11" }, { "MPC8533E", "MPC8533E_v11" }, { "MPC8540", "MPC8540_v21" }, From 9538de4fe708ca09af3a786fb9b26e2269ebc8f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:27 +0000 Subject: [PATCH 1441/1634] target-ppc: Extract MPC83xx aliases 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 --- target-ppc/translate_init.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 91473dcf40..8f765ad478 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7461,16 +7461,12 @@ enum { POWERPC_SVR_8343A = 0x80570030, POWERPC_SVR_8343E = 0x80560010, POWERPC_SVR_8343EA = 0x80560030, -#define POWERPC_SVR_8347 POWERPC_SVR_8347T POWERPC_SVR_8347P = 0x80550010, /* PBGA package */ POWERPC_SVR_8347T = 0x80530010, /* TBGA package */ -#define POWERPC_SVR_8347A POWERPC_SVR_8347AT POWERPC_SVR_8347AP = 0x80550030, /* PBGA package */ POWERPC_SVR_8347AT = 0x80530030, /* TBGA package */ -#define POWERPC_SVR_8347E POWERPC_SVR_8347ET POWERPC_SVR_8347EP = 0x80540010, /* PBGA package */ POWERPC_SVR_8347ET = 0x80520010, /* TBGA package */ -#define POWERPC_SVR_8347EA POWERPC_SVR_8347EAT POWERPC_SVR_8347EAP = 0x80540030, /* PBGA package */ POWERPC_SVR_8347EAT = 0x80520030, /* TBGA package */ POWERPC_SVR_8349 = 0x80510010, @@ -8237,36 +8233,24 @@ static const ppc_def_t ppc_defs[] = { /* MPC8343EA */ POWERPC_DEF_SVR("MPC8343EA", CPU_POWERPC_MPC834x, POWERPC_SVR_8343EA, e300) - /* MPC8347 */ - POWERPC_DEF_SVR("MPC8347", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347, e300) /* MPC8347T */ POWERPC_DEF_SVR("MPC8347T", CPU_POWERPC_MPC834x, POWERPC_SVR_8347T, e300) /* MPC8347P */ POWERPC_DEF_SVR("MPC8347P", CPU_POWERPC_MPC834x, POWERPC_SVR_8347P, e300) - /* MPC8347A */ - POWERPC_DEF_SVR("MPC8347A", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347A, e300) /* MPC8347AT */ POWERPC_DEF_SVR("MPC8347AT", CPU_POWERPC_MPC834x, POWERPC_SVR_8347AT, e300) /* MPC8347AP */ POWERPC_DEF_SVR("MPC8347AP", CPU_POWERPC_MPC834x, POWERPC_SVR_8347AP, e300) - /* MPC8347E */ - POWERPC_DEF_SVR("MPC8347E", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347E, e300) /* MPC8347ET */ POWERPC_DEF_SVR("MPC8347ET", CPU_POWERPC_MPC834x, POWERPC_SVR_8347ET, e300) /* MPC8343EP */ POWERPC_DEF_SVR("MPC8347EP", CPU_POWERPC_MPC834x, POWERPC_SVR_8347EP, e300) - /* MPC8347EA */ - POWERPC_DEF_SVR("MPC8347EA", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EA, e300) /* MPC8347EAT */ POWERPC_DEF_SVR("MPC8347EAT", CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAT, e300) @@ -8974,6 +8958,10 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC885", "MPC8xx" }, { "PowerQUICC-II", "MPC82xx" }, + { "MPC8347", "MPC8347T" }, + { "MPC8347A", "MPC8347AT" }, + { "MPC8347E", "MPC8347ET" }, + { "MPC8347EA", "MPC8347EAT" }, { "e500", "e500v2_v22" }, { "e500v1", "e500_v20" }, { "e500v2", "e500v2_v22" }, From 0683641cc754e3d786acdeab8d00723dbd87727b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:28 +0000 Subject: [PATCH 1442/1634] target-ppc: Extract e300 alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8f765ad478..d2cee80dc6 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7119,7 +7119,6 @@ enum { #define CPU_POWERPC_MPC5567 CPU_POWERPC_e200z6 /* e300 family */ /* e300 cores */ -#define CPU_POWERPC_e300 CPU_POWERPC_e300c3 CPU_POWERPC_e300c1 = 0x00830010, CPU_POWERPC_e300c2 = 0x00840010, CPU_POWERPC_e300c3 = 0x00850010, @@ -8160,8 +8159,6 @@ static const ppc_def_t ppc_defs[] = { CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200) #endif /* e300 family */ - /* Generic PowerPC e300 core */ - POWERPC_DEF("e300", CPU_POWERPC_e300, e300) /* PowerPC e300c1 core */ POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300) /* PowerPC e300c2 core */ @@ -8958,6 +8955,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC885", "MPC8xx" }, { "PowerQUICC-II", "MPC82xx" }, + { "e300", "e300c3" }, { "MPC8347", "MPC8347T" }, { "MPC8347A", "MPC8347AT" }, { "MPC8347E", "MPC8347ET" }, From 4475e98f995ab726ce8bbf70225b2d90b20b9cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:29 +0000 Subject: [PATCH 1443/1634] target-ppc: Extract e200 alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d2cee80dc6..a4eae26c33 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7077,7 +7077,6 @@ enum { #define CPU_POWERPC_MPC8280 CPU_POWERPC_G2LEgp3 /* e200 family */ /* e200 cores */ -#define CPU_POWERPC_e200 CPU_POWERPC_e200z6 #if 0 CPU_POWERPC_e200z0 = xxx, #endif @@ -8024,8 +8023,6 @@ static const ppc_def_t ppc_defs[] = { /* MPC8280 */ POWERPC_DEF("MPC8280", CPU_POWERPC_MPC8280, G2LE) /* e200 family */ - /* Generic PowerPC e200 core */ - POWERPC_DEF("e200", CPU_POWERPC_e200, e200) /* Generic MPC55xx core */ #if defined (TODO) POWERPC_DEF_SVR("MPC55xx", @@ -8955,6 +8952,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC885", "MPC8xx" }, { "PowerQUICC-II", "MPC82xx" }, + { "e200", "e200z6" }, { "e300", "e300c3" }, { "MPC8347", "MPC8347T" }, { "MPC8347A", "MPC8347AT" }, From 63499f2109f7849420cc8858204bff267a0edcd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:30 +0000 Subject: [PATCH 1444/1634] target-ppc: Extract MPC82xx alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index a4eae26c33..2ab7d16a38 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7046,7 +7046,6 @@ enum { #define CPU_POWERPC_MPC5200B_v20 CPU_POWERPC_G2LEgp1 #define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 /* MPC82xx microcontrollers */ -#define CPU_POWERPC_MPC82xx CPU_POWERPC_MPC8280 #define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 #define CPU_POWERPC_MPC8241 CPU_POWERPC_G2_HIP4 #define CPU_POWERPC_MPC8245 CPU_POWERPC_G2_HIP4 @@ -7912,8 +7911,6 @@ static const ppc_def_t ppc_defs[] = { /* Generic MPC52xx core */ POWERPC_DEF_SVR("MPC52xx", CPU_POWERPC_MPC52xx, POWERPC_SVR_52xx, G2LE) - /* Generic MPC82xx core */ - POWERPC_DEF("MPC82xx", CPU_POWERPC_MPC82xx, G2) /* PowerPC G2 core */ POWERPC_DEF("G2", CPU_POWERPC_G2, G2) /* PowerPC G2 H4 core */ @@ -8951,6 +8948,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC880", "MPC8xx" }, { "MPC885", "MPC8xx" }, + { "MPC82xx", "MPC8280" }, { "PowerQUICC-II", "MPC82xx" }, { "e200", "e200z6" }, { "e300", "e300c3" }, From 4d55320fdb64b9110fa379520434f70d60d90bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:31 +0000 Subject: [PATCH 1445/1634] target-ppc: Extract MPC8247/MPC8248/MPC8270-80 aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This depends on the fix for "G2leGP3" PVR. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2ab7d16a38..8fd68ed16a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7049,8 +7049,6 @@ enum { #define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 #define CPU_POWERPC_MPC8241 CPU_POWERPC_G2_HIP4 #define CPU_POWERPC_MPC8245 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8247 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8248 CPU_POWERPC_G2LEgp3 #define CPU_POWERPC_MPC8250 CPU_POWERPC_MPC8250_HiP4 #define CPU_POWERPC_MPC8250_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8250_HiP4 CPU_POWERPC_G2_HIP4 @@ -7069,11 +7067,6 @@ enum { #define CPU_POWERPC_MPC8266 CPU_POWERPC_MPC8266_HiP4 #define CPU_POWERPC_MPC8266_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8266_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8270 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8271 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8272 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8275 CPU_POWERPC_G2LEgp3 -#define CPU_POWERPC_MPC8280 CPU_POWERPC_G2LEgp3 /* e200 family */ /* e200 cores */ #if 0 @@ -7969,10 +7962,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("MPC8241", CPU_POWERPC_MPC8241, G2) /* MPC8245 */ POWERPC_DEF("MPC8245", CPU_POWERPC_MPC8245, G2) - /* MPC8247 */ - POWERPC_DEF("MPC8247", CPU_POWERPC_MPC8247, G2LE) - /* MPC8248 */ - POWERPC_DEF("MPC8248", CPU_POWERPC_MPC8248, G2LE) /* MPC8250 */ POWERPC_DEF("MPC8250", CPU_POWERPC_MPC8250, G2) /* MPC8250 HiP3 */ @@ -8009,16 +7998,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("MPC8266_HiP3", CPU_POWERPC_MPC8266_HiP3, G2) /* MPC8266 HiP4 */ POWERPC_DEF("MPC8266_HiP4", CPU_POWERPC_MPC8266_HiP4, G2) - /* MPC8270 */ - POWERPC_DEF("MPC8270", CPU_POWERPC_MPC8270, G2LE) - /* MPC8271 */ - POWERPC_DEF("MPC8271", CPU_POWERPC_MPC8271, G2LE) - /* MPC8272 */ - POWERPC_DEF("MPC8272", CPU_POWERPC_MPC8272, G2LE) - /* MPC8275 */ - POWERPC_DEF("MPC8275", CPU_POWERPC_MPC8275, G2LE) - /* MPC8280 */ - POWERPC_DEF("MPC8280", CPU_POWERPC_MPC8280, G2LE) /* e200 family */ /* Generic MPC55xx core */ #if defined (TODO) @@ -8950,6 +8929,13 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC82xx", "MPC8280" }, { "PowerQUICC-II", "MPC82xx" }, + { "MPC8247", "G2leGP3" }, + { "MPC8248", "G2leGP3" }, + { "MPC8270", "G2leGP3" }, + { "MPC8271", "G2leGP3" }, + { "MPC8272", "G2leGP3" }, + { "MPC8275", "G2leGP3" }, + { "MPC8280", "G2leGP3" }, { "e200", "e200z6" }, { "e300", "e300c3" }, { "MPC8347", "MPC8347T" }, From f172e4b99f73115705842bcd676253644e8c356c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:32 +0000 Subject: [PATCH 1446/1634] target-ppc: Extract MPC82xx aliases to *_HiP4 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 --- target-ppc/translate_init.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8fd68ed16a..6ba6d267e0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7049,22 +7049,16 @@ enum { #define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 #define CPU_POWERPC_MPC8241 CPU_POWERPC_G2_HIP4 #define CPU_POWERPC_MPC8245 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8250 CPU_POWERPC_MPC8250_HiP4 #define CPU_POWERPC_MPC8250_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8250_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8255 CPU_POWERPC_MPC8255_HiP4 #define CPU_POWERPC_MPC8255_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8255_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8260 CPU_POWERPC_MPC8260_HiP4 #define CPU_POWERPC_MPC8260_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8260_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8264 CPU_POWERPC_MPC8264_HiP4 #define CPU_POWERPC_MPC8264_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8264_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8265 CPU_POWERPC_MPC8265_HiP4 #define CPU_POWERPC_MPC8265_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8265_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8266 CPU_POWERPC_MPC8266_HiP4 #define CPU_POWERPC_MPC8266_HiP3 CPU_POWERPC_G2_HIP3 #define CPU_POWERPC_MPC8266_HiP4 CPU_POWERPC_G2_HIP4 /* e200 family */ @@ -7962,38 +7956,26 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("MPC8241", CPU_POWERPC_MPC8241, G2) /* MPC8245 */ POWERPC_DEF("MPC8245", CPU_POWERPC_MPC8245, G2) - /* MPC8250 */ - POWERPC_DEF("MPC8250", CPU_POWERPC_MPC8250, G2) /* MPC8250 HiP3 */ POWERPC_DEF("MPC8250_HiP3", CPU_POWERPC_MPC8250_HiP3, G2) /* MPC8250 HiP4 */ POWERPC_DEF("MPC8250_HiP4", CPU_POWERPC_MPC8250_HiP4, G2) - /* MPC8255 */ - POWERPC_DEF("MPC8255", CPU_POWERPC_MPC8255, G2) /* MPC8255 HiP3 */ POWERPC_DEF("MPC8255_HiP3", CPU_POWERPC_MPC8255_HiP3, G2) /* MPC8255 HiP4 */ POWERPC_DEF("MPC8255_HiP4", CPU_POWERPC_MPC8255_HiP4, G2) - /* MPC8260 */ - POWERPC_DEF("MPC8260", CPU_POWERPC_MPC8260, G2) /* MPC8260 HiP3 */ POWERPC_DEF("MPC8260_HiP3", CPU_POWERPC_MPC8260_HiP3, G2) /* MPC8260 HiP4 */ POWERPC_DEF("MPC8260_HiP4", CPU_POWERPC_MPC8260_HiP4, G2) - /* MPC8264 */ - POWERPC_DEF("MPC8264", CPU_POWERPC_MPC8264, G2) /* MPC8264 HiP3 */ POWERPC_DEF("MPC8264_HiP3", CPU_POWERPC_MPC8264_HiP3, G2) /* MPC8264 HiP4 */ POWERPC_DEF("MPC8264_HiP4", CPU_POWERPC_MPC8264_HiP4, G2) - /* MPC8265 */ - POWERPC_DEF("MPC8265", CPU_POWERPC_MPC8265, G2) /* MPC8265 HiP3 */ POWERPC_DEF("MPC8265_HiP3", CPU_POWERPC_MPC8265_HiP3, G2) /* MPC8265 HiP4 */ POWERPC_DEF("MPC8265_HiP4", CPU_POWERPC_MPC8265_HiP4, G2) - /* MPC8266 */ - POWERPC_DEF("MPC8266", CPU_POWERPC_MPC8266, G2) /* MPC8266 HiP3 */ POWERPC_DEF("MPC8266_HiP3", CPU_POWERPC_MPC8266_HiP3, G2) /* MPC8266 HiP4 */ @@ -8931,6 +8913,12 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "PowerQUICC-II", "MPC82xx" }, { "MPC8247", "G2leGP3" }, { "MPC8248", "G2leGP3" }, + { "MPC8250", "MPC8250_HiP4" }, + { "MPC8255", "MPC8255_HiP4" }, + { "MPC8260", "MPC8260_HiP4" }, + { "MPC8264", "MPC8264_HiP4" }, + { "MPC8265", "MPC8265_HiP4" }, + { "MPC8266", "MPC8266_HiP4" }, { "MPC8270", "G2leGP3" }, { "MPC8271", "G2leGP3" }, { "MPC8272", "G2leGP3" }, From d329ceb2baa441629e83006a7e86933d871edadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:33 +0000 Subject: [PATCH 1447/1634] target-ppc: Extract MPC82xx_HiP{3, 4} aliases 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 --- target-ppc/translate_init.c | 56 ++++++++++--------------------------- 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6ba6d267e0..89c9e24015 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7047,20 +7047,6 @@ enum { #define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 /* MPC82xx microcontrollers */ #define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 -#define CPU_POWERPC_MPC8241 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8245 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8250_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8250_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8255_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8255_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8260_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8260_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8264_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8264_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8265_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8265_HiP4 CPU_POWERPC_G2_HIP4 -#define CPU_POWERPC_MPC8266_HiP3 CPU_POWERPC_G2_HIP3 -#define CPU_POWERPC_MPC8266_HiP4 CPU_POWERPC_G2_HIP4 /* e200 family */ /* e200 cores */ #if 0 @@ -7952,34 +7938,6 @@ static const ppc_def_t ppc_defs[] = { /* MPC5200B v2.1 */ POWERPC_DEF_SVR("MPC5200B_v21", CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE) - /* MPC8241 */ - POWERPC_DEF("MPC8241", CPU_POWERPC_MPC8241, G2) - /* MPC8245 */ - POWERPC_DEF("MPC8245", CPU_POWERPC_MPC8245, G2) - /* MPC8250 HiP3 */ - POWERPC_DEF("MPC8250_HiP3", CPU_POWERPC_MPC8250_HiP3, G2) - /* MPC8250 HiP4 */ - POWERPC_DEF("MPC8250_HiP4", CPU_POWERPC_MPC8250_HiP4, G2) - /* MPC8255 HiP3 */ - POWERPC_DEF("MPC8255_HiP3", CPU_POWERPC_MPC8255_HiP3, G2) - /* MPC8255 HiP4 */ - POWERPC_DEF("MPC8255_HiP4", CPU_POWERPC_MPC8255_HiP4, G2) - /* MPC8260 HiP3 */ - POWERPC_DEF("MPC8260_HiP3", CPU_POWERPC_MPC8260_HiP3, G2) - /* MPC8260 HiP4 */ - POWERPC_DEF("MPC8260_HiP4", CPU_POWERPC_MPC8260_HiP4, G2) - /* MPC8264 HiP3 */ - POWERPC_DEF("MPC8264_HiP3", CPU_POWERPC_MPC8264_HiP3, G2) - /* MPC8264 HiP4 */ - POWERPC_DEF("MPC8264_HiP4", CPU_POWERPC_MPC8264_HiP4, G2) - /* MPC8265 HiP3 */ - POWERPC_DEF("MPC8265_HiP3", CPU_POWERPC_MPC8265_HiP3, G2) - /* MPC8265 HiP4 */ - POWERPC_DEF("MPC8265_HiP4", CPU_POWERPC_MPC8265_HiP4, G2) - /* MPC8266 HiP3 */ - POWERPC_DEF("MPC8266_HiP3", CPU_POWERPC_MPC8266_HiP3, G2) - /* MPC8266 HiP4 */ - POWERPC_DEF("MPC8266_HiP4", CPU_POWERPC_MPC8266_HiP4, G2) /* e200 family */ /* Generic MPC55xx core */ #if defined (TODO) @@ -8911,14 +8869,28 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC82xx", "MPC8280" }, { "PowerQUICC-II", "MPC82xx" }, + { "MPC8241", "G2HiP4" }, + { "MPC8245", "G2HiP4" }, { "MPC8247", "G2leGP3" }, { "MPC8248", "G2leGP3" }, { "MPC8250", "MPC8250_HiP4" }, + { "MPC8250_HiP3", "G2HiP3" }, + { "MPC8250_HiP4", "G2HiP4" }, { "MPC8255", "MPC8255_HiP4" }, + { "MPC8255_HiP3", "G2HiP3" }, + { "MPC8255_HiP4", "G2HiP4" }, { "MPC8260", "MPC8260_HiP4" }, + { "MPC8260_HiP3", "G2HiP3" }, + { "MPC8260_HiP4", "G2HiP4" }, { "MPC8264", "MPC8264_HiP4" }, + { "MPC8264_HiP3", "G2HiP3" }, + { "MPC8264_HiP4", "G2HiP4" }, { "MPC8265", "MPC8265_HiP4" }, + { "MPC8265_HiP3", "G2HiP3" }, + { "MPC8265_HiP4", "G2HiP4" }, { "MPC8266", "MPC8266_HiP4" }, + { "MPC8266_HiP3", "G2HiP3" }, + { "MPC8266_HiP4", "G2HiP4" }, { "MPC8270", "G2leGP3" }, { "MPC8271", "G2leGP3" }, { "MPC8272", "G2leGP3" }, From cf9314cd77f07398303423dd17c520fa92d0b30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:34 +0000 Subject: [PATCH 1448/1634] target-ppc: Extract MPC52xx alias 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 --- target-ppc/translate_init.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 89c9e24015..625811edc0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7037,7 +7037,6 @@ enum { CPU_POWERPC_G2LEgp3 = 0x80822013, /* MPC52xx microcontrollers */ /* XXX: MPC 5121 ? */ -#define CPU_POWERPC_MPC52xx CPU_POWERPC_MPC5200 #define CPU_POWERPC_MPC5200 CPU_POWERPC_MPC5200_v12 #define CPU_POWERPC_MPC5200_v10 CPU_POWERPC_G2LEgp1 #define CPU_POWERPC_MPC5200_v11 CPU_POWERPC_G2LEgp1 @@ -7364,7 +7363,6 @@ enum { /* System version register (used on MPC 8xxx) */ enum { POWERPC_SVR_NONE = 0x00000000, -#define POWERPC_SVR_52xx POWERPC_SVR_5200 #define POWERPC_SVR_5200 POWERPC_SVR_5200_v12 POWERPC_SVR_5200_v10 = 0x80110010, POWERPC_SVR_5200_v11 = 0x80110011, @@ -7881,9 +7879,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx) #endif /* MPC82xx family (aka PowerQUICC-II) */ - /* Generic MPC52xx core */ - POWERPC_DEF_SVR("MPC52xx", - CPU_POWERPC_MPC52xx, POWERPC_SVR_52xx, G2LE) /* PowerPC G2 core */ POWERPC_DEF("G2", CPU_POWERPC_G2, G2) /* PowerPC G2 H4 core */ @@ -8867,6 +8862,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC880", "MPC8xx" }, { "MPC885", "MPC8xx" }, + { "MPC52xx", "MPC5200" }, + { "MPC82xx", "MPC8280" }, { "PowerQUICC-II", "MPC82xx" }, { "MPC8241", "G2HiP4" }, From 236824f276fafbfbb5399ca2c9c72298a401e223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:35 +0000 Subject: [PATCH 1449/1634] target-ppc: Extract MPC5200/MPC5200B aliases 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 --- target-ppc/translate_init.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 625811edc0..2e41f0bb60 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7037,11 +7037,9 @@ enum { CPU_POWERPC_G2LEgp3 = 0x80822013, /* MPC52xx microcontrollers */ /* XXX: MPC 5121 ? */ -#define CPU_POWERPC_MPC5200 CPU_POWERPC_MPC5200_v12 #define CPU_POWERPC_MPC5200_v10 CPU_POWERPC_G2LEgp1 #define CPU_POWERPC_MPC5200_v11 CPU_POWERPC_G2LEgp1 #define CPU_POWERPC_MPC5200_v12 CPU_POWERPC_G2LEgp1 -#define CPU_POWERPC_MPC5200B CPU_POWERPC_MPC5200B_v21 #define CPU_POWERPC_MPC5200B_v20 CPU_POWERPC_G2LEgp1 #define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 /* MPC82xx microcontrollers */ @@ -7363,11 +7361,9 @@ enum { /* System version register (used on MPC 8xxx) */ enum { POWERPC_SVR_NONE = 0x00000000, -#define POWERPC_SVR_5200 POWERPC_SVR_5200_v12 POWERPC_SVR_5200_v10 = 0x80110010, POWERPC_SVR_5200_v11 = 0x80110011, POWERPC_SVR_5200_v12 = 0x80110012, -#define POWERPC_SVR_5200B POWERPC_SVR_5200B_v21 POWERPC_SVR_5200B_v20 = 0x80110020, POWERPC_SVR_5200B_v21 = 0x80110021, #define POWERPC_SVR_55xx POWERPC_SVR_5567 @@ -7912,9 +7908,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF_SVR("MPC5121", CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE) #endif - /* MPC5200 */ - POWERPC_DEF_SVR("MPC5200", - CPU_POWERPC_MPC5200, POWERPC_SVR_5200, G2LE) /* MPC5200 v1.0 */ POWERPC_DEF_SVR("MPC5200_v10", CPU_POWERPC_MPC5200_v10, POWERPC_SVR_5200_v10, G2LE) @@ -7924,9 +7917,6 @@ static const ppc_def_t ppc_defs[] = { /* MPC5200 v1.2 */ POWERPC_DEF_SVR("MPC5200_v12", CPU_POWERPC_MPC5200_v12, POWERPC_SVR_5200_v12, G2LE) - /* MPC5200B */ - POWERPC_DEF_SVR("MPC5200B", - CPU_POWERPC_MPC5200B, POWERPC_SVR_5200B, G2LE) /* MPC5200B v2.0 */ POWERPC_DEF_SVR("MPC5200B_v20", CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE) @@ -8863,6 +8853,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC885", "MPC8xx" }, { "MPC52xx", "MPC5200" }, + { "MPC5200", "MPC5200_v12" }, + { "MPC5200B", "MPC5200B_v21" }, { "MPC82xx", "MPC8280" }, { "PowerQUICC-II", "MPC82xx" }, From 7b48a1ad3242fc7f6a19620f8a23f92a4f9ffb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:36 +0000 Subject: [PATCH 1450/1634] target-ppc: Extract MPC8240 alias 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 --- target-ppc/translate_init.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 2e41f0bb60..4e5278d691 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7042,8 +7042,6 @@ enum { #define CPU_POWERPC_MPC5200_v12 CPU_POWERPC_G2LEgp1 #define CPU_POWERPC_MPC5200B_v20 CPU_POWERPC_G2LEgp1 #define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 - /* MPC82xx microcontrollers */ -#define CPU_POWERPC_MPC8240 CPU_POWERPC_MPC603 /* e200 family */ /* e200 cores */ #if 0 @@ -7899,9 +7897,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE) /* PowerPC G2LE GP3 core */ POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE) - /* PowerPC MPC603 microcontrollers */ - /* MPC8240 */ - POWERPC_DEF("MPC8240", CPU_POWERPC_MPC8240, 603E) /* PowerPC G2 microcontrollers */ #if defined(TODO) /* MPC5121 */ @@ -8852,6 +8847,9 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "MPC880", "MPC8xx" }, { "MPC885", "MPC8xx" }, + /* PowerPC MPC603 microcontrollers */ + { "MPC8240", "603" }, + { "MPC52xx", "MPC5200" }, { "MPC5200", "MPC5200_v12" }, { "MPC5200B", "MPC5200B_v21" }, From 4bdba7fd2efbd57b9dc12bfb930f085a54f3df47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:37 +0000 Subject: [PATCH 1451/1634] target-ppc: Extract 405GPe alias 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 --- target-ppc/translate_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4e5278d691..3fa131fb2b 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6891,7 +6891,6 @@ enum { CPU_POWERPC_405GPb = 0x40110040, CPU_POWERPC_405GPc = 0x40110082, CPU_POWERPC_405GPd = 0x401100C4, -#define CPU_POWERPC_405GPe CPU_POWERPC_405CRc CPU_POWERPC_405GPR = 0x50910951, #if 0 CPU_POWERPC_405H = xxx, @@ -7658,8 +7657,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405) /* PowerPC 405 GPd */ POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405) - /* PowerPC 405 GPe */ - POWERPC_DEF("405GPe", CPU_POWERPC_405GPe, 405) /* PowerPC 405 GPR */ POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405) #if defined(TODO) @@ -8805,6 +8802,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "405", "405D4" }, { "405CR", "405CRc" }, { "405GP", "405GPd" }, + { "405GPe", "405CRc" }, { "x2vp7", "x2vp4" }, { "x2vp50", "x2vp20" }, From df43f4b863ba4f7f89afedddc86ad9e11157b51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:38 +0000 Subject: [PATCH 1452/1634] target-ppc: Extract 970 aliases 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 --- target-ppc/translate_init.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3fa131fb2b..bcb22cc350 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7320,14 +7320,12 @@ enum { CPU_POWERPC_POWER7_v21 = 0x003F0201, CPU_POWERPC_POWER7_v23 = 0x003F0203, CPU_POWERPC_970 = 0x00390202, -#define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 CPU_POWERPC_970FX_v10 = 0x00391100, CPU_POWERPC_970FX_v20 = 0x003C0200, CPU_POWERPC_970FX_v21 = 0x003C0201, CPU_POWERPC_970FX_v30 = 0x003C0300, CPU_POWERPC_970FX_v31 = 0x003C0301, CPU_POWERPC_970GX = 0x00450000, -#define CPU_POWERPC_970MP CPU_POWERPC_970MP_v11 CPU_POWERPC_970MP_v10 = 0x00440100, CPU_POWERPC_970MP_v11 = 0x00440101, #define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32 @@ -8711,8 +8709,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7) /* PowerPC 970 */ POWERPC_DEF("970", CPU_POWERPC_970, 970) - /* PowerPC 970FX (G5) */ - POWERPC_DEF("970fx", CPU_POWERPC_970FX, 970FX) /* PowerPC 970FX v1.0 (G5) */ POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX) /* PowerPC 970FX v2.0 (G5) */ @@ -8725,8 +8721,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX) /* PowerPC 970GX (G5) */ POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX) - /* PowerPC 970MP */ - POWERPC_DEF("970mp", CPU_POWERPC_970MP, 970MP) /* PowerPC 970MP v1.0 */ POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP) /* PowerPC 970MP v1.1 */ @@ -8959,6 +8953,8 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Boxer", "POWER3" }, { "Dino", "POWER3" }, { "POWER3+", "631" }, + { "970fx", "970fx_v3.1" }, + { "970mp", "970mp_v1.1" }, { "Apache", "RS64" }, { "A35", "RS64" }, { "NorthStar", "RS64-II" }, From f591784b639c72138f0cfd30b46dcf328f9adc8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:39 +0000 Subject: [PATCH 1453/1634] target-ppc: Extract POWER7 alias 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 --- target-ppc/translate_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index bcb22cc350..9d4831fbaa 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7315,7 +7315,6 @@ enum { CPU_POWERPC_POWER6 = 0x003E0000, CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ CPU_POWERPC_POWER6A = 0x0F000002, -#define CPU_POWERPC_POWER7 CPU_POWERPC_POWER7_v20 CPU_POWERPC_POWER7_v20 = 0x003F0200, CPU_POWERPC_POWER7_v21 = 0x003F0201, CPU_POWERPC_POWER7_v23 = 0x003F0203, @@ -8703,7 +8702,6 @@ static const ppc_def_t ppc_defs[] = { POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6) #endif /* POWER7 */ - POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7) POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7) POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7) POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7) @@ -8953,6 +8951,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Boxer", "POWER3" }, { "Dino", "POWER3" }, { "POWER3+", "631" }, + { "POWER7", "POWER7_v2.0" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" }, { "Apache", "RS64" }, From de400129daf3ff0f7468363f6d886fcdcc626ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:40 +0000 Subject: [PATCH 1454/1634] target-ppc: Get model name from type name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are about to drop the redundant name field along with ppc_def_t. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 9d4831fbaa..7eb565d205 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9979,9 +9979,14 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) ObjectClass *oc = data; CPUListState *s = user_data; PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + const char *typename = object_class_get_name(oc); + char *name; + name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", - pcc->info->name, pcc->info->pvr); + name, pcc->info->pvr); + g_free(name); } void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) @@ -10014,12 +10019,14 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; CpuDefinitionInfoList **first = user_data; - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + const char *typename; CpuDefinitionInfoList *entry; CpuDefinitionInfo *info; + typename = object_class_get_name(oc); info = g_malloc0(sizeof(*info)); - info->name = g_strdup(pcc->info->name); + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); entry = g_malloc0(sizeof(*entry)); entry->value = info; From cfe34f44b3a13ed32891e0b3c84be91d3d91a4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:41 +0000 Subject: [PATCH 1455/1634] target-ppc: Convert CPU definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turn the array of model definitions into a set of self-registering QOM types with their own class_init. Unique identifiers are obtained from the combination of PVR, SVR and family identifiers; this requires all alias #defines to be removed from the list. Possibly there are some more left after this commit that are not currently being compiled. Prepares for introducing abstract intermediate CPU types for families. Keep the right-aligned macro line breaks within 78 chars to aid three-way merges. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/cpu-qom.h | 17 +++- target-ppc/cpu.h | 20 ----- target-ppc/kvm.c | 32 ++++--- target-ppc/translate_init.c | 163 ++++++++++++++++++------------------ 4 files changed, 115 insertions(+), 117 deletions(-) diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 4e8ceca574..2bf0ab62d4 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -53,8 +53,21 @@ typedef struct PowerPCCPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); - /* TODO inline fields here */ - ppc_def_t *info; + uint32_t pvr; + uint32_t svr; + uint64_t insns_flags; + uint64_t insns_flags2; + uint64_t msr_mask; + powerpc_mmu_t mmu_model; + powerpc_excp_t excp_model; + powerpc_input_t bus_model; + uint32_t flags; + int bfd_mach; +#if defined(TARGET_PPC64) + const struct ppc_segment_page_sizes *sps; +#endif + void (*init_proc)(CPUPPCState *env); + int (*check_pow)(CPUPPCState *env); } PowerPCCPUClass; /** diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 20f4565a1a..e4cf96ce2f 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -307,7 +307,6 @@ enum powerpc_input_t { #define PPC_INPUT(env) (env->bus_model) /*****************************************************************************/ -typedef struct ppc_def_t ppc_def_t; typedef struct opc_handler_t opc_handler_t; /*****************************************************************************/ @@ -902,25 +901,6 @@ struct ppc_segment_page_sizes { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 -struct ppc_def_t { - const char *name; - uint32_t pvr; - uint32_t svr; - uint64_t insns_flags; - uint64_t insns_flags2; - uint64_t msr_mask; - powerpc_mmu_t mmu_model; - powerpc_excp_t excp_model; - powerpc_input_t bus_model; - uint32_t flags; - int bfd_mach; -#if defined(TARGET_PPC64) - const struct ppc_segment_page_sizes *sps; -#endif - void (*init_proc)(CPUPPCState *env); - int (*check_pow)(CPUPPCState *env); -}; - struct CPUPPCState { /* First are the most commonly used resources * during translated code execution diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 8e6441614e..a89c3cf7a5 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -1263,7 +1263,7 @@ static void kvmppc_host_cpu_initfn(Object *obj) assert(kvm_enabled()); - if (pcc->info->pvr != mfpvr()) { + if (pcc->pvr != mfpvr()) { fprintf(stderr, "Your host CPU is unsupported.\n" "Please choose a supported model instead, see -cpu ?.\n"); exit(1); @@ -1275,30 +1275,38 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); uint32_t host_pvr = mfpvr(); PowerPCCPUClass *pvr_pcc; - ppc_def_t *spec; uint32_t vmx = kvmppc_get_vmx(); uint32_t dfp = kvmppc_get_dfp(); - spec = g_malloc0(sizeof(*spec)); - pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); if (pvr_pcc != NULL) { - memcpy(spec, pvr_pcc->info, sizeof(*spec)); + pcc->pvr = pvr_pcc->pvr; + pcc->svr = pvr_pcc->svr; + pcc->insns_flags = pvr_pcc->insns_flags; + pcc->insns_flags2 = pvr_pcc->insns_flags2; + pcc->msr_mask = pvr_pcc->msr_mask; + pcc->mmu_model = pvr_pcc->mmu_model; + pcc->excp_model = pvr_pcc->excp_model; + pcc->bus_model = pvr_pcc->bus_model; + pcc->flags = pvr_pcc->flags; + pcc->bfd_mach = pvr_pcc->bfd_mach; +#ifdef TARGET_PPC64 + pcc->sps = pvr_pcc->sps; +#endif + pcc->init_proc = pvr_pcc->init_proc; + pcc->check_pow = pvr_pcc->check_pow; } - pcc->info = spec; - /* Override the display name for -cpu ? and QMP */ - pcc->info->name = "host"; - /* Now fix up the spec with information we can query from the host */ + /* Now fix up the class with information we can query from the host */ if (vmx != -1) { /* Only override when we know what the host supports */ - alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); - alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); + alter_insns(&pcc->insns_flags, PPC_ALTIVEC, vmx > 0); + alter_insns(&pcc->insns_flags2, PPC2_VSX, vmx > 1); } if (dfp != -1) { /* Only override when we know what the host supports */ - alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + alter_insns(&pcc->insns_flags2, PPC2_DFP, dfp); } } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7eb565d205..f7071971ee 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7503,26 +7503,59 @@ enum { /*****************************************************************************/ /* PowerPC CPU definitions */ +#define POWERPC_DEF_PREFIX(pvr, svr, type) \ + glue(glue(glue(glue(pvr, _), svr), _), type) +#if defined(TARGET_PPCEMB) +#define POWERPC_DEF_CONDITION(type) \ + if (glue(POWERPC_MMU_, type) != POWERPC_MMU_BOOKE) { \ + return; \ + } +#else +#define POWERPC_DEF_CONDITION(type) +#endif #define POWERPC_DEF_SVR(_name, _pvr, _svr, _type) \ - { \ - .name = _name, \ - .pvr = _pvr, \ - .svr = _svr, \ - .insns_flags = glue(POWERPC_INSNS_,_type), \ - .insns_flags2 = glue(POWERPC_INSNS2_,_type), \ - .msr_mask = glue(POWERPC_MSRM_,_type), \ - .mmu_model = glue(POWERPC_MMU_,_type), \ - .excp_model = glue(POWERPC_EXCP_,_type), \ - .bus_model = glue(POWERPC_INPUT_,_type), \ - .bfd_mach = glue(POWERPC_BFDM_,_type), \ - .flags = glue(POWERPC_FLAG_,_type), \ - .init_proc = &glue(init_proc_,_type), \ - .check_pow = &glue(check_pow_,_type), \ - }, + static void \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ + (ObjectClass *oc, void *data) \ + { \ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ + \ + pcc->pvr = _pvr; \ + pcc->svr = _svr; \ + pcc->insns_flags = glue(POWERPC_INSNS_, _type); \ + pcc->insns_flags2 = glue(POWERPC_INSNS2_, _type); \ + pcc->msr_mask = glue(POWERPC_MSRM_, _type); \ + pcc->mmu_model = glue(POWERPC_MMU_, _type); \ + pcc->excp_model = glue(POWERPC_EXCP_, _type); \ + pcc->bus_model = glue(POWERPC_INPUT_, _type); \ + pcc->bfd_mach = glue(POWERPC_BFDM_, _type); \ + pcc->flags = glue(POWERPC_FLAG_, _type); \ + pcc->init_proc = &glue(init_proc_, _type); \ + pcc->check_pow = &glue(check_pow_, _type); \ + } \ + \ + static const TypeInfo \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info) = { \ + .name = _name "-" TYPE_POWERPC_CPU, \ + .parent = TYPE_POWERPC_CPU, \ + .class_init = \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init), \ + }; \ + \ + static void \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)(void) \ + { \ + POWERPC_DEF_CONDITION(_type) \ + type_register_static( \ + &glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info)); \ + } \ + \ + type_init( \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)) + #define POWERPC_DEF(_name, _pvr, _type) \ POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type) -static const ppc_def_t ppc_defs[] = { /* Embedded PowerPC */ /* PowerPC 401 family */ /* Generic PowerPC 401 */ @@ -8782,7 +8815,6 @@ static const ppc_def_t ppc_defs[] = { /* PA PA6T */ POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T) #endif -}; typedef struct PowerPCCPUAlias { const char *alias; @@ -8981,8 +9013,10 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { /*****************************************************************************/ /* Generic CPU instantiation routine */ -static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) +static void init_ppc_proc(PowerPCCPU *cpu) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + CPUPPCState *env = &cpu->env; #if !defined(CONFIG_USER_ONLY) int i; @@ -9010,23 +9044,23 @@ static void init_ppc_proc (CPUPPCState *env, const ppc_def_t *def) #endif SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, - def->pvr); + pcc->pvr); /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ - if (def->svr != POWERPC_SVR_NONE) { - if (def->svr & POWERPC_SVR_E500) { + if (pcc->svr != POWERPC_SVR_NONE) { + if (pcc->svr & POWERPC_SVR_E500) { spr_register(env, SPR_E500_SVR, "SVR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, - def->svr & ~POWERPC_SVR_E500); + pcc->svr & ~POWERPC_SVR_E500); } else { spr_register(env, SPR_SVR, "SVR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS, - def->svr); + pcc->svr); } } /* PowerPC implementation specific initialisations (SPRs, timers, ...) */ - (*def->init_proc)(env); + (*pcc->init_proc)(env); #if !defined(CONFIG_USER_ONLY) env->excp_prefix = env->hreset_excp_prefix; #endif @@ -9377,13 +9411,12 @@ static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) { PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; - const ppc_def_t *def = pcc->info; opcode_t *opc; fill_new_table(env->opcodes, 0x40); for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) { - if (((opc->handler.type & def->insns_flags) != 0) || - ((opc->handler.type2 & def->insns_flags2) != 0)) { + if (((opc->handler.type & pcc->insns_flags) != 0) || + ((opc->handler.type2 & pcc->insns_flags2) != 0)) { if (register_insn(env->opcodes, opc) < 0) { error_setg(errp, "ERROR initializing PowerPC instruction " "0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2, @@ -9615,7 +9648,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) PowerPCCPU *cpu = POWERPC_CPU(dev); CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - ppc_def_t *def = pcc->info; Error *local_err = NULL; #if !defined(CONFIG_USER_ONLY) int max_smt = kvm_enabled() ? kvmppc_smt_threads() : 1; @@ -9646,17 +9678,17 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) error_propagate(errp, local_err); return; } - init_ppc_proc(env, def); + init_ppc_proc(cpu); - if (def->insns_flags & PPC_FLOAT) { + if (pcc->insns_flags & PPC_FLOAT) { gdb_register_coprocessor(env, gdb_get_float_reg, gdb_set_float_reg, 33, "power-fpu.xml", 0); } - if (def->insns_flags & PPC_ALTIVEC) { + if (pcc->insns_flags & PPC_ALTIVEC) { gdb_register_coprocessor(env, gdb_get_avr_reg, gdb_set_avr_reg, 34, "power-altivec.xml", 0); } - if (def->insns_flags & PPC_SPE) { + if (pcc->insns_flags & PPC_SPE) { gdb_register_coprocessor(env, gdb_get_spe_reg, gdb_set_spe_reg, 34, "power-spe.xml", 0); } @@ -9782,7 +9814,7 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) } printf("PowerPC %-12s : PVR %08x MSR %016" PRIx64 "\n" " MMU model : %s\n", - def->name, def->pvr, def->msr_mask, mmu_model); + pcc->name, pcc->pvr, pcc->msr_mask, mmu_model); #if !defined(CONFIG_USER_ONLY) if (env->tlb != NULL) { printf(" %d %s TLB in %d ways\n", @@ -9840,7 +9872,7 @@ static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) return -1; } - return pcc->info->pvr == pvr ? 0 : -1; + return pcc->pvr == pvr ? 0 : -1; } PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr) @@ -9964,9 +9996,9 @@ static gint ppc_cpu_list_compare(gconstpointer a, gconstpointer b) return -1; } else { /* Avoid an integer overflow during subtraction */ - if (pcc_a->info->pvr < pcc_b->info->pvr) { + if (pcc_a->pvr < pcc_b->pvr) { return -1; - } else if (pcc_a->info->pvr > pcc_b->info->pvr) { + } else if (pcc_a->pvr > pcc_b->pvr) { return 1; } else { return 0; @@ -9985,7 +10017,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", - name, pcc->info->pvr); + name, pcc->pvr); g_free(name); } @@ -10046,27 +10078,6 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) return cpu_list; } -static void ppc_cpu_def_class_init(ObjectClass *oc, void *data) -{ - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - ppc_def_t *info = data; - - pcc->info = info; -} - -static void ppc_cpu_register_model(const ppc_def_t *def) -{ - TypeInfo type_info = { - .parent = TYPE_POWERPC_CPU, - .class_init = ppc_cpu_def_class_init, - .class_data = (void *)def, - }; - - type_info.name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, def->name), - type_register(&type_info); - g_free((gpointer)type_info.name); -} - /* CPUClass::reset() */ static void ppc_cpu_reset(CPUState *s) { @@ -10138,24 +10149,23 @@ static void ppc_cpu_initfn(Object *obj) PowerPCCPU *cpu = POWERPC_CPU(obj); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; - ppc_def_t *def = pcc->info; cs->env_ptr = env; cpu_exec_init(env); - env->msr_mask = def->msr_mask; - env->mmu_model = def->mmu_model; - env->excp_model = def->excp_model; - env->bus_model = def->bus_model; - env->insns_flags = def->insns_flags; - env->insns_flags2 = def->insns_flags2; - env->flags = def->flags; - env->bfd_mach = def->bfd_mach; - env->check_pow = def->check_pow; + env->msr_mask = pcc->msr_mask; + env->mmu_model = pcc->mmu_model; + env->excp_model = pcc->excp_model; + env->bus_model = pcc->bus_model; + env->insns_flags = pcc->insns_flags; + env->insns_flags2 = pcc->insns_flags2; + env->flags = pcc->flags; + env->bfd_mach = pcc->bfd_mach; + env->check_pow = pcc->check_pow; #if defined(TARGET_PPC64) - if (def->sps) { - env->sps = *def->sps; + if (pcc->sps) { + env->sps = *pcc->sps; } else if (env->mmu_model & POWERPC_MMU_64) { /* Use default sets of page sizes */ static const struct ppc_segment_page_sizes defsps = { @@ -10206,20 +10216,7 @@ static const TypeInfo ppc_cpu_type_info = { static void ppc_cpu_register_types(void) { - int i; - type_register_static(&ppc_cpu_type_info); - - for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { - const ppc_def_t *def = &ppc_defs[i]; -#if defined(TARGET_PPCEMB) - /* When using the ppcemb target, we only support 440 style cores */ - if (def->mmu_model != POWERPC_MMU_BOOKE) { - continue; - } -#endif - ppc_cpu_register_model(def); - } } type_init(ppc_cpu_register_types) From 7856e3a41ba8ec5da3dc0b449dc6feaf999d3ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:42 +0000 Subject: [PATCH 1456/1634] target-ppc: Introduce abstract CPU family types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of assigning *_ constants, set .parent to a family type. Introduce a POWERPC_FAMILY() macro to keep type registration close to its implementation. This macro will need tweaking later. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 501 +++++++++++++++++++++++++++++++----- 1 file changed, 432 insertions(+), 69 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f7071971ee..c300aa88e0 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3252,6 +3252,28 @@ static int check_pow_hid0_74xx (CPUPPCState *env) /*****************************************************************************/ /* PowerPC implementations definitions */ +#define POWERPC_FAMILY(_name) \ + static void \ + glue(glue(ppc_, _name), _cpu_family_class_init)(ObjectClass *, void *); \ + \ + static const TypeInfo \ + glue(glue(ppc_, _name), _cpu_family_type_info) = { \ + .name = stringify(_name) "-family-" TYPE_POWERPC_CPU, \ + .parent = TYPE_POWERPC_CPU, \ + .abstract = true, \ + .class_init = glue(glue(ppc_, _name), _cpu_family_class_init), \ + }; \ + \ + static void glue(glue(ppc_, _name), _cpu_family_register_types)(void) \ + { \ + type_register_static( \ + &glue(glue(ppc_, _name), _cpu_family_type_info)); \ + } \ + \ + type_init(glue(glue(ppc_, _name), _cpu_family_register_types)) \ + \ + static void glue(glue(ppc_, _name), _cpu_family_class_init) + /* PowerPC 401 */ #define POWERPC_INSNS_401 (PPC_INSNS_BASE | PPC_STRING | \ PPC_WRTEE | PPC_DCR | \ @@ -3267,7 +3289,6 @@ static int check_pow_hid0_74xx (CPUPPCState *env) #define POWERPC_BFDM_401 (bfd_mach_ppc_403) #define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_401 check_pow_nocheck static void init_proc_401 (CPUPPCState *env) { @@ -3284,6 +3305,14 @@ static void init_proc_401 (CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } +POWERPC_FAMILY(401)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_401; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 401x2 */ #define POWERPC_INSNS_401x2 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_DCR | PPC_WRTEE | \ @@ -3300,7 +3329,6 @@ static void init_proc_401 (CPUPPCState *env) #define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) #define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_401x2 check_pow_nocheck static void init_proc_401x2 (CPUPPCState *env) { @@ -3325,6 +3353,14 @@ static void init_proc_401x2 (CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } +POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_401x2; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 401x3 */ #define POWERPC_INSNS_401x3 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_DCR | PPC_WRTEE | \ @@ -3341,9 +3377,7 @@ static void init_proc_401x2 (CPUPPCState *env) #define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) #define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_401x3 check_pow_nocheck -__attribute__ (( unused )) static void init_proc_401x3 (CPUPPCState *env) { gen_spr_40x(env); @@ -3361,6 +3395,14 @@ static void init_proc_401x3 (CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } +POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_401x3; + pcc->check_pow = check_pow_nocheck; +} + /* IOP480 */ #define POWERPC_INSNS_IOP480 (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_WRTEE | \ @@ -3377,7 +3419,6 @@ static void init_proc_401x3 (CPUPPCState *env) #define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) #define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_IOP480 check_pow_nocheck static void init_proc_IOP480 (CPUPPCState *env) { @@ -3402,6 +3443,14 @@ static void init_proc_IOP480 (CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } +POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_IOP480; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 403 */ #define POWERPC_INSNS_403 (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_WRTEE | \ @@ -3417,7 +3466,6 @@ static void init_proc_IOP480 (CPUPPCState *env) #define POWERPC_BFDM_403 (bfd_mach_ppc_403) #define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_403 check_pow_nocheck static void init_proc_403 (CPUPPCState *env) { @@ -3435,6 +3483,14 @@ static void init_proc_403 (CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } +POWERPC_FAMILY(403)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_403; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 403 GCX */ #define POWERPC_INSNS_403GCX (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_WRTEE | \ @@ -3451,7 +3507,6 @@ static void init_proc_403 (CPUPPCState *env) #define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) #define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_403GCX check_pow_nocheck static void init_proc_403GCX (CPUPPCState *env) { @@ -3488,6 +3543,14 @@ static void init_proc_403GCX (CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } +POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_403GCX; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 405 */ #define POWERPC_INSNS_405 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_DCR | PPC_WRTEE | \ @@ -3504,7 +3567,6 @@ static void init_proc_403GCX (CPUPPCState *env) #define POWERPC_BFDM_405 (bfd_mach_ppc_403) #define POWERPC_FLAG_405 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) -#define check_pow_405 check_pow_nocheck static void init_proc_405 (CPUPPCState *env) { @@ -3540,6 +3602,14 @@ static void init_proc_405 (CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } +POWERPC_FAMILY(405)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_405; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 440 EP */ #define POWERPC_INSNS_440EP (PPC_INSNS_BASE | PPC_STRING | \ PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | \ @@ -3559,7 +3629,6 @@ static void init_proc_405 (CPUPPCState *env) #define POWERPC_BFDM_440EP (bfd_mach_ppc_403) #define POWERPC_FLAG_440EP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) -#define check_pow_440EP check_pow_nocheck static void init_proc_440EP (CPUPPCState *env) { @@ -3627,6 +3696,14 @@ static void init_proc_440EP (CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } +POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_440EP; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 440 GP */ #define POWERPC_INSNS_440GP (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI | \ @@ -3643,9 +3720,7 @@ static void init_proc_440EP (CPUPPCState *env) #define POWERPC_BFDM_440GP (bfd_mach_ppc_403) #define POWERPC_FLAG_440GP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) -#define check_pow_440GP check_pow_nocheck -__attribute__ (( unused )) static void init_proc_440GP (CPUPPCState *env) { /* Time base */ @@ -3694,6 +3769,14 @@ static void init_proc_440GP (CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } +POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_440GP; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 440x4 */ #define POWERPC_INSNS_440x4 (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_WRTEE | \ @@ -3710,9 +3793,7 @@ static void init_proc_440GP (CPUPPCState *env) #define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) #define POWERPC_FLAG_440x4 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) -#define check_pow_440x4 check_pow_nocheck -__attribute__ (( unused )) static void init_proc_440x4 (CPUPPCState *env) { /* Time base */ @@ -3761,6 +3842,14 @@ static void init_proc_440x4 (CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } +POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_440x4; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 440x5 */ #define POWERPC_INSNS_440x5 (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_WRTEE | PPC_RFMCI | \ @@ -3777,7 +3866,6 @@ static void init_proc_440x4 (CPUPPCState *env) #define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) #define POWERPC_FLAG_440x5 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) -#define check_pow_440x5 check_pow_nocheck static void init_proc_440x5 (CPUPPCState *env) { @@ -3845,6 +3933,14 @@ static void init_proc_440x5 (CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } +POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_440x5; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 460 (guessed) */ #define POWERPC_INSNS_460 (PPC_INSNS_BASE | PPC_STRING | \ PPC_DCR | PPC_DCRX | PPC_DCRUX | \ @@ -3862,9 +3958,7 @@ static void init_proc_440x5 (CPUPPCState *env) #define POWERPC_BFDM_460 (bfd_mach_ppc_403) #define POWERPC_FLAG_460 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) -#define check_pow_460 check_pow_nocheck -__attribute__ (( unused )) static void init_proc_460 (CPUPPCState *env) { /* Time base */ @@ -3936,6 +4030,14 @@ static void init_proc_460 (CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } +POWERPC_FAMILY(460)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_460; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 460F (guessed) */ #define POWERPC_INSNS_460F (PPC_INSNS_BASE | PPC_STRING | \ PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | \ @@ -3956,9 +4058,7 @@ static void init_proc_460 (CPUPPCState *env) #define POWERPC_BFDM_460F (bfd_mach_ppc_403) #define POWERPC_FLAG_460F (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) -#define check_pow_460F check_pow_nocheck -__attribute__ (( unused )) static void init_proc_460F (CPUPPCState *env) { /* Time base */ @@ -4030,6 +4130,14 @@ static void init_proc_460F (CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } +POWERPC_FAMILY(460F)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_460F; + pcc->check_pow = check_pow_nocheck; +} + /* Freescale 5xx cores (aka RCPU) */ #define POWERPC_INSNS_MPC5xx (PPC_INSNS_BASE | PPC_STRING | \ PPC_MEM_EIEIO | PPC_MEM_SYNC | \ @@ -4043,9 +4151,7 @@ static void init_proc_460F (CPUPPCState *env) #define POWERPC_BFDM_MPC5xx (bfd_mach_ppc_505) #define POWERPC_FLAG_MPC5xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_MPC5xx check_pow_none -__attribute__ (( unused )) static void init_proc_MPC5xx (CPUPPCState *env) { /* Time base */ @@ -4058,6 +4164,14 @@ static void init_proc_MPC5xx (CPUPPCState *env) /* XXX: TODO: allocate internal IRQ controller */ } +POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_MPC5xx; + pcc->check_pow = check_pow_none; +} + /* Freescale 8xx cores (aka PowerQUICC) */ #define POWERPC_INSNS_MPC8xx (PPC_INSNS_BASE | PPC_STRING | \ PPC_MEM_EIEIO | PPC_MEM_SYNC | \ @@ -4070,9 +4184,7 @@ static void init_proc_MPC5xx (CPUPPCState *env) #define POWERPC_BFDM_MPC8xx (bfd_mach_ppc_860) #define POWERPC_FLAG_MPC8xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_MPC8xx check_pow_none -__attribute__ (( unused )) static void init_proc_MPC8xx (CPUPPCState *env) { /* Time base */ @@ -4085,6 +4197,14 @@ static void init_proc_MPC8xx (CPUPPCState *env) /* XXX: TODO: allocate internal IRQ controller */ } +POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_MPC8xx; + pcc->check_pow = check_pow_none; +} + /* Freescale 82xx cores (aka PowerQUICC-II) */ /* PowerPC G2 */ #define POWERPC_INSNS_G2 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ @@ -4102,7 +4222,6 @@ static void init_proc_MPC8xx (CPUPPCState *env) #define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) -#define check_pow_G2 check_pow_hid0 static void init_proc_G2 (CPUPPCState *env) { @@ -4144,6 +4263,14 @@ static void init_proc_G2 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_G2; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC G2LE */ #define POWERPC_INSNS_G2LE (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -4160,7 +4287,6 @@ static void init_proc_G2 (CPUPPCState *env) #define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) -#define check_pow_G2LE check_pow_hid0 static void init_proc_G2LE (CPUPPCState *env) { @@ -4202,6 +4328,14 @@ static void init_proc_G2LE (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_G2LE; + pcc->check_pow = check_pow_hid0; +} + /* e200 core */ /* XXX: unimplemented instructions: * dcblc @@ -4228,9 +4362,7 @@ static void init_proc_G2LE (CPUPPCState *env) #define POWERPC_FLAG_e200 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_e200 check_pow_hid0 -__attribute__ (( unused )) static void init_proc_e200 (CPUPPCState *env) { /* Time base */ @@ -4338,6 +4470,14 @@ static void init_proc_e200 (CPUPPCState *env) /* XXX: TODO: allocate internal IRQ controller */ } +POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_e200; + pcc->check_pow = check_pow_hid0; +} + /* e300 core */ #define POWERPC_INSNS_e300 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -4354,9 +4494,7 @@ static void init_proc_e200 (CPUPPCState *env) #define POWERPC_BFDM_e300 (bfd_mach_ppc_603) #define POWERPC_FLAG_e300 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) -#define check_pow_e300 check_pow_hid0 -__attribute__ (( unused )) static void init_proc_e300 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4390,6 +4528,14 @@ static void init_proc_e300 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_e300; + pcc->check_pow = check_pow_hid0; +} + /* e500v1 core */ #define POWERPC_INSNS_e500v1 (PPC_INSNS_BASE | PPC_ISEL | \ PPC_SPE | PPC_SPE_SINGLE | \ @@ -4406,8 +4552,6 @@ static void init_proc_e300 (CPUPPCState *env) #define POWERPC_FLAG_e500v1 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_e500v1 check_pow_hid0 -#define init_proc_e500v1 init_proc_e500v1 /* e500v2 core */ #define POWERPC_INSNS_e500v2 (PPC_INSNS_BASE | PPC_ISEL | \ @@ -4425,8 +4569,6 @@ static void init_proc_e300 (CPUPPCState *env) #define POWERPC_FLAG_e500v2 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_e500v2 check_pow_hid0 -#define init_proc_e500v2 init_proc_e500v2 /* e500mc core */ #define POWERPC_INSNS_e500mc (PPC_INSNS_BASE | PPC_ISEL | \ @@ -4446,8 +4588,6 @@ static void init_proc_e300 (CPUPPCState *env) #define POWERPC_BFDM_e500mc (bfd_mach_ppc_e500) #define POWERPC_FLAG_e500mc (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_e500mc check_pow_none -#define init_proc_e500mc init_proc_e500mc /* e5500 core */ #define POWERPC_INSNS_e5500 (PPC_INSNS_BASE | PPC_ISEL | \ @@ -4468,8 +4608,6 @@ static void init_proc_e300 (CPUPPCState *env) #define POWERPC_BFDM_e5500 (bfd_mach_ppc_e500) #define POWERPC_FLAG_e5500 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_e5500 check_pow_none -#define init_proc_e5500 init_proc_e5500 #if !defined(CONFIG_USER_ONLY) static void spr_write_mas73(void *opaque, int sprn, int gprn) @@ -4685,21 +4823,53 @@ static void init_proc_e500v1(CPUPPCState *env) init_proc_e500(env, fsl_e500v1); } +POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_e500v1; + pcc->check_pow = check_pow_hid0; +} + static void init_proc_e500v2(CPUPPCState *env) { init_proc_e500(env, fsl_e500v2); } +POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_e500v2; + pcc->check_pow = check_pow_hid0; +} + static void init_proc_e500mc(CPUPPCState *env) { init_proc_e500(env, fsl_e500mc); } +POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_e500mc; + pcc->check_pow = check_pow_none; +} + #ifdef TARGET_PPC64 static void init_proc_e5500(CPUPPCState *env) { init_proc_e500(env, fsl_e5500); } + +POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_e5500; + pcc->check_pow = check_pow_none; +} #endif /* Non-embedded PowerPC */ @@ -4725,7 +4895,6 @@ static void init_proc_e5500(CPUPPCState *env) #define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601 (bfd_mach_ppc_601) #define POWERPC_FLAG_601 (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK) -#define check_pow_601 check_pow_none static void init_proc_601 (CPUPPCState *env) { @@ -4764,6 +4933,14 @@ static void init_proc_601 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(601)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_601; + pcc->check_pow = check_pow_none; +} + /* PowerPC 601v */ #define POWERPC_INSNS_601v (PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | \ PPC_FLOAT | \ @@ -4778,7 +4955,6 @@ static void init_proc_601 (CPUPPCState *env) #define POWERPC_INPUT_601v (PPC_FLAGS_INPUT_6xx) #define POWERPC_BFDM_601v (bfd_mach_ppc_601) #define POWERPC_FLAG_601v (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK) -#define check_pow_601v check_pow_none static void init_proc_601v (CPUPPCState *env) { @@ -4790,6 +4966,14 @@ static void init_proc_601v (CPUPPCState *env) 0x00000000); } +POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_601v; + pcc->check_pow = check_pow_none; +} + /* PowerPC 602 */ #define POWERPC_INSNS_602 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -4807,7 +4991,6 @@ static void init_proc_601v (CPUPPCState *env) #define POWERPC_BFDM_602 (bfd_mach_ppc_602) #define POWERPC_FLAG_602 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) -#define check_pow_602 check_pow_hid0 static void init_proc_602 (CPUPPCState *env) { @@ -4836,6 +5019,14 @@ static void init_proc_602 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(602)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_602; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 603 */ #define POWERPC_INSNS_603 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -4852,7 +5043,6 @@ static void init_proc_602 (CPUPPCState *env) #define POWERPC_BFDM_603 (bfd_mach_ppc_603) #define POWERPC_FLAG_603 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) -#define check_pow_603 check_pow_hid0 static void init_proc_603 (CPUPPCState *env) { @@ -4881,6 +5071,14 @@ static void init_proc_603 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(603)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_603; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 603e */ #define POWERPC_INSNS_603E (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -4897,7 +5095,6 @@ static void init_proc_603 (CPUPPCState *env) #define POWERPC_BFDM_603E (bfd_mach_ppc_ec603e) #define POWERPC_FLAG_603E (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) -#define check_pow_603E check_pow_hid0 static void init_proc_603E (CPUPPCState *env) { @@ -4931,6 +5128,14 @@ static void init_proc_603E (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_603E; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 604 */ #define POWERPC_INSNS_604 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -4947,7 +5152,6 @@ static void init_proc_603E (CPUPPCState *env) #define POWERPC_BFDM_604 (bfd_mach_ppc_604) #define POWERPC_FLAG_604 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_604 check_pow_nocheck static void init_proc_604 (CPUPPCState *env) { @@ -4970,6 +5174,14 @@ static void init_proc_604 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(604)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_604; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 604E */ #define POWERPC_INSNS_604E (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -4986,7 +5198,6 @@ static void init_proc_604 (CPUPPCState *env) #define POWERPC_BFDM_604E (bfd_mach_ppc_604) #define POWERPC_FLAG_604E (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_604E check_pow_nocheck static void init_proc_604E (CPUPPCState *env) { @@ -5029,6 +5240,14 @@ static void init_proc_604E (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_604E; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 740 */ #define POWERPC_INSNS_740 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5045,7 +5264,6 @@ static void init_proc_604E (CPUPPCState *env) #define POWERPC_BFDM_740 (bfd_mach_ppc_750) #define POWERPC_FLAG_740 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_740 check_pow_hid0 static void init_proc_740 (CPUPPCState *env) { @@ -5075,6 +5293,14 @@ static void init_proc_740 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(740)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_740; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 750 */ #define POWERPC_INSNS_750 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5091,7 +5317,6 @@ static void init_proc_740 (CPUPPCState *env) #define POWERPC_BFDM_750 (bfd_mach_ppc_750) #define POWERPC_FLAG_750 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_750 check_pow_hid0 static void init_proc_750 (CPUPPCState *env) { @@ -5129,6 +5354,14 @@ static void init_proc_750 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(750)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_750; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 750 CL */ /* XXX: not implemented: * cache lock instructions: @@ -5183,7 +5416,6 @@ static void init_proc_750 (CPUPPCState *env) #define POWERPC_BFDM_750cl (bfd_mach_ppc_750) #define POWERPC_FLAG_750cl (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_750cl check_pow_hid0 static void init_proc_750cl (CPUPPCState *env) { @@ -5306,6 +5538,14 @@ static void init_proc_750cl (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_750cl; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 750CX */ #define POWERPC_INSNS_750cx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5322,7 +5562,6 @@ static void init_proc_750cl (CPUPPCState *env) #define POWERPC_BFDM_750cx (bfd_mach_ppc_750) #define POWERPC_FLAG_750cx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_750cx check_pow_hid0 static void init_proc_750cx (CPUPPCState *env) { @@ -5364,6 +5603,14 @@ static void init_proc_750cx (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_750cx; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 750FX */ #define POWERPC_INSNS_750fx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5380,7 +5627,6 @@ static void init_proc_750cx (CPUPPCState *env) #define POWERPC_BFDM_750fx (bfd_mach_ppc_750) #define POWERPC_FLAG_750fx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_750fx check_pow_hid0 static void init_proc_750fx (CPUPPCState *env) { @@ -5427,6 +5673,14 @@ static void init_proc_750fx (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_750fx; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 750GX */ #define POWERPC_INSNS_750gx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5443,7 +5697,6 @@ static void init_proc_750fx (CPUPPCState *env) #define POWERPC_BFDM_750gx (bfd_mach_ppc_750) #define POWERPC_FLAG_750gx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_750gx check_pow_hid0 static void init_proc_750gx (CPUPPCState *env) { @@ -5490,6 +5743,14 @@ static void init_proc_750gx (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_750gx; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 745 */ #define POWERPC_INSNS_745 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5506,7 +5767,6 @@ static void init_proc_750gx (CPUPPCState *env) #define POWERPC_BFDM_745 (bfd_mach_ppc_750) #define POWERPC_FLAG_745 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_745 check_pow_hid0 static void init_proc_745 (CPUPPCState *env) { @@ -5544,6 +5804,14 @@ static void init_proc_745 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(745)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_745; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 755 */ #define POWERPC_INSNS_755 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5560,7 +5828,6 @@ static void init_proc_745 (CPUPPCState *env) #define POWERPC_BFDM_755 (bfd_mach_ppc_750) #define POWERPC_FLAG_755 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_755 check_pow_hid0 static void init_proc_755 (CPUPPCState *env) { @@ -5609,6 +5876,14 @@ static void init_proc_755 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(755)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_755; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 7400 (aka G4) */ #define POWERPC_INSNS_7400 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5630,7 +5905,6 @@ static void init_proc_755 (CPUPPCState *env) #define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7400 check_pow_hid0 static void init_proc_7400 (CPUPPCState *env) { @@ -5662,6 +5936,14 @@ static void init_proc_7400 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_7400; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 7410 (aka G4) */ #define POWERPC_INSNS_7410 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5683,7 +5965,6 @@ static void init_proc_7400 (CPUPPCState *env) #define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7410 check_pow_hid0 static void init_proc_7410 (CPUPPCState *env) { @@ -5721,6 +6002,14 @@ static void init_proc_7410 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_7410; + pcc->check_pow = check_pow_hid0; +} + /* PowerPC 7440 (aka G4) */ #define POWERPC_INSNS_7440 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5742,9 +6031,7 @@ static void init_proc_7410 (CPUPPCState *env) #define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7440 check_pow_hid0_74xx -__attribute__ (( unused )) static void init_proc_7440 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5807,6 +6094,14 @@ static void init_proc_7440 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_7440; + pcc->check_pow = check_pow_hid0_74xx; +} + /* PowerPC 7450 (aka G4) */ #define POWERPC_INSNS_7450 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5828,9 +6123,7 @@ static void init_proc_7440 (CPUPPCState *env) #define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7450 check_pow_hid0_74xx -__attribute__ (( unused )) static void init_proc_7450 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5919,6 +6212,14 @@ static void init_proc_7450 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_7450; + pcc->check_pow = check_pow_hid0_74xx; +} + /* PowerPC 7445 (aka G4) */ #define POWERPC_INSNS_7445 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -5940,9 +6241,7 @@ static void init_proc_7450 (CPUPPCState *env) #define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7445 check_pow_hid0_74xx -__attribute__ (( unused )) static void init_proc_7445 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6034,6 +6333,14 @@ static void init_proc_7445 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_7445; + pcc->check_pow = check_pow_hid0_74xx; +} + /* PowerPC 7455 (aka G4) */ #define POWERPC_INSNS_7455 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6055,9 +6362,7 @@ static void init_proc_7445 (CPUPPCState *env) #define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7455 check_pow_hid0_74xx -__attribute__ (( unused )) static void init_proc_7455 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6151,6 +6456,14 @@ static void init_proc_7455 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_7455; + pcc->check_pow = check_pow_hid0_74xx; +} + /* PowerPC 7457 (aka G4) */ #define POWERPC_INSNS_7457 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6172,9 +6485,7 @@ static void init_proc_7455 (CPUPPCState *env) #define POWERPC_FLAG_7457 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK) -#define check_pow_7457 check_pow_hid0_74xx -__attribute__ (( unused )) static void init_proc_7457 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6292,6 +6603,14 @@ static void init_proc_7457 (CPUPPCState *env) ppc6xx_irq_init(env); } +POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_7457; + pcc->check_pow = check_pow_hid0_74xx; +} + #if defined (TARGET_PPC64) /* PowerPC 970 */ #define POWERPC_INSNS_970 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ @@ -6389,6 +6708,14 @@ static void init_proc_970 (CPUPPCState *env) vscr_init(env, 0x00010000); } +POWERPC_FAMILY(970)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_970; + pcc->check_pow = check_pow_970; +} + /* PowerPC 970FX (aka G5) */ #define POWERPC_INSNS_970FX (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6491,6 +6818,14 @@ static void init_proc_970FX (CPUPPCState *env) vscr_init(env, 0x00010000); } +POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_970FX; + pcc->check_pow = check_pow_970FX; +} + /* PowerPC 970 GX */ #define POWERPC_INSNS_970GX (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6581,6 +6916,14 @@ static void init_proc_970GX (CPUPPCState *env) vscr_init(env, 0x00010000); } +POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_970GX; + pcc->check_pow = check_pow_970GX; +} + /* PowerPC 970 MP */ #define POWERPC_INSNS_970MP (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6671,6 +7014,14 @@ static void init_proc_970MP (CPUPPCState *env) vscr_init(env, 0x00010000); } +POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_970MP; + pcc->check_pow = check_pow_970MP; +} + /* POWER7 */ #define POWERPC_INSNS_POWER7 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6691,7 +7042,6 @@ static void init_proc_970MP (CPUPPCState *env) #define POWERPC_FLAG_POWER7 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR) -#define check_pow_POWER7 check_pow_nocheck static void init_proc_POWER7 (CPUPPCState *env) { @@ -6755,6 +7105,14 @@ static void init_proc_POWER7 (CPUPPCState *env) vscr_init(env, 0x00010000); } +POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_POWER7; + pcc->check_pow = check_pow_nocheck; +} + /* PowerPC 620 */ #define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ @@ -6773,9 +7131,7 @@ static void init_proc_POWER7 (CPUPPCState *env) #define POWERPC_BFDM_620 (bfd_mach_ppc64) #define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) -#define check_pow_620 check_pow_nocheck /* Check this */ -__attribute__ (( unused )) static void init_proc_620 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6796,6 +7152,15 @@ static void init_proc_620 (CPUPPCState *env) /* Allocate hardware IRQ controller */ ppc6xx_irq_init(env); } + +POWERPC_FAMILY(620)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->init_proc = init_proc_620; + pcc->check_pow = check_pow_nocheck; /* Check this */ +} + #endif /* defined (TARGET_PPC64) */ /*****************************************************************************/ @@ -7530,14 +7895,12 @@ enum { pcc->bus_model = glue(POWERPC_INPUT_, _type); \ pcc->bfd_mach = glue(POWERPC_BFDM_, _type); \ pcc->flags = glue(POWERPC_FLAG_, _type); \ - pcc->init_proc = &glue(init_proc_, _type); \ - pcc->check_pow = &glue(check_pow_, _type); \ } \ \ static const TypeInfo \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info) = { \ .name = _name "-" TYPE_POWERPC_CPU, \ - .parent = TYPE_POWERPC_CPU, \ + .parent = stringify(_type) "-family-" TYPE_POWERPC_CPU, \ .class_init = \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init), \ }; \ From 53116ebfc98b72a00297255e216fac87c65e23a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:43 +0000 Subject: [PATCH 1457/1634] target-ppc: Set instruction flags on CPU family classes 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 --- target-ppc/translate_init.c | 994 ++++++++++++++++++------------------ 1 file changed, 499 insertions(+), 495 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index c300aa88e0..06df1613e3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3275,13 +3275,6 @@ static int check_pow_hid0_74xx (CPUPPCState *env) static void glue(glue(ppc_, _name), _cpu_family_class_init) /* PowerPC 401 */ -#define POWERPC_INSNS_401 (PPC_INSNS_BASE | PPC_STRING | \ - PPC_WRTEE | PPC_DCR | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ - PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_4xx_COMMON | PPC_40x_EXCP) -#define POWERPC_INSNS2_401 (PPC_NONE) #define POWERPC_MSRM_401 (0x00000000000FD201ULL) #define POWERPC_MMU_401 (POWERPC_MMU_REAL) #define POWERPC_EXCP_401 (POWERPC_EXCP_40x) @@ -3311,17 +3304,16 @@ POWERPC_FAMILY(401)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_401; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_WRTEE | PPC_DCR | + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | + PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_4xx_COMMON | PPC_40x_EXCP; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 401x2 */ -#define POWERPC_INSNS_401x2 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_DCR | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP) -#define POWERPC_INSNS2_401x2 (PPC_NONE) #define POWERPC_MSRM_401x2 (0x00000000001FD231ULL) #define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) @@ -3359,17 +3351,17 @@ POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_401x2; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_DCR | PPC_WRTEE | + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + 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; } /* PowerPC 401x3 */ -#define POWERPC_INSNS_401x3 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_DCR | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP) -#define POWERPC_INSNS2_401x3 (PPC_NONE) #define POWERPC_MSRM_401x3 (0x00000000001FD631ULL) #define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) @@ -3401,17 +3393,17 @@ POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_401x3; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_DCR | PPC_WRTEE | + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + 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; } /* IOP480 */ -#define POWERPC_INSNS_IOP480 (PPC_INSNS_BASE | PPC_STRING | \ - PPC_DCR | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP) -#define POWERPC_INSNS2_IOP480 (PPC_NONE) #define POWERPC_MSRM_IOP480 (0x00000000001FD231ULL) #define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) @@ -3449,16 +3441,17 @@ POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_IOP480; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_DCR | PPC_WRTEE | + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + 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; } /* PowerPC 403 */ -#define POWERPC_INSNS_403 (PPC_INSNS_BASE | PPC_STRING | \ - PPC_DCR | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ - PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_4xx_COMMON | PPC_40x_EXCP) -#define POWERPC_INSNS2_403 (PPC_NONE) #define POWERPC_MSRM_403 (0x000000000007D00DULL) #define POWERPC_MMU_403 (POWERPC_MMU_REAL) #define POWERPC_EXCP_403 (POWERPC_EXCP_40x) @@ -3489,17 +3482,16 @@ POWERPC_FAMILY(403)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_403; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_DCR | PPC_WRTEE | + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | + PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_4xx_COMMON | PPC_40x_EXCP; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 403 GCX */ -#define POWERPC_INSNS_403GCX (PPC_INSNS_BASE | PPC_STRING | \ - PPC_DCR | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ - PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_40x_EXCP) -#define POWERPC_INSNS2_403GCX (PPC_NONE) #define POWERPC_MSRM_403GCX (0x000000000007D00DULL) #define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z) #define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) @@ -3549,17 +3541,17 @@ POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_403GCX; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_DCR | PPC_WRTEE | + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | + PPC_CACHE_DCBZ | + 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; } /* PowerPC 405 */ -#define POWERPC_INSNS_405 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_DCR | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \ - PPC_4xx_COMMON | PPC_405_MAC | PPC_40x_EXCP) -#define POWERPC_INSNS2_405 (PPC_NONE) #define POWERPC_MSRM_405 (0x000000000006E630ULL) #define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx) #define POWERPC_EXCP_405 (POWERPC_EXCP_40x) @@ -3608,20 +3600,17 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_405; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_DCR | PPC_WRTEE | + PPC_CACHE | PPC_CACHE_ICBI | PPC_40x_ICBT | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + 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; } /* PowerPC 440 EP */ -#define POWERPC_INSNS_440EP (PPC_INSNS_BASE | PPC_STRING | \ - PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_DCR | PPC_WRTEE | PPC_RFMCI | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_MFTB | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define POWERPC_INSNS2_440EP (PPC_NONE) #define POWERPC_MSRM_440EP (0x000000000006FF30ULL) #define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) @@ -3702,17 +3691,20 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_440EP; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_DCR | PPC_WRTEE | PPC_RFMCI | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_MFTB | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 440 GP */ -#define POWERPC_INSNS_440GP (PPC_INSNS_BASE | PPC_STRING | \ - PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define POWERPC_INSNS2_440GP (PPC_NONE) #define POWERPC_MSRM_440GP (0x000000000006FF30ULL) #define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) @@ -3775,17 +3767,17 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_440GP; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_MFAPIDI | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_TLBIVA | PPC_MFTB | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 440x4 */ -#define POWERPC_INSNS_440x4 (PPC_INSNS_BASE | PPC_STRING | \ - PPC_DCR | PPC_WRTEE | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_MFTB | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define POWERPC_INSNS2_440x4 (PPC_NONE) #define POWERPC_MSRM_440x4 (0x000000000006FF30ULL) #define POWERPC_MMU_440x4 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) @@ -3848,17 +3840,17 @@ POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_440x4; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_DCR | PPC_WRTEE | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_MFTB | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 440x5 */ -#define POWERPC_INSNS_440x5 (PPC_INSNS_BASE | PPC_STRING | \ - PPC_DCR | PPC_WRTEE | PPC_RFMCI | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_MFTB | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define POWERPC_INSNS2_440x5 (PPC_NONE) #define POWERPC_MSRM_440x5 (0x000000000006FF30ULL) #define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) @@ -3939,18 +3931,17 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_440x5; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_DCR | PPC_WRTEE | PPC_RFMCI | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_MFTB | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 460 (guessed) */ -#define POWERPC_INSNS_460 (PPC_INSNS_BASE | PPC_STRING | \ - PPC_DCR | PPC_DCRX | PPC_DCRUX | \ - PPC_WRTEE | PPC_MFAPIDI | PPC_MFTB | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVA | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define POWERPC_INSNS2_460 (PPC_NONE) #define POWERPC_MSRM_460 (0x000000000006FF30ULL) #define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) @@ -4036,21 +4027,18 @@ POWERPC_FAMILY(460)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_460; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_DCR | PPC_DCRX | PPC_DCRUX | + PPC_WRTEE | PPC_MFAPIDI | PPC_MFTB | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_TLBIVA | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 460F (guessed) */ -#define POWERPC_INSNS_460F (PPC_INSNS_BASE | PPC_STRING | \ - PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | PPC_MFTB | \ - PPC_DCR | PPC_DCRX | PPC_DCRUX | \ - PPC_WRTEE | PPC_MFAPIDI | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVA | \ - PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \ - PPC_440_SPEC) -#define POWERPC_INSNS2_460F (PPC_NONE) #define POWERPC_MSRM_460 (0x000000000006FF30ULL) #define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) #define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) @@ -4136,14 +4124,21 @@ POWERPC_FAMILY(460F)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_460F; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | PPC_MFTB | + PPC_DCR | PPC_DCRX | PPC_DCRUX | + PPC_WRTEE | PPC_MFAPIDI | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_TLBIVA | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->insns_flags2 = PPC_NONE; } /* Freescale 5xx cores (aka RCPU) */ -#define POWERPC_INSNS_MPC5xx (PPC_INSNS_BASE | PPC_STRING | \ - PPC_MEM_EIEIO | PPC_MEM_SYNC | \ - PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | \ - PPC_MFTB) -#define POWERPC_INSNS2_MPC5xx (PPC_NONE) #define POWERPC_MSRM_MPC5xx (0x000000000001FF43ULL) #define POWERPC_MMU_MPC5xx (POWERPC_MMU_REAL) #define POWERPC_EXCP_MPC5xx (POWERPC_EXCP_603) @@ -4170,13 +4165,14 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_MPC5xx; pcc->check_pow = check_pow_none; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_MEM_EIEIO | PPC_MEM_SYNC | + PPC_CACHE_ICBI | PPC_FLOAT | PPC_FLOAT_STFIWX | + PPC_MFTB; + pcc->insns_flags2 = PPC_NONE; } /* Freescale 8xx cores (aka PowerQUICC) */ -#define POWERPC_INSNS_MPC8xx (PPC_INSNS_BASE | PPC_STRING | \ - PPC_MEM_EIEIO | PPC_MEM_SYNC | \ - PPC_CACHE_ICBI | PPC_MFTB) -#define POWERPC_INSNS2_MPC8xx (PPC_NONE) #define POWERPC_MSRM_MPC8xx (0x000000000001F673ULL) #define POWERPC_MMU_MPC8xx (POWERPC_MMU_MPC8xx) #define POWERPC_EXCP_MPC8xx (POWERPC_EXCP_603) @@ -4203,18 +4199,14 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_MPC8xx; pcc->check_pow = check_pow_none; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_MEM_EIEIO | PPC_MEM_SYNC | + PPC_CACHE_ICBI | PPC_MFTB; + pcc->insns_flags2 = PPC_NONE; } /* Freescale 82xx cores (aka PowerQUICC-II) */ /* PowerPC G2 */ -#define POWERPC_INSNS_G2 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_G2 (PPC_NONE) #define POWERPC_MSRM_G2 (0x000000000006FFF2ULL) #define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) @@ -4269,17 +4261,17 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_G2; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC G2LE */ -#define POWERPC_INSNS_G2LE (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_G2LE (PPC_NONE) #define POWERPC_MSRM_G2LE (0x000000000007FFF3ULL) #define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx) #define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) @@ -4334,26 +4326,17 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_G2LE; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* e200 core */ -/* XXX: unimplemented instructions: - * dcblc - * dcbtlst - * dcbtstls - * icblc - * icbtls - * tlbivax - * all SPE multiply-accumulate instructions - */ -#define POWERPC_INSNS_e200 (PPC_INSNS_BASE | PPC_ISEL | \ - PPC_SPE | PPC_SPE_SINGLE | \ - PPC_WRTEE | PPC_RFDI | \ - PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX | \ - PPC_BOOKE) -#define POWERPC_INSNS2_e200 (PPC_NONE) #define POWERPC_MSRM_e200 (0x000000000606FF30ULL) #define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE206) #define POWERPC_EXCP_e200 (POWERPC_EXCP_BOOKE) @@ -4476,17 +4459,26 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_e200; pcc->check_pow = check_pow_hid0; + /* XXX: unimplemented instructions: + * dcblc + * dcbtlst + * dcbtstls + * icblc + * icbtls + * tlbivax + * all SPE multiply-accumulate instructions + */ + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | + PPC_SPE | PPC_SPE_SINGLE | + PPC_WRTEE | PPC_RFDI | + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_TLBIVAX | + PPC_BOOKE; + pcc->insns_flags2 = PPC_NONE; } /* e300 core */ -#define POWERPC_INSNS_e300 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_e300 (PPC_NONE) #define POWERPC_MSRM_e300 (0x000000000007FFF3ULL) #define POWERPC_MMU_e300 (POWERPC_MMU_SOFT_6xx) #define POWERPC_EXCP_e300 (POWERPC_EXCP_603) @@ -4534,16 +4526,17 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_e300; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* e500v1 core */ -#define POWERPC_INSNS_e500v1 (PPC_INSNS_BASE | PPC_ISEL | \ - PPC_SPE | PPC_SPE_SINGLE | \ - PPC_WRTEE | PPC_RFDI | \ - PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC) -#define POWERPC_INSNS2_e500v1 (PPC2_BOOKE206) #define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL) #define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE206) #define POWERPC_EXCP_e500v1 (POWERPC_EXCP_BOOKE) @@ -4554,13 +4547,6 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK) /* e500v2 core */ -#define POWERPC_INSNS_e500v2 (PPC_INSNS_BASE | PPC_ISEL | \ - PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE | \ - PPC_WRTEE | PPC_RFDI | \ - PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC) -#define POWERPC_INSNS2_e500v2 (PPC2_BOOKE206) #define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL) #define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE206) #define POWERPC_EXCP_e500v2 (POWERPC_EXCP_BOOKE) @@ -4571,15 +4557,6 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK) /* e500mc core */ -#define POWERPC_INSNS_e500mc (PPC_INSNS_BASE | PPC_ISEL | \ - PPC_WRTEE | PPC_RFDI | PPC_RFMCI | \ - PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_FLOAT | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ - PPC_FLOAT_STFIWX | PPC_WAIT | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC) -#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206 | PPC2_PRCNTL) #define POWERPC_MSRM_e500mc (0x000000001402FB36ULL) #define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206) #define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE) @@ -4590,16 +4567,6 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) /* e5500 core */ -#define POWERPC_INSNS_e5500 (PPC_INSNS_BASE | PPC_ISEL | \ - PPC_WRTEE | PPC_RFDI | PPC_RFMCI | \ - PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ - PPC_FLOAT | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \ - PPC_FLOAT_STFIWX | PPC_WAIT | \ - PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | \ - PPC_64B | PPC_POPCNTB | PPC_POPCNTWD) -#define POWERPC_INSNS2_e5500 (PPC2_BOOKE206 | PPC2_PRCNTL) #define POWERPC_MSRM_e5500 (0x000000009402FB36ULL) #define POWERPC_MMU_e5500 (POWERPC_MMU_BOOKE206) #define POWERPC_EXCP_e5500 (POWERPC_EXCP_BOOKE) @@ -4829,6 +4796,13 @@ POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_e500v1; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | + PPC_SPE | PPC_SPE_SINGLE | + PPC_WRTEE | PPC_RFDI | + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; + pcc->insns_flags2 = PPC2_BOOKE206; } static void init_proc_e500v2(CPUPPCState *env) @@ -4842,6 +4816,13 @@ POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_e500v2; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | + PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE | + PPC_WRTEE | PPC_RFDI | + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; + pcc->insns_flags2 = PPC2_BOOKE206; } static void init_proc_e500mc(CPUPPCState *env) @@ -4855,6 +4836,15 @@ POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_e500mc; pcc->check_pow = check_pow_none; + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | + PPC_WRTEE | PPC_RFDI | PPC_RFMCI | + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_FLOAT | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | + PPC_FLOAT_STFIWX | PPC_WAIT | + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL; } #ifdef TARGET_PPC64 @@ -4869,6 +4859,16 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_e5500; pcc->check_pow = check_pow_none; + pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | + PPC_WRTEE | PPC_RFDI | PPC_RFMCI | + PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_FLOAT | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | + PPC_FLOAT_STFIWX | PPC_WAIT | + PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | + PPC_64B | PPC_POPCNTB | PPC_POPCNTWD; + pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL; } #endif @@ -4876,18 +4876,18 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) /* POWER : same as 601, without mfmsr, mfsr */ #if defined(TODO) -#define POWERPC_INSNS_POWER (XXX_TODO) /* POWER RSC (from RAD6000) */ #define POWERPC_MSRM_POWER (0x00000000FEF0ULL) + +POWERPC_FAMILY(POWER)(ObjectClass *oc, void *data) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + pcc->insns_flags = XXX_TODO; +} #endif /* TODO */ /* PowerPC 601 */ -#define POWERPC_INSNS_601 (PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | \ - PPC_FLOAT | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_601 (PPC_NONE) #define POWERPC_MSRM_601 (0x000000000000FD70ULL) #define POWERPC_MSRR_601 (0x0000000000001040ULL) //#define POWERPC_MMU_601 (POWERPC_MMU_601) @@ -4939,15 +4939,15 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_601; pcc->check_pow = check_pow_none; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | + PPC_FLOAT | + 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; } /* PowerPC 601v */ -#define POWERPC_INSNS_601v (PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | \ - PPC_FLOAT | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_601v (PPC_NONE) #define POWERPC_MSRM_601v (0x000000000000FD70ULL) #define POWERPC_MSRR_601v (0x0000000000001040ULL) #define POWERPC_MMU_601v (POWERPC_MMU_601) @@ -4972,17 +4972,15 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_601v; pcc->check_pow = check_pow_none; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | + PPC_FLOAT | + 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; } /* PowerPC 602 */ -#define POWERPC_INSNS_602 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_6xx_TLB | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_602_SPEC) -#define POWERPC_INSNS2_602 (PPC_NONE) #define POWERPC_MSRM_602 (0x0000000000C7FF73ULL) /* XXX: 602 MMU is quite specific. Should add a special case */ #define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx) @@ -5025,17 +5023,17 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_602; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + 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; } /* PowerPC 603 */ -#define POWERPC_INSNS_603 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_603 (PPC_NONE) #define POWERPC_MSRM_603 (0x000000000007FF73ULL) #define POWERPC_MMU_603 (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_603 (POWERPC_EXCP_603) @@ -5077,17 +5075,17 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_603; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 603e */ -#define POWERPC_INSNS_603E (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_603E (PPC_NONE) #define POWERPC_MSRM_603E (0x000000000007FF73ULL) #define POWERPC_MMU_603E (POWERPC_MMU_SOFT_6xx) //#define POWERPC_EXCP_603E (POWERPC_EXCP_603E) @@ -5134,17 +5132,17 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_603E; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 604 */ -#define POWERPC_INSNS_604 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_604 (PPC_NONE) #define POWERPC_MSRM_604 (0x000000000005FF77ULL) #define POWERPC_MMU_604 (POWERPC_MMU_32B) //#define POWERPC_EXCP_604 (POWERPC_EXCP_604) @@ -5180,17 +5178,17 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_604; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 604E */ -#define POWERPC_INSNS_604E (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_604E (PPC_NONE) #define POWERPC_MSRM_604E (0x000000000005FF77ULL) #define POWERPC_MMU_604E (POWERPC_MMU_32B) #define POWERPC_EXCP_604E (POWERPC_EXCP_604) @@ -5246,17 +5244,17 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_604E; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 740 */ -#define POWERPC_INSNS_740 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_740 (PPC_NONE) #define POWERPC_MSRM_740 (0x000000000005FF77ULL) #define POWERPC_MMU_740 (POWERPC_MMU_32B) #define POWERPC_EXCP_740 (POWERPC_EXCP_7x0) @@ -5299,17 +5297,17 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_740; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 750 */ -#define POWERPC_INSNS_750 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_750 (PPC_NONE) #define POWERPC_MSRM_750 (0x000000000005FF77ULL) #define POWERPC_MMU_750 (POWERPC_MMU_32B) #define POWERPC_EXCP_750 (POWERPC_EXCP_7x0) @@ -5360,55 +5358,17 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_750; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 750 CL */ -/* XXX: not implemented: - * cache lock instructions: - * dcbz_l - * floating point paired instructions - * psq_lux - * psq_lx - * psq_stux - * psq_stx - * ps_abs - * ps_add - * ps_cmpo0 - * ps_cmpo1 - * ps_cmpu0 - * ps_cmpu1 - * ps_div - * ps_madd - * ps_madds0 - * ps_madds1 - * ps_merge00 - * ps_merge01 - * ps_merge10 - * ps_merge11 - * ps_mr - * ps_msub - * ps_mul - * ps_muls0 - * ps_muls1 - * ps_nabs - * ps_neg - * ps_nmadd - * ps_nmsub - * ps_res - * ps_rsqrte - * ps_sel - * ps_sub - * ps_sum0 - * ps_sum1 - */ -#define POWERPC_INSNS_750cl (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_750cl (PPC_NONE) #define POWERPC_MSRM_750cl (0x000000000005FF77ULL) #define POWERPC_MMU_750cl (POWERPC_MMU_32B) #define POWERPC_EXCP_750cl (POWERPC_EXCP_7x0) @@ -5544,17 +5504,55 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_750cl; pcc->check_pow = check_pow_hid0; + /* XXX: not implemented: + * cache lock instructions: + * dcbz_l + * floating point paired instructions + * psq_lux + * psq_lx + * psq_stux + * psq_stx + * ps_abs + * ps_add + * ps_cmpo0 + * ps_cmpo1 + * ps_cmpu0 + * ps_cmpu1 + * ps_div + * ps_madd + * ps_madds0 + * ps_madds1 + * ps_merge00 + * ps_merge01 + * ps_merge10 + * ps_merge11 + * ps_mr + * ps_msub + * ps_mul + * ps_muls0 + * ps_muls1 + * ps_nabs + * ps_neg + * ps_nmadd + * ps_nmsub + * ps_res + * ps_rsqrte + * ps_sel + * ps_sub + * ps_sum0 + * ps_sum1 + */ + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 750CX */ -#define POWERPC_INSNS_750cx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_750cx (PPC_NONE) #define POWERPC_MSRM_750cx (0x000000000005FF77ULL) #define POWERPC_MMU_750cx (POWERPC_MMU_32B) #define POWERPC_EXCP_750cx (POWERPC_EXCP_7x0) @@ -5609,17 +5607,17 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_750cx; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 750FX */ -#define POWERPC_INSNS_750fx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_750fx (PPC_NONE) #define POWERPC_MSRM_750fx (0x000000000005FF77ULL) #define POWERPC_MMU_750fx (POWERPC_MMU_32B) #define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0) @@ -5679,17 +5677,17 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_750fx; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 750GX */ -#define POWERPC_INSNS_750gx (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_750gx (PPC_NONE) #define POWERPC_MSRM_750gx (0x000000000005FF77ULL) #define POWERPC_MMU_750gx (POWERPC_MMU_32B) #define POWERPC_EXCP_750gx (POWERPC_EXCP_7x0) @@ -5749,17 +5747,17 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_750gx; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 745 */ -#define POWERPC_INSNS_745 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_745 (PPC_NONE) #define POWERPC_MSRM_745 (0x000000000005FF77ULL) #define POWERPC_MMU_745 (POWERPC_MMU_SOFT_6xx) #define POWERPC_EXCP_745 (POWERPC_EXCP_7x5) @@ -5810,17 +5808,17 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_745; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 755 */ -#define POWERPC_INSNS_755 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN) -#define POWERPC_INSNS2_755 (PPC_NONE) #define POWERPC_MSRM_755 (0x000000000005FF77ULL) #define POWERPC_MMU_755 (POWERPC_MMU_SOFT_6xx) #define POWERPC_EXCP_755 (POWERPC_EXCP_7x5) @@ -5882,21 +5880,17 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_755; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | PPC_6xx_TLB | + PPC_SEGMENT | PPC_EXTERN; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 7400 (aka G4) */ -#define POWERPC_INSNS_7400 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_MEM_TLBIA | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_ALTIVEC) -#define POWERPC_INSNS2_7400 (PPC_NONE) #define POWERPC_MSRM_7400 (0x000000000205FF77ULL) #define POWERPC_MMU_7400 (POWERPC_MMU_32B) #define POWERPC_EXCP_7400 (POWERPC_EXCP_74xx) @@ -5942,21 +5936,21 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_7400; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 7410 (aka G4) */ -#define POWERPC_INSNS_7410 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_MEM_TLBIA | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_ALTIVEC) -#define POWERPC_INSNS2_7410 (PPC_NONE) #define POWERPC_MSRM_7410 (0x000000000205FF77ULL) #define POWERPC_MMU_7410 (POWERPC_MMU_32B) #define POWERPC_EXCP_7410 (POWERPC_EXCP_74xx) @@ -6008,21 +6002,21 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_7410; pcc->check_pow = check_pow_hid0; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 7440 (aka G4) */ -#define POWERPC_INSNS_7440 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_MEM_TLBIA | PPC_74xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_ALTIVEC) -#define POWERPC_INSNS2_7440 (PPC_NONE) #define POWERPC_MSRM_7440 (0x000000000205FF77ULL) #define POWERPC_MMU_7440 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7440 (POWERPC_EXCP_74xx) @@ -6100,21 +6094,21 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_7440; pcc->check_pow = check_pow_hid0_74xx; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | PPC_74xx_TLB | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 7450 (aka G4) */ -#define POWERPC_INSNS_7450 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_MEM_TLBIA | PPC_74xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_ALTIVEC) -#define POWERPC_INSNS2_7450 (PPC_NONE) #define POWERPC_MSRM_7450 (0x000000000205FF77ULL) #define POWERPC_MMU_7450 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7450 (POWERPC_EXCP_74xx) @@ -6218,21 +6212,21 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_7450; pcc->check_pow = check_pow_hid0_74xx; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | PPC_74xx_TLB | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 7445 (aka G4) */ -#define POWERPC_INSNS_7445 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_MEM_TLBIA | PPC_74xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_ALTIVEC) -#define POWERPC_INSNS2_7445 (PPC_NONE) #define POWERPC_MSRM_7445 (0x000000000205FF77ULL) #define POWERPC_MMU_7445 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7445 (POWERPC_EXCP_74xx) @@ -6339,21 +6333,21 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_7445; pcc->check_pow = check_pow_hid0_74xx; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | PPC_74xx_TLB | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 7455 (aka G4) */ -#define POWERPC_INSNS_7455 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_MEM_TLBIA | PPC_74xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_ALTIVEC) -#define POWERPC_INSNS2_7455 (PPC_NONE) #define POWERPC_MSRM_7455 (0x000000000205FF77ULL) #define POWERPC_MMU_7455 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7455 (POWERPC_EXCP_74xx) @@ -6462,21 +6456,21 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_7455; pcc->check_pow = check_pow_hid0_74xx; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | PPC_74xx_TLB | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 7457 (aka G4) */ -#define POWERPC_INSNS_7457 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | \ - PPC_CACHE_DCBA | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_MEM_TLBIA | PPC_74xx_TLB | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_ALTIVEC) -#define POWERPC_INSNS2_7457 (PPC_NONE) #define POWERPC_MSRM_7457 (0x000000000205FF77ULL) #define POWERPC_MMU_7457 (POWERPC_MMU_SOFT_74xx) #define POWERPC_EXCP_7457 (POWERPC_EXCP_74xx) @@ -6609,20 +6603,22 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_7457; pcc->check_pow = check_pow_hid0_74xx; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | PPC_74xx_TLB | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; } #if defined (TARGET_PPC64) /* PowerPC 970 */ -#define POWERPC_INSNS_970 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_64B | PPC_ALTIVEC | \ - PPC_SEGMENT_64B | PPC_SLBI) -#define POWERPC_INSNS2_970 (PPC_NONE) #define POWERPC_MSRM_970 (0x900000000204FF36ULL) #define POWERPC_MMU_970 (POWERPC_MMU_64B) //#define POWERPC_EXCP_970 (POWERPC_EXCP_970) @@ -6714,19 +6710,19 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_970; pcc->check_pow = check_pow_970; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 970FX (aka G5) */ -#define POWERPC_INSNS_970FX (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_64B | PPC_ALTIVEC | \ - PPC_SEGMENT_64B | PPC_SLBI) -#define POWERPC_INSNS2_970FX (PPC_NONE) #define POWERPC_MSRM_970FX (0x800000000204FF36ULL) #define POWERPC_MMU_970FX (POWERPC_MMU_64B) #define POWERPC_EXCP_970FX (POWERPC_EXCP_970) @@ -6824,19 +6820,19 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_970FX; pcc->check_pow = check_pow_970FX; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 970 GX */ -#define POWERPC_INSNS_970GX (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_64B | PPC_ALTIVEC | \ - PPC_SEGMENT_64B | PPC_SLBI) -#define POWERPC_INSNS2_970GX (PPC_NONE) #define POWERPC_MSRM_970GX (0x800000000204FF36ULL) #define POWERPC_MMU_970GX (POWERPC_MMU_64B) #define POWERPC_EXCP_970GX (POWERPC_EXCP_970) @@ -6922,19 +6918,19 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_970GX; pcc->check_pow = check_pow_970GX; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI; + pcc->insns_flags2 = PPC_NONE; } /* PowerPC 970 MP */ -#define POWERPC_INSNS_970MP (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_64B | PPC_ALTIVEC | \ - PPC_SEGMENT_64B | PPC_SLBI) -#define POWERPC_INSNS2_970MP (PPC_NONE) #define POWERPC_MSRM_970MP (0x900000000204FF36ULL) #define POWERPC_MMU_970MP (POWERPC_MMU_64B) #define POWERPC_EXCP_970MP (POWERPC_EXCP_970) @@ -7020,20 +7016,19 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_970MP; pcc->check_pow = check_pow_970MP; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI; + pcc->insns_flags2 = PPC_NONE; } /* POWER7 */ -#define POWERPC_INSNS_POWER7 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_64B | PPC_ALTIVEC | \ - PPC_SEGMENT_64B | PPC_SLBI | \ - PPC_POPCNTB | PPC_POPCNTWD) -#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP | PPC2_DBRX) #define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) #define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) #define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) @@ -7111,19 +7106,20 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI | + PPC_POPCNTB | PPC_POPCNTWD; + pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX; } /* PowerPC 620 */ -#define POWERPC_INSNS_620 (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | \ - PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | \ - PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \ - PPC_FLOAT_STFIWX | \ - PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | \ - PPC_MEM_SYNC | PPC_MEM_EIEIO | \ - PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | \ - PPC_SEGMENT | PPC_EXTERN | \ - PPC_64B | PPC_SLBI) -#define POWERPC_INSNS2_620 (PPC_NONE) #define POWERPC_MSRM_620 (0x800000000005FF77ULL) //#define POWERPC_MMU_620 (POWERPC_MMU_620) #define POWERPC_EXCP_620 (POWERPC_EXCP_970) @@ -7159,6 +7155,16 @@ POWERPC_FAMILY(620)(ObjectClass *oc, void *data) pcc->init_proc = init_proc_620; pcc->check_pow = check_pow_nocheck; /* Check this */ + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_SEGMENT | PPC_EXTERN | + PPC_64B | PPC_SLBI; + pcc->insns_flags2 = PPC_NONE; } #endif /* defined (TARGET_PPC64) */ @@ -7887,8 +7893,6 @@ enum { \ pcc->pvr = _pvr; \ pcc->svr = _svr; \ - pcc->insns_flags = glue(POWERPC_INSNS_, _type); \ - pcc->insns_flags2 = glue(POWERPC_INSNS2_, _type); \ pcc->msr_mask = glue(POWERPC_MSRM_, _type); \ pcc->mmu_model = glue(POWERPC_MMU_, _type); \ pcc->excp_model = glue(POWERPC_EXCP_, _type); \ From 4d7fb187e07b35dcbe51e906927a94ed691e0c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:44 +0000 Subject: [PATCH 1458/1634] target-ppc: Register all types for TARGET_PPCEMB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't attempt to suppress registration of CPU types, since the criteria is actually a property of the class and should thus become a field. Since we can't check a field set in a class_init function before registering the type that leads to execution of that function, guard the -cpu class lookup instead and suppress exposing these classes in -cpu ? and in QMP. In case someone tries to hot-add an incompatible CPU via device_add, error out in realize. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 43 +++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 06df1613e3..ca5602842d 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7876,14 +7876,6 @@ enum { /* PowerPC CPU definitions */ #define POWERPC_DEF_PREFIX(pvr, svr, type) \ glue(glue(glue(glue(pvr, _), svr), _), type) -#if defined(TARGET_PPCEMB) -#define POWERPC_DEF_CONDITION(type) \ - if (glue(POWERPC_MMU_, type) != POWERPC_MMU_BOOKE) { \ - return; \ - } -#else -#define POWERPC_DEF_CONDITION(type) -#endif #define POWERPC_DEF_SVR(_name, _pvr, _svr, _type) \ static void \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ @@ -7912,7 +7904,6 @@ enum { static void \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)(void) \ { \ - POWERPC_DEF_CONDITION(_type) \ type_register_static( \ &glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info)); \ } \ @@ -10040,6 +10031,15 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) } } +#if defined(TARGET_PPCEMB) + if (pcc->mmu_model != POWERPC_MMU_BOOKE) { + error_setg(errp, "CPU does not possess a BookE MMU. " + "Please use qemu-system-ppc or qemu-system-ppc64 instead " + "or choose another CPU model."); + return; + } +#endif + create_ppc_opcodes(cpu, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); @@ -10239,6 +10239,12 @@ static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) return -1; } +#if defined(TARGET_PPCEMB) + if (pcc->mmu_model != POWERPC_MMU_BOOKE) { + return -1; + } +#endif + return pcc->pvr == pvr ? 0 : -1; } @@ -10261,8 +10267,14 @@ static gint ppc_cpu_compare_class_name(gconstpointer a, gconstpointer b) { ObjectClass *oc = (ObjectClass *)a; const char *name = b; +#if defined(TARGET_PPCEMB) + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); +#endif if (strncasecmp(name, object_class_get_name(oc), strlen(name)) == 0 && +#if defined(TARGET_PPCEMB) + pcc->mmu_model == POWERPC_MMU_BOOKE && +#endif strcmp(object_class_get_name(oc) + strlen(name), "-" TYPE_POWERPC_CPU) == 0) { return 0; @@ -10381,6 +10393,12 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) const char *typename = object_class_get_name(oc); char *name; +#if defined(TARGET_PPCEMB) + if (pcc->mmu_model != POWERPC_MMU_BOOKE) { + return; + } +#endif + name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", @@ -10421,6 +10439,13 @@ static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) const char *typename; CpuDefinitionInfoList *entry; CpuDefinitionInfo *info; +#if defined(TARGET_PPCEMB) + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + if (pcc->mmu_model != POWERPC_MMU_BOOKE) { + return; + } +#endif typename = object_class_get_name(oc); info = g_malloc0(sizeof(*info)); From ba9fd9f1509c9729286a1071e217db9df05e6896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:45 +0000 Subject: [PATCH 1459/1634] target-ppc: Set remaining fields on CPU family classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now POWERPC_DEF_SVR() no longer sets family-specific fields itself. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 805 +++++++++++++++++------------------- 1 file changed, 375 insertions(+), 430 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ca5602842d..eea9adf6f3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3275,14 +3275,6 @@ static int check_pow_hid0_74xx (CPUPPCState *env) static void glue(glue(ppc_, _name), _cpu_family_class_init) /* PowerPC 401 */ -#define POWERPC_MSRM_401 (0x00000000000FD201ULL) -#define POWERPC_MMU_401 (POWERPC_MMU_REAL) -#define POWERPC_EXCP_401 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_401 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_401 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_401 (CPUPPCState *env) { gen_spr_40x(env); @@ -3311,17 +3303,16 @@ POWERPC_FAMILY(401)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_401; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 401x2 */ -#define POWERPC_MSRM_401x2 (0x00000000001FD231ULL) -#define POWERPC_MMU_401x2 (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_401x2 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_401x2 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_401x2 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x2 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_401x2 (CPUPPCState *env) { gen_spr_40x(env); @@ -3359,17 +3350,16 @@ POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_401; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 401x3 */ -#define POWERPC_MSRM_401x3 (0x00000000001FD631ULL) -#define POWERPC_MMU_401x3 (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_401x3 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_401x3 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_401x3 (bfd_mach_ppc_403) -#define POWERPC_FLAG_401x3 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_401x3 (CPUPPCState *env) { gen_spr_40x(env); @@ -3401,17 +3391,16 @@ POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_401; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | + POWERPC_FLAG_BUS_CLK; } /* IOP480 */ -#define POWERPC_MSRM_IOP480 (0x00000000001FD231ULL) -#define POWERPC_MMU_IOP480 (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_IOP480 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_IOP480 (bfd_mach_ppc_403) -#define POWERPC_FLAG_IOP480 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_IOP480 (CPUPPCState *env) { gen_spr_40x(env); @@ -3449,17 +3438,16 @@ POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_401; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 403 */ -#define POWERPC_MSRM_403 (0x000000000007D00DULL) -#define POWERPC_MMU_403 (POWERPC_MMU_REAL) -#define POWERPC_EXCP_403 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_403 (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_403 (bfd_mach_ppc_403) -#define POWERPC_FLAG_403 (POWERPC_FLAG_CE | POWERPC_FLAG_PX | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_403 (CPUPPCState *env) { gen_spr_40x(env); @@ -3489,17 +3477,16 @@ POWERPC_FAMILY(403)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_401; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_PX | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 403 GCX */ -#define POWERPC_MSRM_403GCX (0x000000000007D00DULL) -#define POWERPC_MMU_403GCX (POWERPC_MMU_SOFT_4xx_Z) -#define POWERPC_EXCP_403GCX (POWERPC_EXCP_40x) -#define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401) -#define POWERPC_BFDM_403GCX (bfd_mach_ppc_403) -#define POWERPC_FLAG_403GCX (POWERPC_FLAG_CE | POWERPC_FLAG_PX | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_403GCX (CPUPPCState *env) { gen_spr_40x(env); @@ -3549,17 +3536,16 @@ POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_401; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_PX | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 405 */ -#define POWERPC_MSRM_405 (0x000000000006E630ULL) -#define POWERPC_MMU_405 (POWERPC_MMU_SOFT_4xx) -#define POWERPC_EXCP_405 (POWERPC_EXCP_40x) -#define POWERPC_INPUT_405 (PPC_FLAGS_INPUT_405) -#define POWERPC_BFDM_405 (bfd_mach_ppc_403) -#define POWERPC_FLAG_405 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) - static void init_proc_405 (CPUPPCState *env) { /* Time base */ @@ -3608,17 +3594,16 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_405; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 440 EP */ -#define POWERPC_MSRM_440EP (0x000000000006FF30ULL) -#define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440EP (bfd_mach_ppc_403) -#define POWERPC_FLAG_440EP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) - static void init_proc_440EP (CPUPPCState *env) { /* Time base */ @@ -3702,17 +3687,16 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 440 GP */ -#define POWERPC_MSRM_440GP (0x000000000006FF30ULL) -#define POWERPC_MMU_440GP (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440GP (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440GP (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440GP (bfd_mach_ppc_403) -#define POWERPC_FLAG_440GP (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) - static void init_proc_440GP (CPUPPCState *env) { /* Time base */ @@ -3775,17 +3759,16 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 440x4 */ -#define POWERPC_MSRM_440x4 (0x000000000006FF30ULL) -#define POWERPC_MMU_440x4 (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440x4 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440x4 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440x4 (bfd_mach_ppc_403) -#define POWERPC_FLAG_440x4 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) - static void init_proc_440x4 (CPUPPCState *env) { /* Time base */ @@ -3848,17 +3831,16 @@ POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 440x5 */ -#define POWERPC_MSRM_440x5 (0x000000000006FF30ULL) -#define POWERPC_MMU_440x5 (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_440x5 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_440x5 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_440x5 (bfd_mach_ppc_403) -#define POWERPC_FLAG_440x5 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) - static void init_proc_440x5 (CPUPPCState *env) { /* Time base */ @@ -3939,17 +3921,16 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 460 (guessed) */ -#define POWERPC_MSRM_460 (0x000000000006FF30ULL) -#define POWERPC_MMU_460 (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_460 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_460 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_460 (bfd_mach_ppc_403) -#define POWERPC_FLAG_460 (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) - static void init_proc_460 (CPUPPCState *env) { /* Time base */ @@ -4036,17 +4017,16 @@ POWERPC_FAMILY(460)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 460F (guessed) */ -#define POWERPC_MSRM_460 (0x000000000006FF30ULL) -#define POWERPC_MMU_460F (POWERPC_MMU_BOOKE) -#define POWERPC_EXCP_460F (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_460F (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_460F (bfd_mach_ppc_403) -#define POWERPC_FLAG_460F (POWERPC_FLAG_CE | POWERPC_FLAG_DWE | \ - POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK) - static void init_proc_460F (CPUPPCState *env) { /* Time base */ @@ -4136,17 +4116,16 @@ POWERPC_FAMILY(460F)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } /* Freescale 5xx cores (aka RCPU) */ -#define POWERPC_MSRM_MPC5xx (0x000000000001FF43ULL) -#define POWERPC_MMU_MPC5xx (POWERPC_MMU_REAL) -#define POWERPC_EXCP_MPC5xx (POWERPC_EXCP_603) -#define POWERPC_INPUT_MPC5xx (PPC_FLAGS_INPUT_RCPU) -#define POWERPC_BFDM_MPC5xx (bfd_mach_ppc_505) -#define POWERPC_FLAG_MPC5xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_MPC5xx (CPUPPCState *env) { /* Time base */ @@ -4170,17 +4149,16 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_RCPU; + pcc->bfd_mach = bfd_mach_ppc_505; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_BUS_CLK; } /* Freescale 8xx cores (aka PowerQUICC) */ -#define POWERPC_MSRM_MPC8xx (0x000000000001F673ULL) -#define POWERPC_MMU_MPC8xx (POWERPC_MMU_MPC8xx) -#define POWERPC_EXCP_MPC8xx (POWERPC_EXCP_603) -#define POWERPC_INPUT_MPC8xx (PPC_FLAGS_INPUT_RCPU) -#define POWERPC_BFDM_MPC8xx (bfd_mach_ppc_860) -#define POWERPC_FLAG_MPC8xx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_MPC8xx (CPUPPCState *env) { /* Time base */ @@ -4203,18 +4181,17 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_RCPU; + pcc->bfd_mach = bfd_mach_ppc_860; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_BUS_CLK; } /* Freescale 82xx cores (aka PowerQUICC-II) */ /* PowerPC G2 */ -#define POWERPC_MSRM_G2 (0x000000000006FFF2ULL) -#define POWERPC_MMU_G2 (POWERPC_MMU_SOFT_6xx) -//#define POWERPC_EXCP_G2 (POWERPC_EXCP_G2) -#define POWERPC_INPUT_G2 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_G2 (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_G2 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) - static void init_proc_G2 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4269,17 +4246,16 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_ec603e; + pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } /* PowerPC G2LE */ -#define POWERPC_MSRM_G2LE (0x000000000007FFF3ULL) -#define POWERPC_MMU_G2LE (POWERPC_MMU_SOFT_6xx) -#define POWERPC_EXCP_G2LE (POWERPC_EXCP_G2) -#define POWERPC_INPUT_G2LE (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_G2LE (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_G2LE (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) - static void init_proc_G2LE (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4334,18 +4310,16 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_ec603e; + pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } /* e200 core */ -#define POWERPC_MSRM_e200 (0x000000000606FF30ULL) -#define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE206) -#define POWERPC_EXCP_e200 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_e200 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_e200 (bfd_mach_ppc_860) -#define POWERPC_FLAG_e200 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ - POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_e200 (CPUPPCState *env) { /* Time base */ @@ -4476,17 +4450,17 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_860; + pcc->flags = POWERPC_FLAG_SPE | POWERPC_FLAG_CE | + POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | + POWERPC_FLAG_BUS_CLK; } /* e300 core */ -#define POWERPC_MSRM_e300 (0x000000000007FFF3ULL) -#define POWERPC_MMU_e300 (POWERPC_MMU_SOFT_6xx) -#define POWERPC_EXCP_e300 (POWERPC_EXCP_603) -#define POWERPC_INPUT_e300 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_e300 (bfd_mach_ppc_603) -#define POWERPC_FLAG_e300 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) - static void init_proc_e300 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4534,47 +4508,19 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_603; + pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } /* e500v1 core */ -#define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL) -#define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE206) -#define POWERPC_EXCP_e500v1 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_e500v1 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_e500v1 (bfd_mach_ppc_860) -#define POWERPC_FLAG_e500v1 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ - POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_BUS_CLK) - /* e500v2 core */ -#define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL) -#define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE206) -#define POWERPC_EXCP_e500v2 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_e500v2 (PPC_FLAGS_INPUT_BookE) -#define POWERPC_BFDM_e500v2 (bfd_mach_ppc_860) -#define POWERPC_FLAG_e500v2 (POWERPC_FLAG_SPE | POWERPC_FLAG_CE | \ - POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_BUS_CLK) - /* e500mc core */ -#define POWERPC_MSRM_e500mc (0x000000001402FB36ULL) -#define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206) -#define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_e500mc (PPC_FLAGS_INPUT_BookE) -/* Fixme: figure out the correct flag for e500mc */ -#define POWERPC_BFDM_e500mc (bfd_mach_ppc_e500) -#define POWERPC_FLAG_e500mc (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - /* e5500 core */ -#define POWERPC_MSRM_e5500 (0x000000009402FB36ULL) -#define POWERPC_MMU_e5500 (POWERPC_MMU_BOOKE206) -#define POWERPC_EXCP_e5500 (POWERPC_EXCP_BOOKE) -#define POWERPC_INPUT_e5500 (PPC_FLAGS_INPUT_BookE) -/* Fixme: figure out the correct flag for e5500 */ -#define POWERPC_BFDM_e5500 (bfd_mach_ppc_e500) -#define POWERPC_FLAG_e5500 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) #if !defined(CONFIG_USER_ONLY) static void spr_write_mas73(void *opaque, int sprn, int gprn) @@ -4803,6 +4749,14 @@ POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; pcc->insns_flags2 = PPC2_BOOKE206; + pcc->msr_mask = 0x000000000606FF30ULL; + pcc->mmu_model = POWERPC_MMU_BOOKE206; + pcc->excp_model = POWERPC_EXCP_BOOKE; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_860; + pcc->flags = POWERPC_FLAG_SPE | POWERPC_FLAG_CE | + POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | + POWERPC_FLAG_BUS_CLK; } static void init_proc_e500v2(CPUPPCState *env) @@ -4823,6 +4777,14 @@ POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data) PPC_CACHE_DCBZ | PPC_CACHE_DCBA | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; pcc->insns_flags2 = PPC2_BOOKE206; + pcc->msr_mask = 0x000000000606FF30ULL; + pcc->mmu_model = POWERPC_MMU_BOOKE206; + pcc->excp_model = POWERPC_EXCP_BOOKE; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_860; + pcc->flags = POWERPC_FLAG_SPE | POWERPC_FLAG_CE | + POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | + POWERPC_FLAG_BUS_CLK; } static void init_proc_e500mc(CPUPPCState *env) @@ -4845,6 +4807,14 @@ POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data) PPC_FLOAT_STFIWX | PPC_WAIT | PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC; pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL; + pcc->msr_mask = 0x000000001402FB36ULL; + pcc->mmu_model = POWERPC_MMU_BOOKE206; + pcc->excp_model = POWERPC_EXCP_BOOKE; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + /* FIXME: figure out the correct flag for e500mc */ + pcc->bfd_mach = bfd_mach_ppc_e500; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } #ifdef TARGET_PPC64 @@ -4869,6 +4839,14 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | PPC_64B | PPC_POPCNTB | PPC_POPCNTWD; pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL; + pcc->msr_mask = 0x000000009402FB36ULL; + pcc->mmu_model = POWERPC_MMU_BOOKE206; + pcc->excp_model = POWERPC_EXCP_BOOKE; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + /* FIXME: figure out the correct flag for e5500 */ + pcc->bfd_mach = bfd_mach_ppc_e500; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } #endif @@ -4876,25 +4854,18 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) /* POWER : same as 601, without mfmsr, mfsr */ #if defined(TODO) -/* POWER RSC (from RAD6000) */ -#define POWERPC_MSRM_POWER (0x00000000FEF0ULL) - POWERPC_FAMILY(POWER)(ObjectClass *oc, void *data) { PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); pcc->insns_flags = XXX_TODO; + /* POWER RSC (from RAD6000) */ + pcc->msr_mask = 0x00000000FEF0ULL; } #endif /* TODO */ /* PowerPC 601 */ -#define POWERPC_MSRM_601 (0x000000000000FD70ULL) #define POWERPC_MSRR_601 (0x0000000000001040ULL) -//#define POWERPC_MMU_601 (POWERPC_MMU_601) -//#define POWERPC_EXCP_601 (POWERPC_EXCP_601) -#define POWERPC_INPUT_601 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_601 (bfd_mach_ppc_601) -#define POWERPC_FLAG_601 (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK) static void init_proc_601 (CPUPPCState *env) { @@ -4945,16 +4916,16 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_601; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_601; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; } /* PowerPC 601v */ -#define POWERPC_MSRM_601v (0x000000000000FD70ULL) #define POWERPC_MSRR_601v (0x0000000000001040ULL) -#define POWERPC_MMU_601v (POWERPC_MMU_601) -#define POWERPC_EXCP_601v (POWERPC_EXCP_601) -#define POWERPC_INPUT_601v (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_601v (bfd_mach_ppc_601) -#define POWERPC_FLAG_601v (POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK) static void init_proc_601v (CPUPPCState *env) { @@ -4978,18 +4949,15 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_601; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_601; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; } /* PowerPC 602 */ -#define POWERPC_MSRM_602 (0x0000000000C7FF73ULL) -/* XXX: 602 MMU is quite specific. Should add a special case */ -#define POWERPC_MMU_602 (POWERPC_MMU_SOFT_6xx) -//#define POWERPC_EXCP_602 (POWERPC_EXCP_602) -#define POWERPC_INPUT_602 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_602 (bfd_mach_ppc_602) -#define POWERPC_FLAG_602 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) - static void init_proc_602 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5031,17 +4999,17 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_602; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_602; + pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 603 */ -#define POWERPC_MSRM_603 (0x000000000007FF73ULL) -#define POWERPC_MMU_603 (POWERPC_MMU_SOFT_6xx) -//#define POWERPC_EXCP_603 (POWERPC_EXCP_603) -#define POWERPC_INPUT_603 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_603 (bfd_mach_ppc_603) -#define POWERPC_FLAG_603 (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) - static void init_proc_603 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5083,17 +5051,16 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_603; + pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 603e */ -#define POWERPC_MSRM_603E (0x000000000007FF73ULL) -#define POWERPC_MMU_603E (POWERPC_MMU_SOFT_6xx) -//#define POWERPC_EXCP_603E (POWERPC_EXCP_603E) -#define POWERPC_INPUT_603E (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_603E (bfd_mach_ppc_ec603e) -#define POWERPC_FLAG_603E (POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK) - static void init_proc_603E (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5140,17 +5107,16 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_ec603e; + pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } /* PowerPC 604 */ -#define POWERPC_MSRM_604 (0x000000000005FF77ULL) -#define POWERPC_MMU_604 (POWERPC_MMU_32B) -//#define POWERPC_EXCP_604 (POWERPC_EXCP_604) -#define POWERPC_INPUT_604 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_604 (bfd_mach_ppc_604) -#define POWERPC_FLAG_604 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_604 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5186,17 +5152,16 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_604; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_604; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 604E */ -#define POWERPC_MSRM_604E (0x000000000005FF77ULL) -#define POWERPC_MMU_604E (POWERPC_MMU_32B) -#define POWERPC_EXCP_604E (POWERPC_EXCP_604) -#define POWERPC_INPUT_604E (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_604E (bfd_mach_ppc_604) -#define POWERPC_FLAG_604E (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_604E (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5252,17 +5217,16 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_604; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_604; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 740 */ -#define POWERPC_MSRM_740 (0x000000000005FF77ULL) -#define POWERPC_MMU_740 (POWERPC_MMU_32B) -#define POWERPC_EXCP_740 (POWERPC_EXCP_7x0) -#define POWERPC_INPUT_740 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_740 (bfd_mach_ppc_750) -#define POWERPC_FLAG_740 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_740 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5305,17 +5269,16 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_7x0; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 750 */ -#define POWERPC_MSRM_750 (0x000000000005FF77ULL) -#define POWERPC_MMU_750 (POWERPC_MMU_32B) -#define POWERPC_EXCP_750 (POWERPC_EXCP_7x0) -#define POWERPC_INPUT_750 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_750 (bfd_mach_ppc_750) -#define POWERPC_FLAG_750 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_750 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5366,17 +5329,16 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_7x0; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 750 CL */ -#define POWERPC_MSRM_750cl (0x000000000005FF77ULL) -#define POWERPC_MMU_750cl (POWERPC_MMU_32B) -#define POWERPC_EXCP_750cl (POWERPC_EXCP_7x0) -#define POWERPC_INPUT_750cl (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_750cl (bfd_mach_ppc_750) -#define POWERPC_FLAG_750cl (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_750cl (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5550,17 +5512,16 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_7x0; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 750CX */ -#define POWERPC_MSRM_750cx (0x000000000005FF77ULL) -#define POWERPC_MMU_750cx (POWERPC_MMU_32B) -#define POWERPC_EXCP_750cx (POWERPC_EXCP_7x0) -#define POWERPC_INPUT_750cx (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_750cx (bfd_mach_ppc_750) -#define POWERPC_FLAG_750cx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_750cx (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5615,17 +5576,16 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_7x0; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 750FX */ -#define POWERPC_MSRM_750fx (0x000000000005FF77ULL) -#define POWERPC_MMU_750fx (POWERPC_MMU_32B) -#define POWERPC_EXCP_750fx (POWERPC_EXCP_7x0) -#define POWERPC_INPUT_750fx (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_750fx (bfd_mach_ppc_750) -#define POWERPC_FLAG_750fx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_750fx (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5685,17 +5645,16 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_7x0; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 750GX */ -#define POWERPC_MSRM_750gx (0x000000000005FF77ULL) -#define POWERPC_MMU_750gx (POWERPC_MMU_32B) -#define POWERPC_EXCP_750gx (POWERPC_EXCP_7x0) -#define POWERPC_INPUT_750gx (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_750gx (bfd_mach_ppc_750) -#define POWERPC_FLAG_750gx (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_750gx (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5755,17 +5714,16 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) 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; + pcc->excp_model = POWERPC_EXCP_7x0; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 745 */ -#define POWERPC_MSRM_745 (0x000000000005FF77ULL) -#define POWERPC_MMU_745 (POWERPC_MMU_SOFT_6xx) -#define POWERPC_EXCP_745 (POWERPC_EXCP_7x5) -#define POWERPC_INPUT_745 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_745 (bfd_mach_ppc_750) -#define POWERPC_FLAG_745 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_745 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5816,17 +5774,16 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 755 */ -#define POWERPC_MSRM_755 (0x000000000005FF77ULL) -#define POWERPC_MMU_755 (POWERPC_MMU_SOFT_6xx) -#define POWERPC_EXCP_755 (POWERPC_EXCP_7x5) -#define POWERPC_INPUT_755 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_755 (bfd_mach_ppc_750) -#define POWERPC_FLAG_755 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_755 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5888,18 +5845,16 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_750; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } /* PowerPC 7400 (aka G4) */ -#define POWERPC_MSRM_7400 (0x000000000205FF77ULL) -#define POWERPC_MMU_7400 (POWERPC_MMU_32B) -#define POWERPC_EXCP_7400 (POWERPC_EXCP_74xx) -#define POWERPC_INPUT_7400 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7400 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7400 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_7400 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5948,18 +5903,17 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x000000000205FF77ULL; + pcc->mmu_model = POWERPC_MMU_32B; + pcc->excp_model = POWERPC_EXCP_74xx; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 7410 (aka G4) */ -#define POWERPC_MSRM_7410 (0x000000000205FF77ULL) -#define POWERPC_MMU_7410 (POWERPC_MMU_32B) -#define POWERPC_EXCP_7410 (POWERPC_EXCP_74xx) -#define POWERPC_INPUT_7410 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7410 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7410 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_7410 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6014,18 +5968,17 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) PPC_SEGMENT | PPC_EXTERN | PPC_ALTIVEC; pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x000000000205FF77ULL; + pcc->mmu_model = POWERPC_MMU_32B; + pcc->excp_model = POWERPC_EXCP_74xx; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 7440 (aka G4) */ -#define POWERPC_MSRM_7440 (0x000000000205FF77ULL) -#define POWERPC_MMU_7440 (POWERPC_MMU_SOFT_74xx) -#define POWERPC_EXCP_7440 (POWERPC_EXCP_74xx) -#define POWERPC_INPUT_7440 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7440 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7440 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_7440 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6106,18 +6059,17 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 7450 (aka G4) */ -#define POWERPC_MSRM_7450 (0x000000000205FF77ULL) -#define POWERPC_MMU_7450 (POWERPC_MMU_SOFT_74xx) -#define POWERPC_EXCP_7450 (POWERPC_EXCP_74xx) -#define POWERPC_INPUT_7450 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7450 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7450 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_7450 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6224,18 +6176,17 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 7445 (aka G4) */ -#define POWERPC_MSRM_7445 (0x000000000205FF77ULL) -#define POWERPC_MMU_7445 (POWERPC_MMU_SOFT_74xx) -#define POWERPC_EXCP_7445 (POWERPC_EXCP_74xx) -#define POWERPC_INPUT_7445 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7445 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7445 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_7445 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6345,18 +6296,17 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 7455 (aka G4) */ -#define POWERPC_MSRM_7455 (0x000000000205FF77ULL) -#define POWERPC_MMU_7455 (POWERPC_MMU_SOFT_74xx) -#define POWERPC_EXCP_7455 (POWERPC_EXCP_74xx) -#define POWERPC_INPUT_7455 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7455 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7455 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_7455 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6468,18 +6418,17 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 7457 (aka G4) */ -#define POWERPC_MSRM_7457 (0x000000000205FF77ULL) -#define POWERPC_MMU_7457 (POWERPC_MMU_SOFT_74xx) -#define POWERPC_EXCP_7457 (POWERPC_EXCP_74xx) -#define POWERPC_INPUT_7457 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_7457 (bfd_mach_ppc_7400) -#define POWERPC_FLAG_7457 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static void init_proc_7457 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6615,19 +6564,18 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) 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; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } #if defined (TARGET_PPC64) /* PowerPC 970 */ -#define POWERPC_MSRM_970 (0x900000000204FF36ULL) -#define POWERPC_MMU_970 (POWERPC_MMU_64B) -//#define POWERPC_EXCP_970 (POWERPC_EXCP_970) -#define POWERPC_INPUT_970 (PPC_FLAGS_INPUT_970) -#define POWERPC_BFDM_970 (bfd_mach_ppc64) -#define POWERPC_FLAG_970 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - #if defined(CONFIG_USER_ONLY) #define POWERPC970_HID5_INIT 0x00000080 #else @@ -6720,18 +6668,17 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x900000000204FF36ULL; + pcc->mmu_model = POWERPC_MMU_64B; + pcc->excp_model = POWERPC_EXCP_970; + pcc->bus_model = PPC_FLAGS_INPUT_970; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 970FX (aka G5) */ -#define POWERPC_MSRM_970FX (0x800000000204FF36ULL) -#define POWERPC_MMU_970FX (POWERPC_MMU_64B) -#define POWERPC_EXCP_970FX (POWERPC_EXCP_970) -#define POWERPC_INPUT_970FX (PPC_FLAGS_INPUT_970) -#define POWERPC_BFDM_970FX (bfd_mach_ppc64) -#define POWERPC_FLAG_970FX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static int check_pow_970FX (CPUPPCState *env) { if (env->spr[SPR_HID0] & 0x00600000) @@ -6830,18 +6777,17 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x800000000204FF36ULL; + pcc->mmu_model = POWERPC_MMU_64B; + pcc->excp_model = POWERPC_EXCP_970; + pcc->bus_model = PPC_FLAGS_INPUT_970; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 970 GX */ -#define POWERPC_MSRM_970GX (0x800000000204FF36ULL) -#define POWERPC_MMU_970GX (POWERPC_MMU_64B) -#define POWERPC_EXCP_970GX (POWERPC_EXCP_970) -#define POWERPC_INPUT_970GX (PPC_FLAGS_INPUT_970) -#define POWERPC_BFDM_970GX (bfd_mach_ppc64) -#define POWERPC_FLAG_970GX (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static int check_pow_970GX (CPUPPCState *env) { if (env->spr[SPR_HID0] & 0x00600000) @@ -6928,18 +6874,17 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data) PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x800000000204FF36ULL; + pcc->mmu_model = POWERPC_MMU_64B; + pcc->excp_model = POWERPC_EXCP_970; + pcc->bus_model = PPC_FLAGS_INPUT_970; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* PowerPC 970 MP */ -#define POWERPC_MSRM_970MP (0x900000000204FF36ULL) -#define POWERPC_MMU_970MP (POWERPC_MMU_64B) -#define POWERPC_EXCP_970MP (POWERPC_EXCP_970) -#define POWERPC_INPUT_970MP (PPC_FLAGS_INPUT_970) -#define POWERPC_BFDM_970MP (bfd_mach_ppc64) -#define POWERPC_FLAG_970MP (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK) - static int check_pow_970MP (CPUPPCState *env) { if (env->spr[SPR_HID0] & 0x01C00000) @@ -7026,18 +6971,17 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) PPC_64B | PPC_ALTIVEC | PPC_SEGMENT_64B | PPC_SLBI; pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x900000000204FF36ULL; + pcc->mmu_model = POWERPC_MMU_64B; + pcc->excp_model = POWERPC_EXCP_970; + pcc->bus_model = PPC_FLAGS_INPUT_970; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; } /* POWER7 */ -#define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) -#define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) -#define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) -#define POWERPC_INPUT_POWER7 (PPC_FLAGS_INPUT_POWER7) -#define POWERPC_BFDM_POWER7 (bfd_mach_ppc64) -#define POWERPC_FLAG_POWER7 (POWERPC_FLAG_VRE | POWERPC_FLAG_SE | \ - POWERPC_FLAG_BE | POWERPC_FLAG_PMM | \ - POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR) - static void init_proc_POWER7 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -7117,17 +7061,17 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) PPC_SEGMENT_64B | PPC_SLBI | PPC_POPCNTB | PPC_POPCNTWD; pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX; + pcc->msr_mask = 0x800000000204FF36ULL; + pcc->mmu_model = POWERPC_MMU_2_06; + pcc->excp_model = POWERPC_EXCP_POWER7; + pcc->bus_model = PPC_FLAGS_INPUT_POWER7; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR; } /* PowerPC 620 */ -#define POWERPC_MSRM_620 (0x800000000005FF77ULL) -//#define POWERPC_MMU_620 (POWERPC_MMU_620) -#define POWERPC_EXCP_620 (POWERPC_EXCP_970) -#define POWERPC_INPUT_620 (PPC_FLAGS_INPUT_6xx) -#define POWERPC_BFDM_620 (bfd_mach_ppc64) -#define POWERPC_FLAG_620 (POWERPC_FLAG_SE | POWERPC_FLAG_BE | \ - POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK) - static void init_proc_620 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -7165,6 +7109,13 @@ POWERPC_FAMILY(620)(ObjectClass *oc, void *data) PPC_SEGMENT | PPC_EXTERN | PPC_64B | PPC_SLBI; pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x800000000005FF77ULL; + pcc->mmu_model = POWERPC_MMU_620; + pcc->excp_model = POWERPC_EXCP_970; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE | + POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } #endif /* defined (TARGET_PPC64) */ @@ -7885,12 +7836,6 @@ enum { \ pcc->pvr = _pvr; \ pcc->svr = _svr; \ - pcc->msr_mask = glue(POWERPC_MSRM_, _type); \ - pcc->mmu_model = glue(POWERPC_MMU_, _type); \ - pcc->excp_model = glue(POWERPC_EXCP_, _type); \ - pcc->bus_model = glue(POWERPC_INPUT_, _type); \ - pcc->bfd_mach = glue(POWERPC_BFDM_, _type); \ - pcc->flags = glue(POWERPC_FLAG_, _type); \ } \ \ static const TypeInfo \ From ca5dff0a3e532ea9168934fc361e96d969007284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:46 +0000 Subject: [PATCH 1460/1634] target-ppc: Turn descriptive CPU family comments into device descriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gets rid of some more overly long comments that have lost most of their purpose now that in most cases there's only two functions left per CPU family. The class field is inherited by the actual CPU models, so override it. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 159 ++++++++++++++++++++++++------------ 1 file changed, 107 insertions(+), 52 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index eea9adf6f3..3ec7c1e86f 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -3274,7 +3274,6 @@ static int check_pow_hid0_74xx (CPUPPCState *env) \ static void glue(glue(ppc_, _name), _cpu_family_class_init) -/* PowerPC 401 */ static void init_proc_401 (CPUPPCState *env) { gen_spr_40x(env); @@ -3292,8 +3291,10 @@ static void init_proc_401 (CPUPPCState *env) POWERPC_FAMILY(401)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 401"; pcc->init_proc = init_proc_401; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3312,7 +3313,6 @@ POWERPC_FAMILY(401)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 401x2 */ static void init_proc_401x2 (CPUPPCState *env) { gen_spr_40x(env); @@ -3338,8 +3338,10 @@ static void init_proc_401x2 (CPUPPCState *env) POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 401x2"; pcc->init_proc = init_proc_401x2; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -3359,7 +3361,6 @@ POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 401x3 */ static void init_proc_401x3 (CPUPPCState *env) { gen_spr_40x(env); @@ -3379,8 +3380,10 @@ static void init_proc_401x3 (CPUPPCState *env) POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 401x3"; pcc->init_proc = init_proc_401x3; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -3400,7 +3403,6 @@ POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* IOP480 */ static void init_proc_IOP480 (CPUPPCState *env) { gen_spr_40x(env); @@ -3426,8 +3428,10 @@ static void init_proc_IOP480 (CPUPPCState *env) POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "IOP480"; pcc->init_proc = init_proc_IOP480; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3447,7 +3451,6 @@ POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 403 */ static void init_proc_403 (CPUPPCState *env) { gen_spr_40x(env); @@ -3466,8 +3469,10 @@ static void init_proc_403 (CPUPPCState *env) POWERPC_FAMILY(403)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 403"; pcc->init_proc = init_proc_403; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3486,7 +3491,6 @@ POWERPC_FAMILY(403)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 403 GCX */ static void init_proc_403GCX (CPUPPCState *env) { gen_spr_40x(env); @@ -3524,8 +3528,10 @@ static void init_proc_403GCX (CPUPPCState *env) POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 403 GCX"; pcc->init_proc = init_proc_403GCX; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3545,7 +3551,6 @@ POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 405 */ static void init_proc_405 (CPUPPCState *env) { /* Time base */ @@ -3582,8 +3587,10 @@ static void init_proc_405 (CPUPPCState *env) POWERPC_FAMILY(405)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 405"; pcc->init_proc = init_proc_405; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -3603,7 +3610,6 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 440 EP */ static void init_proc_440EP (CPUPPCState *env) { /* Time base */ @@ -3672,8 +3678,10 @@ static void init_proc_440EP (CPUPPCState *env) POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 440 EP"; pcc->init_proc = init_proc_440EP; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3696,7 +3704,6 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 440 GP */ static void init_proc_440GP (CPUPPCState *env) { /* Time base */ @@ -3747,8 +3754,10 @@ static void init_proc_440GP (CPUPPCState *env) POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 440 GP"; pcc->init_proc = init_proc_440GP; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3768,7 +3777,6 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 440x4 */ static void init_proc_440x4 (CPUPPCState *env) { /* Time base */ @@ -3819,8 +3827,10 @@ static void init_proc_440x4 (CPUPPCState *env) POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 440x4"; pcc->init_proc = init_proc_440x4; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3840,7 +3850,6 @@ POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 440x5 */ static void init_proc_440x5 (CPUPPCState *env) { /* Time base */ @@ -3909,8 +3918,10 @@ static void init_proc_440x5 (CPUPPCState *env) POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 440x5"; pcc->init_proc = init_proc_440x5; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -3930,7 +3941,6 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 460 (guessed) */ static void init_proc_460 (CPUPPCState *env) { /* Time base */ @@ -4004,8 +4014,10 @@ static void init_proc_460 (CPUPPCState *env) POWERPC_FAMILY(460)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 460 (guessed)"; pcc->init_proc = init_proc_460; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -4026,7 +4038,6 @@ POWERPC_FAMILY(460)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 460F (guessed) */ static void init_proc_460F (CPUPPCState *env) { /* Time base */ @@ -4100,8 +4111,10 @@ static void init_proc_460F (CPUPPCState *env) POWERPC_FAMILY(460F)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 460F (guessed)"; pcc->init_proc = init_proc_460F; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -4125,7 +4138,6 @@ POWERPC_FAMILY(460F)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -/* Freescale 5xx cores (aka RCPU) */ static void init_proc_MPC5xx (CPUPPCState *env) { /* Time base */ @@ -4140,8 +4152,10 @@ static void init_proc_MPC5xx (CPUPPCState *env) POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "Freescale 5xx cores (aka RCPU)"; pcc->init_proc = init_proc_MPC5xx; pcc->check_pow = check_pow_none; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -4158,7 +4172,6 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* Freescale 8xx cores (aka PowerQUICC) */ static void init_proc_MPC8xx (CPUPPCState *env) { /* Time base */ @@ -4173,8 +4186,10 @@ static void init_proc_MPC8xx (CPUPPCState *env) POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "Freescale 8xx cores (aka PowerQUICC)"; pcc->init_proc = init_proc_MPC8xx; pcc->check_pow = check_pow_none; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | @@ -4191,7 +4206,7 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) } /* Freescale 82xx cores (aka PowerQUICC-II) */ -/* PowerPC G2 */ + static void init_proc_G2 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4234,8 +4249,10 @@ static void init_proc_G2 (CPUPPCState *env) POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC G2"; pcc->init_proc = init_proc_G2; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -4255,7 +4272,6 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC G2LE */ static void init_proc_G2LE (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4298,8 +4314,10 @@ static void init_proc_G2LE (CPUPPCState *env) POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC G2LE"; pcc->init_proc = init_proc_G2LE; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -4319,7 +4337,6 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -/* e200 core */ static void init_proc_e200 (CPUPPCState *env) { /* Time base */ @@ -4429,8 +4446,10 @@ static void init_proc_e200 (CPUPPCState *env) POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "e200 core"; pcc->init_proc = init_proc_e200; pcc->check_pow = check_pow_hid0; /* XXX: unimplemented instructions: @@ -4460,7 +4479,6 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* e300 core */ static void init_proc_e300 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4496,8 +4514,10 @@ static void init_proc_e300 (CPUPPCState *env) POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "e300 core"; pcc->init_proc = init_proc_e300; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -4517,11 +4537,6 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -/* e500v1 core */ -/* e500v2 core */ -/* e500mc core */ -/* e5500 core */ - #if !defined(CONFIG_USER_ONLY) static void spr_write_mas73(void *opaque, int sprn, int gprn) { @@ -4738,8 +4753,10 @@ static void init_proc_e500v1(CPUPPCState *env) POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "e500v1 core"; pcc->init_proc = init_proc_e500v1; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | @@ -4766,8 +4783,10 @@ static void init_proc_e500v2(CPUPPCState *env) POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "e500v2 core"; pcc->init_proc = init_proc_e500v2; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | @@ -4794,8 +4813,10 @@ static void init_proc_e500mc(CPUPPCState *env) POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "e500mc core"; pcc->init_proc = init_proc_e500mc; pcc->check_pow = check_pow_none; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | @@ -4825,8 +4846,10 @@ static void init_proc_e5500(CPUPPCState *env) POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "e5500 core"; pcc->init_proc = init_proc_e5500; pcc->check_pow = check_pow_none; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | @@ -4856,15 +4879,16 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) #if defined(TODO) POWERPC_FAMILY(POWER)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "POWER"; pcc->insns_flags = XXX_TODO; /* POWER RSC (from RAD6000) */ pcc->msr_mask = 0x00000000FEF0ULL; } #endif /* TODO */ -/* PowerPC 601 */ #define POWERPC_MSRR_601 (0x0000000000001040ULL) static void init_proc_601 (CPUPPCState *env) @@ -4906,8 +4930,10 @@ static void init_proc_601 (CPUPPCState *env) POWERPC_FAMILY(601)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 601"; pcc->init_proc = init_proc_601; pcc->check_pow = check_pow_none; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | @@ -4924,7 +4950,6 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data) pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; } -/* PowerPC 601v */ #define POWERPC_MSRR_601v (0x0000000000001040ULL) static void init_proc_601v (CPUPPCState *env) @@ -4939,8 +4964,10 @@ static void init_proc_601v (CPUPPCState *env) POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 601v"; pcc->init_proc = init_proc_601v; pcc->check_pow = check_pow_none; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR | @@ -4957,7 +4984,6 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; } -/* PowerPC 602 */ static void init_proc_602 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -4987,8 +5013,10 @@ static void init_proc_602 (CPUPPCState *env) POWERPC_FAMILY(602)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 602"; pcc->init_proc = init_proc_602; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5009,7 +5037,6 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 603 */ static void init_proc_603 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5039,8 +5066,10 @@ static void init_proc_603 (CPUPPCState *env) POWERPC_FAMILY(603)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 603"; pcc->init_proc = init_proc_603; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5060,7 +5089,6 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 603e */ static void init_proc_603E (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5095,8 +5123,10 @@ static void init_proc_603E (CPUPPCState *env) POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 603e"; pcc->init_proc = init_proc_603E; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5116,7 +5146,6 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 604 */ static void init_proc_604 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5140,8 +5169,10 @@ static void init_proc_604 (CPUPPCState *env) POWERPC_FAMILY(604)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 604"; pcc->init_proc = init_proc_604; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5161,7 +5192,6 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 604E */ static void init_proc_604E (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5205,8 +5235,10 @@ static void init_proc_604E (CPUPPCState *env) POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 604E"; pcc->init_proc = init_proc_604E; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5226,7 +5258,6 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 740 */ static void init_proc_740 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5257,8 +5288,10 @@ static void init_proc_740 (CPUPPCState *env) POWERPC_FAMILY(740)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 740"; pcc->init_proc = init_proc_740; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5278,7 +5311,6 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 750 */ static void init_proc_750 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5317,8 +5349,10 @@ static void init_proc_750 (CPUPPCState *env) POWERPC_FAMILY(750)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 750"; pcc->init_proc = init_proc_750; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5338,7 +5372,6 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 750 CL */ static void init_proc_750cl (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5462,8 +5495,10 @@ static void init_proc_750cl (CPUPPCState *env) POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 750 CL"; pcc->init_proc = init_proc_750cl; pcc->check_pow = check_pow_hid0; /* XXX: not implemented: @@ -5521,7 +5556,6 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 750CX */ static void init_proc_750cx (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5564,8 +5598,10 @@ static void init_proc_750cx (CPUPPCState *env) POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 750CX"; pcc->init_proc = init_proc_750cx; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5585,7 +5621,6 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 750FX */ static void init_proc_750fx (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5633,8 +5668,10 @@ static void init_proc_750fx (CPUPPCState *env) POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 750FX"; pcc->init_proc = init_proc_750fx; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5654,7 +5691,6 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 750GX */ static void init_proc_750gx (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5702,8 +5738,10 @@ static void init_proc_750gx (CPUPPCState *env) POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 750GX"; pcc->init_proc = init_proc_750gx; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5723,7 +5761,6 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 745 */ static void init_proc_745 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5762,8 +5799,10 @@ static void init_proc_745 (CPUPPCState *env) POWERPC_FAMILY(745)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 745"; pcc->init_proc = init_proc_745; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5783,7 +5822,6 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 755 */ static void init_proc_755 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5833,8 +5871,10 @@ static void init_proc_755 (CPUPPCState *env) POWERPC_FAMILY(755)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 755"; pcc->init_proc = init_proc_755; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5854,7 +5894,6 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data) POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK; } -/* PowerPC 7400 (aka G4) */ static void init_proc_7400 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5887,8 +5926,10 @@ static void init_proc_7400 (CPUPPCState *env) POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 7400 (aka G4)"; pcc->init_proc = init_proc_7400; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5913,7 +5954,6 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 7410 (aka G4) */ static void init_proc_7410 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -5952,8 +5992,10 @@ static void init_proc_7410 (CPUPPCState *env) POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 7410 (aka G4)"; pcc->init_proc = init_proc_7410; pcc->check_pow = check_pow_hid0; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -5978,7 +6020,6 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 7440 (aka G4) */ static void init_proc_7440 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6043,8 +6084,10 @@ static void init_proc_7440 (CPUPPCState *env) POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 7440 (aka G4)"; pcc->init_proc = init_proc_7440; pcc->check_pow = check_pow_hid0_74xx; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6069,7 +6112,6 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 7450 (aka G4) */ static void init_proc_7450 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6160,8 +6202,10 @@ static void init_proc_7450 (CPUPPCState *env) POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 7450 (aka G4)"; pcc->init_proc = init_proc_7450; pcc->check_pow = check_pow_hid0_74xx; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6186,7 +6230,6 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 7445 (aka G4) */ static void init_proc_7445 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6280,8 +6323,10 @@ static void init_proc_7445 (CPUPPCState *env) POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 7445 (aka G4)"; pcc->init_proc = init_proc_7445; pcc->check_pow = check_pow_hid0_74xx; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6306,7 +6351,6 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 7455 (aka G4) */ static void init_proc_7455 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6402,8 +6446,10 @@ static void init_proc_7455 (CPUPPCState *env) POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 7455 (aka G4)"; pcc->init_proc = init_proc_7455; pcc->check_pow = check_pow_hid0_74xx; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6428,7 +6474,6 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 7457 (aka G4) */ static void init_proc_7457 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -6548,8 +6593,10 @@ static void init_proc_7457 (CPUPPCState *env) POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 7457 (aka G4)"; pcc->init_proc = init_proc_7457; pcc->check_pow = check_pow_hid0_74xx; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6575,7 +6622,6 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) } #if defined (TARGET_PPC64) -/* PowerPC 970 */ #if defined(CONFIG_USER_ONLY) #define POWERPC970_HID5_INIT 0x00000080 #else @@ -6654,8 +6700,10 @@ static void init_proc_970 (CPUPPCState *env) POWERPC_FAMILY(970)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 970"; pcc->init_proc = init_proc_970; pcc->check_pow = check_pow_970; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6678,7 +6726,6 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 970FX (aka G5) */ static int check_pow_970FX (CPUPPCState *env) { if (env->spr[SPR_HID0] & 0x00600000) @@ -6763,8 +6810,10 @@ static void init_proc_970FX (CPUPPCState *env) POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 970FX (aka G5)"; pcc->init_proc = init_proc_970FX; pcc->check_pow = check_pow_970FX; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6787,7 +6836,6 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 970 GX */ static int check_pow_970GX (CPUPPCState *env) { if (env->spr[SPR_HID0] & 0x00600000) @@ -6860,8 +6908,10 @@ static void init_proc_970GX (CPUPPCState *env) POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 970 GX"; pcc->init_proc = init_proc_970GX; pcc->check_pow = check_pow_970GX; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6884,7 +6934,6 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* PowerPC 970 MP */ static int check_pow_970MP (CPUPPCState *env) { if (env->spr[SPR_HID0] & 0x01C00000) @@ -6957,8 +7006,10 @@ static void init_proc_970MP (CPUPPCState *env) POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 970 MP"; pcc->init_proc = init_proc_970MP; pcc->check_pow = check_pow_970MP; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -6981,7 +7032,6 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } -/* POWER7 */ static void init_proc_POWER7 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -7046,8 +7096,10 @@ static void init_proc_POWER7 (CPUPPCState *env) POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "POWER7"; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -7071,7 +7123,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR; } -/* PowerPC 620 */ static void init_proc_620 (CPUPPCState *env) { gen_spr_ne_601(env); @@ -7095,8 +7146,10 @@ static void init_proc_620 (CPUPPCState *env) POWERPC_FAMILY(620)(ObjectClass *oc, void *data) { + DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + dc->desc = "PowerPC 620"; pcc->init_proc = init_proc_620; pcc->check_pow = check_pow_nocheck; /* Check this */ pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | @@ -7832,10 +7885,12 @@ enum { glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ (ObjectClass *oc, void *data) \ { \ + DeviceClass *dc = DEVICE_CLASS(oc); \ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ \ pcc->pvr = _pvr; \ pcc->svr = _svr; \ + dc->desc = NULL; \ } \ \ static const TypeInfo \ From e0233c9abe16d8f7cdeb76ea54e84c68fe2b0037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:47 +0000 Subject: [PATCH 1461/1634] target-ppc: Turn descriptive CPU model comments into device descriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix microcontroller typo while at it. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 1606 ++++++++++++++++------------------- 1 file changed, 750 insertions(+), 856 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3ec7c1e86f..bd5230cedf 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7876,11 +7876,11 @@ enum { POWERPC_SVR_8641D = 0x80900121, }; -/*****************************************************************************/ -/* PowerPC CPU definitions */ +/***************************************************************************/ +/* PowerPC CPU definitions */ #define POWERPC_DEF_PREFIX(pvr, svr, type) \ glue(glue(glue(glue(pvr, _), svr), _), type) -#define POWERPC_DEF_SVR(_name, _pvr, _svr, _type) \ +#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ static void \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ (ObjectClass *oc, void *data) \ @@ -7890,7 +7890,7 @@ enum { \ pcc->pvr = _pvr; \ pcc->svr = _svr; \ - dc->desc = NULL; \ + dc->desc = _desc; \ } \ \ static const TypeInfo \ @@ -7911,1267 +7911,1161 @@ enum { type_init( \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)) -#define POWERPC_DEF(_name, _pvr, _type) \ -POWERPC_DEF_SVR(_name, _pvr, POWERPC_SVR_NONE, _type) +#define POWERPC_DEF(_name, _pvr, _type, _desc) \ + POWERPC_DEF_SVR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type) /* Embedded PowerPC */ /* PowerPC 401 family */ - /* Generic PowerPC 401 */ - POWERPC_DEF("401", CPU_POWERPC_401, 401) + POWERPC_DEF("401", CPU_POWERPC_401, 401, + "Generic PowerPC 401") /* PowerPC 401 cores */ - /* PowerPC 401A1 */ - POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401) - /* PowerPC 401B2 */ - POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2) + POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401, + "PowerPC 401A1") + POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2, + "PowerPC 401B2") #if defined (TODO) - /* PowerPC 401B3 */ - POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3) + POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3, + "PowerPC 401B3") #endif - /* PowerPC 401C2 */ - POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2) - /* PowerPC 401D2 */ - POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2) - /* PowerPC 401E2 */ - POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2) - /* PowerPC 401F2 */ - POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2) - /* PowerPC 401G2 */ + POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2, + "PowerPC 401C2") + POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2, + "PowerPC 401D2") + POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2, + "PowerPC 401E2") + POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2, + "PowerPC 401F2") /* XXX: to be checked */ - POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2) + POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2, + "PowerPC 401G2") /* PowerPC 401 microcontrolers */ #if defined (TODO) - /* PowerPC 401GF */ - POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401) + POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401, + "PowerPC 401GF") #endif - /* IOP480 (401 microcontroler) */ - POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480) - /* IBM Processor for Network Resources */ - POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401) + POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480, + "IOP480 (401 microcontroller)") + POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401, + "IBM Processor for Network Resources") #if defined (TODO) - POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401) + POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401, + NULL) #endif /* PowerPC 403 family */ /* PowerPC 403 microcontrolers */ - /* PowerPC 403 GA */ - POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403) - /* PowerPC 403 GB */ - POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403) - /* PowerPC 403 GC */ - POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403) - /* PowerPC 403 GCX */ - POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX) + POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403, + "PowerPC 403 GA") + POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403, + "PowerPC 403 GB") + POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403, + "PowerPC 403 GC") + POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX, + "PowerPC 403 GCX") #if defined (TODO) - /* PowerPC 403 GP */ - POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403) + POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403, + "PowerPC 403 GP") #endif /* PowerPC 405 family */ /* PowerPC 405 cores */ #if defined (TODO) - /* PowerPC 405 A3 */ - POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405) + POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405, + "PowerPC 405 A3") #endif #if defined (TODO) - /* PowerPC 405 A4 */ - POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405) + POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405, + "PowerPC 405 A4") #endif #if defined (TODO) - /* PowerPC 405 B3 */ - POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405) + POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405, + "PowerPC 405 B3") #endif #if defined (TODO) - /* PowerPC 405 B4 */ - POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405) + POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405, + "PowerPC 405 B4") #endif #if defined (TODO) - /* PowerPC 405 C3 */ - POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405) + POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405, + "PowerPC 405 C3") #endif #if defined (TODO) - /* PowerPC 405 C4 */ - POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405) + POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405, + "PowerPC 405 C4") #endif - /* PowerPC 405 D2 */ - POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405) + POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405, + "PowerPC 405 D2") #if defined (TODO) - /* PowerPC 405 D3 */ - POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405) + POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405, + "PowerPC 405 D3") #endif - /* PowerPC 405 D4 */ - POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405) + POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405, + "PowerPC 405 D4") #if defined (TODO) - /* PowerPC 405 D5 */ - POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405) + POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405, + "PowerPC 405 D5") #endif #if defined (TODO) - /* PowerPC 405 E4 */ - POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405) + POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405, + "PowerPC 405 E4") #endif #if defined (TODO) - /* PowerPC 405 F4 */ - POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405) + POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405, + "PowerPC 405 F4") #endif #if defined (TODO) - /* PowerPC 405 F5 */ - POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405) + POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405, + "PowerPC 405 F5") #endif #if defined (TODO) - /* PowerPC 405 F6 */ - POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405) + POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405, + "PowerPC 405 F6") #endif /* PowerPC 405 microcontrolers */ - /* PowerPC 405 CRa */ - POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405) - /* PowerPC 405 CRb */ - POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405) - /* PowerPC 405 CRc */ - POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405) - /* PowerPC 405 EP */ - POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405) + POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405, + "PowerPC 405 CRa") + POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405, + "PowerPC 405 CRb") + POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405, + "PowerPC 405 CRc") + POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405, + "PowerPC 405 EP") #if defined(TODO) - /* PowerPC 405 EXr */ - POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405) + POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405, + "PowerPC 405 EXr") #endif - /* PowerPC 405 EZ */ - POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405) + POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405, + "PowerPC 405 EZ") #if defined(TODO) - /* PowerPC 405 FX */ - POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405) + POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405, + "PowerPC 405 FX") #endif - /* PowerPC 405 GPa */ - POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405) - /* PowerPC 405 GPb */ - POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405) - /* PowerPC 405 GPc */ - POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405) - /* PowerPC 405 GPd */ - POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405) - /* PowerPC 405 GPR */ - POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405) + POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405, + "PowerPC 405 GPa") + POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405, + "PowerPC 405 GPb") + POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405, + "PowerPC 405 GPc") + POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405, + "PowerPC 405 GPd") + POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405, + "PowerPC 405 GPR") #if defined(TODO) - /* PowerPC 405 H */ - POWERPC_DEF("405H", CPU_POWERPC_405H, 405) + POWERPC_DEF("405H", CPU_POWERPC_405H, 405, + "PowerPC 405 H") #endif #if defined(TODO) - /* PowerPC 405 L */ - POWERPC_DEF("405L", CPU_POWERPC_405L, 405) + POWERPC_DEF("405L", CPU_POWERPC_405L, 405, + "PowerPC 405 L") #endif - /* PowerPC 405 LP */ - POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405) + POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405, + "PowerPC 405 LP") #if defined(TODO) - /* PowerPC 405 PM */ - POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405) + POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405, + "PowerPC 405 PM") #endif #if defined(TODO) - /* PowerPC 405 PS */ - POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405) + POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405, + "PowerPC 405 PS") #endif #if defined(TODO) - /* PowerPC 405 S */ - POWERPC_DEF("405S", CPU_POWERPC_405S, 405) + POWERPC_DEF("405S", CPU_POWERPC_405S, 405, + "PowerPC 405 S") #endif - /* Npe405 H */ - POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405) - /* Npe405 H2 */ - POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405) - /* Npe405 L */ - POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405) - /* Npe4GS3 */ - POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405) + POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405, + "Npe405 H") + POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405, + "Npe405 H2") + POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405, + "Npe405 L") + POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405, + "Npe4GS3") #if defined (TODO) - POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405) + POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405, + NULL) #endif #if defined (TODO) - POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405) + POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405, + NULL) #endif #if defined (TODO) - /* PowerPC LC77700 (Sanyo) */ - POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405) + POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405, + "PowerPC LC77700 (Sanyo)") #endif /* PowerPC 401/403/405 based set-top-box microcontrolers */ #if defined (TODO) - /* STB010000 */ - POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2) + POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2, + "STB010000") #endif #if defined (TODO) - /* STB01010 */ - POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2) + POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2, + "STB01010") #endif #if defined (TODO) - /* STB0210 */ - POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3) + POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3, + "STB0210") #endif - /* STB03xx */ - POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405) + POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405, + "STB03xx") #if defined (TODO) - /* STB043x */ - POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405) + POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405, + "STB043x") #endif #if defined (TODO) - /* STB045x */ - POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405) + POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405, + "STB045x") #endif - /* STB04xx */ - POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405) - /* STB25xx */ - POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405) + POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405, + "STB04xx") + POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405, + "STB25xx") #if defined (TODO) - /* STB130 */ - POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405) + POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405, + "STB130") #endif /* Xilinx PowerPC 405 cores */ - POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405) - POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405) + POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405, + NULL) + POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405, + NULL) #if defined (TODO) - /* Zarlink ZL10310 */ - POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405) + POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405, + "Zarlink ZL10310") #endif #if defined (TODO) - /* Zarlink ZL10311 */ - POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405) + POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405, + "Zarlink ZL10311") #endif #if defined (TODO) - /* Zarlink ZL10320 */ - POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405) + POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405, + "Zarlink ZL10320") #endif #if defined (TODO) - /* Zarlink ZL10321 */ - POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405) + POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405, + "Zarlink ZL10321") #endif /* PowerPC 440 family */ #if defined(TODO_USER_ONLY) - /* Generic PowerPC 440 */ - POWERPC_DEF("440", CPU_POWERPC_440, 440GP) + POWERPC_DEF("440", CPU_POWERPC_440, 440GP, + "Generic PowerPC 440") #endif /* PowerPC 440 cores */ #if defined (TODO) - /* PowerPC 440 A4 */ - POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4) + POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4, + "PowerPC 440 A4") #endif - /* PowerPC 440 Xilinx 5 */ - POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5) + POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5, + "PowerPC 440 Xilinx 5") #if defined (TODO) - /* PowerPC 440 A5 */ - POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5) + POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5, + "PowerPC 440 A5") #endif #if defined (TODO) - /* PowerPC 440 B4 */ - POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4) + POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4, + "PowerPC 440 B4") #endif #if defined (TODO) - /* PowerPC 440 G4 */ - POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4) + POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4, + "PowerPC 440 G4") #endif #if defined (TODO) - /* PowerPC 440 F5 */ - POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5) + POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5, + "PowerPC 440 F5") #endif #if defined (TODO) - /* PowerPC 440 G5 */ - POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5) + POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5, + "PowerPC 440 G5") #endif #if defined (TODO) - /* PowerPC 440H4 */ - POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4) + POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4, + "PowerPC 440H4") #endif #if defined (TODO) - /* PowerPC 440H6 */ - POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5) + POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5, + "PowerPC 440H6") #endif /* PowerPC 440 microcontrolers */ - /* PowerPC 440 EPa */ - POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP) - /* PowerPC 440 EPb */ - POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP) - /* PowerPC 440 EPX */ - POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP) + POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP, + "PowerPC 440 EPa") + POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP, + "PowerPC 440 EPb") + POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP, + "PowerPC 440 EPX") #if defined(TODO_USER_ONLY) - /* PowerPC 440 GPb */ - POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP) + POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP, + "PowerPC 440 GPb") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 GPc */ - POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP) + POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP, + "PowerPC 440 GPc") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 GRa */ - POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5) + POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5, + "PowerPC 440 GRa") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 GRX */ - POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5) + POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5, + "PowerPC 440 GRX") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 GXa */ - POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP) + POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP, + "PowerPC 440 GXa") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 GXb */ - POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP) + POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP, + "PowerPC 440 GXb") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 GXc */ - POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP) + POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP, + "PowerPC 440 GXc") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 GXf */ - POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP) + POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP, + "PowerPC 440 GXf") #endif #if defined(TODO) - /* PowerPC 440 S */ - POWERPC_DEF("440S", CPU_POWERPC_440S, 440) + POWERPC_DEF("440S", CPU_POWERPC_440S, 440, + "PowerPC 440 S") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 SP */ - POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP) + POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP, + "PowerPC 440 SP") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 SP2 */ - POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP) + POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP, + "PowerPC 440 SP2") #endif #if defined(TODO_USER_ONLY) - /* PowerPC 440 SPE */ - POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP) + POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP, + "PowerPC 440 SPE") #endif /* PowerPC 460 family */ #if defined (TODO) - /* Generic PowerPC 464 */ - POWERPC_DEF("464", CPU_POWERPC_464, 460) + POWERPC_DEF("464", CPU_POWERPC_464, 460, + "Generic PowerPC 464") #endif /* PowerPC 464 microcontrolers */ #if defined (TODO) - /* PowerPC 464H90 */ - POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460) + POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460, + "PowerPC 464H90") #endif #if defined (TODO) - /* PowerPC 464H90F */ - POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F) + POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F, + "PowerPC 464H90F") #endif /* Freescale embedded PowerPC cores */ /* MPC5xx family (aka RCPU) */ #if defined(TODO_USER_ONLY) - /* Generic MPC5xx core */ - POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx) + POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx, + "Generic MPC5xx core") #endif /* MPC8xx family (aka PowerQUICC) */ #if defined(TODO_USER_ONLY) - /* Generic MPC8xx core */ - POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx) + POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx, + "Generic MPC8xx core") #endif /* MPC82xx family (aka PowerQUICC-II) */ - /* PowerPC G2 core */ - POWERPC_DEF("G2", CPU_POWERPC_G2, G2) - /* PowerPC G2 H4 core */ - POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2) - /* PowerPC G2 GP core */ - POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2) - /* PowerPC G2 LS core */ - POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2) - /* PowerPC G2 HiP3 core */ - POWERPC_DEF("G2HiP3", CPU_POWERPC_G2_HIP3, G2) - /* PowerPC G2 HiP4 core */ - POWERPC_DEF("G2HiP4", CPU_POWERPC_G2_HIP4, G2) - /* PowerPC MPC603 core */ - POWERPC_DEF("MPC603", CPU_POWERPC_MPC603, 603E) - /* PowerPC G2le core (same as G2 plus little-endian mode support) */ - POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE) - /* PowerPC G2LE GP core */ - POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE) - /* PowerPC G2LE LS core */ - POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE) - /* PowerPC G2LE GP1 core */ - POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE) - /* PowerPC G2LE GP3 core */ - POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE) + POWERPC_DEF("G2", CPU_POWERPC_G2, G2, + "PowerPC G2 core") + POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2, + "PowerPC G2 H4 core") + POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2, + "PowerPC G2 GP core") + POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2, + "PowerPC G2 LS core") + POWERPC_DEF("G2HiP3", CPU_POWERPC_G2_HIP3, G2, + "PowerPC G2 HiP3 core") + POWERPC_DEF("G2HiP4", CPU_POWERPC_G2_HIP4, G2, + "PowerPC G2 HiP4 core") + POWERPC_DEF("MPC603", CPU_POWERPC_MPC603, 603E, + "PowerPC MPC603 core") + POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE, + "PowerPC G2le core (same as G2 plus little-endian mode support)") + POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE, + "PowerPC G2LE GP core") + POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE, + "PowerPC G2LE LS core") + POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE, + "PowerPC G2LE GP1 core") + POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE, + "PowerPC G2LE GP3 core") /* PowerPC G2 microcontrollers */ #if defined(TODO) - /* MPC5121 */ - POWERPC_DEF_SVR("MPC5121", + POWERPC_DEF_SVR("MPC5121", "MPC5121", CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE) #endif - /* MPC5200 v1.0 */ - POWERPC_DEF_SVR("MPC5200_v10", + POWERPC_DEF_SVR("MPC5200_v10", "MPC5200 v1.0", CPU_POWERPC_MPC5200_v10, POWERPC_SVR_5200_v10, G2LE) - /* MPC5200 v1.1 */ - POWERPC_DEF_SVR("MPC5200_v11", + POWERPC_DEF_SVR("MPC5200_v11", "MPC5200 v1.1", CPU_POWERPC_MPC5200_v11, POWERPC_SVR_5200_v11, G2LE) - /* MPC5200 v1.2 */ - POWERPC_DEF_SVR("MPC5200_v12", + POWERPC_DEF_SVR("MPC5200_v12", "MPC5200 v1.2", CPU_POWERPC_MPC5200_v12, POWERPC_SVR_5200_v12, G2LE) - /* MPC5200B v2.0 */ - POWERPC_DEF_SVR("MPC5200B_v20", + POWERPC_DEF_SVR("MPC5200B_v20", "MPC5200B v2.0", CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE) - /* MPC5200B v2.1 */ - POWERPC_DEF_SVR("MPC5200B_v21", + POWERPC_DEF_SVR("MPC5200B_v21", "MPC5200B v2.1", CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE) /* e200 family */ - /* Generic MPC55xx core */ #if defined (TODO) - POWERPC_DEF_SVR("MPC55xx", + POWERPC_DEF_SVR("MPC55xx", "Generic MPC55xx core", CPU_POWERPC_MPC55xx, POWERPC_SVR_55xx, e200) #endif #if defined (TODO) - /* PowerPC e200z0 core */ - POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200) + POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200, + "PowerPC e200z0 core") #endif #if defined (TODO) - /* PowerPC e200z1 core */ - POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200) + POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200, + "PowerPC e200z1 core") #endif #if defined (TODO) - /* PowerPC e200z3 core */ - POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200) + POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200, + "PowerPC e200z3 core") #endif - /* PowerPC e200z5 core */ - POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200) - /* PowerPC e200z6 core */ - POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200) + POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200, + "PowerPC e200z5 core") + POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200, + "PowerPC e200z6 core") /* PowerPC e200 microcontrollers */ #if defined (TODO) - /* MPC5514E */ - POWERPC_DEF_SVR("MPC5514E", + POWERPC_DEF_SVR("MPC5514E", "MPC5514E", CPU_POWERPC_MPC5514E, POWERPC_SVR_5514E, e200) #endif #if defined (TODO) - /* MPC5514E v0 */ - POWERPC_DEF_SVR("MPC5514E_v0", + POWERPC_DEF_SVR("MPC5514E_v0", "MPC5514E v0", CPU_POWERPC_MPC5514E_v0, POWERPC_SVR_5514E_v0, e200) #endif #if defined (TODO) - /* MPC5514E v1 */ - POWERPC_DEF_SVR("MPC5514E_v1", + POWERPC_DEF_SVR("MPC5514E_v1", "MPC5514E v1", CPU_POWERPC_MPC5514E_v1, POWERPC_SVR_5514E_v1, e200) #endif #if defined (TODO) - /* MPC5514G */ - POWERPC_DEF_SVR("MPC5514G", + POWERPC_DEF_SVR("MPC5514G", "MPC5514G", CPU_POWERPC_MPC5514G, POWERPC_SVR_5514G, e200) #endif #if defined (TODO) - /* MPC5514G v0 */ - POWERPC_DEF_SVR("MPC5514G_v0", + POWERPC_DEF_SVR("MPC5514G_v0", "MPC5514G v0", CPU_POWERPC_MPC5514G_v0, POWERPC_SVR_5514G_v0, e200) #endif #if defined (TODO) - /* MPC5514G v1 */ - POWERPC_DEF_SVR("MPC5514G_v1", + POWERPC_DEF_SVR("MPC5514G_v1", "MPC5514G v1", CPU_POWERPC_MPC5514G_v1, POWERPC_SVR_5514G_v1, e200) #endif #if defined (TODO) - /* MPC5515S */ - POWERPC_DEF_SVR("MPC5515S", + POWERPC_DEF_SVR("MPC5515S", "MPC5515S", CPU_POWERPC_MPC5515S, POWERPC_SVR_5515S, e200) #endif #if defined (TODO) - /* MPC5516E */ - POWERPC_DEF_SVR("MPC5516E", + POWERPC_DEF_SVR("MPC5516E", "MPC5516E", CPU_POWERPC_MPC5516E, POWERPC_SVR_5516E, e200) #endif #if defined (TODO) - /* MPC5516E v0 */ - POWERPC_DEF_SVR("MPC5516E_v0", + POWERPC_DEF_SVR("MPC5516E_v0", "MPC5516E v0", CPU_POWERPC_MPC5516E_v0, POWERPC_SVR_5516E_v0, e200) #endif #if defined (TODO) - /* MPC5516E v1 */ - POWERPC_DEF_SVR("MPC5516E_v1", + POWERPC_DEF_SVR("MPC5516E_v1", "MPC5516E v1", CPU_POWERPC_MPC5516E_v1, POWERPC_SVR_5516E_v1, e200) #endif #if defined (TODO) - /* MPC5516G */ - POWERPC_DEF_SVR("MPC5516G", + POWERPC_DEF_SVR("MPC5516G", "MPC5516G", CPU_POWERPC_MPC5516G, POWERPC_SVR_5516G, e200) #endif #if defined (TODO) - /* MPC5516G v0 */ - POWERPC_DEF_SVR("MPC5516G_v0", + POWERPC_DEF_SVR("MPC5516G_v0", "MPC5516G v0", CPU_POWERPC_MPC5516G_v0, POWERPC_SVR_5516G_v0, e200) #endif #if defined (TODO) - /* MPC5516G v1 */ - POWERPC_DEF_SVR("MPC5516G_v1", + POWERPC_DEF_SVR("MPC5516G_v1", "MPC5516G v1", CPU_POWERPC_MPC5516G_v1, POWERPC_SVR_5516G_v1, e200) #endif #if defined (TODO) - /* MPC5516S */ - POWERPC_DEF_SVR("MPC5516S", + POWERPC_DEF_SVR("MPC5516S", "MPC5516S", CPU_POWERPC_MPC5516S, POWERPC_SVR_5516S, e200) #endif #if defined (TODO) - /* MPC5533 */ - POWERPC_DEF_SVR("MPC5533", + POWERPC_DEF_SVR("MPC5533", "MPC5533", CPU_POWERPC_MPC5533, POWERPC_SVR_5533, e200) #endif #if defined (TODO) - /* MPC5534 */ - POWERPC_DEF_SVR("MPC5534", + POWERPC_DEF_SVR("MPC5534", "MPC5534", CPU_POWERPC_MPC5534, POWERPC_SVR_5534, e200) #endif #if defined (TODO) - /* MPC5553 */ - POWERPC_DEF_SVR("MPC5553", + POWERPC_DEF_SVR("MPC5553", "MPC5553", CPU_POWERPC_MPC5553, POWERPC_SVR_5553, e200) #endif #if defined (TODO) - /* MPC5554 */ - POWERPC_DEF_SVR("MPC5554", + POWERPC_DEF_SVR("MPC5554", "MPC5554", CPU_POWERPC_MPC5554, POWERPC_SVR_5554, e200) #endif #if defined (TODO) - /* MPC5561 */ - POWERPC_DEF_SVR("MPC5561", + POWERPC_DEF_SVR("MPC5561", "MPC5561", CPU_POWERPC_MPC5561, POWERPC_SVR_5561, e200) #endif #if defined (TODO) - /* MPC5565 */ - POWERPC_DEF_SVR("MPC5565", + POWERPC_DEF_SVR("MPC5565", "MPC5565", CPU_POWERPC_MPC5565, POWERPC_SVR_5565, e200) #endif #if defined (TODO) - /* MPC5566 */ - POWERPC_DEF_SVR("MPC5566", + POWERPC_DEF_SVR("MPC5566", "MPC5566", CPU_POWERPC_MPC5566, POWERPC_SVR_5566, e200) #endif #if defined (TODO) - /* MPC5567 */ - POWERPC_DEF_SVR("MPC5567", + POWERPC_DEF_SVR("MPC5567", "MPC5567", CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200) #endif /* e300 family */ - /* PowerPC e300c1 core */ - POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300) - /* PowerPC e300c2 core */ - POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300) - /* PowerPC e300c3 core */ - POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300) - /* PowerPC e300c4 core */ - POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300) + POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300, + "PowerPC e300c1 core") + POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300, + "PowerPC e300c2 core") + POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300, + "PowerPC e300c3 core") + POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300, + "PowerPC e300c4 core") /* PowerPC e300 microcontrollers */ #if defined (TODO) - /* MPC8313 */ - POWERPC_DEF_SVR("MPC8313", + POWERPC_DEF_SVR("MPC8313", "MPC8313", CPU_POWERPC_MPC831x, POWERPC_SVR_8313, e300) #endif #if defined (TODO) - /* MPC8313E */ - POWERPC_DEF_SVR("MPC8313E", + POWERPC_DEF_SVR("MPC8313E", "MPC8313E", CPU_POWERPC_MPC831x, POWERPC_SVR_8313E, e300) #endif #if defined (TODO) - /* MPC8314 */ - POWERPC_DEF_SVR("MPC8314", + POWERPC_DEF_SVR("MPC8314", "MPC8314", CPU_POWERPC_MPC831x, POWERPC_SVR_8314, e300) #endif #if defined (TODO) - /* MPC8314E */ - POWERPC_DEF_SVR("MPC8314E", + POWERPC_DEF_SVR("MPC8314E", "MPC8314E", CPU_POWERPC_MPC831x, POWERPC_SVR_8314E, e300) #endif #if defined (TODO) - /* MPC8315 */ - POWERPC_DEF_SVR("MPC8315", + POWERPC_DEF_SVR("MPC8315", "MPC8315", CPU_POWERPC_MPC831x, POWERPC_SVR_8315, e300) #endif #if defined (TODO) - /* MPC8315E */ - POWERPC_DEF_SVR("MPC8315E", + POWERPC_DEF_SVR("MPC8315E", "MPC8315E", CPU_POWERPC_MPC831x, POWERPC_SVR_8315E, e300) #endif #if defined (TODO) - /* MPC8321 */ - POWERPC_DEF_SVR("MPC8321", + POWERPC_DEF_SVR("MPC8321", "MPC8321", CPU_POWERPC_MPC832x, POWERPC_SVR_8321, e300) #endif #if defined (TODO) - /* MPC8321E */ - POWERPC_DEF_SVR("MPC8321E", + POWERPC_DEF_SVR("MPC8321E", "MPC8321E", CPU_POWERPC_MPC832x, POWERPC_SVR_8321E, e300) #endif #if defined (TODO) - /* MPC8323 */ - POWERPC_DEF_SVR("MPC8323", + POWERPC_DEF_SVR("MPC8323", "MPC8323", CPU_POWERPC_MPC832x, POWERPC_SVR_8323, e300) #endif #if defined (TODO) - /* MPC8323E */ - POWERPC_DEF_SVR("MPC8323E", + POWERPC_DEF_SVR("MPC8323E", "MPC8323E", CPU_POWERPC_MPC832x, POWERPC_SVR_8323E, e300) #endif - /* MPC8343 */ - POWERPC_DEF_SVR("MPC8343", + POWERPC_DEF_SVR("MPC8343", "MPC8343", CPU_POWERPC_MPC834x, POWERPC_SVR_8343, e300) - /* MPC8343A */ - POWERPC_DEF_SVR("MPC8343A", + POWERPC_DEF_SVR("MPC8343A", "MPC8343A", CPU_POWERPC_MPC834x, POWERPC_SVR_8343A, e300) - /* MPC8343E */ - POWERPC_DEF_SVR("MPC8343E", + POWERPC_DEF_SVR("MPC8343E", "MPC8343E", CPU_POWERPC_MPC834x, POWERPC_SVR_8343E, e300) - /* MPC8343EA */ - POWERPC_DEF_SVR("MPC8343EA", + POWERPC_DEF_SVR("MPC8343EA", "MPC8343EA", CPU_POWERPC_MPC834x, POWERPC_SVR_8343EA, e300) - /* MPC8347T */ - POWERPC_DEF_SVR("MPC8347T", + POWERPC_DEF_SVR("MPC8347T", "MPC8347T", CPU_POWERPC_MPC834x, POWERPC_SVR_8347T, e300) - /* MPC8347P */ - POWERPC_DEF_SVR("MPC8347P", + POWERPC_DEF_SVR("MPC8347P", "MPC8347P", CPU_POWERPC_MPC834x, POWERPC_SVR_8347P, e300) - /* MPC8347AT */ - POWERPC_DEF_SVR("MPC8347AT", + POWERPC_DEF_SVR("MPC8347AT", "MPC8347AT", CPU_POWERPC_MPC834x, POWERPC_SVR_8347AT, e300) - /* MPC8347AP */ - POWERPC_DEF_SVR("MPC8347AP", + POWERPC_DEF_SVR("MPC8347AP", "MPC8347AP", CPU_POWERPC_MPC834x, POWERPC_SVR_8347AP, e300) - /* MPC8347ET */ - POWERPC_DEF_SVR("MPC8347ET", + POWERPC_DEF_SVR("MPC8347ET", "MPC8347ET", CPU_POWERPC_MPC834x, POWERPC_SVR_8347ET, e300) - /* MPC8343EP */ - POWERPC_DEF_SVR("MPC8347EP", + POWERPC_DEF_SVR("MPC8347EP", "MPC8343EP", CPU_POWERPC_MPC834x, POWERPC_SVR_8347EP, e300) - /* MPC8347EAT */ - POWERPC_DEF_SVR("MPC8347EAT", + POWERPC_DEF_SVR("MPC8347EAT", "MPC8347EAT", CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAT, e300) - /* MPC8343EAP */ - POWERPC_DEF_SVR("MPC8347EAP", + POWERPC_DEF_SVR("MPC8347EAP", "MPC8343EAP", CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAP, e300) - /* MPC8349 */ - POWERPC_DEF_SVR("MPC8349", + POWERPC_DEF_SVR("MPC8349", "MPC8349", CPU_POWERPC_MPC834x, POWERPC_SVR_8349, e300) - /* MPC8349A */ - POWERPC_DEF_SVR("MPC8349A", + POWERPC_DEF_SVR("MPC8349A", "MPC8349A", CPU_POWERPC_MPC834x, POWERPC_SVR_8349A, e300) - /* MPC8349E */ - POWERPC_DEF_SVR("MPC8349E", + POWERPC_DEF_SVR("MPC8349E", "MPC8349E", CPU_POWERPC_MPC834x, POWERPC_SVR_8349E, e300) - /* MPC8349EA */ - POWERPC_DEF_SVR("MPC8349EA", + POWERPC_DEF_SVR("MPC8349EA", "MPC8349EA", CPU_POWERPC_MPC834x, POWERPC_SVR_8349EA, e300) #if defined (TODO) - /* MPC8358E */ - POWERPC_DEF_SVR("MPC8358E", + POWERPC_DEF_SVR("MPC8358E", "MPC8358E", CPU_POWERPC_MPC835x, POWERPC_SVR_8358E, e300) #endif #if defined (TODO) - /* MPC8360E */ - POWERPC_DEF_SVR("MPC8360E", + POWERPC_DEF_SVR("MPC8360E", "MPC8360E", CPU_POWERPC_MPC836x, POWERPC_SVR_8360E, e300) #endif - /* MPC8377 */ - POWERPC_DEF_SVR("MPC8377", + POWERPC_DEF_SVR("MPC8377", "MPC8377", CPU_POWERPC_MPC837x, POWERPC_SVR_8377, e300) - /* MPC8377E */ - POWERPC_DEF_SVR("MPC8377E", + POWERPC_DEF_SVR("MPC8377E", "MPC8377E", CPU_POWERPC_MPC837x, POWERPC_SVR_8377E, e300) - /* MPC8378 */ - POWERPC_DEF_SVR("MPC8378", + POWERPC_DEF_SVR("MPC8378", "MPC8378", CPU_POWERPC_MPC837x, POWERPC_SVR_8378, e300) - /* MPC8378E */ - POWERPC_DEF_SVR("MPC8378E", + POWERPC_DEF_SVR("MPC8378E", "MPC8378E", CPU_POWERPC_MPC837x, POWERPC_SVR_8378E, e300) - /* MPC8379 */ - POWERPC_DEF_SVR("MPC8379", + POWERPC_DEF_SVR("MPC8379", "MPC8379", CPU_POWERPC_MPC837x, POWERPC_SVR_8379, e300) - /* MPC8379E */ - POWERPC_DEF_SVR("MPC8379E", + POWERPC_DEF_SVR("MPC8379E", "MPC8379E", CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300) /* e500 family */ - /* PowerPC e500 v1.0 core */ - POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1) - /* PowerPC e500 v2.0 core */ - POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1) - /* PowerPC e500v2 v1.0 core */ - POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2) - /* PowerPC e500v2 v2.0 core */ - POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2) - /* PowerPC e500v2 v2.1 core */ - POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2) - /* PowerPC e500v2 v2.2 core */ - POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2) - /* PowerPC e500v2 v3.0 core */ - POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2) - POWERPC_DEF_SVR("e500mc", CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc) + POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1, + "PowerPC e500 v1.0 core") + POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1, + "PowerPC e500 v2.0 core") + POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2, + "PowerPC e500v2 v1.0 core") + POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2, + "PowerPC e500v2 v2.0 core") + POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2, + "PowerPC e500v2 v2.1 core") + POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2, + "PowerPC e500v2 v2.2 core") + POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2, + "PowerPC e500v2 v3.0 core") + POWERPC_DEF_SVR("e500mc", "e500mc", + CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc) #ifdef TARGET_PPC64 - POWERPC_DEF_SVR("e5500", CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500) + POWERPC_DEF_SVR("e5500", "e5500", + CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500) #endif /* PowerPC e500 microcontrollers */ - /* MPC8533 v1.0 */ - POWERPC_DEF_SVR("MPC8533_v10", + POWERPC_DEF_SVR("MPC8533_v10", "MPC8533 v1.0", CPU_POWERPC_MPC8533_v10, POWERPC_SVR_8533_v10, e500v2) - /* MPC8533 v1.1 */ - POWERPC_DEF_SVR("MPC8533_v11", + POWERPC_DEF_SVR("MPC8533_v11", "MPC8533 v1.1", CPU_POWERPC_MPC8533_v11, POWERPC_SVR_8533_v11, e500v2) - /* MPC8533E v1.0 */ - POWERPC_DEF_SVR("MPC8533E_v10", + POWERPC_DEF_SVR("MPC8533E_v10", "MPC8533E v1.0", CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500v2) - POWERPC_DEF_SVR("MPC8533E_v11", + POWERPC_DEF_SVR("MPC8533E_v11", "MPC8533E v1.1", CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500v2) - /* MPC8540 v1.0 */ - POWERPC_DEF_SVR("MPC8540_v10", + POWERPC_DEF_SVR("MPC8540_v10", "MPC8540 v1.0", CPU_POWERPC_MPC8540_v10, POWERPC_SVR_8540_v10, e500v1) - /* MPC8540 v2.0 */ - POWERPC_DEF_SVR("MPC8540_v20", + POWERPC_DEF_SVR("MPC8540_v20", "MPC8540 v2.0", CPU_POWERPC_MPC8540_v20, POWERPC_SVR_8540_v20, e500v1) - /* MPC8540 v2.1 */ - POWERPC_DEF_SVR("MPC8540_v21", + POWERPC_DEF_SVR("MPC8540_v21", "MPC8540 v2.1", CPU_POWERPC_MPC8540_v21, POWERPC_SVR_8540_v21, e500v1) - /* MPC8541 v1.0 */ - POWERPC_DEF_SVR("MPC8541_v10", + POWERPC_DEF_SVR("MPC8541_v10", "MPC8541 v1.0", CPU_POWERPC_MPC8541_v10, POWERPC_SVR_8541_v10, e500v1) - /* MPC8541 v1.1 */ - POWERPC_DEF_SVR("MPC8541_v11", + POWERPC_DEF_SVR("MPC8541_v11", "MPC8541 v1.1", CPU_POWERPC_MPC8541_v11, POWERPC_SVR_8541_v11, e500v1) - /* MPC8541E v1.0 */ - POWERPC_DEF_SVR("MPC8541E_v10", + POWERPC_DEF_SVR("MPC8541E_v10", "MPC8541E v1.0", CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500v1) - /* MPC8541E v1.1 */ - POWERPC_DEF_SVR("MPC8541E_v11", + POWERPC_DEF_SVR("MPC8541E_v11", "MPC8541E v1.1", CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500v1) - /* MPC8543 v1.0 */ - POWERPC_DEF_SVR("MPC8543_v10", + POWERPC_DEF_SVR("MPC8543_v10", "MPC8543 v1.0", CPU_POWERPC_MPC8543_v10, POWERPC_SVR_8543_v10, e500v2) - /* MPC8543 v1.1 */ - POWERPC_DEF_SVR("MPC8543_v11", + POWERPC_DEF_SVR("MPC8543_v11", "MPC8543 v1.1", CPU_POWERPC_MPC8543_v11, POWERPC_SVR_8543_v11, e500v2) - /* MPC8543 v2.0 */ - POWERPC_DEF_SVR("MPC8543_v20", + POWERPC_DEF_SVR("MPC8543_v20", "MPC8543 v2.0", CPU_POWERPC_MPC8543_v20, POWERPC_SVR_8543_v20, e500v2) - /* MPC8543 v2.1 */ - POWERPC_DEF_SVR("MPC8543_v21", + POWERPC_DEF_SVR("MPC8543_v21", "MPC8543 v2.1", CPU_POWERPC_MPC8543_v21, POWERPC_SVR_8543_v21, e500v2) - /* MPC8543E v1.0 */ - POWERPC_DEF_SVR("MPC8543E_v10", + POWERPC_DEF_SVR("MPC8543E_v10", "MPC8543E v1.0", CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500v2) - /* MPC8543E v1.1 */ - POWERPC_DEF_SVR("MPC8543E_v11", + POWERPC_DEF_SVR("MPC8543E_v11", "MPC8543E v1.1", CPU_POWERPC_MPC8543E_v11, POWERPC_SVR_8543E_v11, e500v2) - /* MPC8543E v2.0 */ - POWERPC_DEF_SVR("MPC8543E_v20", + POWERPC_DEF_SVR("MPC8543E_v20", "MPC8543E v2.0", CPU_POWERPC_MPC8543E_v20, POWERPC_SVR_8543E_v20, e500v2) - /* MPC8543E v2.1 */ - POWERPC_DEF_SVR("MPC8543E_v21", + POWERPC_DEF_SVR("MPC8543E_v21", "MPC8543E v2.1", CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500v2) - /* MPC8544 v1.0 */ - POWERPC_DEF_SVR("MPC8544_v10", + POWERPC_DEF_SVR("MPC8544_v10", "MPC8544 v1.0", CPU_POWERPC_MPC8544_v10, POWERPC_SVR_8544_v10, e500v2) - /* MPC8544 v1.1 */ - POWERPC_DEF_SVR("MPC8544_v11", + POWERPC_DEF_SVR("MPC8544_v11", "MPC8544 v1.1", CPU_POWERPC_MPC8544_v11, POWERPC_SVR_8544_v11, e500v2) - /* MPC8544E v1.0 */ - POWERPC_DEF_SVR("MPC8544E_v10", + POWERPC_DEF_SVR("MPC8544E_v10", "MPC8544E v1.0", CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500v2) - /* MPC8544E v1.1 */ - POWERPC_DEF_SVR("MPC8544E_v11", + POWERPC_DEF_SVR("MPC8544E_v11", "MPC8544E v1.1", CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500v2) - /* MPC8545 v2.0 */ - POWERPC_DEF_SVR("MPC8545_v20", + POWERPC_DEF_SVR("MPC8545_v20", "MPC8545 v2.0", CPU_POWERPC_MPC8545_v20, POWERPC_SVR_8545_v20, e500v2) - /* MPC8545 v2.1 */ - POWERPC_DEF_SVR("MPC8545_v21", + POWERPC_DEF_SVR("MPC8545_v21", "MPC8545 v2.1", CPU_POWERPC_MPC8545_v21, POWERPC_SVR_8545_v21, e500v2) - /* MPC8545E v2.0 */ - POWERPC_DEF_SVR("MPC8545E_v20", + POWERPC_DEF_SVR("MPC8545E_v20", "MPC8545E v2.0", CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500v2) - /* MPC8545E v2.1 */ - POWERPC_DEF_SVR("MPC8545E_v21", + POWERPC_DEF_SVR("MPC8545E_v21", "MPC8545E v2.1", CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500v2) - /* MPC8547E v2.0 */ - POWERPC_DEF_SVR("MPC8547E_v20", + POWERPC_DEF_SVR("MPC8547E_v20", "MPC8547E v2.0", CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500v2) - /* MPC8547E v2.1 */ - POWERPC_DEF_SVR("MPC8547E_v21", + POWERPC_DEF_SVR("MPC8547E_v21", "MPC8547E v2.1", CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500v2) - /* MPC8548 v1.0 */ - POWERPC_DEF_SVR("MPC8548_v10", + POWERPC_DEF_SVR("MPC8548_v10", "MPC8548 v1.0", CPU_POWERPC_MPC8548_v10, POWERPC_SVR_8548_v10, e500v2) - /* MPC8548 v1.1 */ - POWERPC_DEF_SVR("MPC8548_v11", + POWERPC_DEF_SVR("MPC8548_v11", "MPC8548 v1.1", CPU_POWERPC_MPC8548_v11, POWERPC_SVR_8548_v11, e500v2) - /* MPC8548 v2.0 */ - POWERPC_DEF_SVR("MPC8548_v20", + POWERPC_DEF_SVR("MPC8548_v20", "MPC8548 v2.0", CPU_POWERPC_MPC8548_v20, POWERPC_SVR_8548_v20, e500v2) - /* MPC8548 v2.1 */ - POWERPC_DEF_SVR("MPC8548_v21", + POWERPC_DEF_SVR("MPC8548_v21", "MPC8548 v2.1", CPU_POWERPC_MPC8548_v21, POWERPC_SVR_8548_v21, e500v2) - /* MPC8548E v1.0 */ - POWERPC_DEF_SVR("MPC8548E_v10", + POWERPC_DEF_SVR("MPC8548E_v10", "MPC8548E v1.0", CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500v2) - /* MPC8548E v1.1 */ - POWERPC_DEF_SVR("MPC8548E_v11", + POWERPC_DEF_SVR("MPC8548E_v11", "MPC8548E v1.1", CPU_POWERPC_MPC8548E_v11, POWERPC_SVR_8548E_v11, e500v2) - /* MPC8548E v2.0 */ - POWERPC_DEF_SVR("MPC8548E_v20", + POWERPC_DEF_SVR("MPC8548E_v20", "MPC8548E v2.0", CPU_POWERPC_MPC8548E_v20, POWERPC_SVR_8548E_v20, e500v2) - /* MPC8548E v2.1 */ - POWERPC_DEF_SVR("MPC8548E_v21", + POWERPC_DEF_SVR("MPC8548E_v21", "MPC8548E v2.1", CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2) - /* MPC8555 v1.0 */ - POWERPC_DEF_SVR("MPC8555_v10", + POWERPC_DEF_SVR("MPC8555_v10", "MPC8555 v1.0", CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2) - /* MPC8555 v1.1 */ - POWERPC_DEF_SVR("MPC8555_v11", + POWERPC_DEF_SVR("MPC8555_v11", "MPC8555 v1.1", CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2) - /* MPC8555E v1.0 */ - POWERPC_DEF_SVR("MPC8555E_v10", + POWERPC_DEF_SVR("MPC8555E_v10", "MPC8555E v1.0", CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2) - /* MPC8555E v1.1 */ - POWERPC_DEF_SVR("MPC8555E_v11", + POWERPC_DEF_SVR("MPC8555E_v11", "MPC8555E v1.1", CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2) - /* MPC8560 v1.0 */ - POWERPC_DEF_SVR("MPC8560_v10", + POWERPC_DEF_SVR("MPC8560_v10", "MPC8560 v1.0", CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2) - /* MPC8560 v2.0 */ - POWERPC_DEF_SVR("MPC8560_v20", + POWERPC_DEF_SVR("MPC8560_v20", "MPC8560 v2.0", CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v2) - /* MPC8560 v2.1 */ - POWERPC_DEF_SVR("MPC8560_v21", + POWERPC_DEF_SVR("MPC8560_v21", "MPC8560 v2.1", CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v2) - /* MPC8567 */ - POWERPC_DEF_SVR("MPC8567", + POWERPC_DEF_SVR("MPC8567", "MPC8567", CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500v2) - /* MPC8567E */ - POWERPC_DEF_SVR("MPC8567E", + POWERPC_DEF_SVR("MPC8567E", "MPC8567E", CPU_POWERPC_MPC8567E, POWERPC_SVR_8567E, e500v2) - /* MPC8568 */ - POWERPC_DEF_SVR("MPC8568", + POWERPC_DEF_SVR("MPC8568", "MPC8568", CPU_POWERPC_MPC8568, POWERPC_SVR_8568, e500v2) - /* MPC8568E */ - POWERPC_DEF_SVR("MPC8568E", + POWERPC_DEF_SVR("MPC8568E", "MPC8568E", CPU_POWERPC_MPC8568E, POWERPC_SVR_8568E, e500v2) - /* MPC8572 */ - POWERPC_DEF_SVR("MPC8572", + POWERPC_DEF_SVR("MPC8572", "MPC8572", CPU_POWERPC_MPC8572, POWERPC_SVR_8572, e500v2) - /* MPC8572E */ - POWERPC_DEF_SVR("MPC8572E", + POWERPC_DEF_SVR("MPC8572E", "MPC8572E", CPU_POWERPC_MPC8572E, POWERPC_SVR_8572E, e500v2) /* e600 family */ - /* PowerPC e600 core */ - POWERPC_DEF("e600", CPU_POWERPC_e600, 7400) + POWERPC_DEF("e600", CPU_POWERPC_e600, 7400, + "PowerPC e600 core") /* PowerPC e600 microcontrollers */ #if defined (TODO) - /* MPC8610 */ - POWERPC_DEF_SVR("MPC8610", + POWERPC_DEF_SVR("MPC8610", "MPC8610", CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400) #endif - /* MPC8641 */ - POWERPC_DEF_SVR("MPC8641", + POWERPC_DEF_SVR("MPC8641", "MPC8641", CPU_POWERPC_MPC8641, POWERPC_SVR_8641, 7400) - /* MPC8641D */ - POWERPC_DEF_SVR("MPC8641D", + POWERPC_DEF_SVR("MPC8641D", "MPC8641D", CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400) /* 32 bits "classic" PowerPC */ /* PowerPC 6xx family */ - /* PowerPC 601v0 */ - POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601) - /* PowerPC 601v1 */ - POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601) - /* PowerPC 601v2 */ - POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v) - /* PowerPC 602 */ - POWERPC_DEF("602", CPU_POWERPC_602, 602) - /* PowerPC 603 */ - POWERPC_DEF("603", CPU_POWERPC_603, 603) - /* PowerPC 603e v1.1 */ - POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E) - /* PowerPC 603e v1.2 */ - POWERPC_DEF("603e_v1.2", CPU_POWERPC_603E_v12, 603E) - /* PowerPC 603e v1.3 */ - POWERPC_DEF("603e_v1.3", CPU_POWERPC_603E_v13, 603E) - /* PowerPC 603e v1.4 */ - POWERPC_DEF("603e_v1.4", CPU_POWERPC_603E_v14, 603E) - /* PowerPC 603e v2.2 */ - POWERPC_DEF("603e_v2.2", CPU_POWERPC_603E_v22, 603E) - /* PowerPC 603e v3 */ - POWERPC_DEF("603e_v3", CPU_POWERPC_603E_v3, 603E) - /* PowerPC 603e v4 */ - POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E) - /* PowerPC 603e v4.1 */ - POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E) - /* PowerPC 603e (aka PID7) */ - POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E) - /* PowerPC 603e7t */ - POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E) - /* PowerPC 603e7v */ - POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E) - /* PowerPC 603e7v1 */ - POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E) - /* PowerPC 603e7v2 */ - POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E) - /* PowerPC 603p (aka PID7v) */ - POWERPC_DEF("603p", CPU_POWERPC_603P, 603E) - /* PowerPC 604 */ - POWERPC_DEF("604", CPU_POWERPC_604, 604) - /* PowerPC 604e v1.0 */ - POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E) - /* PowerPC 604e v2.2 */ - POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604E) - /* PowerPC 604e v2.4 */ - POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E) - /* PowerPC 604r (aka PIDA) */ - POWERPC_DEF("604r", CPU_POWERPC_604R, 604E) + POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601, + "PowerPC 601v0") + POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601, + "PowerPC 601v1") + POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v, + "PowerPC 601v2") + POWERPC_DEF("602", CPU_POWERPC_602, 602, + "PowerPC 602") + POWERPC_DEF("603", CPU_POWERPC_603, 603, + "PowerPC 603") + POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E, + "PowerPC 603e v1.1") + POWERPC_DEF("603e_v1.2", CPU_POWERPC_603E_v12, 603E, + "PowerPC 603e v1.2") + POWERPC_DEF("603e_v1.3", CPU_POWERPC_603E_v13, 603E, + "PowerPC 603e v1.3") + POWERPC_DEF("603e_v1.4", CPU_POWERPC_603E_v14, 603E, + "PowerPC 603e v1.4") + POWERPC_DEF("603e_v2.2", CPU_POWERPC_603E_v22, 603E, + "PowerPC 603e v2.2") + POWERPC_DEF("603e_v3", CPU_POWERPC_603E_v3, 603E, + "PowerPC 603e v3") + POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E, + "PowerPC 603e v4") + POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E, + "PowerPC 603e v4.1") + POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E, + "PowerPC 603e (aka PID7)") + POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E, + "PowerPC 603e7t") + POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E, + "PowerPC 603e7v") + POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E, + "PowerPC 603e7v1") + POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E, + "PowerPC 603e7v2") + POWERPC_DEF("603p", CPU_POWERPC_603P, 603E, + "PowerPC 603p (aka PID7v)") + POWERPC_DEF("604", CPU_POWERPC_604, 604, + "PowerPC 604") + POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E, + "PowerPC 604e v1.0") + POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604E, + "PowerPC 604e v2.2") + POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E, + "PowerPC 604e v2.4") + POWERPC_DEF("604r", CPU_POWERPC_604R, 604E, + "PowerPC 604r (aka PIDA)") #if defined(TODO) - /* PowerPC 604ev */ - POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E) + POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E, + "PowerPC 604ev") #endif /* PowerPC 7xx family */ - /* PowerPC 740 v1.0 (G3) */ - POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740) - /* PowerPC 750 v1.0 (G3) */ - POWERPC_DEF("750_v1.0", CPU_POWERPC_7x0_v10, 750) - /* PowerPC 740 v2.0 (G3) */ - POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 740) - /* PowerPC 750 v2.0 (G3) */ - POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 750) - /* PowerPC 740 v2.1 (G3) */ - POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 740) - /* PowerPC 750 v2.1 (G3) */ - POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 750) - /* PowerPC 740 v2.2 (G3) */ - POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 740) - /* PowerPC 750 v2.2 (G3) */ - POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 750) - /* PowerPC 740 v3.0 (G3) */ - POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 740) - /* PowerPC 750 v3.0 (G3) */ - POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 750) - /* PowerPC 740 v3.1 (G3) */ - POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 740) - /* PowerPC 750 v3.1 (G3) */ - POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 750) - /* PowerPC 740E (G3) */ - POWERPC_DEF("740e", CPU_POWERPC_740E, 740) - /* PowerPC 750E (G3) */ - POWERPC_DEF("750e", CPU_POWERPC_750E, 750) - /* PowerPC 740P (G3) */ - POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740) - /* PowerPC 750P (G3) */ - POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750) - /* PowerPC 750CL v1.0 */ - POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl) - /* PowerPC 750CL v2.0 */ - POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl) - /* PowerPC 750CX v1.0 (G3 embedded) */ - POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx) - /* PowerPC 750CX v2.1 (G3 embedded) */ - POWERPC_DEF("750cx_v2.0", CPU_POWERPC_750CX_v20, 750cx) - /* PowerPC 750CX v2.1 (G3 embedded) */ - POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx) - /* PowerPC 750CX v2.2 (G3 embedded) */ - POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx) - /* PowerPC 750CXe v2.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx) - /* PowerPC 750CXe v2.2 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 750cx) - /* PowerPC 750CXe v2.3 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 750cx) - /* PowerPC 750CXe v2.4 (G3 embedded) */ - POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 750cx) - /* PowerPC 750CXe v2.4b (G3 embedded) */ - POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 750cx) - /* PowerPC 750CXe v3.0 (G3 embedded) */ - POWERPC_DEF("750cxe_v3.0", CPU_POWERPC_750CXE_v30, 750cx) - /* PowerPC 750CXe v3.1 (G3 embedded) */ - POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 750cx) - /* PowerPC 750CXe v3.1b (G3 embedded) */ - POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 750cx) - /* PowerPC 750CXr (G3 embedded) */ - POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx) - /* PowerPC 750FL (G3 embedded) */ - POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx) - /* PowerPC 750FX v1.0 (G3 embedded) */ - POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx) - /* PowerPC 750FX v2.0 (G3 embedded) */ - POWERPC_DEF("750fx_v2.0", CPU_POWERPC_750FX_v20, 750fx) - /* PowerPC 750FX v2.1 (G3 embedded) */ - POWERPC_DEF("750fx_v2.1", CPU_POWERPC_750FX_v21, 750fx) - /* PowerPC 750FX v2.2 (G3 embedded) */ - POWERPC_DEF("750fx_v2.2", CPU_POWERPC_750FX_v22, 750fx) - /* PowerPC 750FX v2.3 (G3 embedded) */ - POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx) - /* PowerPC 750GL (G3 embedded) */ - POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx) - /* PowerPC 750GX v1.0 (G3 embedded) */ - POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx) - /* PowerPC 750GX v1.1 (G3 embedded) */ - POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx) - /* PowerPC 750GX v1.2 (G3 embedded) */ - POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx) - /* PowerPC 750L v2.0 (G3 embedded) */ - POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750) - /* PowerPC 750L v2.1 (G3 embedded) */ - POWERPC_DEF("750l_v2.1", CPU_POWERPC_750L_v21, 750) - /* PowerPC 750L v2.2 (G3 embedded) */ - POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 750) - /* PowerPC 750L v3.0 (G3 embedded) */ - POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750) - /* PowerPC 750L v3.2 (G3 embedded) */ - POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750) - /* PowerPC 745 v1.0 */ - POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745) - /* PowerPC 755 v1.0 */ - POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 755) - /* PowerPC 745 v1.1 */ - POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 745) - /* PowerPC 755 v1.1 */ - POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 755) - /* PowerPC 745 v2.0 */ - POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 745) - /* PowerPC 755 v2.0 */ - POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 755) - /* PowerPC 745 v2.1 */ - POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 745) - /* PowerPC 755 v2.1 */ - POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 755) - /* PowerPC 745 v2.2 */ - POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 745) - /* PowerPC 755 v2.2 */ - POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 755) - /* PowerPC 745 v2.3 */ - POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 745) - /* PowerPC 755 v2.3 */ - POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 755) - /* PowerPC 745 v2.4 */ - POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 745) - /* PowerPC 755 v2.4 */ - POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 755) - /* PowerPC 745 v2.5 */ - POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 745) - /* PowerPC 755 v2.5 */ - POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 755) - /* PowerPC 745 v2.6 */ - POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 745) - /* PowerPC 755 v2.6 */ - POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 755) - /* PowerPC 745 v2.7 */ - POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 745) - /* PowerPC 755 v2.7 */ - POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 755) - /* PowerPC 745 v2.8 */ - POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 745) - /* PowerPC 755 v2.8 */ - POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755) + POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740, + "PowerPC 740 v1.0 (G3)") + POWERPC_DEF("750_v1.0", CPU_POWERPC_7x0_v10, 750, + "PowerPC 750 v1.0 (G3)") + POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 740, + "PowerPC 740 v2.0 (G3)") + POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 750, + "PowerPC 750 v2.0 (G3)") + POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 740, + "PowerPC 740 v2.1 (G3)") + POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 750, + "PowerPC 750 v2.1 (G3)") + POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 740, + "PowerPC 740 v2.2 (G3)") + POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 750, + "PowerPC 750 v2.2 (G3)") + POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 740, + "PowerPC 740 v3.0 (G3)") + POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 750, + "PowerPC 750 v3.0 (G3)") + POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 740, + "PowerPC 740 v3.1 (G3)") + POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 750, + "PowerPC 750 v3.1 (G3)") + POWERPC_DEF("740e", CPU_POWERPC_740E, 740, + "PowerPC 740E (G3)") + POWERPC_DEF("750e", CPU_POWERPC_750E, 750, + "PowerPC 750E (G3)") + POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740, + "PowerPC 740P (G3)") + POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750, + "PowerPC 750P (G3)") + POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl, + "PowerPC 750CL v1.0") + POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl, + "PowerPC 750CL v2.0") + POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx, + "PowerPC 750CX v1.0 (G3 embedded)") + POWERPC_DEF("750cx_v2.0", CPU_POWERPC_750CX_v20, 750cx, + "PowerPC 750CX v2.1 (G3 embedded)") + POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx, + "PowerPC 750CX v2.1 (G3 embedded)") + POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx, + "PowerPC 750CX v2.2 (G3 embedded)") + POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx, + "PowerPC 750CXe v2.1 (G3 embedded)") + POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 750cx, + "PowerPC 750CXe v2.2 (G3 embedded)") + POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 750cx, + "PowerPC 750CXe v2.3 (G3 embedded)") + POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 750cx, + "PowerPC 750CXe v2.4 (G3 embedded)") + POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 750cx, + "PowerPC 750CXe v2.4b (G3 embedded)") + POWERPC_DEF("750cxe_v3.0", CPU_POWERPC_750CXE_v30, 750cx, + "PowerPC 750CXe v3.0 (G3 embedded)") + POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 750cx, + "PowerPC 750CXe v3.1 (G3 embedded)") + POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 750cx, + "PowerPC 750CXe v3.1b (G3 embedded)") + POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx, + "PowerPC 750CXr (G3 embedded)") + POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx, + "PowerPC 750FL (G3 embedded)") + POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx, + "PowerPC 750FX v1.0 (G3 embedded)") + POWERPC_DEF("750fx_v2.0", CPU_POWERPC_750FX_v20, 750fx, + "PowerPC 750FX v2.0 (G3 embedded)") + POWERPC_DEF("750fx_v2.1", CPU_POWERPC_750FX_v21, 750fx, + "PowerPC 750FX v2.1 (G3 embedded)") + POWERPC_DEF("750fx_v2.2", CPU_POWERPC_750FX_v22, 750fx, + "PowerPC 750FX v2.2 (G3 embedded)") + POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx, + "PowerPC 750FX v2.3 (G3 embedded)") + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx, + "PowerPC 750GL (G3 embedded)") + POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx, + "PowerPC 750GX v1.0 (G3 embedded)") + POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx, + "PowerPC 750GX v1.1 (G3 embedded)") + POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx, + "PowerPC 750GX v1.2 (G3 embedded)") + POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750, + "PowerPC 750L v2.0 (G3 embedded)") + POWERPC_DEF("750l_v2.1", CPU_POWERPC_750L_v21, 750, + "PowerPC 750L v2.1 (G3 embedded)") + POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 750, + "PowerPC 750L v2.2 (G3 embedded)") + POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750, + "PowerPC 750L v3.0 (G3 embedded)") + POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750, + "PowerPC 750L v3.2 (G3 embedded)") + POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745, + "PowerPC 745 v1.0") + POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 755, + "PowerPC 755 v1.0") + POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 745, + "PowerPC 745 v1.1") + POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 755, + "PowerPC 755 v1.1") + POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 745, + "PowerPC 745 v2.0") + POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 755, + "PowerPC 755 v2.0") + POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 745, + "PowerPC 745 v2.1") + POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 755, + "PowerPC 755 v2.1") + POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 745, + "PowerPC 745 v2.2") + POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 755, + "PowerPC 755 v2.2") + POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 745, + "PowerPC 745 v2.3") + POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 755, + "PowerPC 755 v2.3") + POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 745, + "PowerPC 745 v2.4") + POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 755, + "PowerPC 755 v2.4") + POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 745, + "PowerPC 745 v2.5") + POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 755, + "PowerPC 755 v2.5") + POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 745, + "PowerPC 745 v2.6") + POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 755, + "PowerPC 755 v2.6") + POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 745, + "PowerPC 745 v2.7") + POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 755, + "PowerPC 755 v2.7") + POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 745, + "PowerPC 745 v2.8") + POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755, + "PowerPC 755 v2.8") #if defined (TODO) - /* PowerPC 745P (G3) */ - POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745) - /* PowerPC 755P (G3) */ - POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755) + POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745, + "PowerPC 745P (G3)") + POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755, + "PowerPC 755P (G3)") #endif /* PowerPC 74xx family */ - /* PowerPC 7400 v1.0 (G4) */ - POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400) - /* PowerPC 7400 v1.1 (G4) */ - POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400) - /* PowerPC 7400 v2.0 (G4) */ - POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400) - /* PowerPC 7400 v2.1 (G4) */ - POWERPC_DEF("7400_v2.1", CPU_POWERPC_7400_v21, 7400) - /* PowerPC 7400 v2.2 (G4) */ - POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400) - /* PowerPC 7400 v2.6 (G4) */ - POWERPC_DEF("7400_v2.6", CPU_POWERPC_7400_v26, 7400) - /* PowerPC 7400 v2.7 (G4) */ - POWERPC_DEF("7400_v2.7", CPU_POWERPC_7400_v27, 7400) - /* PowerPC 7400 v2.8 (G4) */ - POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400) - /* PowerPC 7400 v2.9 (G4) */ - POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400) - /* PowerPC 7410 v1.0 (G4) */ - POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410) - /* PowerPC 7410 v1.1 (G4) */ - POWERPC_DEF("7410_v1.1", CPU_POWERPC_7410_v11, 7410) - /* PowerPC 7410 v1.2 (G4) */ - POWERPC_DEF("7410_v1.2", CPU_POWERPC_7410_v12, 7410) - /* PowerPC 7410 v1.3 (G4) */ - POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410) - /* PowerPC 7410 v1.4 (G4) */ - POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410) - /* PowerPC 7448 v1.0 (G4) */ - POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400) - /* PowerPC 7448 v1.1 (G4) */ - POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400) - /* PowerPC 7448 v2.0 (G4) */ - POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400) - /* PowerPC 7448 v2.1 (G4) */ - POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400) - /* PowerPC 7450 v1.0 (G4) */ - POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450) - /* PowerPC 7450 v1.1 (G4) */ - POWERPC_DEF("7450_v1.1", CPU_POWERPC_7450_v11, 7450) - /* PowerPC 7450 v1.2 (G4) */ - POWERPC_DEF("7450_v1.2", CPU_POWERPC_7450_v12, 7450) - /* PowerPC 7450 v2.0 (G4) */ - POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450) - /* PowerPC 7450 v2.1 (G4) */ - POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450) - /* PowerPC 7441 v2.1 (G4) */ - POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440) - /* PowerPC 7441 v2.3 (G4) */ - POWERPC_DEF("7441_v2.3", CPU_POWERPC_74x1_v23, 7440) - /* PowerPC 7451 v2.3 (G4) */ - POWERPC_DEF("7451_v2.3", CPU_POWERPC_74x1_v23, 7450) - /* PowerPC 7441 v2.10 (G4) */ - POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440) - /* PowerPC 7451 v2.10 (G4) */ - POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450) - /* PowerPC 7445 v1.0 (G4) */ - POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445) - /* PowerPC 7455 v1.0 (G4) */ - POWERPC_DEF("7455_v1.0", CPU_POWERPC_74x5_v10, 7455) - /* PowerPC 7445 v2.1 (G4) */ - POWERPC_DEF("7445_v2.1", CPU_POWERPC_74x5_v21, 7445) - /* PowerPC 7455 v2.1 (G4) */ - POWERPC_DEF("7455_v2.1", CPU_POWERPC_74x5_v21, 7455) - /* PowerPC 7445 v3.2 (G4) */ - POWERPC_DEF("7445_v3.2", CPU_POWERPC_74x5_v32, 7445) - /* PowerPC 7455 v3.2 (G4) */ - POWERPC_DEF("7455_v3.2", CPU_POWERPC_74x5_v32, 7455) - /* PowerPC 7445 v3.3 (G4) */ - POWERPC_DEF("7445_v3.3", CPU_POWERPC_74x5_v33, 7445) - /* PowerPC 7455 v3.3 (G4) */ - POWERPC_DEF("7455_v3.3", CPU_POWERPC_74x5_v33, 7455) - /* PowerPC 7445 v3.4 (G4) */ - POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445) - /* PowerPC 7455 v3.4 (G4) */ - POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455) - /* PowerPC 7447 v1.0 (G4) */ - POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445) - /* PowerPC 7457 v1.0 (G4) */ - POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455) - /* PowerPC 7447 v1.1 (G4) */ - POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445) - /* PowerPC 7457 v1.1 (G4) */ - POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455) - /* PowerPC 7457 v1.2 (G4) */ - POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455) - /* PowerPC 7447A v1.0 (G4) */ - POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445) - /* PowerPC 7457A v1.0 (G4) */ - POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455) - /* PowerPC 7447A v1.1 (G4) */ - POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445) - /* PowerPC 7457A v1.1 (G4) */ - POWERPC_DEF("7457A_v1.1", CPU_POWERPC_74x7A_v11, 7455) - /* PowerPC 7447A v1.2 (G4) */ - POWERPC_DEF("7447A_v1.2", CPU_POWERPC_74x7A_v12, 7445) - /* PowerPC 7457A v1.2 (G4) */ - POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455) + POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400, + "PowerPC 7400 v1.0 (G4)") + POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400, + "PowerPC 7400 v1.1 (G4)") + POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400, + "PowerPC 7400 v2.0 (G4)") + POWERPC_DEF("7400_v2.1", CPU_POWERPC_7400_v21, 7400, + "PowerPC 7400 v2.1 (G4)") + POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400, + "PowerPC 7400 v2.2 (G4)") + POWERPC_DEF("7400_v2.6", CPU_POWERPC_7400_v26, 7400, + "PowerPC 7400 v2.6 (G4)") + POWERPC_DEF("7400_v2.7", CPU_POWERPC_7400_v27, 7400, + "PowerPC 7400 v2.7 (G4)") + POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400, + "PowerPC 7400 v2.8 (G4)") + POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400, + "PowerPC 7400 v2.9 (G4)") + POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410, + "PowerPC 7410 v1.0 (G4)") + POWERPC_DEF("7410_v1.1", CPU_POWERPC_7410_v11, 7410, + "PowerPC 7410 v1.1 (G4)") + POWERPC_DEF("7410_v1.2", CPU_POWERPC_7410_v12, 7410, + "PowerPC 7410 v1.2 (G4)") + POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410, + "PowerPC 7410 v1.3 (G4)") + POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410, + "PowerPC 7410 v1.4 (G4)") + POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400, + "PowerPC 7448 v1.0 (G4)") + POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400, + "PowerPC 7448 v1.1 (G4)") + POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400, + "PowerPC 7448 v2.0 (G4)") + POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400, + "PowerPC 7448 v2.1 (G4)") + POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450, + "PowerPC 7450 v1.0 (G4)") + POWERPC_DEF("7450_v1.1", CPU_POWERPC_7450_v11, 7450, + "PowerPC 7450 v1.1 (G4)") + POWERPC_DEF("7450_v1.2", CPU_POWERPC_7450_v12, 7450, + "PowerPC 7450 v1.2 (G4)") + POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450, + "PowerPC 7450 v2.0 (G4)") + POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450, + "PowerPC 7450 v2.1 (G4)") + POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440, + "PowerPC 7441 v2.1 (G4)") + POWERPC_DEF("7441_v2.3", CPU_POWERPC_74x1_v23, 7440, + "PowerPC 7441 v2.3 (G4)") + POWERPC_DEF("7451_v2.3", CPU_POWERPC_74x1_v23, 7450, + "PowerPC 7451 v2.3 (G4)") + POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440, + "PowerPC 7441 v2.10 (G4)") + POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450, + "PowerPC 7451 v2.10 (G4)") + POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445, + "PowerPC 7445 v1.0 (G4)") + POWERPC_DEF("7455_v1.0", CPU_POWERPC_74x5_v10, 7455, + "PowerPC 7455 v1.0 (G4)") + POWERPC_DEF("7445_v2.1", CPU_POWERPC_74x5_v21, 7445, + "PowerPC 7445 v2.1 (G4)") + POWERPC_DEF("7455_v2.1", CPU_POWERPC_74x5_v21, 7455, + "PowerPC 7455 v2.1 (G4)") + POWERPC_DEF("7445_v3.2", CPU_POWERPC_74x5_v32, 7445, + "PowerPC 7445 v3.2 (G4)") + POWERPC_DEF("7455_v3.2", CPU_POWERPC_74x5_v32, 7455, + "PowerPC 7455 v3.2 (G4)") + POWERPC_DEF("7445_v3.3", CPU_POWERPC_74x5_v33, 7445, + "PowerPC 7445 v3.3 (G4)") + POWERPC_DEF("7455_v3.3", CPU_POWERPC_74x5_v33, 7455, + "PowerPC 7455 v3.3 (G4)") + POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445, + "PowerPC 7445 v3.4 (G4)") + POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455, + "PowerPC 7455 v3.4 (G4)") + POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445, + "PowerPC 7447 v1.0 (G4)") + POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455, + "PowerPC 7457 v1.0 (G4)") + POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445, + "PowerPC 7447 v1.1 (G4)") + POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455, + "PowerPC 7457 v1.1 (G4)") + POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455, + "PowerPC 7457 v1.2 (G4)") + POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445, + "PowerPC 7447A v1.0 (G4)") + POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455, + "PowerPC 7457A v1.0 (G4)") + POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445, + "PowerPC 7447A v1.1 (G4)") + POWERPC_DEF("7457A_v1.1", CPU_POWERPC_74x7A_v11, 7455, + "PowerPC 7457A v1.1 (G4)") + POWERPC_DEF("7447A_v1.2", CPU_POWERPC_74x7A_v12, 7445, + "PowerPC 7447A v1.2 (G4)") + POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455, + "PowerPC 7457A v1.2 (G4)") /* 64 bits PowerPC */ #if defined (TARGET_PPC64) - /* PowerPC 620 */ - POWERPC_DEF("620", CPU_POWERPC_620, 620) + POWERPC_DEF("620", CPU_POWERPC_620, 620, + "PowerPC 620") #if defined (TODO) - /* PowerPC 630 (POWER3) */ - POWERPC_DEF("630", CPU_POWERPC_630, 630) + POWERPC_DEF("630", CPU_POWERPC_630, 630, + "PowerPC 630 (POWER3)") #endif #if defined (TODO) - /* PowerPC 631 (Power 3+) */ - POWERPC_DEF("631", CPU_POWERPC_631, 631) + POWERPC_DEF("631", CPU_POWERPC_631, 631, + "PowerPC 631 (Power 3+)") #endif #if defined (TODO) - /* POWER4 */ - POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4) + POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4, + "POWER4") #endif #if defined (TODO) - /* POWER4p */ - POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P) + POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P, + "POWER4p") #endif #if defined (TODO) - /* POWER5 */ - POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5) - /* POWER5GR */ - POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5) + POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5, + "POWER5") + POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5, + "POWER5GR") #endif #if defined (TODO) - /* POWER5+ */ - POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P) - /* POWER5GS */ - POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P) + POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P, + "POWER5+") + POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P, + "POWER5GS") #endif #if defined (TODO) - /* POWER6 */ - POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6) - /* POWER6 running in POWER5 mode */ - POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5) - /* POWER6A */ - POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6) + POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6, + "POWER6") + POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5, + "POWER6 running in POWER5 mode") + POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6, + "POWER6A") #endif - /* POWER7 */ - POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7) - POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7) - POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7) - /* PowerPC 970 */ - POWERPC_DEF("970", CPU_POWERPC_970, 970) - /* PowerPC 970FX v1.0 (G5) */ - POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX) - /* PowerPC 970FX v2.0 (G5) */ - POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX) - /* PowerPC 970FX v2.1 (G5) */ - POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX) - /* PowerPC 970FX v3.0 (G5) */ - POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX) - /* PowerPC 970FX v3.1 (G5) */ - POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX) - /* PowerPC 970GX (G5) */ - POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX) - /* PowerPC 970MP v1.0 */ - POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP) - /* PowerPC 970MP v1.1 */ - POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP) + POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7, + "POWER7 v2.0") + POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7, + "POWER7 v2.1") + POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, + "POWER7 v2.3") + POWERPC_DEF("970", CPU_POWERPC_970, 970, + "PowerPC 970") + POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX, + "PowerPC 970FX v1.0 (G5)") + POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX, + "PowerPC 970FX v2.0 (G5)") + POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX, + "PowerPC 970FX v2.1 (G5)") + POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX, + "PowerPC 970FX v3.0 (G5)") + POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX, + "PowerPC 970FX v3.1 (G5)") + POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX, + "PowerPC 970GX (G5)") + POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP, + "PowerPC 970MP v1.0") + POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP, + "PowerPC 970MP v1.1") #if defined (TODO) - /* PowerPC Cell */ - POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970) + POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970, + "PowerPC Cell") #endif #if defined (TODO) - /* PowerPC Cell v1.0 */ - POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970) + POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970, + "PowerPC Cell v1.0") #endif #if defined (TODO) - /* PowerPC Cell v2.0 */ - POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970) + POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970, + "PowerPC Cell v2.0") #endif #if defined (TODO) - /* PowerPC Cell v3.0 */ - POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970) + POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970, + "PowerPC Cell v3.0") #endif #if defined (TODO) - /* PowerPC Cell v3.1 */ - POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970) + POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970, + "PowerPC Cell v3.1") #endif #if defined (TODO) - /* PowerPC Cell v3.2 */ - POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970) + POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970, + "PowerPC Cell v3.2") #endif #if defined (TODO) - /* RS64 (Apache/A35) */ /* This one seems to support the whole POWER2 instruction set * and the PowerPC 64 one. */ /* What about A10 & A30 ? */ - POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64) + POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64, + "RS64 (Apache/A35)") #endif #if defined (TODO) - /* RS64-II (NorthStar/A50) */ - POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64) + POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64, + "RS64-II (NorthStar/A50)") #endif #if defined (TODO) - /* RS64-III (Pulsar) */ - POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64) + POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64, + "RS64-III (Pulsar)") #endif #if defined (TODO) - /* RS64-IV (IceStar/IStar/SStar) */ - POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64) + POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64, + "RS64-IV (IceStar/IStar/SStar)") #endif #endif /* defined (TARGET_PPC64) */ /* POWER */ #if defined (TODO) - /* Original POWER */ - POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER) + POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER, + "Original POWER") #endif #if defined (TODO) - /* POWER2 */ - POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER) + POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER, + "POWER2") #endif /* PA semi cores */ #if defined (TODO) - /* PA PA6T */ - POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T) + POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T, + "PA PA6T") #endif typedef struct PowerPCCPUAlias { From 09cc86f2b16ae242c031a01c6adca0ac5c5791ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:48 +0000 Subject: [PATCH 1462/1634] target-ppc: Update Coding Style for CPU models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the space in #if defined (TODO). Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 200 ++++++++++++++++++------------------ 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index bd5230cedf..31566e0d95 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7923,7 +7923,7 @@ enum { "PowerPC 401A1") POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2, "PowerPC 401B2") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3, "PowerPC 401B3") #endif @@ -7939,7 +7939,7 @@ enum { POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2, "PowerPC 401G2") /* PowerPC 401 microcontrolers */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401, "PowerPC 401GF") #endif @@ -7947,7 +7947,7 @@ enum { "IOP480 (401 microcontroller)") POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401, "IBM Processor for Network Resources") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401, NULL) #endif @@ -7961,61 +7961,61 @@ enum { "PowerPC 403 GC") POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX, "PowerPC 403 GCX") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403, "PowerPC 403 GP") #endif /* PowerPC 405 family */ /* PowerPC 405 cores */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405, "PowerPC 405 A3") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405, "PowerPC 405 A4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405, "PowerPC 405 B3") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405, "PowerPC 405 B4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405, "PowerPC 405 C3") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405, "PowerPC 405 C4") #endif POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405, "PowerPC 405 D2") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405, "PowerPC 405 D3") #endif POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405, "PowerPC 405 D4") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405, "PowerPC 405 D5") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405, "PowerPC 405 E4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405, "PowerPC 405 F4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405, "PowerPC 405 F5") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405, "PowerPC 405 F6") #endif @@ -8078,38 +8078,38 @@ enum { "Npe405 L") POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405, "Npe4GS3") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405, NULL) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405, NULL) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405, "PowerPC LC77700 (Sanyo)") #endif /* PowerPC 401/403/405 based set-top-box microcontrolers */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2, "STB010000") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2, "STB01010") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3, "STB0210") #endif POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405, "STB03xx") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405, "STB043x") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405, "STB045x") #endif @@ -8117,7 +8117,7 @@ enum { "STB04xx") POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405, "STB25xx") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405, "STB130") #endif @@ -8126,19 +8126,19 @@ enum { NULL) POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405, NULL) -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405, "Zarlink ZL10310") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405, "Zarlink ZL10311") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405, "Zarlink ZL10320") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405, "Zarlink ZL10321") #endif @@ -8148,37 +8148,37 @@ enum { "Generic PowerPC 440") #endif /* PowerPC 440 cores */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4, "PowerPC 440 A4") #endif POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5, "PowerPC 440 Xilinx 5") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5, "PowerPC 440 A5") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4, "PowerPC 440 B4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4, "PowerPC 440 G4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5, "PowerPC 440 F5") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5, "PowerPC 440 G5") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4, "PowerPC 440H4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5, "PowerPC 440H6") #endif @@ -8238,16 +8238,16 @@ enum { "PowerPC 440 SPE") #endif /* PowerPC 460 family */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("464", CPU_POWERPC_464, 460, "Generic PowerPC 464") #endif /* PowerPC 464 microcontrolers */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460, "PowerPC 464H90") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F, "PowerPC 464H90F") #endif @@ -8303,19 +8303,19 @@ enum { POWERPC_DEF_SVR("MPC5200B_v21", "MPC5200B v2.1", CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE) /* e200 family */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC55xx", "Generic MPC55xx core", CPU_POWERPC_MPC55xx, POWERPC_SVR_55xx, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200, "PowerPC e200z0 core") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200, "PowerPC e200z1 core") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200, "PowerPC e200z3 core") #endif @@ -8324,91 +8324,91 @@ enum { POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200, "PowerPC e200z6 core") /* PowerPC e200 microcontrollers */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5514E", "MPC5514E", CPU_POWERPC_MPC5514E, POWERPC_SVR_5514E, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5514E_v0", "MPC5514E v0", CPU_POWERPC_MPC5514E_v0, POWERPC_SVR_5514E_v0, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5514E_v1", "MPC5514E v1", CPU_POWERPC_MPC5514E_v1, POWERPC_SVR_5514E_v1, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5514G", "MPC5514G", CPU_POWERPC_MPC5514G, POWERPC_SVR_5514G, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5514G_v0", "MPC5514G v0", CPU_POWERPC_MPC5514G_v0, POWERPC_SVR_5514G_v0, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5514G_v1", "MPC5514G v1", CPU_POWERPC_MPC5514G_v1, POWERPC_SVR_5514G_v1, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5515S", "MPC5515S", CPU_POWERPC_MPC5515S, POWERPC_SVR_5515S, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5516E", "MPC5516E", CPU_POWERPC_MPC5516E, POWERPC_SVR_5516E, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5516E_v0", "MPC5516E v0", CPU_POWERPC_MPC5516E_v0, POWERPC_SVR_5516E_v0, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5516E_v1", "MPC5516E v1", CPU_POWERPC_MPC5516E_v1, POWERPC_SVR_5516E_v1, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5516G", "MPC5516G", CPU_POWERPC_MPC5516G, POWERPC_SVR_5516G, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5516G_v0", "MPC5516G v0", CPU_POWERPC_MPC5516G_v0, POWERPC_SVR_5516G_v0, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5516G_v1", "MPC5516G v1", CPU_POWERPC_MPC5516G_v1, POWERPC_SVR_5516G_v1, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5516S", "MPC5516S", CPU_POWERPC_MPC5516S, POWERPC_SVR_5516S, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5533", "MPC5533", CPU_POWERPC_MPC5533, POWERPC_SVR_5533, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5534", "MPC5534", CPU_POWERPC_MPC5534, POWERPC_SVR_5534, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5553", "MPC5553", CPU_POWERPC_MPC5553, POWERPC_SVR_5553, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5554", "MPC5554", CPU_POWERPC_MPC5554, POWERPC_SVR_5554, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5561", "MPC5561", CPU_POWERPC_MPC5561, POWERPC_SVR_5561, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5565", "MPC5565", CPU_POWERPC_MPC5565, POWERPC_SVR_5565, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5566", "MPC5566", CPU_POWERPC_MPC5566, POWERPC_SVR_5566, e200) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC5567", "MPC5567", CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200) #endif @@ -8422,43 +8422,43 @@ enum { POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300, "PowerPC e300c4 core") /* PowerPC e300 microcontrollers */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8313", "MPC8313", CPU_POWERPC_MPC831x, POWERPC_SVR_8313, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8313E", "MPC8313E", CPU_POWERPC_MPC831x, POWERPC_SVR_8313E, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8314", "MPC8314", CPU_POWERPC_MPC831x, POWERPC_SVR_8314, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8314E", "MPC8314E", CPU_POWERPC_MPC831x, POWERPC_SVR_8314E, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8315", "MPC8315", CPU_POWERPC_MPC831x, POWERPC_SVR_8315, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8315E", "MPC8315E", CPU_POWERPC_MPC831x, POWERPC_SVR_8315E, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8321", "MPC8321", CPU_POWERPC_MPC832x, POWERPC_SVR_8321, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8321E", "MPC8321E", CPU_POWERPC_MPC832x, POWERPC_SVR_8321E, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8323", "MPC8323", CPU_POWERPC_MPC832x, POWERPC_SVR_8323, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8323E", "MPC8323E", CPU_POWERPC_MPC832x, POWERPC_SVR_8323E, e300) #endif @@ -8494,11 +8494,11 @@ enum { CPU_POWERPC_MPC834x, POWERPC_SVR_8349E, e300) POWERPC_DEF_SVR("MPC8349EA", "MPC8349EA", CPU_POWERPC_MPC834x, POWERPC_SVR_8349EA, e300) -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8358E", "MPC8358E", CPU_POWERPC_MPC835x, POWERPC_SVR_8358E, e300) #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8360E", "MPC8360E", CPU_POWERPC_MPC836x, POWERPC_SVR_8360E, e300) #endif @@ -8640,7 +8640,7 @@ enum { POWERPC_DEF("e600", CPU_POWERPC_e600, 7400, "PowerPC e600 core") /* PowerPC e600 microcontrollers */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF_SVR("MPC8610", "MPC8610", CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400) #endif @@ -8839,7 +8839,7 @@ enum { "PowerPC 745 v2.8") POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755, "PowerPC 755 v2.8") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745, "PowerPC 745P (G3)") POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755, @@ -8948,35 +8948,35 @@ enum { #if defined (TARGET_PPC64) POWERPC_DEF("620", CPU_POWERPC_620, 620, "PowerPC 620") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("630", CPU_POWERPC_630, 630, "PowerPC 630 (POWER3)") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("631", CPU_POWERPC_631, 631, "PowerPC 631 (Power 3+)") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4, "POWER4") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P, "POWER4p") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5, "POWER5") POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5, "POWER5GR") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P, "POWER5+") POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P, "POWER5GS") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6, "POWER6") POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5, @@ -9008,31 +9008,31 @@ enum { "PowerPC 970MP v1.0") POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP, "PowerPC 970MP v1.1") -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970, "PowerPC Cell") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970, "PowerPC Cell v1.0") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970, "PowerPC Cell v2.0") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970, "PowerPC Cell v3.0") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970, "PowerPC Cell v3.1") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970, "PowerPC Cell v3.2") #endif -#if defined (TODO) +#if defined(TODO) /* This one seems to support the whole POWER2 instruction set * and the PowerPC 64 one. */ @@ -9040,30 +9040,30 @@ enum { POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64, "RS64 (Apache/A35)") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64, "RS64-II (NorthStar/A50)") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64, "RS64-III (Pulsar)") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64, "RS64-IV (IceStar/IStar/SStar)") #endif #endif /* defined (TARGET_PPC64) */ /* POWER */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER, "Original POWER") #endif -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER, "POWER2") #endif /* PA semi cores */ -#if defined (TODO) +#if defined(TODO) POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T, "PA PA6T") #endif From 953af181f5d1c51e8111c345c70f277185f1a6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:49 +0000 Subject: [PATCH 1463/1634] target-ppc: Split model definitions out of translate_init.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that model definitions only reference their parent type, model definitions are independent of the family definitions and can be compiled independently of TCG translation. Keep all #if defined(TODO) code local to cpu-models.c. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/Makefile.objs | 1 + target-ppc/cpu-models.c | 1225 ++++++++++++++++++++++ target-ppc/cpu-models.h | 727 +++++++++++++ target-ppc/translate_init.c | 1907 +---------------------------------- 4 files changed, 1955 insertions(+), 1905 deletions(-) create mode 100644 target-ppc/cpu-models.c create mode 100644 target-ppc/cpu-models.h diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs index a028dcdcd0..00ac4adc51 100644 --- a/target-ppc/Makefile.objs +++ b/target-ppc/Makefile.objs @@ -1,3 +1,4 @@ +obj-y += cpu-models.o obj-y += translate.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c new file mode 100644 index 0000000000..f0be585a4d --- /dev/null +++ b/target-ppc/cpu-models.c @@ -0,0 +1,1225 @@ +/* + * PowerPC CPU initialization for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2013 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 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 . + */ + +/* A lot of PowerPC definition have been included here. + * Most of them are not usable for now but have been kept + * inside "#if defined(TODO) ... #endif" statements to make tests easier. + */ + +#include "cpu.h" +#include "cpu-models.h" + +#if defined(CONFIG_USER_ONLY) +#define TODO_USER_ONLY 1 +#endif + +/***************************************************************************/ +/* PowerPC CPU definitions */ +#define POWERPC_DEF_PREFIX(pvr, svr, type) \ + glue(glue(glue(glue(pvr, _), svr), _), type) +#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ + static void \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ + (ObjectClass *oc, void *data) \ + { \ + DeviceClass *dc = DEVICE_CLASS(oc); \ + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ + \ + pcc->pvr = _pvr; \ + pcc->svr = _svr; \ + dc->desc = _desc; \ + } \ + \ + static const TypeInfo \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info) = { \ + .name = _name "-" TYPE_POWERPC_CPU, \ + .parent = stringify(_type) "-family-" TYPE_POWERPC_CPU, \ + .class_init = \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init), \ + }; \ + \ + static void \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)(void) \ + { \ + type_register_static( \ + &glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info)); \ + } \ + \ + type_init( \ + glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)) + +#define POWERPC_DEF(_name, _pvr, _type, _desc) \ + POWERPC_DEF_SVR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type) + + /* Embedded PowerPC */ + /* PowerPC 401 family */ + POWERPC_DEF("401", CPU_POWERPC_401, 401, + "Generic PowerPC 401") + /* PowerPC 401 cores */ + POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401, + "PowerPC 401A1") + POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2, + "PowerPC 401B2") +#if defined(TODO) + POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3, + "PowerPC 401B3") +#endif + POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2, + "PowerPC 401C2") + POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2, + "PowerPC 401D2") + POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2, + "PowerPC 401E2") + POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2, + "PowerPC 401F2") + /* XXX: to be checked */ + POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2, + "PowerPC 401G2") + /* PowerPC 401 microcontrolers */ +#if defined(TODO) + POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401, + "PowerPC 401GF") +#endif + POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480, + "IOP480 (401 microcontroller)") + POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401, + "IBM Processor for Network Resources") +#if defined(TODO) + POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401, + NULL) +#endif + /* PowerPC 403 family */ + /* PowerPC 403 microcontrolers */ + POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403, + "PowerPC 403 GA") + POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403, + "PowerPC 403 GB") + POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403, + "PowerPC 403 GC") + POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX, + "PowerPC 403 GCX") +#if defined(TODO) + POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403, + "PowerPC 403 GP") +#endif + /* PowerPC 405 family */ + /* PowerPC 405 cores */ +#if defined(TODO) + POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405, + "PowerPC 405 A3") +#endif +#if defined(TODO) + POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405, + "PowerPC 405 A4") +#endif +#if defined(TODO) + POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405, + "PowerPC 405 B3") +#endif +#if defined(TODO) + POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405, + "PowerPC 405 B4") +#endif +#if defined(TODO) + POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405, + "PowerPC 405 C3") +#endif +#if defined(TODO) + POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405, + "PowerPC 405 C4") +#endif + POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405, + "PowerPC 405 D2") +#if defined(TODO) + POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405, + "PowerPC 405 D3") +#endif + POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405, + "PowerPC 405 D4") +#if defined(TODO) + POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405, + "PowerPC 405 D5") +#endif +#if defined(TODO) + POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405, + "PowerPC 405 E4") +#endif +#if defined(TODO) + POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405, + "PowerPC 405 F4") +#endif +#if defined(TODO) + POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405, + "PowerPC 405 F5") +#endif +#if defined(TODO) + POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405, + "PowerPC 405 F6") +#endif + /* PowerPC 405 microcontrolers */ + POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405, + "PowerPC 405 CRa") + POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405, + "PowerPC 405 CRb") + POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405, + "PowerPC 405 CRc") + POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405, + "PowerPC 405 EP") +#if defined(TODO) + POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405, + "PowerPC 405 EXr") +#endif + POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405, + "PowerPC 405 EZ") +#if defined(TODO) + POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405, + "PowerPC 405 FX") +#endif + POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405, + "PowerPC 405 GPa") + POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405, + "PowerPC 405 GPb") + POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405, + "PowerPC 405 GPc") + POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405, + "PowerPC 405 GPd") + POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405, + "PowerPC 405 GPR") +#if defined(TODO) + POWERPC_DEF("405H", CPU_POWERPC_405H, 405, + "PowerPC 405 H") +#endif +#if defined(TODO) + POWERPC_DEF("405L", CPU_POWERPC_405L, 405, + "PowerPC 405 L") +#endif + POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405, + "PowerPC 405 LP") +#if defined(TODO) + POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405, + "PowerPC 405 PM") +#endif +#if defined(TODO) + POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405, + "PowerPC 405 PS") +#endif +#if defined(TODO) + POWERPC_DEF("405S", CPU_POWERPC_405S, 405, + "PowerPC 405 S") +#endif + POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405, + "Npe405 H") + POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405, + "Npe405 H2") + POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405, + "Npe405 L") + POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405, + "Npe4GS3") +#if defined(TODO) + POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405, + NULL) +#endif +#if defined(TODO) + POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405, + NULL) +#endif +#if defined(TODO) + POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405, + "PowerPC LC77700 (Sanyo)") +#endif + /* PowerPC 401/403/405 based set-top-box microcontrolers */ +#if defined(TODO) + POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2, + "STB010000") +#endif +#if defined(TODO) + POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2, + "STB01010") +#endif +#if defined(TODO) + POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3, + "STB0210") +#endif + POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405, + "STB03xx") +#if defined(TODO) + POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405, + "STB043x") +#endif +#if defined(TODO) + POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405, + "STB045x") +#endif + POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405, + "STB04xx") + POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405, + "STB25xx") +#if defined(TODO) + POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405, + "STB130") +#endif + /* Xilinx PowerPC 405 cores */ + POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405, + NULL) + POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405, + NULL) +#if defined(TODO) + POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405, + "Zarlink ZL10310") +#endif +#if defined(TODO) + POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405, + "Zarlink ZL10311") +#endif +#if defined(TODO) + POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405, + "Zarlink ZL10320") +#endif +#if defined(TODO) + POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405, + "Zarlink ZL10321") +#endif + /* PowerPC 440 family */ +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440", CPU_POWERPC_440, 440GP, + "Generic PowerPC 440") +#endif + /* PowerPC 440 cores */ +#if defined(TODO) + POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4, + "PowerPC 440 A4") +#endif + POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5, + "PowerPC 440 Xilinx 5") +#if defined(TODO) + POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5, + "PowerPC 440 A5") +#endif +#if defined(TODO) + POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4, + "PowerPC 440 B4") +#endif +#if defined(TODO) + POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4, + "PowerPC 440 G4") +#endif +#if defined(TODO) + POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5, + "PowerPC 440 F5") +#endif +#if defined(TODO) + POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5, + "PowerPC 440 G5") +#endif +#if defined(TODO) + POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4, + "PowerPC 440H4") +#endif +#if defined(TODO) + POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5, + "PowerPC 440H6") +#endif + /* PowerPC 440 microcontrolers */ + POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP, + "PowerPC 440 EPa") + POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP, + "PowerPC 440 EPb") + POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP, + "PowerPC 440 EPX") +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP, + "PowerPC 440 GPb") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP, + "PowerPC 440 GPc") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5, + "PowerPC 440 GRa") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5, + "PowerPC 440 GRX") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP, + "PowerPC 440 GXa") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP, + "PowerPC 440 GXb") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP, + "PowerPC 440 GXc") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP, + "PowerPC 440 GXf") +#endif +#if defined(TODO) + POWERPC_DEF("440S", CPU_POWERPC_440S, 440, + "PowerPC 440 S") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP, + "PowerPC 440 SP") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP, + "PowerPC 440 SP2") +#endif +#if defined(TODO_USER_ONLY) + POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP, + "PowerPC 440 SPE") +#endif + /* PowerPC 460 family */ +#if defined(TODO) + POWERPC_DEF("464", CPU_POWERPC_464, 460, + "Generic PowerPC 464") +#endif + /* PowerPC 464 microcontrolers */ +#if defined(TODO) + POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460, + "PowerPC 464H90") +#endif +#if defined(TODO) + POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F, + "PowerPC 464H90F") +#endif + /* Freescale embedded PowerPC cores */ + /* MPC5xx family (aka RCPU) */ +#if defined(TODO_USER_ONLY) + POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx, + "Generic MPC5xx core") +#endif + /* MPC8xx family (aka PowerQUICC) */ +#if defined(TODO_USER_ONLY) + POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx, + "Generic MPC8xx core") +#endif + /* MPC82xx family (aka PowerQUICC-II) */ + POWERPC_DEF("G2", CPU_POWERPC_G2, G2, + "PowerPC G2 core") + POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2, + "PowerPC G2 H4 core") + POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2, + "PowerPC G2 GP core") + POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2, + "PowerPC G2 LS core") + POWERPC_DEF("G2HiP3", CPU_POWERPC_G2_HIP3, G2, + "PowerPC G2 HiP3 core") + POWERPC_DEF("G2HiP4", CPU_POWERPC_G2_HIP4, G2, + "PowerPC G2 HiP4 core") + POWERPC_DEF("MPC603", CPU_POWERPC_MPC603, 603E, + "PowerPC MPC603 core") + POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE, + "PowerPC G2le core (same as G2 plus little-endian mode support)") + POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE, + "PowerPC G2LE GP core") + POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE, + "PowerPC G2LE LS core") + POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE, + "PowerPC G2LE GP1 core") + POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE, + "PowerPC G2LE GP3 core") + /* PowerPC G2 microcontrollers */ +#if defined(TODO) + POWERPC_DEF_SVR("MPC5121", "MPC5121", + CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE) +#endif + POWERPC_DEF_SVR("MPC5200_v10", "MPC5200 v1.0", + CPU_POWERPC_MPC5200_v10, POWERPC_SVR_5200_v10, G2LE) + POWERPC_DEF_SVR("MPC5200_v11", "MPC5200 v1.1", + CPU_POWERPC_MPC5200_v11, POWERPC_SVR_5200_v11, G2LE) + POWERPC_DEF_SVR("MPC5200_v12", "MPC5200 v1.2", + CPU_POWERPC_MPC5200_v12, POWERPC_SVR_5200_v12, G2LE) + POWERPC_DEF_SVR("MPC5200B_v20", "MPC5200B v2.0", + CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE) + POWERPC_DEF_SVR("MPC5200B_v21", "MPC5200B v2.1", + CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE) + /* e200 family */ +#if defined(TODO) + POWERPC_DEF_SVR("MPC55xx", "Generic MPC55xx core", + CPU_POWERPC_MPC55xx, POWERPC_SVR_55xx, e200) +#endif +#if defined(TODO) + POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200, + "PowerPC e200z0 core") +#endif +#if defined(TODO) + POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200, + "PowerPC e200z1 core") +#endif +#if defined(TODO) + POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200, + "PowerPC e200z3 core") +#endif + POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200, + "PowerPC e200z5 core") + POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200, + "PowerPC e200z6 core") + /* PowerPC e200 microcontrollers */ +#if defined(TODO) + POWERPC_DEF_SVR("MPC5514E", "MPC5514E", + CPU_POWERPC_MPC5514E, POWERPC_SVR_5514E, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5514E_v0", "MPC5514E v0", + CPU_POWERPC_MPC5514E_v0, POWERPC_SVR_5514E_v0, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5514E_v1", "MPC5514E v1", + CPU_POWERPC_MPC5514E_v1, POWERPC_SVR_5514E_v1, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5514G", "MPC5514G", + CPU_POWERPC_MPC5514G, POWERPC_SVR_5514G, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5514G_v0", "MPC5514G v0", + CPU_POWERPC_MPC5514G_v0, POWERPC_SVR_5514G_v0, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5514G_v1", "MPC5514G v1", + CPU_POWERPC_MPC5514G_v1, POWERPC_SVR_5514G_v1, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5515S", "MPC5515S", + CPU_POWERPC_MPC5515S, POWERPC_SVR_5515S, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5516E", "MPC5516E", + CPU_POWERPC_MPC5516E, POWERPC_SVR_5516E, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5516E_v0", "MPC5516E v0", + CPU_POWERPC_MPC5516E_v0, POWERPC_SVR_5516E_v0, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5516E_v1", "MPC5516E v1", + CPU_POWERPC_MPC5516E_v1, POWERPC_SVR_5516E_v1, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5516G", "MPC5516G", + CPU_POWERPC_MPC5516G, POWERPC_SVR_5516G, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5516G_v0", "MPC5516G v0", + CPU_POWERPC_MPC5516G_v0, POWERPC_SVR_5516G_v0, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5516G_v1", "MPC5516G v1", + CPU_POWERPC_MPC5516G_v1, POWERPC_SVR_5516G_v1, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5516S", "MPC5516S", + CPU_POWERPC_MPC5516S, POWERPC_SVR_5516S, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5533", "MPC5533", + CPU_POWERPC_MPC5533, POWERPC_SVR_5533, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5534", "MPC5534", + CPU_POWERPC_MPC5534, POWERPC_SVR_5534, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5553", "MPC5553", + CPU_POWERPC_MPC5553, POWERPC_SVR_5553, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5554", "MPC5554", + CPU_POWERPC_MPC5554, POWERPC_SVR_5554, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5561", "MPC5561", + CPU_POWERPC_MPC5561, POWERPC_SVR_5561, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5565", "MPC5565", + CPU_POWERPC_MPC5565, POWERPC_SVR_5565, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5566", "MPC5566", + CPU_POWERPC_MPC5566, POWERPC_SVR_5566, e200) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC5567", "MPC5567", + CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200) +#endif + /* e300 family */ + POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300, + "PowerPC e300c1 core") + POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300, + "PowerPC e300c2 core") + POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300, + "PowerPC e300c3 core") + POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300, + "PowerPC e300c4 core") + /* PowerPC e300 microcontrollers */ +#if defined(TODO) + POWERPC_DEF_SVR("MPC8313", "MPC8313", + CPU_POWERPC_MPC831x, POWERPC_SVR_8313, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8313E", "MPC8313E", + CPU_POWERPC_MPC831x, POWERPC_SVR_8313E, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8314", "MPC8314", + CPU_POWERPC_MPC831x, POWERPC_SVR_8314, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8314E", "MPC8314E", + CPU_POWERPC_MPC831x, POWERPC_SVR_8314E, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8315", "MPC8315", + CPU_POWERPC_MPC831x, POWERPC_SVR_8315, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8315E", "MPC8315E", + CPU_POWERPC_MPC831x, POWERPC_SVR_8315E, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8321", "MPC8321", + CPU_POWERPC_MPC832x, POWERPC_SVR_8321, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8321E", "MPC8321E", + CPU_POWERPC_MPC832x, POWERPC_SVR_8321E, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8323", "MPC8323", + CPU_POWERPC_MPC832x, POWERPC_SVR_8323, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8323E", "MPC8323E", + CPU_POWERPC_MPC832x, POWERPC_SVR_8323E, e300) +#endif + POWERPC_DEF_SVR("MPC8343", "MPC8343", + CPU_POWERPC_MPC834x, POWERPC_SVR_8343, e300) + POWERPC_DEF_SVR("MPC8343A", "MPC8343A", + CPU_POWERPC_MPC834x, POWERPC_SVR_8343A, e300) + POWERPC_DEF_SVR("MPC8343E", "MPC8343E", + CPU_POWERPC_MPC834x, POWERPC_SVR_8343E, e300) + POWERPC_DEF_SVR("MPC8343EA", "MPC8343EA", + CPU_POWERPC_MPC834x, POWERPC_SVR_8343EA, e300) + POWERPC_DEF_SVR("MPC8347T", "MPC8347T", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347T, e300) + POWERPC_DEF_SVR("MPC8347P", "MPC8347P", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347P, e300) + POWERPC_DEF_SVR("MPC8347AT", "MPC8347AT", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347AT, e300) + POWERPC_DEF_SVR("MPC8347AP", "MPC8347AP", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347AP, e300) + POWERPC_DEF_SVR("MPC8347ET", "MPC8347ET", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347ET, e300) + POWERPC_DEF_SVR("MPC8347EP", "MPC8343EP", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347EP, e300) + POWERPC_DEF_SVR("MPC8347EAT", "MPC8347EAT", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAT, e300) + POWERPC_DEF_SVR("MPC8347EAP", "MPC8343EAP", + CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAP, e300) + POWERPC_DEF_SVR("MPC8349", "MPC8349", + CPU_POWERPC_MPC834x, POWERPC_SVR_8349, e300) + POWERPC_DEF_SVR("MPC8349A", "MPC8349A", + CPU_POWERPC_MPC834x, POWERPC_SVR_8349A, e300) + POWERPC_DEF_SVR("MPC8349E", "MPC8349E", + CPU_POWERPC_MPC834x, POWERPC_SVR_8349E, e300) + POWERPC_DEF_SVR("MPC8349EA", "MPC8349EA", + CPU_POWERPC_MPC834x, POWERPC_SVR_8349EA, e300) +#if defined(TODO) + POWERPC_DEF_SVR("MPC8358E", "MPC8358E", + CPU_POWERPC_MPC835x, POWERPC_SVR_8358E, e300) +#endif +#if defined(TODO) + POWERPC_DEF_SVR("MPC8360E", "MPC8360E", + CPU_POWERPC_MPC836x, POWERPC_SVR_8360E, e300) +#endif + POWERPC_DEF_SVR("MPC8377", "MPC8377", + CPU_POWERPC_MPC837x, POWERPC_SVR_8377, e300) + POWERPC_DEF_SVR("MPC8377E", "MPC8377E", + CPU_POWERPC_MPC837x, POWERPC_SVR_8377E, e300) + POWERPC_DEF_SVR("MPC8378", "MPC8378", + CPU_POWERPC_MPC837x, POWERPC_SVR_8378, e300) + POWERPC_DEF_SVR("MPC8378E", "MPC8378E", + CPU_POWERPC_MPC837x, POWERPC_SVR_8378E, e300) + POWERPC_DEF_SVR("MPC8379", "MPC8379", + CPU_POWERPC_MPC837x, POWERPC_SVR_8379, e300) + POWERPC_DEF_SVR("MPC8379E", "MPC8379E", + CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300) + /* e500 family */ + POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1, + "PowerPC e500 v1.0 core") + POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1, + "PowerPC e500 v2.0 core") + POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2, + "PowerPC e500v2 v1.0 core") + POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2, + "PowerPC e500v2 v2.0 core") + POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2, + "PowerPC e500v2 v2.1 core") + POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2, + "PowerPC e500v2 v2.2 core") + POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2, + "PowerPC e500v2 v3.0 core") + POWERPC_DEF_SVR("e500mc", "e500mc", + CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc) +#ifdef TARGET_PPC64 + POWERPC_DEF_SVR("e5500", "e5500", + CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500) +#endif + /* PowerPC e500 microcontrollers */ + POWERPC_DEF_SVR("MPC8533_v10", "MPC8533 v1.0", + CPU_POWERPC_MPC8533_v10, POWERPC_SVR_8533_v10, e500v2) + POWERPC_DEF_SVR("MPC8533_v11", "MPC8533 v1.1", + CPU_POWERPC_MPC8533_v11, POWERPC_SVR_8533_v11, e500v2) + POWERPC_DEF_SVR("MPC8533E_v10", "MPC8533E v1.0", + CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500v2) + POWERPC_DEF_SVR("MPC8533E_v11", "MPC8533E v1.1", + CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500v2) + POWERPC_DEF_SVR("MPC8540_v10", "MPC8540 v1.0", + CPU_POWERPC_MPC8540_v10, POWERPC_SVR_8540_v10, e500v1) + POWERPC_DEF_SVR("MPC8540_v20", "MPC8540 v2.0", + CPU_POWERPC_MPC8540_v20, POWERPC_SVR_8540_v20, e500v1) + POWERPC_DEF_SVR("MPC8540_v21", "MPC8540 v2.1", + CPU_POWERPC_MPC8540_v21, POWERPC_SVR_8540_v21, e500v1) + POWERPC_DEF_SVR("MPC8541_v10", "MPC8541 v1.0", + CPU_POWERPC_MPC8541_v10, POWERPC_SVR_8541_v10, e500v1) + POWERPC_DEF_SVR("MPC8541_v11", "MPC8541 v1.1", + CPU_POWERPC_MPC8541_v11, POWERPC_SVR_8541_v11, e500v1) + POWERPC_DEF_SVR("MPC8541E_v10", "MPC8541E v1.0", + CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500v1) + POWERPC_DEF_SVR("MPC8541E_v11", "MPC8541E v1.1", + CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500v1) + POWERPC_DEF_SVR("MPC8543_v10", "MPC8543 v1.0", + CPU_POWERPC_MPC8543_v10, POWERPC_SVR_8543_v10, e500v2) + POWERPC_DEF_SVR("MPC8543_v11", "MPC8543 v1.1", + CPU_POWERPC_MPC8543_v11, POWERPC_SVR_8543_v11, e500v2) + POWERPC_DEF_SVR("MPC8543_v20", "MPC8543 v2.0", + CPU_POWERPC_MPC8543_v20, POWERPC_SVR_8543_v20, e500v2) + POWERPC_DEF_SVR("MPC8543_v21", "MPC8543 v2.1", + CPU_POWERPC_MPC8543_v21, POWERPC_SVR_8543_v21, e500v2) + POWERPC_DEF_SVR("MPC8543E_v10", "MPC8543E v1.0", + CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500v2) + POWERPC_DEF_SVR("MPC8543E_v11", "MPC8543E v1.1", + CPU_POWERPC_MPC8543E_v11, POWERPC_SVR_8543E_v11, e500v2) + POWERPC_DEF_SVR("MPC8543E_v20", "MPC8543E v2.0", + CPU_POWERPC_MPC8543E_v20, POWERPC_SVR_8543E_v20, e500v2) + POWERPC_DEF_SVR("MPC8543E_v21", "MPC8543E v2.1", + CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500v2) + POWERPC_DEF_SVR("MPC8544_v10", "MPC8544 v1.0", + CPU_POWERPC_MPC8544_v10, POWERPC_SVR_8544_v10, e500v2) + POWERPC_DEF_SVR("MPC8544_v11", "MPC8544 v1.1", + CPU_POWERPC_MPC8544_v11, POWERPC_SVR_8544_v11, e500v2) + POWERPC_DEF_SVR("MPC8544E_v10", "MPC8544E v1.0", + CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500v2) + POWERPC_DEF_SVR("MPC8544E_v11", "MPC8544E v1.1", + CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500v2) + POWERPC_DEF_SVR("MPC8545_v20", "MPC8545 v2.0", + CPU_POWERPC_MPC8545_v20, POWERPC_SVR_8545_v20, e500v2) + POWERPC_DEF_SVR("MPC8545_v21", "MPC8545 v2.1", + CPU_POWERPC_MPC8545_v21, POWERPC_SVR_8545_v21, e500v2) + POWERPC_DEF_SVR("MPC8545E_v20", "MPC8545E v2.0", + CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500v2) + POWERPC_DEF_SVR("MPC8545E_v21", "MPC8545E v2.1", + CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500v2) + POWERPC_DEF_SVR("MPC8547E_v20", "MPC8547E v2.0", + CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500v2) + POWERPC_DEF_SVR("MPC8547E_v21", "MPC8547E v2.1", + CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500v2) + POWERPC_DEF_SVR("MPC8548_v10", "MPC8548 v1.0", + CPU_POWERPC_MPC8548_v10, POWERPC_SVR_8548_v10, e500v2) + POWERPC_DEF_SVR("MPC8548_v11", "MPC8548 v1.1", + CPU_POWERPC_MPC8548_v11, POWERPC_SVR_8548_v11, e500v2) + POWERPC_DEF_SVR("MPC8548_v20", "MPC8548 v2.0", + CPU_POWERPC_MPC8548_v20, POWERPC_SVR_8548_v20, e500v2) + POWERPC_DEF_SVR("MPC8548_v21", "MPC8548 v2.1", + CPU_POWERPC_MPC8548_v21, POWERPC_SVR_8548_v21, e500v2) + POWERPC_DEF_SVR("MPC8548E_v10", "MPC8548E v1.0", + CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500v2) + POWERPC_DEF_SVR("MPC8548E_v11", "MPC8548E v1.1", + CPU_POWERPC_MPC8548E_v11, POWERPC_SVR_8548E_v11, e500v2) + POWERPC_DEF_SVR("MPC8548E_v20", "MPC8548E v2.0", + CPU_POWERPC_MPC8548E_v20, POWERPC_SVR_8548E_v20, e500v2) + POWERPC_DEF_SVR("MPC8548E_v21", "MPC8548E v2.1", + CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2) + POWERPC_DEF_SVR("MPC8555_v10", "MPC8555 v1.0", + CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2) + POWERPC_DEF_SVR("MPC8555_v11", "MPC8555 v1.1", + CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2) + POWERPC_DEF_SVR("MPC8555E_v10", "MPC8555E v1.0", + CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2) + POWERPC_DEF_SVR("MPC8555E_v11", "MPC8555E v1.1", + CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2) + POWERPC_DEF_SVR("MPC8560_v10", "MPC8560 v1.0", + CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2) + POWERPC_DEF_SVR("MPC8560_v20", "MPC8560 v2.0", + CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v2) + POWERPC_DEF_SVR("MPC8560_v21", "MPC8560 v2.1", + CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v2) + POWERPC_DEF_SVR("MPC8567", "MPC8567", + CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500v2) + POWERPC_DEF_SVR("MPC8567E", "MPC8567E", + CPU_POWERPC_MPC8567E, POWERPC_SVR_8567E, e500v2) + POWERPC_DEF_SVR("MPC8568", "MPC8568", + CPU_POWERPC_MPC8568, POWERPC_SVR_8568, e500v2) + POWERPC_DEF_SVR("MPC8568E", "MPC8568E", + CPU_POWERPC_MPC8568E, POWERPC_SVR_8568E, e500v2) + POWERPC_DEF_SVR("MPC8572", "MPC8572", + CPU_POWERPC_MPC8572, POWERPC_SVR_8572, e500v2) + POWERPC_DEF_SVR("MPC8572E", "MPC8572E", + CPU_POWERPC_MPC8572E, POWERPC_SVR_8572E, e500v2) + /* e600 family */ + POWERPC_DEF("e600", CPU_POWERPC_e600, 7400, + "PowerPC e600 core") + /* PowerPC e600 microcontrollers */ +#if defined(TODO) + POWERPC_DEF_SVR("MPC8610", "MPC8610", + CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400) +#endif + POWERPC_DEF_SVR("MPC8641", "MPC8641", + CPU_POWERPC_MPC8641, POWERPC_SVR_8641, 7400) + POWERPC_DEF_SVR("MPC8641D", "MPC8641D", + CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400) + /* 32 bits "classic" PowerPC */ + /* PowerPC 6xx family */ + POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601, + "PowerPC 601v0") + POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601, + "PowerPC 601v1") + POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v, + "PowerPC 601v2") + POWERPC_DEF("602", CPU_POWERPC_602, 602, + "PowerPC 602") + POWERPC_DEF("603", CPU_POWERPC_603, 603, + "PowerPC 603") + POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E, + "PowerPC 603e v1.1") + POWERPC_DEF("603e_v1.2", CPU_POWERPC_603E_v12, 603E, + "PowerPC 603e v1.2") + POWERPC_DEF("603e_v1.3", CPU_POWERPC_603E_v13, 603E, + "PowerPC 603e v1.3") + POWERPC_DEF("603e_v1.4", CPU_POWERPC_603E_v14, 603E, + "PowerPC 603e v1.4") + POWERPC_DEF("603e_v2.2", CPU_POWERPC_603E_v22, 603E, + "PowerPC 603e v2.2") + POWERPC_DEF("603e_v3", CPU_POWERPC_603E_v3, 603E, + "PowerPC 603e v3") + POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E, + "PowerPC 603e v4") + POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E, + "PowerPC 603e v4.1") + POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E, + "PowerPC 603e (aka PID7)") + POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E, + "PowerPC 603e7t") + POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E, + "PowerPC 603e7v") + POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E, + "PowerPC 603e7v1") + POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E, + "PowerPC 603e7v2") + POWERPC_DEF("603p", CPU_POWERPC_603P, 603E, + "PowerPC 603p (aka PID7v)") + POWERPC_DEF("604", CPU_POWERPC_604, 604, + "PowerPC 604") + POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E, + "PowerPC 604e v1.0") + POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604E, + "PowerPC 604e v2.2") + POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E, + "PowerPC 604e v2.4") + POWERPC_DEF("604r", CPU_POWERPC_604R, 604E, + "PowerPC 604r (aka PIDA)") +#if defined(TODO) + POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E, + "PowerPC 604ev") +#endif + /* PowerPC 7xx family */ + POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740, + "PowerPC 740 v1.0 (G3)") + POWERPC_DEF("750_v1.0", CPU_POWERPC_7x0_v10, 750, + "PowerPC 750 v1.0 (G3)") + POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 740, + "PowerPC 740 v2.0 (G3)") + POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 750, + "PowerPC 750 v2.0 (G3)") + POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 740, + "PowerPC 740 v2.1 (G3)") + POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 750, + "PowerPC 750 v2.1 (G3)") + POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 740, + "PowerPC 740 v2.2 (G3)") + POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 750, + "PowerPC 750 v2.2 (G3)") + POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 740, + "PowerPC 740 v3.0 (G3)") + POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 750, + "PowerPC 750 v3.0 (G3)") + POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 740, + "PowerPC 740 v3.1 (G3)") + POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 750, + "PowerPC 750 v3.1 (G3)") + POWERPC_DEF("740e", CPU_POWERPC_740E, 740, + "PowerPC 740E (G3)") + POWERPC_DEF("750e", CPU_POWERPC_750E, 750, + "PowerPC 750E (G3)") + POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740, + "PowerPC 740P (G3)") + POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750, + "PowerPC 750P (G3)") + POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl, + "PowerPC 750CL v1.0") + POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl, + "PowerPC 750CL v2.0") + POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx, + "PowerPC 750CX v1.0 (G3 embedded)") + POWERPC_DEF("750cx_v2.0", CPU_POWERPC_750CX_v20, 750cx, + "PowerPC 750CX v2.1 (G3 embedded)") + POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx, + "PowerPC 750CX v2.1 (G3 embedded)") + POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx, + "PowerPC 750CX v2.2 (G3 embedded)") + POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx, + "PowerPC 750CXe v2.1 (G3 embedded)") + POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 750cx, + "PowerPC 750CXe v2.2 (G3 embedded)") + POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 750cx, + "PowerPC 750CXe v2.3 (G3 embedded)") + POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 750cx, + "PowerPC 750CXe v2.4 (G3 embedded)") + POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 750cx, + "PowerPC 750CXe v2.4b (G3 embedded)") + POWERPC_DEF("750cxe_v3.0", CPU_POWERPC_750CXE_v30, 750cx, + "PowerPC 750CXe v3.0 (G3 embedded)") + POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 750cx, + "PowerPC 750CXe v3.1 (G3 embedded)") + POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 750cx, + "PowerPC 750CXe v3.1b (G3 embedded)") + POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx, + "PowerPC 750CXr (G3 embedded)") + POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx, + "PowerPC 750FL (G3 embedded)") + POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx, + "PowerPC 750FX v1.0 (G3 embedded)") + POWERPC_DEF("750fx_v2.0", CPU_POWERPC_750FX_v20, 750fx, + "PowerPC 750FX v2.0 (G3 embedded)") + POWERPC_DEF("750fx_v2.1", CPU_POWERPC_750FX_v21, 750fx, + "PowerPC 750FX v2.1 (G3 embedded)") + POWERPC_DEF("750fx_v2.2", CPU_POWERPC_750FX_v22, 750fx, + "PowerPC 750FX v2.2 (G3 embedded)") + POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx, + "PowerPC 750FX v2.3 (G3 embedded)") + POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx, + "PowerPC 750GL (G3 embedded)") + POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx, + "PowerPC 750GX v1.0 (G3 embedded)") + POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx, + "PowerPC 750GX v1.1 (G3 embedded)") + POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx, + "PowerPC 750GX v1.2 (G3 embedded)") + POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750, + "PowerPC 750L v2.0 (G3 embedded)") + POWERPC_DEF("750l_v2.1", CPU_POWERPC_750L_v21, 750, + "PowerPC 750L v2.1 (G3 embedded)") + POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 750, + "PowerPC 750L v2.2 (G3 embedded)") + POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750, + "PowerPC 750L v3.0 (G3 embedded)") + POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750, + "PowerPC 750L v3.2 (G3 embedded)") + POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745, + "PowerPC 745 v1.0") + POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 755, + "PowerPC 755 v1.0") + POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 745, + "PowerPC 745 v1.1") + POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 755, + "PowerPC 755 v1.1") + POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 745, + "PowerPC 745 v2.0") + POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 755, + "PowerPC 755 v2.0") + POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 745, + "PowerPC 745 v2.1") + POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 755, + "PowerPC 755 v2.1") + POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 745, + "PowerPC 745 v2.2") + POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 755, + "PowerPC 755 v2.2") + POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 745, + "PowerPC 745 v2.3") + POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 755, + "PowerPC 755 v2.3") + POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 745, + "PowerPC 745 v2.4") + POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 755, + "PowerPC 755 v2.4") + POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 745, + "PowerPC 745 v2.5") + POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 755, + "PowerPC 755 v2.5") + POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 745, + "PowerPC 745 v2.6") + POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 755, + "PowerPC 755 v2.6") + POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 745, + "PowerPC 745 v2.7") + POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 755, + "PowerPC 755 v2.7") + POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 745, + "PowerPC 745 v2.8") + POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755, + "PowerPC 755 v2.8") +#if defined(TODO) + POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745, + "PowerPC 745P (G3)") + POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755, + "PowerPC 755P (G3)") +#endif + /* PowerPC 74xx family */ + POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400, + "PowerPC 7400 v1.0 (G4)") + POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400, + "PowerPC 7400 v1.1 (G4)") + POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400, + "PowerPC 7400 v2.0 (G4)") + POWERPC_DEF("7400_v2.1", CPU_POWERPC_7400_v21, 7400, + "PowerPC 7400 v2.1 (G4)") + POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400, + "PowerPC 7400 v2.2 (G4)") + POWERPC_DEF("7400_v2.6", CPU_POWERPC_7400_v26, 7400, + "PowerPC 7400 v2.6 (G4)") + POWERPC_DEF("7400_v2.7", CPU_POWERPC_7400_v27, 7400, + "PowerPC 7400 v2.7 (G4)") + POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400, + "PowerPC 7400 v2.8 (G4)") + POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400, + "PowerPC 7400 v2.9 (G4)") + POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410, + "PowerPC 7410 v1.0 (G4)") + POWERPC_DEF("7410_v1.1", CPU_POWERPC_7410_v11, 7410, + "PowerPC 7410 v1.1 (G4)") + POWERPC_DEF("7410_v1.2", CPU_POWERPC_7410_v12, 7410, + "PowerPC 7410 v1.2 (G4)") + POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410, + "PowerPC 7410 v1.3 (G4)") + POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410, + "PowerPC 7410 v1.4 (G4)") + POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400, + "PowerPC 7448 v1.0 (G4)") + POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400, + "PowerPC 7448 v1.1 (G4)") + POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400, + "PowerPC 7448 v2.0 (G4)") + POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400, + "PowerPC 7448 v2.1 (G4)") + POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450, + "PowerPC 7450 v1.0 (G4)") + POWERPC_DEF("7450_v1.1", CPU_POWERPC_7450_v11, 7450, + "PowerPC 7450 v1.1 (G4)") + POWERPC_DEF("7450_v1.2", CPU_POWERPC_7450_v12, 7450, + "PowerPC 7450 v1.2 (G4)") + POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450, + "PowerPC 7450 v2.0 (G4)") + POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450, + "PowerPC 7450 v2.1 (G4)") + POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440, + "PowerPC 7441 v2.1 (G4)") + POWERPC_DEF("7441_v2.3", CPU_POWERPC_74x1_v23, 7440, + "PowerPC 7441 v2.3 (G4)") + POWERPC_DEF("7451_v2.3", CPU_POWERPC_74x1_v23, 7450, + "PowerPC 7451 v2.3 (G4)") + POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440, + "PowerPC 7441 v2.10 (G4)") + POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450, + "PowerPC 7451 v2.10 (G4)") + POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445, + "PowerPC 7445 v1.0 (G4)") + POWERPC_DEF("7455_v1.0", CPU_POWERPC_74x5_v10, 7455, + "PowerPC 7455 v1.0 (G4)") + POWERPC_DEF("7445_v2.1", CPU_POWERPC_74x5_v21, 7445, + "PowerPC 7445 v2.1 (G4)") + POWERPC_DEF("7455_v2.1", CPU_POWERPC_74x5_v21, 7455, + "PowerPC 7455 v2.1 (G4)") + POWERPC_DEF("7445_v3.2", CPU_POWERPC_74x5_v32, 7445, + "PowerPC 7445 v3.2 (G4)") + POWERPC_DEF("7455_v3.2", CPU_POWERPC_74x5_v32, 7455, + "PowerPC 7455 v3.2 (G4)") + POWERPC_DEF("7445_v3.3", CPU_POWERPC_74x5_v33, 7445, + "PowerPC 7445 v3.3 (G4)") + POWERPC_DEF("7455_v3.3", CPU_POWERPC_74x5_v33, 7455, + "PowerPC 7455 v3.3 (G4)") + POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445, + "PowerPC 7445 v3.4 (G4)") + POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455, + "PowerPC 7455 v3.4 (G4)") + POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445, + "PowerPC 7447 v1.0 (G4)") + POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455, + "PowerPC 7457 v1.0 (G4)") + POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445, + "PowerPC 7447 v1.1 (G4)") + POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455, + "PowerPC 7457 v1.1 (G4)") + POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455, + "PowerPC 7457 v1.2 (G4)") + POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445, + "PowerPC 7447A v1.0 (G4)") + POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455, + "PowerPC 7457A v1.0 (G4)") + POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445, + "PowerPC 7447A v1.1 (G4)") + POWERPC_DEF("7457A_v1.1", CPU_POWERPC_74x7A_v11, 7455, + "PowerPC 7457A v1.1 (G4)") + POWERPC_DEF("7447A_v1.2", CPU_POWERPC_74x7A_v12, 7445, + "PowerPC 7447A v1.2 (G4)") + POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455, + "PowerPC 7457A v1.2 (G4)") + /* 64 bits PowerPC */ +#if defined (TARGET_PPC64) + POWERPC_DEF("620", CPU_POWERPC_620, 620, + "PowerPC 620") +#if defined(TODO) + POWERPC_DEF("630", CPU_POWERPC_630, 630, + "PowerPC 630 (POWER3)") +#endif +#if defined(TODO) + POWERPC_DEF("631", CPU_POWERPC_631, 631, + "PowerPC 631 (Power 3+)") +#endif +#if defined(TODO) + POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4, + "POWER4") +#endif +#if defined(TODO) + POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P, + "POWER4p") +#endif +#if defined(TODO) + POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5, + "POWER5") + POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5, + "POWER5GR") +#endif +#if defined(TODO) + POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P, + "POWER5+") + POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P, + "POWER5GS") +#endif +#if defined(TODO) + POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6, + "POWER6") + POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5, + "POWER6 running in POWER5 mode") + POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6, + "POWER6A") +#endif + POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7, + "POWER7 v2.0") + POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7, + "POWER7 v2.1") + POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, + "POWER7 v2.3") + POWERPC_DEF("970", CPU_POWERPC_970, 970, + "PowerPC 970") + POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX, + "PowerPC 970FX v1.0 (G5)") + POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX, + "PowerPC 970FX v2.0 (G5)") + POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX, + "PowerPC 970FX v2.1 (G5)") + POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX, + "PowerPC 970FX v3.0 (G5)") + POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX, + "PowerPC 970FX v3.1 (G5)") + POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX, + "PowerPC 970GX (G5)") + POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP, + "PowerPC 970MP v1.0") + POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP, + "PowerPC 970MP v1.1") +#if defined(TODO) + POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970, + "PowerPC Cell") +#endif +#if defined(TODO) + POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970, + "PowerPC Cell v1.0") +#endif +#if defined(TODO) + POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970, + "PowerPC Cell v2.0") +#endif +#if defined(TODO) + POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970, + "PowerPC Cell v3.0") +#endif +#if defined(TODO) + POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970, + "PowerPC Cell v3.1") +#endif +#if defined(TODO) + POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970, + "PowerPC Cell v3.2") +#endif +#if defined(TODO) + /* This one seems to support the whole POWER2 instruction set + * and the PowerPC 64 one. + */ + /* What about A10 & A30 ? */ + POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64, + "RS64 (Apache/A35)") +#endif +#if defined(TODO) + POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64, + "RS64-II (NorthStar/A50)") +#endif +#if defined(TODO) + POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64, + "RS64-III (Pulsar)") +#endif +#if defined(TODO) + POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64, + "RS64-IV (IceStar/IStar/SStar)") +#endif +#endif /* defined (TARGET_PPC64) */ + /* POWER */ +#if defined(TODO) + POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER, + "Original POWER") +#endif +#if defined(TODO) + POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER, + "POWER2") +#endif + /* PA semi cores */ +#if defined(TODO) + POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T, + "PA PA6T") +#endif + diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h new file mode 100644 index 0000000000..edff0f4c3c --- /dev/null +++ b/target-ppc/cpu-models.h @@ -0,0 +1,727 @@ +/* + * PowerPC CPU initialization for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2013 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 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 . + */ +#ifndef TARGET_PPC_CPU_MODELS_H +#define TARGET_PPC_CPU_MODELS_H + +/*****************************************************************************/ +/* PVR definitions for most known PowerPC */ +enum { + /* PowerPC 401 family */ + /* Generic PowerPC 401 */ +#define CPU_POWERPC_401 CPU_POWERPC_401G2 + /* PowerPC 401 cores */ + CPU_POWERPC_401A1 = 0x00210000, + CPU_POWERPC_401B2 = 0x00220000, +#if 0 + CPU_POWERPC_401B3 = xxx, +#endif + CPU_POWERPC_401C2 = 0x00230000, + CPU_POWERPC_401D2 = 0x00240000, + CPU_POWERPC_401E2 = 0x00250000, + CPU_POWERPC_401F2 = 0x00260000, + CPU_POWERPC_401G2 = 0x00270000, + /* PowerPC 401 microcontrolers */ +#if 0 + CPU_POWERPC_401GF = xxx, +#endif +#define CPU_POWERPC_IOP480 CPU_POWERPC_401B2 + /* IBM Processor for Network Resources */ + CPU_POWERPC_COBRA = 0x10100000, /* XXX: 405 ? */ +#if 0 + CPU_POWERPC_XIPCHIP = xxx, +#endif + /* PowerPC 403 family */ + /* PowerPC 403 microcontrollers */ + CPU_POWERPC_403GA = 0x00200011, + CPU_POWERPC_403GB = 0x00200100, + CPU_POWERPC_403GC = 0x00200200, + CPU_POWERPC_403GCX = 0x00201400, +#if 0 + CPU_POWERPC_403GP = xxx, +#endif + /* PowerPC 405 family */ + /* PowerPC 405 cores */ +#if 0 + CPU_POWERPC_405A3 = xxx, +#endif +#if 0 + CPU_POWERPC_405A4 = xxx, +#endif +#if 0 + CPU_POWERPC_405B3 = xxx, +#endif +#if 0 + CPU_POWERPC_405B4 = xxx, +#endif +#if 0 + CPU_POWERPC_405C3 = xxx, +#endif +#if 0 + CPU_POWERPC_405C4 = xxx, +#endif + CPU_POWERPC_405D2 = 0x20010000, +#if 0 + CPU_POWERPC_405D3 = xxx, +#endif + CPU_POWERPC_405D4 = 0x41810000, +#if 0 + CPU_POWERPC_405D5 = xxx, +#endif +#if 0 + CPU_POWERPC_405E4 = xxx, +#endif +#if 0 + CPU_POWERPC_405F4 = xxx, +#endif +#if 0 + CPU_POWERPC_405F5 = xxx, +#endif +#if 0 + CPU_POWERPC_405F6 = xxx, +#endif + /* PowerPC 405 microcontrolers */ + /* XXX: missing 0x200108a0 */ + CPU_POWERPC_405CRa = 0x40110041, + CPU_POWERPC_405CRb = 0x401100C5, + CPU_POWERPC_405CRc = 0x40110145, + CPU_POWERPC_405EP = 0x51210950, +#if 0 + CPU_POWERPC_405EXr = xxx, +#endif + CPU_POWERPC_405EZ = 0x41511460, /* 0x51210950 ? */ +#if 0 + CPU_POWERPC_405FX = xxx, +#endif + CPU_POWERPC_405GPa = 0x40110000, + CPU_POWERPC_405GPb = 0x40110040, + CPU_POWERPC_405GPc = 0x40110082, + CPU_POWERPC_405GPd = 0x401100C4, + CPU_POWERPC_405GPR = 0x50910951, +#if 0 + CPU_POWERPC_405H = xxx, +#endif +#if 0 + CPU_POWERPC_405L = xxx, +#endif + CPU_POWERPC_405LP = 0x41F10000, +#if 0 + CPU_POWERPC_405PM = xxx, +#endif +#if 0 + CPU_POWERPC_405PS = xxx, +#endif +#if 0 + CPU_POWERPC_405S = xxx, +#endif + /* IBM network processors */ + CPU_POWERPC_NPE405H = 0x414100C0, + CPU_POWERPC_NPE405H2 = 0x41410140, + CPU_POWERPC_NPE405L = 0x416100C0, + CPU_POWERPC_NPE4GS3 = 0x40B10000, +#if 0 + CPU_POWERPC_NPCxx1 = xxx, +#endif +#if 0 + CPU_POWERPC_NPR161 = xxx, +#endif +#if 0 + CPU_POWERPC_LC77700 = xxx, +#endif + /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ +#if 0 + CPU_POWERPC_STB01000 = xxx, +#endif +#if 0 + CPU_POWERPC_STB01010 = xxx, +#endif +#if 0 + CPU_POWERPC_STB0210 = xxx, /* 401B3 */ +#endif + CPU_POWERPC_STB03 = 0x40310000, /* 0x40130000 ? */ +#if 0 + CPU_POWERPC_STB043 = xxx, +#endif +#if 0 + CPU_POWERPC_STB045 = xxx, +#endif + CPU_POWERPC_STB04 = 0x41810000, + CPU_POWERPC_STB25 = 0x51510950, +#if 0 + CPU_POWERPC_STB130 = xxx, +#endif + /* Xilinx cores */ + CPU_POWERPC_X2VP4 = 0x20010820, + CPU_POWERPC_X2VP20 = 0x20010860, +#if 0 + CPU_POWERPC_ZL10310 = xxx, +#endif +#if 0 + CPU_POWERPC_ZL10311 = xxx, +#endif +#if 0 + CPU_POWERPC_ZL10320 = xxx, +#endif +#if 0 + CPU_POWERPC_ZL10321 = xxx, +#endif + /* PowerPC 440 family */ + /* Generic PowerPC 440 */ +#define CPU_POWERPC_440 CPU_POWERPC_440GXf + /* PowerPC 440 cores */ +#if 0 + CPU_POWERPC_440A4 = xxx, +#endif + CPU_POWERPC_440_XILINX = 0x7ff21910, +#if 0 + CPU_POWERPC_440A5 = xxx, +#endif +#if 0 + CPU_POWERPC_440B4 = xxx, +#endif +#if 0 + CPU_POWERPC_440F5 = xxx, +#endif +#if 0 + CPU_POWERPC_440G5 = xxx, +#endif +#if 0 + CPU_POWERPC_440H4 = xxx, +#endif +#if 0 + CPU_POWERPC_440H6 = xxx, +#endif + /* PowerPC 440 microcontrolers */ + CPU_POWERPC_440EPa = 0x42221850, + CPU_POWERPC_440EPb = 0x422218D3, + CPU_POWERPC_440GPb = 0x40120440, + CPU_POWERPC_440GPc = 0x40120481, +#define CPU_POWERPC_440GRa CPU_POWERPC_440EPb + CPU_POWERPC_440GRX = 0x200008D0, +#define CPU_POWERPC_440EPX CPU_POWERPC_440GRX + CPU_POWERPC_440GXa = 0x51B21850, + CPU_POWERPC_440GXb = 0x51B21851, + CPU_POWERPC_440GXc = 0x51B21892, + CPU_POWERPC_440GXf = 0x51B21894, +#if 0 + CPU_POWERPC_440S = xxx, +#endif + CPU_POWERPC_440SP = 0x53221850, + CPU_POWERPC_440SP2 = 0x53221891, + CPU_POWERPC_440SPE = 0x53421890, + /* PowerPC 460 family */ +#if 0 + /* Generic PowerPC 464 */ +#define CPU_POWERPC_464 CPU_POWERPC_464H90 +#endif + /* PowerPC 464 microcontrolers */ +#if 0 + CPU_POWERPC_464H90 = xxx, +#endif +#if 0 + CPU_POWERPC_464H90FP = xxx, +#endif + /* Freescale embedded PowerPC cores */ + /* PowerPC MPC 5xx cores (aka RCPU) */ + CPU_POWERPC_MPC5xx = 0x00020020, + /* PowerPC MPC 8xx cores (aka PowerQUICC) */ + CPU_POWERPC_MPC8xx = 0x00500000, + /* G2 cores (aka PowerQUICC-II) */ + CPU_POWERPC_G2 = 0x00810011, + CPU_POWERPC_G2H4 = 0x80811010, + CPU_POWERPC_G2gp = 0x80821010, + CPU_POWERPC_G2ls = 0x90810010, + CPU_POWERPC_MPC603 = 0x00810100, + CPU_POWERPC_G2_HIP3 = 0x00810101, + CPU_POWERPC_G2_HIP4 = 0x80811014, + /* G2_LE core (aka PowerQUICC-II) */ + CPU_POWERPC_G2LE = 0x80820010, + CPU_POWERPC_G2LEgp = 0x80822010, + CPU_POWERPC_G2LEls = 0xA0822010, + CPU_POWERPC_G2LEgp1 = 0x80822011, + CPU_POWERPC_G2LEgp3 = 0x80822013, + /* MPC52xx microcontrollers */ + /* XXX: MPC 5121 ? */ +#define CPU_POWERPC_MPC5200_v10 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200_v11 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200_v12 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200B_v20 CPU_POWERPC_G2LEgp1 +#define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 + /* e200 family */ + /* e200 cores */ +#if 0 + CPU_POWERPC_e200z0 = xxx, +#endif +#if 0 + CPU_POWERPC_e200z1 = xxx, +#endif +#if 0 /* ? */ + CPU_POWERPC_e200z3 = 0x81120000, +#endif + CPU_POWERPC_e200z5 = 0x81000000, + CPU_POWERPC_e200z6 = 0x81120000, + /* MPC55xx microcontrollers */ +#define CPU_POWERPC_MPC55xx CPU_POWERPC_MPC5567 +#if 0 +#define CPU_POWERPC_MPC5514E CPU_POWERPC_MPC5514E_v1 +#define CPU_POWERPC_MPC5514E_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5514E_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5514G CPU_POWERPC_MPC5514G_v1 +#define CPU_POWERPC_MPC5514G_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5514G_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5515S CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516E CPU_POWERPC_MPC5516E_v1 +#define CPU_POWERPC_MPC5516E_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5516E_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516G CPU_POWERPC_MPC5516G_v1 +#define CPU_POWERPC_MPC5516G_v0 CPU_POWERPC_e200z0 +#define CPU_POWERPC_MPC5516G_v1 CPU_POWERPC_e200z1 +#define CPU_POWERPC_MPC5516S CPU_POWERPC_e200z1 +#endif +#if 0 +#define CPU_POWERPC_MPC5533 CPU_POWERPC_e200z3 +#define CPU_POWERPC_MPC5534 CPU_POWERPC_e200z3 +#endif +#define CPU_POWERPC_MPC5553 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5554 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5561 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5565 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5566 CPU_POWERPC_e200z6 +#define CPU_POWERPC_MPC5567 CPU_POWERPC_e200z6 + /* e300 family */ + /* e300 cores */ + CPU_POWERPC_e300c1 = 0x00830010, + CPU_POWERPC_e300c2 = 0x00840010, + CPU_POWERPC_e300c3 = 0x00850010, + CPU_POWERPC_e300c4 = 0x00860010, + /* MPC83xx microcontrollers */ +#define CPU_POWERPC_MPC831x CPU_POWERPC_e300c3 +#define CPU_POWERPC_MPC832x CPU_POWERPC_e300c2 +#define CPU_POWERPC_MPC834x CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC835x CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC836x CPU_POWERPC_e300c1 +#define CPU_POWERPC_MPC837x CPU_POWERPC_e300c4 + /* e500 family */ + /* e500 cores */ +#define CPU_POWERPC_e500 CPU_POWERPC_e500v2_v22 + CPU_POWERPC_e500v1_v10 = 0x80200010, + CPU_POWERPC_e500v1_v20 = 0x80200020, + CPU_POWERPC_e500v2_v10 = 0x80210010, + CPU_POWERPC_e500v2_v11 = 0x80210011, + CPU_POWERPC_e500v2_v20 = 0x80210020, + CPU_POWERPC_e500v2_v21 = 0x80210021, + CPU_POWERPC_e500v2_v22 = 0x80210022, + CPU_POWERPC_e500v2_v30 = 0x80210030, + CPU_POWERPC_e500mc = 0x80230020, + CPU_POWERPC_e5500 = 0x80240020, + /* MPC85xx microcontrollers */ +#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8533_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8533E_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8533E_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8540_v10 CPU_POWERPC_e500v1_v10 +#define CPU_POWERPC_MPC8540_v20 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8540_v21 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8541_v10 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8541_v11 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8541E_v10 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8541E_v11 CPU_POWERPC_e500v1_v20 +#define CPU_POWERPC_MPC8543_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8543_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8543_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8543_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8543E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8543E_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8543E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8543E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8544_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8544_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8544E_v11 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8544E_v10 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8545_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8545_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8545_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8545E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8545E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8545E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8547E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8547E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8547E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8548_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8548_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8548_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8548_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8548E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8548E_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8548E_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8548E_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v2_v11 +#define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v2_v10 +#define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v2_v20 +#define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v2_v21 +#define CPU_POWERPC_MPC8567 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8567E CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8568 CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8568E CPU_POWERPC_e500v2_v22 +#define CPU_POWERPC_MPC8572 CPU_POWERPC_e500v2_v30 +#define CPU_POWERPC_MPC8572E CPU_POWERPC_e500v2_v30 + /* e600 family */ + /* e600 cores */ + CPU_POWERPC_e600 = 0x80040010, + /* MPC86xx microcontrollers */ +#define CPU_POWERPC_MPC8610 CPU_POWERPC_e600 +#define CPU_POWERPC_MPC8641 CPU_POWERPC_e600 +#define CPU_POWERPC_MPC8641D CPU_POWERPC_e600 + /* PowerPC 6xx cores */ + CPU_POWERPC_601_v0 = 0x00010001, + CPU_POWERPC_601_v1 = 0x00010001, + CPU_POWERPC_601_v2 = 0x00010002, + CPU_POWERPC_602 = 0x00050100, + CPU_POWERPC_603 = 0x00030100, + CPU_POWERPC_603E_v11 = 0x00060101, + CPU_POWERPC_603E_v12 = 0x00060102, + CPU_POWERPC_603E_v13 = 0x00060103, + CPU_POWERPC_603E_v14 = 0x00060104, + CPU_POWERPC_603E_v22 = 0x00060202, + CPU_POWERPC_603E_v3 = 0x00060300, + CPU_POWERPC_603E_v4 = 0x00060400, + CPU_POWERPC_603E_v41 = 0x00060401, + CPU_POWERPC_603E7t = 0x00071201, + CPU_POWERPC_603E7v = 0x00070100, + CPU_POWERPC_603E7v1 = 0x00070101, + CPU_POWERPC_603E7v2 = 0x00070201, + CPU_POWERPC_603E7 = 0x00070200, + CPU_POWERPC_603P = 0x00070000, + /* XXX: missing 0x00040303 (604) */ + CPU_POWERPC_604 = 0x00040103, + /* XXX: missing 0x00091203 */ + /* XXX: missing 0x00092110 */ + /* XXX: missing 0x00092120 */ + CPU_POWERPC_604E_v10 = 0x00090100, + CPU_POWERPC_604E_v22 = 0x00090202, + CPU_POWERPC_604E_v24 = 0x00090204, + /* XXX: missing 0x000a0100 */ + /* XXX: missing 0x00093102 */ + CPU_POWERPC_604R = 0x000a0101, +#if 0 + CPU_POWERPC_604EV = xxx, /* XXX: same as 604R ? */ +#endif + /* PowerPC 740/750 cores (aka G3) */ + /* XXX: missing 0x00084202 */ + CPU_POWERPC_7x0_v10 = 0x00080100, + CPU_POWERPC_7x0_v20 = 0x00080200, + CPU_POWERPC_7x0_v21 = 0x00080201, + CPU_POWERPC_7x0_v22 = 0x00080202, + CPU_POWERPC_7x0_v30 = 0x00080300, + CPU_POWERPC_7x0_v31 = 0x00080301, + CPU_POWERPC_740E = 0x00080100, + CPU_POWERPC_750E = 0x00080200, + CPU_POWERPC_7x0P = 0x10080000, + /* XXX: missing 0x00087010 (CL ?) */ + CPU_POWERPC_750CL_v10 = 0x00087200, + CPU_POWERPC_750CL_v20 = 0x00087210, /* aka rev E */ + CPU_POWERPC_750CX_v10 = 0x00082100, + CPU_POWERPC_750CX_v20 = 0x00082200, + CPU_POWERPC_750CX_v21 = 0x00082201, + CPU_POWERPC_750CX_v22 = 0x00082202, + CPU_POWERPC_750CXE_v21 = 0x00082211, + CPU_POWERPC_750CXE_v22 = 0x00082212, + CPU_POWERPC_750CXE_v23 = 0x00082213, + CPU_POWERPC_750CXE_v24 = 0x00082214, + CPU_POWERPC_750CXE_v24b = 0x00083214, + CPU_POWERPC_750CXE_v30 = 0x00082310, + CPU_POWERPC_750CXE_v31 = 0x00082311, + CPU_POWERPC_750CXE_v31b = 0x00083311, + CPU_POWERPC_750CXR = 0x00083410, + CPU_POWERPC_750FL = 0x70000203, + CPU_POWERPC_750FX_v10 = 0x70000100, + CPU_POWERPC_750FX_v20 = 0x70000200, + CPU_POWERPC_750FX_v21 = 0x70000201, + CPU_POWERPC_750FX_v22 = 0x70000202, + CPU_POWERPC_750FX_v23 = 0x70000203, + CPU_POWERPC_750GL = 0x70020102, + CPU_POWERPC_750GX_v10 = 0x70020100, + CPU_POWERPC_750GX_v11 = 0x70020101, + CPU_POWERPC_750GX_v12 = 0x70020102, + CPU_POWERPC_750L_v20 = 0x00088200, + CPU_POWERPC_750L_v21 = 0x00088201, + CPU_POWERPC_750L_v22 = 0x00088202, + CPU_POWERPC_750L_v30 = 0x00088300, + CPU_POWERPC_750L_v32 = 0x00088302, + /* PowerPC 745/755 cores */ + CPU_POWERPC_7x5_v10 = 0x00083100, + CPU_POWERPC_7x5_v11 = 0x00083101, + CPU_POWERPC_7x5_v20 = 0x00083200, + CPU_POWERPC_7x5_v21 = 0x00083201, + CPU_POWERPC_7x5_v22 = 0x00083202, /* aka D */ + CPU_POWERPC_7x5_v23 = 0x00083203, /* aka E */ + CPU_POWERPC_7x5_v24 = 0x00083204, + CPU_POWERPC_7x5_v25 = 0x00083205, + CPU_POWERPC_7x5_v26 = 0x00083206, + CPU_POWERPC_7x5_v27 = 0x00083207, + CPU_POWERPC_7x5_v28 = 0x00083208, +#if 0 + CPU_POWERPC_7x5P = xxx, +#endif + /* PowerPC 74xx cores (aka G4) */ + /* XXX: missing 0x000C1101 */ + CPU_POWERPC_7400_v10 = 0x000C0100, + CPU_POWERPC_7400_v11 = 0x000C0101, + CPU_POWERPC_7400_v20 = 0x000C0200, + CPU_POWERPC_7400_v21 = 0x000C0201, + CPU_POWERPC_7400_v22 = 0x000C0202, + CPU_POWERPC_7400_v26 = 0x000C0206, + CPU_POWERPC_7400_v27 = 0x000C0207, + CPU_POWERPC_7400_v28 = 0x000C0208, + CPU_POWERPC_7400_v29 = 0x000C0209, + CPU_POWERPC_7410_v10 = 0x800C1100, + CPU_POWERPC_7410_v11 = 0x800C1101, + CPU_POWERPC_7410_v12 = 0x800C1102, /* aka C */ + CPU_POWERPC_7410_v13 = 0x800C1103, /* aka D */ + CPU_POWERPC_7410_v14 = 0x800C1104, /* aka E */ + CPU_POWERPC_7448_v10 = 0x80040100, + CPU_POWERPC_7448_v11 = 0x80040101, + CPU_POWERPC_7448_v20 = 0x80040200, + CPU_POWERPC_7448_v21 = 0x80040201, + CPU_POWERPC_7450_v10 = 0x80000100, + CPU_POWERPC_7450_v11 = 0x80000101, + CPU_POWERPC_7450_v12 = 0x80000102, + CPU_POWERPC_7450_v20 = 0x80000200, /* aka A, B, C, D: 2.04 */ + CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ + CPU_POWERPC_74x1_v23 = 0x80000203, /* aka G: 2.3 */ + /* XXX: this entry might be a bug in some documentation */ + CPU_POWERPC_74x1_v210 = 0x80000210, /* aka G: 2.3 ? */ + CPU_POWERPC_74x5_v10 = 0x80010100, + /* XXX: missing 0x80010200 */ + CPU_POWERPC_74x5_v21 = 0x80010201, /* aka C: 2.1 */ + CPU_POWERPC_74x5_v32 = 0x80010302, + CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ + CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ + CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ + CPU_POWERPC_74x7_v11 = 0x80020101, /* aka B: 1.1 */ + CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ + CPU_POWERPC_74x7A_v10 = 0x80030100, /* aka A: 1.0 */ + CPU_POWERPC_74x7A_v11 = 0x80030101, /* aka B: 1.1 */ + CPU_POWERPC_74x7A_v12 = 0x80030102, /* aka C: 1.2 */ + /* 64 bits PowerPC */ +#if defined(TARGET_PPC64) + CPU_POWERPC_620 = 0x00140000, + CPU_POWERPC_630 = 0x00400000, + CPU_POWERPC_631 = 0x00410104, + CPU_POWERPC_POWER4 = 0x00350000, + CPU_POWERPC_POWER4P = 0x00380000, + /* XXX: missing 0x003A0201 */ + CPU_POWERPC_POWER5 = 0x003A0203, +#define CPU_POWERPC_POWER5GR CPU_POWERPC_POWER5 + CPU_POWERPC_POWER5P = 0x003B0000, +#define CPU_POWERPC_POWER5GS CPU_POWERPC_POWER5P + CPU_POWERPC_POWER6 = 0x003E0000, + CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ + CPU_POWERPC_POWER6A = 0x0F000002, + CPU_POWERPC_POWER7_v20 = 0x003F0200, + CPU_POWERPC_POWER7_v21 = 0x003F0201, + CPU_POWERPC_POWER7_v23 = 0x003F0203, + CPU_POWERPC_970 = 0x00390202, + CPU_POWERPC_970FX_v10 = 0x00391100, + CPU_POWERPC_970FX_v20 = 0x003C0200, + CPU_POWERPC_970FX_v21 = 0x003C0201, + CPU_POWERPC_970FX_v30 = 0x003C0300, + CPU_POWERPC_970FX_v31 = 0x003C0301, + CPU_POWERPC_970GX = 0x00450000, + CPU_POWERPC_970MP_v10 = 0x00440100, + CPU_POWERPC_970MP_v11 = 0x00440101, +#define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32 + CPU_POWERPC_CELL_v10 = 0x00700100, + CPU_POWERPC_CELL_v20 = 0x00700400, + CPU_POWERPC_CELL_v30 = 0x00700500, + CPU_POWERPC_CELL_v31 = 0x00700501, +#define CPU_POWERPC_CELL_v32 CPU_POWERPC_CELL_v31 + CPU_POWERPC_RS64 = 0x00330000, + CPU_POWERPC_RS64II = 0x00340000, + CPU_POWERPC_RS64III = 0x00360000, + CPU_POWERPC_RS64IV = 0x00370000, +#endif /* defined(TARGET_PPC64) */ + /* Original POWER */ + /* XXX: should be POWER (RIOS), RSC3308, RSC4608, + * POWER2 (RIOS2) & RSC2 (P2SC) here + */ +#if 0 + CPU_POWER = xxx, /* 0x20000 ? 0x30000 for RSC ? */ +#endif +#if 0 + CPU_POWER2 = xxx, /* 0x40000 ? */ +#endif + /* PA Semi core */ + CPU_POWERPC_PA6T = 0x00900000, +}; + +/* System version register (used on MPC 8xxx) */ +enum { + POWERPC_SVR_NONE = 0x00000000, + POWERPC_SVR_5200_v10 = 0x80110010, + POWERPC_SVR_5200_v11 = 0x80110011, + POWERPC_SVR_5200_v12 = 0x80110012, + POWERPC_SVR_5200B_v20 = 0x80110020, + POWERPC_SVR_5200B_v21 = 0x80110021, +#define POWERPC_SVR_55xx POWERPC_SVR_5567 +#if 0 + POWERPC_SVR_5533 = xxx, +#endif +#if 0 + POWERPC_SVR_5534 = xxx, +#endif +#if 0 + POWERPC_SVR_5553 = xxx, +#endif +#if 0 + POWERPC_SVR_5554 = xxx, +#endif +#if 0 + POWERPC_SVR_5561 = xxx, +#endif +#if 0 + POWERPC_SVR_5565 = xxx, +#endif +#if 0 + POWERPC_SVR_5566 = xxx, +#endif +#if 0 + POWERPC_SVR_5567 = xxx, +#endif +#if 0 + POWERPC_SVR_8313 = xxx, +#endif +#if 0 + POWERPC_SVR_8313E = xxx, +#endif +#if 0 + POWERPC_SVR_8314 = xxx, +#endif +#if 0 + POWERPC_SVR_8314E = xxx, +#endif +#if 0 + POWERPC_SVR_8315 = xxx, +#endif +#if 0 + POWERPC_SVR_8315E = xxx, +#endif +#if 0 + POWERPC_SVR_8321 = xxx, +#endif +#if 0 + POWERPC_SVR_8321E = xxx, +#endif +#if 0 + POWERPC_SVR_8323 = xxx, +#endif +#if 0 + POWERPC_SVR_8323E = xxx, +#endif + POWERPC_SVR_8343 = 0x80570010, + POWERPC_SVR_8343A = 0x80570030, + POWERPC_SVR_8343E = 0x80560010, + POWERPC_SVR_8343EA = 0x80560030, + POWERPC_SVR_8347P = 0x80550010, /* PBGA package */ + POWERPC_SVR_8347T = 0x80530010, /* TBGA package */ + POWERPC_SVR_8347AP = 0x80550030, /* PBGA package */ + POWERPC_SVR_8347AT = 0x80530030, /* TBGA package */ + POWERPC_SVR_8347EP = 0x80540010, /* PBGA package */ + POWERPC_SVR_8347ET = 0x80520010, /* TBGA package */ + POWERPC_SVR_8347EAP = 0x80540030, /* PBGA package */ + POWERPC_SVR_8347EAT = 0x80520030, /* TBGA package */ + POWERPC_SVR_8349 = 0x80510010, + POWERPC_SVR_8349A = 0x80510030, + POWERPC_SVR_8349E = 0x80500010, + POWERPC_SVR_8349EA = 0x80500030, +#if 0 + POWERPC_SVR_8358E = xxx, +#endif +#if 0 + POWERPC_SVR_8360E = xxx, +#endif +#define POWERPC_SVR_E500 0x40000000 + POWERPC_SVR_8377 = 0x80C70010 | POWERPC_SVR_E500, + POWERPC_SVR_8377E = 0x80C60010 | POWERPC_SVR_E500, + POWERPC_SVR_8378 = 0x80C50010 | POWERPC_SVR_E500, + POWERPC_SVR_8378E = 0x80C40010 | POWERPC_SVR_E500, + POWERPC_SVR_8379 = 0x80C30010 | POWERPC_SVR_E500, + POWERPC_SVR_8379E = 0x80C00010 | POWERPC_SVR_E500, + POWERPC_SVR_8533_v10 = 0x80340010 | POWERPC_SVR_E500, + POWERPC_SVR_8533_v11 = 0x80340011 | POWERPC_SVR_E500, + POWERPC_SVR_8533E_v10 = 0x803C0010 | POWERPC_SVR_E500, + POWERPC_SVR_8533E_v11 = 0x803C0011 | POWERPC_SVR_E500, + POWERPC_SVR_8540_v10 = 0x80300010 | POWERPC_SVR_E500, + POWERPC_SVR_8540_v20 = 0x80300020 | POWERPC_SVR_E500, + POWERPC_SVR_8540_v21 = 0x80300021 | POWERPC_SVR_E500, + POWERPC_SVR_8541_v10 = 0x80720010 | POWERPC_SVR_E500, + POWERPC_SVR_8541_v11 = 0x80720011 | POWERPC_SVR_E500, + POWERPC_SVR_8541E_v10 = 0x807A0010 | POWERPC_SVR_E500, + POWERPC_SVR_8541E_v11 = 0x807A0011 | POWERPC_SVR_E500, + POWERPC_SVR_8543_v10 = 0x80320010 | POWERPC_SVR_E500, + POWERPC_SVR_8543_v11 = 0x80320011 | POWERPC_SVR_E500, + POWERPC_SVR_8543_v20 = 0x80320020 | POWERPC_SVR_E500, + POWERPC_SVR_8543_v21 = 0x80320021 | POWERPC_SVR_E500, + POWERPC_SVR_8543E_v10 = 0x803A0010 | POWERPC_SVR_E500, + POWERPC_SVR_8543E_v11 = 0x803A0011 | POWERPC_SVR_E500, + POWERPC_SVR_8543E_v20 = 0x803A0020 | POWERPC_SVR_E500, + POWERPC_SVR_8543E_v21 = 0x803A0021 | POWERPC_SVR_E500, + POWERPC_SVR_8544_v10 = 0x80340110 | POWERPC_SVR_E500, + POWERPC_SVR_8544_v11 = 0x80340111 | POWERPC_SVR_E500, + POWERPC_SVR_8544E_v10 = 0x803C0110 | POWERPC_SVR_E500, + POWERPC_SVR_8544E_v11 = 0x803C0111 | POWERPC_SVR_E500, + POWERPC_SVR_8545_v20 = 0x80310220 | POWERPC_SVR_E500, + POWERPC_SVR_8545_v21 = 0x80310221 | POWERPC_SVR_E500, + POWERPC_SVR_8545E_v20 = 0x80390220 | POWERPC_SVR_E500, + POWERPC_SVR_8545E_v21 = 0x80390221 | POWERPC_SVR_E500, + POWERPC_SVR_8547E_v20 = 0x80390120 | POWERPC_SVR_E500, + POWERPC_SVR_8547E_v21 = 0x80390121 | POWERPC_SVR_E500, + POWERPC_SVR_8548_v10 = 0x80310010 | POWERPC_SVR_E500, + POWERPC_SVR_8548_v11 = 0x80310011 | POWERPC_SVR_E500, + POWERPC_SVR_8548_v20 = 0x80310020 | POWERPC_SVR_E500, + POWERPC_SVR_8548_v21 = 0x80310021 | POWERPC_SVR_E500, + POWERPC_SVR_8548E_v10 = 0x80390010 | POWERPC_SVR_E500, + POWERPC_SVR_8548E_v11 = 0x80390011 | POWERPC_SVR_E500, + POWERPC_SVR_8548E_v20 = 0x80390020 | POWERPC_SVR_E500, + POWERPC_SVR_8548E_v21 = 0x80390021 | POWERPC_SVR_E500, + POWERPC_SVR_8555_v10 = 0x80710010 | POWERPC_SVR_E500, + POWERPC_SVR_8555_v11 = 0x80710011 | POWERPC_SVR_E500, + POWERPC_SVR_8555E_v10 = 0x80790010 | POWERPC_SVR_E500, + POWERPC_SVR_8555E_v11 = 0x80790011 | POWERPC_SVR_E500, + POWERPC_SVR_8560_v10 = 0x80700010 | POWERPC_SVR_E500, + POWERPC_SVR_8560_v20 = 0x80700020 | POWERPC_SVR_E500, + POWERPC_SVR_8560_v21 = 0x80700021 | POWERPC_SVR_E500, + POWERPC_SVR_8567 = 0x80750111 | POWERPC_SVR_E500, + POWERPC_SVR_8567E = 0x807D0111 | POWERPC_SVR_E500, + POWERPC_SVR_8568 = 0x80750011 | POWERPC_SVR_E500, + POWERPC_SVR_8568E = 0x807D0011 | POWERPC_SVR_E500, + POWERPC_SVR_8572 = 0x80E00010 | POWERPC_SVR_E500, + POWERPC_SVR_8572E = 0x80E80010 | POWERPC_SVR_E500, +#if 0 + POWERPC_SVR_8610 = xxx, +#endif + POWERPC_SVR_8641 = 0x80900021, + POWERPC_SVR_8641D = 0x80900121, +}; + +#endif diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 31566e0d95..b0d435735a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -18,24 +18,17 @@ * License along with this library; if not, see . */ -/* A lot of PowerPC definition have been included here. - * Most of them are not usable for now but have been kept - * inside "#if defined(TODO) ... #endif" statements to make tests easier. - */ - #include "disas/bfd.h" #include "exec/gdbstub.h" #include #include "kvm_ppc.h" #include "sysemu/arch_init.h" #include "sysemu/cpus.h" +#include "cpu-models.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR //#define PPC_DUMP_SPR_ACCESSES -#if defined(CONFIG_USER_ONLY) -#define TODO_USER_ONLY 1 -#endif /* For user-mode emulation, we don't emulate any IRQ controller */ #if defined(CONFIG_USER_ONLY) @@ -4876,18 +4869,16 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) /* Non-embedded PowerPC */ /* POWER : same as 601, without mfmsr, mfsr */ -#if defined(TODO) POWERPC_FAMILY(POWER)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); dc->desc = "POWER"; - pcc->insns_flags = XXX_TODO; + /* pcc->insns_flags = XXX_TODO; */ /* POWER RSC (from RAD6000) */ pcc->msr_mask = 0x00000000FEF0ULL; } -#endif /* TODO */ #define POWERPC_MSRR_601 (0x0000000000001040ULL) @@ -7173,1900 +7164,6 @@ POWERPC_FAMILY(620)(ObjectClass *oc, void *data) #endif /* defined (TARGET_PPC64) */ -/*****************************************************************************/ -/* PVR definitions for most known PowerPC */ -enum { - /* PowerPC 401 family */ - /* Generic PowerPC 401 */ -#define CPU_POWERPC_401 CPU_POWERPC_401G2 - /* PowerPC 401 cores */ - CPU_POWERPC_401A1 = 0x00210000, - CPU_POWERPC_401B2 = 0x00220000, -#if 0 - CPU_POWERPC_401B3 = xxx, -#endif - CPU_POWERPC_401C2 = 0x00230000, - CPU_POWERPC_401D2 = 0x00240000, - CPU_POWERPC_401E2 = 0x00250000, - CPU_POWERPC_401F2 = 0x00260000, - CPU_POWERPC_401G2 = 0x00270000, - /* PowerPC 401 microcontrolers */ -#if 0 - CPU_POWERPC_401GF = xxx, -#endif -#define CPU_POWERPC_IOP480 CPU_POWERPC_401B2 - /* IBM Processor for Network Resources */ - CPU_POWERPC_COBRA = 0x10100000, /* XXX: 405 ? */ -#if 0 - CPU_POWERPC_XIPCHIP = xxx, -#endif - /* PowerPC 403 family */ - /* PowerPC 403 microcontrollers */ - CPU_POWERPC_403GA = 0x00200011, - CPU_POWERPC_403GB = 0x00200100, - CPU_POWERPC_403GC = 0x00200200, - CPU_POWERPC_403GCX = 0x00201400, -#if 0 - CPU_POWERPC_403GP = xxx, -#endif - /* PowerPC 405 family */ - /* PowerPC 405 cores */ -#if 0 - CPU_POWERPC_405A3 = xxx, -#endif -#if 0 - CPU_POWERPC_405A4 = xxx, -#endif -#if 0 - CPU_POWERPC_405B3 = xxx, -#endif -#if 0 - CPU_POWERPC_405B4 = xxx, -#endif -#if 0 - CPU_POWERPC_405C3 = xxx, -#endif -#if 0 - CPU_POWERPC_405C4 = xxx, -#endif - CPU_POWERPC_405D2 = 0x20010000, -#if 0 - CPU_POWERPC_405D3 = xxx, -#endif - CPU_POWERPC_405D4 = 0x41810000, -#if 0 - CPU_POWERPC_405D5 = xxx, -#endif -#if 0 - CPU_POWERPC_405E4 = xxx, -#endif -#if 0 - CPU_POWERPC_405F4 = xxx, -#endif -#if 0 - CPU_POWERPC_405F5 = xxx, -#endif -#if 0 - CPU_POWERPC_405F6 = xxx, -#endif - /* PowerPC 405 microcontrolers */ - /* XXX: missing 0x200108a0 */ - CPU_POWERPC_405CRa = 0x40110041, - CPU_POWERPC_405CRb = 0x401100C5, - CPU_POWERPC_405CRc = 0x40110145, - CPU_POWERPC_405EP = 0x51210950, -#if 0 - CPU_POWERPC_405EXr = xxx, -#endif - CPU_POWERPC_405EZ = 0x41511460, /* 0x51210950 ? */ -#if 0 - CPU_POWERPC_405FX = xxx, -#endif - CPU_POWERPC_405GPa = 0x40110000, - CPU_POWERPC_405GPb = 0x40110040, - CPU_POWERPC_405GPc = 0x40110082, - CPU_POWERPC_405GPd = 0x401100C4, - CPU_POWERPC_405GPR = 0x50910951, -#if 0 - CPU_POWERPC_405H = xxx, -#endif -#if 0 - CPU_POWERPC_405L = xxx, -#endif - CPU_POWERPC_405LP = 0x41F10000, -#if 0 - CPU_POWERPC_405PM = xxx, -#endif -#if 0 - CPU_POWERPC_405PS = xxx, -#endif -#if 0 - CPU_POWERPC_405S = xxx, -#endif - /* IBM network processors */ - CPU_POWERPC_NPE405H = 0x414100C0, - CPU_POWERPC_NPE405H2 = 0x41410140, - CPU_POWERPC_NPE405L = 0x416100C0, - CPU_POWERPC_NPE4GS3 = 0x40B10000, -#if 0 - CPU_POWERPC_NPCxx1 = xxx, -#endif -#if 0 - CPU_POWERPC_NPR161 = xxx, -#endif -#if 0 - CPU_POWERPC_LC77700 = xxx, -#endif - /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ -#if 0 - CPU_POWERPC_STB01000 = xxx, -#endif -#if 0 - CPU_POWERPC_STB01010 = xxx, -#endif -#if 0 - CPU_POWERPC_STB0210 = xxx, /* 401B3 */ -#endif - CPU_POWERPC_STB03 = 0x40310000, /* 0x40130000 ? */ -#if 0 - CPU_POWERPC_STB043 = xxx, -#endif -#if 0 - CPU_POWERPC_STB045 = xxx, -#endif - CPU_POWERPC_STB04 = 0x41810000, - CPU_POWERPC_STB25 = 0x51510950, -#if 0 - CPU_POWERPC_STB130 = xxx, -#endif - /* Xilinx cores */ - CPU_POWERPC_X2VP4 = 0x20010820, - CPU_POWERPC_X2VP20 = 0x20010860, -#if 0 - CPU_POWERPC_ZL10310 = xxx, -#endif -#if 0 - CPU_POWERPC_ZL10311 = xxx, -#endif -#if 0 - CPU_POWERPC_ZL10320 = xxx, -#endif -#if 0 - CPU_POWERPC_ZL10321 = xxx, -#endif - /* PowerPC 440 family */ - /* Generic PowerPC 440 */ -#define CPU_POWERPC_440 CPU_POWERPC_440GXf - /* PowerPC 440 cores */ -#if 0 - CPU_POWERPC_440A4 = xxx, -#endif - CPU_POWERPC_440_XILINX = 0x7ff21910, -#if 0 - CPU_POWERPC_440A5 = xxx, -#endif -#if 0 - CPU_POWERPC_440B4 = xxx, -#endif -#if 0 - CPU_POWERPC_440F5 = xxx, -#endif -#if 0 - CPU_POWERPC_440G5 = xxx, -#endif -#if 0 - CPU_POWERPC_440H4 = xxx, -#endif -#if 0 - CPU_POWERPC_440H6 = xxx, -#endif - /* PowerPC 440 microcontrolers */ - CPU_POWERPC_440EPa = 0x42221850, - CPU_POWERPC_440EPb = 0x422218D3, - CPU_POWERPC_440GPb = 0x40120440, - CPU_POWERPC_440GPc = 0x40120481, -#define CPU_POWERPC_440GRa CPU_POWERPC_440EPb - CPU_POWERPC_440GRX = 0x200008D0, -#define CPU_POWERPC_440EPX CPU_POWERPC_440GRX - CPU_POWERPC_440GXa = 0x51B21850, - CPU_POWERPC_440GXb = 0x51B21851, - CPU_POWERPC_440GXc = 0x51B21892, - CPU_POWERPC_440GXf = 0x51B21894, -#if 0 - CPU_POWERPC_440S = xxx, -#endif - CPU_POWERPC_440SP = 0x53221850, - CPU_POWERPC_440SP2 = 0x53221891, - CPU_POWERPC_440SPE = 0x53421890, - /* PowerPC 460 family */ -#if 0 - /* Generic PowerPC 464 */ -#define CPU_POWERPC_464 CPU_POWERPC_464H90 -#endif - /* PowerPC 464 microcontrolers */ -#if 0 - CPU_POWERPC_464H90 = xxx, -#endif -#if 0 - CPU_POWERPC_464H90FP = xxx, -#endif - /* Freescale embedded PowerPC cores */ - /* PowerPC MPC 5xx cores (aka RCPU) */ - CPU_POWERPC_MPC5xx = 0x00020020, - /* PowerPC MPC 8xx cores (aka PowerQUICC) */ - CPU_POWERPC_MPC8xx = 0x00500000, - /* G2 cores (aka PowerQUICC-II) */ - CPU_POWERPC_G2 = 0x00810011, - CPU_POWERPC_G2H4 = 0x80811010, - CPU_POWERPC_G2gp = 0x80821010, - CPU_POWERPC_G2ls = 0x90810010, - CPU_POWERPC_MPC603 = 0x00810100, - CPU_POWERPC_G2_HIP3 = 0x00810101, - CPU_POWERPC_G2_HIP4 = 0x80811014, - /* G2_LE core (aka PowerQUICC-II) */ - CPU_POWERPC_G2LE = 0x80820010, - CPU_POWERPC_G2LEgp = 0x80822010, - CPU_POWERPC_G2LEls = 0xA0822010, - CPU_POWERPC_G2LEgp1 = 0x80822011, - CPU_POWERPC_G2LEgp3 = 0x80822013, - /* MPC52xx microcontrollers */ - /* XXX: MPC 5121 ? */ -#define CPU_POWERPC_MPC5200_v10 CPU_POWERPC_G2LEgp1 -#define CPU_POWERPC_MPC5200_v11 CPU_POWERPC_G2LEgp1 -#define CPU_POWERPC_MPC5200_v12 CPU_POWERPC_G2LEgp1 -#define CPU_POWERPC_MPC5200B_v20 CPU_POWERPC_G2LEgp1 -#define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 - /* e200 family */ - /* e200 cores */ -#if 0 - CPU_POWERPC_e200z0 = xxx, -#endif -#if 0 - CPU_POWERPC_e200z1 = xxx, -#endif -#if 0 /* ? */ - CPU_POWERPC_e200z3 = 0x81120000, -#endif - CPU_POWERPC_e200z5 = 0x81000000, - CPU_POWERPC_e200z6 = 0x81120000, - /* MPC55xx microcontrollers */ -#define CPU_POWERPC_MPC55xx CPU_POWERPC_MPC5567 -#if 0 -#define CPU_POWERPC_MPC5514E CPU_POWERPC_MPC5514E_v1 -#define CPU_POWERPC_MPC5514E_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5514E_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5514G CPU_POWERPC_MPC5514G_v1 -#define CPU_POWERPC_MPC5514G_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5514G_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5515S CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516E CPU_POWERPC_MPC5516E_v1 -#define CPU_POWERPC_MPC5516E_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5516E_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516G CPU_POWERPC_MPC5516G_v1 -#define CPU_POWERPC_MPC5516G_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5516G_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516S CPU_POWERPC_e200z1 -#endif -#if 0 -#define CPU_POWERPC_MPC5533 CPU_POWERPC_e200z3 -#define CPU_POWERPC_MPC5534 CPU_POWERPC_e200z3 -#endif -#define CPU_POWERPC_MPC5553 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5554 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5561 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5565 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5566 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5567 CPU_POWERPC_e200z6 - /* e300 family */ - /* e300 cores */ - CPU_POWERPC_e300c1 = 0x00830010, - CPU_POWERPC_e300c2 = 0x00840010, - CPU_POWERPC_e300c3 = 0x00850010, - CPU_POWERPC_e300c4 = 0x00860010, - /* MPC83xx microcontrollers */ -#define CPU_POWERPC_MPC831x CPU_POWERPC_e300c3 -#define CPU_POWERPC_MPC832x CPU_POWERPC_e300c2 -#define CPU_POWERPC_MPC834x CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC835x CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC836x CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC837x CPU_POWERPC_e300c4 - /* e500 family */ - /* e500 cores */ -#define CPU_POWERPC_e500 CPU_POWERPC_e500v2_v22 - CPU_POWERPC_e500v1_v10 = 0x80200010, - CPU_POWERPC_e500v1_v20 = 0x80200020, - CPU_POWERPC_e500v2_v10 = 0x80210010, - CPU_POWERPC_e500v2_v11 = 0x80210011, - CPU_POWERPC_e500v2_v20 = 0x80210020, - CPU_POWERPC_e500v2_v21 = 0x80210021, - CPU_POWERPC_e500v2_v22 = 0x80210022, - CPU_POWERPC_e500v2_v30 = 0x80210030, - CPU_POWERPC_e500mc = 0x80230020, - CPU_POWERPC_e5500 = 0x80240020, - /* MPC85xx microcontrollers */ -#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8533_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8533E_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8533E_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8540_v10 CPU_POWERPC_e500v1_v10 -#define CPU_POWERPC_MPC8540_v20 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8540_v21 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8541_v10 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8541_v11 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8541E_v10 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8541E_v11 CPU_POWERPC_e500v1_v20 -#define CPU_POWERPC_MPC8543_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8543_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8543_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8543_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8543E_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8543E_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8543E_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8543E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8544_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8544_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8544E_v11 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8544E_v10 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8545_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8545_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8545_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8545E_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8545E_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8545E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8547E_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8547E_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8547E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8548_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8548_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8548_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8548_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8548E_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8548E_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8548E_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8548E_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8555_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8555_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8555E_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8555E_v11 CPU_POWERPC_e500v2_v11 -#define CPU_POWERPC_MPC8560_v10 CPU_POWERPC_e500v2_v10 -#define CPU_POWERPC_MPC8560_v20 CPU_POWERPC_e500v2_v20 -#define CPU_POWERPC_MPC8560_v21 CPU_POWERPC_e500v2_v21 -#define CPU_POWERPC_MPC8567 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8567E CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8568 CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8568E CPU_POWERPC_e500v2_v22 -#define CPU_POWERPC_MPC8572 CPU_POWERPC_e500v2_v30 -#define CPU_POWERPC_MPC8572E CPU_POWERPC_e500v2_v30 - /* e600 family */ - /* e600 cores */ - CPU_POWERPC_e600 = 0x80040010, - /* MPC86xx microcontrollers */ -#define CPU_POWERPC_MPC8610 CPU_POWERPC_e600 -#define CPU_POWERPC_MPC8641 CPU_POWERPC_e600 -#define CPU_POWERPC_MPC8641D CPU_POWERPC_e600 - /* PowerPC 6xx cores */ - CPU_POWERPC_601_v0 = 0x00010001, - CPU_POWERPC_601_v1 = 0x00010001, - CPU_POWERPC_601_v2 = 0x00010002, - CPU_POWERPC_602 = 0x00050100, - CPU_POWERPC_603 = 0x00030100, - CPU_POWERPC_603E_v11 = 0x00060101, - CPU_POWERPC_603E_v12 = 0x00060102, - CPU_POWERPC_603E_v13 = 0x00060103, - CPU_POWERPC_603E_v14 = 0x00060104, - CPU_POWERPC_603E_v22 = 0x00060202, - CPU_POWERPC_603E_v3 = 0x00060300, - CPU_POWERPC_603E_v4 = 0x00060400, - CPU_POWERPC_603E_v41 = 0x00060401, - CPU_POWERPC_603E7t = 0x00071201, - CPU_POWERPC_603E7v = 0x00070100, - CPU_POWERPC_603E7v1 = 0x00070101, - CPU_POWERPC_603E7v2 = 0x00070201, - CPU_POWERPC_603E7 = 0x00070200, - CPU_POWERPC_603P = 0x00070000, - /* XXX: missing 0x00040303 (604) */ - CPU_POWERPC_604 = 0x00040103, - /* XXX: missing 0x00091203 */ - /* XXX: missing 0x00092110 */ - /* XXX: missing 0x00092120 */ - CPU_POWERPC_604E_v10 = 0x00090100, - CPU_POWERPC_604E_v22 = 0x00090202, - CPU_POWERPC_604E_v24 = 0x00090204, - /* XXX: missing 0x000a0100 */ - /* XXX: missing 0x00093102 */ - CPU_POWERPC_604R = 0x000a0101, -#if 0 - CPU_POWERPC_604EV = xxx, /* XXX: same as 604R ? */ -#endif - /* PowerPC 740/750 cores (aka G3) */ - /* XXX: missing 0x00084202 */ - CPU_POWERPC_7x0_v10 = 0x00080100, - CPU_POWERPC_7x0_v20 = 0x00080200, - CPU_POWERPC_7x0_v21 = 0x00080201, - CPU_POWERPC_7x0_v22 = 0x00080202, - CPU_POWERPC_7x0_v30 = 0x00080300, - CPU_POWERPC_7x0_v31 = 0x00080301, - CPU_POWERPC_740E = 0x00080100, - CPU_POWERPC_750E = 0x00080200, - CPU_POWERPC_7x0P = 0x10080000, - /* XXX: missing 0x00087010 (CL ?) */ - CPU_POWERPC_750CL_v10 = 0x00087200, - CPU_POWERPC_750CL_v20 = 0x00087210, /* aka rev E */ - CPU_POWERPC_750CX_v10 = 0x00082100, - CPU_POWERPC_750CX_v20 = 0x00082200, - CPU_POWERPC_750CX_v21 = 0x00082201, - CPU_POWERPC_750CX_v22 = 0x00082202, - CPU_POWERPC_750CXE_v21 = 0x00082211, - CPU_POWERPC_750CXE_v22 = 0x00082212, - CPU_POWERPC_750CXE_v23 = 0x00082213, - CPU_POWERPC_750CXE_v24 = 0x00082214, - CPU_POWERPC_750CXE_v24b = 0x00083214, - CPU_POWERPC_750CXE_v30 = 0x00082310, - CPU_POWERPC_750CXE_v31 = 0x00082311, - CPU_POWERPC_750CXE_v31b = 0x00083311, - CPU_POWERPC_750CXR = 0x00083410, - CPU_POWERPC_750FL = 0x70000203, - CPU_POWERPC_750FX_v10 = 0x70000100, - CPU_POWERPC_750FX_v20 = 0x70000200, - CPU_POWERPC_750FX_v21 = 0x70000201, - CPU_POWERPC_750FX_v22 = 0x70000202, - CPU_POWERPC_750FX_v23 = 0x70000203, - CPU_POWERPC_750GL = 0x70020102, - CPU_POWERPC_750GX_v10 = 0x70020100, - CPU_POWERPC_750GX_v11 = 0x70020101, - CPU_POWERPC_750GX_v12 = 0x70020102, - CPU_POWERPC_750L_v20 = 0x00088200, - CPU_POWERPC_750L_v21 = 0x00088201, - CPU_POWERPC_750L_v22 = 0x00088202, - CPU_POWERPC_750L_v30 = 0x00088300, - CPU_POWERPC_750L_v32 = 0x00088302, - /* PowerPC 745/755 cores */ - CPU_POWERPC_7x5_v10 = 0x00083100, - CPU_POWERPC_7x5_v11 = 0x00083101, - CPU_POWERPC_7x5_v20 = 0x00083200, - CPU_POWERPC_7x5_v21 = 0x00083201, - CPU_POWERPC_7x5_v22 = 0x00083202, /* aka D */ - CPU_POWERPC_7x5_v23 = 0x00083203, /* aka E */ - CPU_POWERPC_7x5_v24 = 0x00083204, - CPU_POWERPC_7x5_v25 = 0x00083205, - CPU_POWERPC_7x5_v26 = 0x00083206, - CPU_POWERPC_7x5_v27 = 0x00083207, - CPU_POWERPC_7x5_v28 = 0x00083208, -#if 0 - CPU_POWERPC_7x5P = xxx, -#endif - /* PowerPC 74xx cores (aka G4) */ - /* XXX: missing 0x000C1101 */ - CPU_POWERPC_7400_v10 = 0x000C0100, - CPU_POWERPC_7400_v11 = 0x000C0101, - CPU_POWERPC_7400_v20 = 0x000C0200, - CPU_POWERPC_7400_v21 = 0x000C0201, - CPU_POWERPC_7400_v22 = 0x000C0202, - CPU_POWERPC_7400_v26 = 0x000C0206, - CPU_POWERPC_7400_v27 = 0x000C0207, - CPU_POWERPC_7400_v28 = 0x000C0208, - CPU_POWERPC_7400_v29 = 0x000C0209, - CPU_POWERPC_7410_v10 = 0x800C1100, - CPU_POWERPC_7410_v11 = 0x800C1101, - CPU_POWERPC_7410_v12 = 0x800C1102, /* aka C */ - CPU_POWERPC_7410_v13 = 0x800C1103, /* aka D */ - CPU_POWERPC_7410_v14 = 0x800C1104, /* aka E */ - CPU_POWERPC_7448_v10 = 0x80040100, - CPU_POWERPC_7448_v11 = 0x80040101, - CPU_POWERPC_7448_v20 = 0x80040200, - CPU_POWERPC_7448_v21 = 0x80040201, - CPU_POWERPC_7450_v10 = 0x80000100, - CPU_POWERPC_7450_v11 = 0x80000101, - CPU_POWERPC_7450_v12 = 0x80000102, - CPU_POWERPC_7450_v20 = 0x80000200, /* aka A, B, C, D: 2.04 */ - CPU_POWERPC_7450_v21 = 0x80000201, /* aka E */ - CPU_POWERPC_74x1_v23 = 0x80000203, /* aka G: 2.3 */ - /* XXX: this entry might be a bug in some documentation */ - CPU_POWERPC_74x1_v210 = 0x80000210, /* aka G: 2.3 ? */ - CPU_POWERPC_74x5_v10 = 0x80010100, - /* XXX: missing 0x80010200 */ - CPU_POWERPC_74x5_v21 = 0x80010201, /* aka C: 2.1 */ - CPU_POWERPC_74x5_v32 = 0x80010302, - CPU_POWERPC_74x5_v33 = 0x80010303, /* aka F: 3.3 */ - CPU_POWERPC_74x5_v34 = 0x80010304, /* aka G: 3.4 */ - CPU_POWERPC_74x7_v10 = 0x80020100, /* aka A: 1.0 */ - CPU_POWERPC_74x7_v11 = 0x80020101, /* aka B: 1.1 */ - CPU_POWERPC_74x7_v12 = 0x80020102, /* aka C: 1.2 */ - CPU_POWERPC_74x7A_v10 = 0x80030100, /* aka A: 1.0 */ - CPU_POWERPC_74x7A_v11 = 0x80030101, /* aka B: 1.1 */ - CPU_POWERPC_74x7A_v12 = 0x80030102, /* aka C: 1.2 */ - /* 64 bits PowerPC */ -#if defined(TARGET_PPC64) - CPU_POWERPC_620 = 0x00140000, - CPU_POWERPC_630 = 0x00400000, - CPU_POWERPC_631 = 0x00410104, - CPU_POWERPC_POWER4 = 0x00350000, - CPU_POWERPC_POWER4P = 0x00380000, - /* XXX: missing 0x003A0201 */ - CPU_POWERPC_POWER5 = 0x003A0203, -#define CPU_POWERPC_POWER5GR CPU_POWERPC_POWER5 - CPU_POWERPC_POWER5P = 0x003B0000, -#define CPU_POWERPC_POWER5GS CPU_POWERPC_POWER5P - CPU_POWERPC_POWER6 = 0x003E0000, - CPU_POWERPC_POWER6_5 = 0x0F000001, /* POWER6 in POWER5 mode */ - CPU_POWERPC_POWER6A = 0x0F000002, - CPU_POWERPC_POWER7_v20 = 0x003F0200, - CPU_POWERPC_POWER7_v21 = 0x003F0201, - CPU_POWERPC_POWER7_v23 = 0x003F0203, - CPU_POWERPC_970 = 0x00390202, - CPU_POWERPC_970FX_v10 = 0x00391100, - CPU_POWERPC_970FX_v20 = 0x003C0200, - CPU_POWERPC_970FX_v21 = 0x003C0201, - CPU_POWERPC_970FX_v30 = 0x003C0300, - CPU_POWERPC_970FX_v31 = 0x003C0301, - CPU_POWERPC_970GX = 0x00450000, - CPU_POWERPC_970MP_v10 = 0x00440100, - CPU_POWERPC_970MP_v11 = 0x00440101, -#define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32 - CPU_POWERPC_CELL_v10 = 0x00700100, - CPU_POWERPC_CELL_v20 = 0x00700400, - CPU_POWERPC_CELL_v30 = 0x00700500, - CPU_POWERPC_CELL_v31 = 0x00700501, -#define CPU_POWERPC_CELL_v32 CPU_POWERPC_CELL_v31 - CPU_POWERPC_RS64 = 0x00330000, - CPU_POWERPC_RS64II = 0x00340000, - CPU_POWERPC_RS64III = 0x00360000, - CPU_POWERPC_RS64IV = 0x00370000, -#endif /* defined(TARGET_PPC64) */ - /* Original POWER */ - /* XXX: should be POWER (RIOS), RSC3308, RSC4608, - * POWER2 (RIOS2) & RSC2 (P2SC) here - */ -#if 0 - CPU_POWER = xxx, /* 0x20000 ? 0x30000 for RSC ? */ -#endif -#if 0 - CPU_POWER2 = xxx, /* 0x40000 ? */ -#endif - /* PA Semi core */ - CPU_POWERPC_PA6T = 0x00900000, -}; - -/* System version register (used on MPC 8xxx) */ -enum { - POWERPC_SVR_NONE = 0x00000000, - POWERPC_SVR_5200_v10 = 0x80110010, - POWERPC_SVR_5200_v11 = 0x80110011, - POWERPC_SVR_5200_v12 = 0x80110012, - POWERPC_SVR_5200B_v20 = 0x80110020, - POWERPC_SVR_5200B_v21 = 0x80110021, -#define POWERPC_SVR_55xx POWERPC_SVR_5567 -#if 0 - POWERPC_SVR_5533 = xxx, -#endif -#if 0 - POWERPC_SVR_5534 = xxx, -#endif -#if 0 - POWERPC_SVR_5553 = xxx, -#endif -#if 0 - POWERPC_SVR_5554 = xxx, -#endif -#if 0 - POWERPC_SVR_5561 = xxx, -#endif -#if 0 - POWERPC_SVR_5565 = xxx, -#endif -#if 0 - POWERPC_SVR_5566 = xxx, -#endif -#if 0 - POWERPC_SVR_5567 = xxx, -#endif -#if 0 - POWERPC_SVR_8313 = xxx, -#endif -#if 0 - POWERPC_SVR_8313E = xxx, -#endif -#if 0 - POWERPC_SVR_8314 = xxx, -#endif -#if 0 - POWERPC_SVR_8314E = xxx, -#endif -#if 0 - POWERPC_SVR_8315 = xxx, -#endif -#if 0 - POWERPC_SVR_8315E = xxx, -#endif -#if 0 - POWERPC_SVR_8321 = xxx, -#endif -#if 0 - POWERPC_SVR_8321E = xxx, -#endif -#if 0 - POWERPC_SVR_8323 = xxx, -#endif -#if 0 - POWERPC_SVR_8323E = xxx, -#endif - POWERPC_SVR_8343 = 0x80570010, - POWERPC_SVR_8343A = 0x80570030, - POWERPC_SVR_8343E = 0x80560010, - POWERPC_SVR_8343EA = 0x80560030, - POWERPC_SVR_8347P = 0x80550010, /* PBGA package */ - POWERPC_SVR_8347T = 0x80530010, /* TBGA package */ - POWERPC_SVR_8347AP = 0x80550030, /* PBGA package */ - POWERPC_SVR_8347AT = 0x80530030, /* TBGA package */ - POWERPC_SVR_8347EP = 0x80540010, /* PBGA package */ - POWERPC_SVR_8347ET = 0x80520010, /* TBGA package */ - POWERPC_SVR_8347EAP = 0x80540030, /* PBGA package */ - POWERPC_SVR_8347EAT = 0x80520030, /* TBGA package */ - POWERPC_SVR_8349 = 0x80510010, - POWERPC_SVR_8349A = 0x80510030, - POWERPC_SVR_8349E = 0x80500010, - POWERPC_SVR_8349EA = 0x80500030, -#if 0 - POWERPC_SVR_8358E = xxx, -#endif -#if 0 - POWERPC_SVR_8360E = xxx, -#endif -#define POWERPC_SVR_E500 0x40000000 - POWERPC_SVR_8377 = 0x80C70010 | POWERPC_SVR_E500, - POWERPC_SVR_8377E = 0x80C60010 | POWERPC_SVR_E500, - POWERPC_SVR_8378 = 0x80C50010 | POWERPC_SVR_E500, - POWERPC_SVR_8378E = 0x80C40010 | POWERPC_SVR_E500, - POWERPC_SVR_8379 = 0x80C30010 | POWERPC_SVR_E500, - POWERPC_SVR_8379E = 0x80C00010 | POWERPC_SVR_E500, - POWERPC_SVR_8533_v10 = 0x80340010 | POWERPC_SVR_E500, - POWERPC_SVR_8533_v11 = 0x80340011 | POWERPC_SVR_E500, - POWERPC_SVR_8533E_v10 = 0x803C0010 | POWERPC_SVR_E500, - POWERPC_SVR_8533E_v11 = 0x803C0011 | POWERPC_SVR_E500, - POWERPC_SVR_8540_v10 = 0x80300010 | POWERPC_SVR_E500, - POWERPC_SVR_8540_v20 = 0x80300020 | POWERPC_SVR_E500, - POWERPC_SVR_8540_v21 = 0x80300021 | POWERPC_SVR_E500, - POWERPC_SVR_8541_v10 = 0x80720010 | POWERPC_SVR_E500, - POWERPC_SVR_8541_v11 = 0x80720011 | POWERPC_SVR_E500, - POWERPC_SVR_8541E_v10 = 0x807A0010 | POWERPC_SVR_E500, - POWERPC_SVR_8541E_v11 = 0x807A0011 | POWERPC_SVR_E500, - POWERPC_SVR_8543_v10 = 0x80320010 | POWERPC_SVR_E500, - POWERPC_SVR_8543_v11 = 0x80320011 | POWERPC_SVR_E500, - POWERPC_SVR_8543_v20 = 0x80320020 | POWERPC_SVR_E500, - POWERPC_SVR_8543_v21 = 0x80320021 | POWERPC_SVR_E500, - POWERPC_SVR_8543E_v10 = 0x803A0010 | POWERPC_SVR_E500, - POWERPC_SVR_8543E_v11 = 0x803A0011 | POWERPC_SVR_E500, - POWERPC_SVR_8543E_v20 = 0x803A0020 | POWERPC_SVR_E500, - POWERPC_SVR_8543E_v21 = 0x803A0021 | POWERPC_SVR_E500, - POWERPC_SVR_8544_v10 = 0x80340110 | POWERPC_SVR_E500, - POWERPC_SVR_8544_v11 = 0x80340111 | POWERPC_SVR_E500, - POWERPC_SVR_8544E_v10 = 0x803C0110 | POWERPC_SVR_E500, - POWERPC_SVR_8544E_v11 = 0x803C0111 | POWERPC_SVR_E500, - POWERPC_SVR_8545_v20 = 0x80310220 | POWERPC_SVR_E500, - POWERPC_SVR_8545_v21 = 0x80310221 | POWERPC_SVR_E500, - POWERPC_SVR_8545E_v20 = 0x80390220 | POWERPC_SVR_E500, - POWERPC_SVR_8545E_v21 = 0x80390221 | POWERPC_SVR_E500, - POWERPC_SVR_8547E_v20 = 0x80390120 | POWERPC_SVR_E500, - POWERPC_SVR_8547E_v21 = 0x80390121 | POWERPC_SVR_E500, - POWERPC_SVR_8548_v10 = 0x80310010 | POWERPC_SVR_E500, - POWERPC_SVR_8548_v11 = 0x80310011 | POWERPC_SVR_E500, - POWERPC_SVR_8548_v20 = 0x80310020 | POWERPC_SVR_E500, - POWERPC_SVR_8548_v21 = 0x80310021 | POWERPC_SVR_E500, - POWERPC_SVR_8548E_v10 = 0x80390010 | POWERPC_SVR_E500, - POWERPC_SVR_8548E_v11 = 0x80390011 | POWERPC_SVR_E500, - POWERPC_SVR_8548E_v20 = 0x80390020 | POWERPC_SVR_E500, - POWERPC_SVR_8548E_v21 = 0x80390021 | POWERPC_SVR_E500, - POWERPC_SVR_8555_v10 = 0x80710010 | POWERPC_SVR_E500, - POWERPC_SVR_8555_v11 = 0x80710011 | POWERPC_SVR_E500, - POWERPC_SVR_8555E_v10 = 0x80790010 | POWERPC_SVR_E500, - POWERPC_SVR_8555E_v11 = 0x80790011 | POWERPC_SVR_E500, - POWERPC_SVR_8560_v10 = 0x80700010 | POWERPC_SVR_E500, - POWERPC_SVR_8560_v20 = 0x80700020 | POWERPC_SVR_E500, - POWERPC_SVR_8560_v21 = 0x80700021 | POWERPC_SVR_E500, - POWERPC_SVR_8567 = 0x80750111 | POWERPC_SVR_E500, - POWERPC_SVR_8567E = 0x807D0111 | POWERPC_SVR_E500, - POWERPC_SVR_8568 = 0x80750011 | POWERPC_SVR_E500, - POWERPC_SVR_8568E = 0x807D0011 | POWERPC_SVR_E500, - POWERPC_SVR_8572 = 0x80E00010 | POWERPC_SVR_E500, - POWERPC_SVR_8572E = 0x80E80010 | POWERPC_SVR_E500, -#if 0 - POWERPC_SVR_8610 = xxx, -#endif - POWERPC_SVR_8641 = 0x80900021, - POWERPC_SVR_8641D = 0x80900121, -}; - -/***************************************************************************/ -/* PowerPC CPU definitions */ -#define POWERPC_DEF_PREFIX(pvr, svr, type) \ - glue(glue(glue(glue(pvr, _), svr), _), type) -#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ - static void \ - glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ - (ObjectClass *oc, void *data) \ - { \ - DeviceClass *dc = DEVICE_CLASS(oc); \ - PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ - \ - pcc->pvr = _pvr; \ - pcc->svr = _svr; \ - dc->desc = _desc; \ - } \ - \ - static const TypeInfo \ - glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info) = { \ - .name = _name "-" TYPE_POWERPC_CPU, \ - .parent = stringify(_type) "-family-" TYPE_POWERPC_CPU, \ - .class_init = \ - glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init), \ - }; \ - \ - static void \ - glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)(void) \ - { \ - type_register_static( \ - &glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_type_info)); \ - } \ - \ - type_init( \ - glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)) - -#define POWERPC_DEF(_name, _pvr, _type, _desc) \ - POWERPC_DEF_SVR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type) - - /* Embedded PowerPC */ - /* PowerPC 401 family */ - POWERPC_DEF("401", CPU_POWERPC_401, 401, - "Generic PowerPC 401") - /* PowerPC 401 cores */ - POWERPC_DEF("401A1", CPU_POWERPC_401A1, 401, - "PowerPC 401A1") - POWERPC_DEF("401B2", CPU_POWERPC_401B2, 401x2, - "PowerPC 401B2") -#if defined(TODO) - POWERPC_DEF("401B3", CPU_POWERPC_401B3, 401x3, - "PowerPC 401B3") -#endif - POWERPC_DEF("401C2", CPU_POWERPC_401C2, 401x2, - "PowerPC 401C2") - POWERPC_DEF("401D2", CPU_POWERPC_401D2, 401x2, - "PowerPC 401D2") - POWERPC_DEF("401E2", CPU_POWERPC_401E2, 401x2, - "PowerPC 401E2") - POWERPC_DEF("401F2", CPU_POWERPC_401F2, 401x2, - "PowerPC 401F2") - /* XXX: to be checked */ - POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2, - "PowerPC 401G2") - /* PowerPC 401 microcontrolers */ -#if defined(TODO) - POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401, - "PowerPC 401GF") -#endif - POWERPC_DEF("IOP480", CPU_POWERPC_IOP480, IOP480, - "IOP480 (401 microcontroller)") - POWERPC_DEF("Cobra", CPU_POWERPC_COBRA, 401, - "IBM Processor for Network Resources") -#if defined(TODO) - POWERPC_DEF("Xipchip", CPU_POWERPC_XIPCHIP, 401, - NULL) -#endif - /* PowerPC 403 family */ - /* PowerPC 403 microcontrolers */ - POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403, - "PowerPC 403 GA") - POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403, - "PowerPC 403 GB") - POWERPC_DEF("403GC", CPU_POWERPC_403GC, 403, - "PowerPC 403 GC") - POWERPC_DEF("403GCX", CPU_POWERPC_403GCX, 403GCX, - "PowerPC 403 GCX") -#if defined(TODO) - POWERPC_DEF("403GP", CPU_POWERPC_403GP, 403, - "PowerPC 403 GP") -#endif - /* PowerPC 405 family */ - /* PowerPC 405 cores */ -#if defined(TODO) - POWERPC_DEF("405A3", CPU_POWERPC_405A3, 405, - "PowerPC 405 A3") -#endif -#if defined(TODO) - POWERPC_DEF("405A4", CPU_POWERPC_405A4, 405, - "PowerPC 405 A4") -#endif -#if defined(TODO) - POWERPC_DEF("405B3", CPU_POWERPC_405B3, 405, - "PowerPC 405 B3") -#endif -#if defined(TODO) - POWERPC_DEF("405B4", CPU_POWERPC_405B4, 405, - "PowerPC 405 B4") -#endif -#if defined(TODO) - POWERPC_DEF("405C3", CPU_POWERPC_405C3, 405, - "PowerPC 405 C3") -#endif -#if defined(TODO) - POWERPC_DEF("405C4", CPU_POWERPC_405C4, 405, - "PowerPC 405 C4") -#endif - POWERPC_DEF("405D2", CPU_POWERPC_405D2, 405, - "PowerPC 405 D2") -#if defined(TODO) - POWERPC_DEF("405D3", CPU_POWERPC_405D3, 405, - "PowerPC 405 D3") -#endif - POWERPC_DEF("405D4", CPU_POWERPC_405D4, 405, - "PowerPC 405 D4") -#if defined(TODO) - POWERPC_DEF("405D5", CPU_POWERPC_405D5, 405, - "PowerPC 405 D5") -#endif -#if defined(TODO) - POWERPC_DEF("405E4", CPU_POWERPC_405E4, 405, - "PowerPC 405 E4") -#endif -#if defined(TODO) - POWERPC_DEF("405F4", CPU_POWERPC_405F4, 405, - "PowerPC 405 F4") -#endif -#if defined(TODO) - POWERPC_DEF("405F5", CPU_POWERPC_405F5, 405, - "PowerPC 405 F5") -#endif -#if defined(TODO) - POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405, - "PowerPC 405 F6") -#endif - /* PowerPC 405 microcontrolers */ - POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405, - "PowerPC 405 CRa") - POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405, - "PowerPC 405 CRb") - POWERPC_DEF("405CRc", CPU_POWERPC_405CRc, 405, - "PowerPC 405 CRc") - POWERPC_DEF("405EP", CPU_POWERPC_405EP, 405, - "PowerPC 405 EP") -#if defined(TODO) - POWERPC_DEF("405EXr", CPU_POWERPC_405EXr, 405, - "PowerPC 405 EXr") -#endif - POWERPC_DEF("405EZ", CPU_POWERPC_405EZ, 405, - "PowerPC 405 EZ") -#if defined(TODO) - POWERPC_DEF("405FX", CPU_POWERPC_405FX, 405, - "PowerPC 405 FX") -#endif - POWERPC_DEF("405GPa", CPU_POWERPC_405GPa, 405, - "PowerPC 405 GPa") - POWERPC_DEF("405GPb", CPU_POWERPC_405GPb, 405, - "PowerPC 405 GPb") - POWERPC_DEF("405GPc", CPU_POWERPC_405GPc, 405, - "PowerPC 405 GPc") - POWERPC_DEF("405GPd", CPU_POWERPC_405GPd, 405, - "PowerPC 405 GPd") - POWERPC_DEF("405GPR", CPU_POWERPC_405GPR, 405, - "PowerPC 405 GPR") -#if defined(TODO) - POWERPC_DEF("405H", CPU_POWERPC_405H, 405, - "PowerPC 405 H") -#endif -#if defined(TODO) - POWERPC_DEF("405L", CPU_POWERPC_405L, 405, - "PowerPC 405 L") -#endif - POWERPC_DEF("405LP", CPU_POWERPC_405LP, 405, - "PowerPC 405 LP") -#if defined(TODO) - POWERPC_DEF("405PM", CPU_POWERPC_405PM, 405, - "PowerPC 405 PM") -#endif -#if defined(TODO) - POWERPC_DEF("405PS", CPU_POWERPC_405PS, 405, - "PowerPC 405 PS") -#endif -#if defined(TODO) - POWERPC_DEF("405S", CPU_POWERPC_405S, 405, - "PowerPC 405 S") -#endif - POWERPC_DEF("Npe405H", CPU_POWERPC_NPE405H, 405, - "Npe405 H") - POWERPC_DEF("Npe405H2", CPU_POWERPC_NPE405H2, 405, - "Npe405 H2") - POWERPC_DEF("Npe405L", CPU_POWERPC_NPE405L, 405, - "Npe405 L") - POWERPC_DEF("Npe4GS3", CPU_POWERPC_NPE4GS3, 405, - "Npe4GS3") -#if defined(TODO) - POWERPC_DEF("Npcxx1", CPU_POWERPC_NPCxx1, 405, - NULL) -#endif -#if defined(TODO) - POWERPC_DEF("Npr161", CPU_POWERPC_NPR161, 405, - NULL) -#endif -#if defined(TODO) - POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405, - "PowerPC LC77700 (Sanyo)") -#endif - /* PowerPC 401/403/405 based set-top-box microcontrolers */ -#if defined(TODO) - POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2, - "STB010000") -#endif -#if defined(TODO) - POWERPC_DEF("STB01010", CPU_POWERPC_STB01010, 401x2, - "STB01010") -#endif -#if defined(TODO) - POWERPC_DEF("STB0210", CPU_POWERPC_STB0210, 401x3, - "STB0210") -#endif - POWERPC_DEF("STB03", CPU_POWERPC_STB03, 405, - "STB03xx") -#if defined(TODO) - POWERPC_DEF("STB043", CPU_POWERPC_STB043, 405, - "STB043x") -#endif -#if defined(TODO) - POWERPC_DEF("STB045", CPU_POWERPC_STB045, 405, - "STB045x") -#endif - POWERPC_DEF("STB04", CPU_POWERPC_STB04, 405, - "STB04xx") - POWERPC_DEF("STB25", CPU_POWERPC_STB25, 405, - "STB25xx") -#if defined(TODO) - POWERPC_DEF("STB130", CPU_POWERPC_STB130, 405, - "STB130") -#endif - /* Xilinx PowerPC 405 cores */ - POWERPC_DEF("x2vp4", CPU_POWERPC_X2VP4, 405, - NULL) - POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405, - NULL) -#if defined(TODO) - POWERPC_DEF("zl10310", CPU_POWERPC_ZL10310, 405, - "Zarlink ZL10310") -#endif -#if defined(TODO) - POWERPC_DEF("zl10311", CPU_POWERPC_ZL10311, 405, - "Zarlink ZL10311") -#endif -#if defined(TODO) - POWERPC_DEF("zl10320", CPU_POWERPC_ZL10320, 405, - "Zarlink ZL10320") -#endif -#if defined(TODO) - POWERPC_DEF("zl10321", CPU_POWERPC_ZL10321, 405, - "Zarlink ZL10321") -#endif - /* PowerPC 440 family */ -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440", CPU_POWERPC_440, 440GP, - "Generic PowerPC 440") -#endif - /* PowerPC 440 cores */ -#if defined(TODO) - POWERPC_DEF("440A4", CPU_POWERPC_440A4, 440x4, - "PowerPC 440 A4") -#endif - POWERPC_DEF("440-Xilinx", CPU_POWERPC_440_XILINX, 440x5, - "PowerPC 440 Xilinx 5") -#if defined(TODO) - POWERPC_DEF("440A5", CPU_POWERPC_440A5, 440x5, - "PowerPC 440 A5") -#endif -#if defined(TODO) - POWERPC_DEF("440B4", CPU_POWERPC_440B4, 440x4, - "PowerPC 440 B4") -#endif -#if defined(TODO) - POWERPC_DEF("440G4", CPU_POWERPC_440G4, 440x4, - "PowerPC 440 G4") -#endif -#if defined(TODO) - POWERPC_DEF("440F5", CPU_POWERPC_440F5, 440x5, - "PowerPC 440 F5") -#endif -#if defined(TODO) - POWERPC_DEF("440G5", CPU_POWERPC_440G5, 440x5, - "PowerPC 440 G5") -#endif -#if defined(TODO) - POWERPC_DEF("440H4", CPU_POWERPC_440H4, 440x4, - "PowerPC 440H4") -#endif -#if defined(TODO) - POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5, - "PowerPC 440H6") -#endif - /* PowerPC 440 microcontrolers */ - POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP, - "PowerPC 440 EPa") - POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP, - "PowerPC 440 EPb") - POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP, - "PowerPC 440 EPX") -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GPb", CPU_POWERPC_440GPb, 440GP, - "PowerPC 440 GPb") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GPc", CPU_POWERPC_440GPc, 440GP, - "PowerPC 440 GPc") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GRa", CPU_POWERPC_440GRa, 440x5, - "PowerPC 440 GRa") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GRX", CPU_POWERPC_440GRX, 440x5, - "PowerPC 440 GRX") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GXa", CPU_POWERPC_440GXa, 440EP, - "PowerPC 440 GXa") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GXb", CPU_POWERPC_440GXb, 440EP, - "PowerPC 440 GXb") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GXc", CPU_POWERPC_440GXc, 440EP, - "PowerPC 440 GXc") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440GXf", CPU_POWERPC_440GXf, 440EP, - "PowerPC 440 GXf") -#endif -#if defined(TODO) - POWERPC_DEF("440S", CPU_POWERPC_440S, 440, - "PowerPC 440 S") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440SP", CPU_POWERPC_440SP, 440EP, - "PowerPC 440 SP") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440SP2", CPU_POWERPC_440SP2, 440EP, - "PowerPC 440 SP2") -#endif -#if defined(TODO_USER_ONLY) - POWERPC_DEF("440SPE", CPU_POWERPC_440SPE, 440EP, - "PowerPC 440 SPE") -#endif - /* PowerPC 460 family */ -#if defined(TODO) - POWERPC_DEF("464", CPU_POWERPC_464, 460, - "Generic PowerPC 464") -#endif - /* PowerPC 464 microcontrolers */ -#if defined(TODO) - POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460, - "PowerPC 464H90") -#endif -#if defined(TODO) - POWERPC_DEF("464H90F", CPU_POWERPC_464H90F, 460F, - "PowerPC 464H90F") -#endif - /* Freescale embedded PowerPC cores */ - /* MPC5xx family (aka RCPU) */ -#if defined(TODO_USER_ONLY) - POWERPC_DEF("MPC5xx", CPU_POWERPC_MPC5xx, MPC5xx, - "Generic MPC5xx core") -#endif - /* MPC8xx family (aka PowerQUICC) */ -#if defined(TODO_USER_ONLY) - POWERPC_DEF("MPC8xx", CPU_POWERPC_MPC8xx, MPC8xx, - "Generic MPC8xx core") -#endif - /* MPC82xx family (aka PowerQUICC-II) */ - POWERPC_DEF("G2", CPU_POWERPC_G2, G2, - "PowerPC G2 core") - POWERPC_DEF("G2H4", CPU_POWERPC_G2H4, G2, - "PowerPC G2 H4 core") - POWERPC_DEF("G2GP", CPU_POWERPC_G2gp, G2, - "PowerPC G2 GP core") - POWERPC_DEF("G2LS", CPU_POWERPC_G2ls, G2, - "PowerPC G2 LS core") - POWERPC_DEF("G2HiP3", CPU_POWERPC_G2_HIP3, G2, - "PowerPC G2 HiP3 core") - POWERPC_DEF("G2HiP4", CPU_POWERPC_G2_HIP4, G2, - "PowerPC G2 HiP4 core") - POWERPC_DEF("MPC603", CPU_POWERPC_MPC603, 603E, - "PowerPC MPC603 core") - POWERPC_DEF("G2le", CPU_POWERPC_G2LE, G2LE, - "PowerPC G2le core (same as G2 plus little-endian mode support)") - POWERPC_DEF("G2leGP", CPU_POWERPC_G2LEgp, G2LE, - "PowerPC G2LE GP core") - POWERPC_DEF("G2leLS", CPU_POWERPC_G2LEls, G2LE, - "PowerPC G2LE LS core") - POWERPC_DEF("G2leGP1", CPU_POWERPC_G2LEgp1, G2LE, - "PowerPC G2LE GP1 core") - POWERPC_DEF("G2leGP3", CPU_POWERPC_G2LEgp3, G2LE, - "PowerPC G2LE GP3 core") - /* PowerPC G2 microcontrollers */ -#if defined(TODO) - POWERPC_DEF_SVR("MPC5121", "MPC5121", - CPU_POWERPC_MPC5121, POWERPC_SVR_5121, G2LE) -#endif - POWERPC_DEF_SVR("MPC5200_v10", "MPC5200 v1.0", - CPU_POWERPC_MPC5200_v10, POWERPC_SVR_5200_v10, G2LE) - POWERPC_DEF_SVR("MPC5200_v11", "MPC5200 v1.1", - CPU_POWERPC_MPC5200_v11, POWERPC_SVR_5200_v11, G2LE) - POWERPC_DEF_SVR("MPC5200_v12", "MPC5200 v1.2", - CPU_POWERPC_MPC5200_v12, POWERPC_SVR_5200_v12, G2LE) - POWERPC_DEF_SVR("MPC5200B_v20", "MPC5200B v2.0", - CPU_POWERPC_MPC5200B_v20, POWERPC_SVR_5200B_v20, G2LE) - POWERPC_DEF_SVR("MPC5200B_v21", "MPC5200B v2.1", - CPU_POWERPC_MPC5200B_v21, POWERPC_SVR_5200B_v21, G2LE) - /* e200 family */ -#if defined(TODO) - POWERPC_DEF_SVR("MPC55xx", "Generic MPC55xx core", - CPU_POWERPC_MPC55xx, POWERPC_SVR_55xx, e200) -#endif -#if defined(TODO) - POWERPC_DEF("e200z0", CPU_POWERPC_e200z0, e200, - "PowerPC e200z0 core") -#endif -#if defined(TODO) - POWERPC_DEF("e200z1", CPU_POWERPC_e200z1, e200, - "PowerPC e200z1 core") -#endif -#if defined(TODO) - POWERPC_DEF("e200z3", CPU_POWERPC_e200z3, e200, - "PowerPC e200z3 core") -#endif - POWERPC_DEF("e200z5", CPU_POWERPC_e200z5, e200, - "PowerPC e200z5 core") - POWERPC_DEF("e200z6", CPU_POWERPC_e200z6, e200, - "PowerPC e200z6 core") - /* PowerPC e200 microcontrollers */ -#if defined(TODO) - POWERPC_DEF_SVR("MPC5514E", "MPC5514E", - CPU_POWERPC_MPC5514E, POWERPC_SVR_5514E, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5514E_v0", "MPC5514E v0", - CPU_POWERPC_MPC5514E_v0, POWERPC_SVR_5514E_v0, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5514E_v1", "MPC5514E v1", - CPU_POWERPC_MPC5514E_v1, POWERPC_SVR_5514E_v1, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5514G", "MPC5514G", - CPU_POWERPC_MPC5514G, POWERPC_SVR_5514G, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5514G_v0", "MPC5514G v0", - CPU_POWERPC_MPC5514G_v0, POWERPC_SVR_5514G_v0, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5514G_v1", "MPC5514G v1", - CPU_POWERPC_MPC5514G_v1, POWERPC_SVR_5514G_v1, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5515S", "MPC5515S", - CPU_POWERPC_MPC5515S, POWERPC_SVR_5515S, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5516E", "MPC5516E", - CPU_POWERPC_MPC5516E, POWERPC_SVR_5516E, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5516E_v0", "MPC5516E v0", - CPU_POWERPC_MPC5516E_v0, POWERPC_SVR_5516E_v0, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5516E_v1", "MPC5516E v1", - CPU_POWERPC_MPC5516E_v1, POWERPC_SVR_5516E_v1, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5516G", "MPC5516G", - CPU_POWERPC_MPC5516G, POWERPC_SVR_5516G, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5516G_v0", "MPC5516G v0", - CPU_POWERPC_MPC5516G_v0, POWERPC_SVR_5516G_v0, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5516G_v1", "MPC5516G v1", - CPU_POWERPC_MPC5516G_v1, POWERPC_SVR_5516G_v1, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5516S", "MPC5516S", - CPU_POWERPC_MPC5516S, POWERPC_SVR_5516S, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5533", "MPC5533", - CPU_POWERPC_MPC5533, POWERPC_SVR_5533, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5534", "MPC5534", - CPU_POWERPC_MPC5534, POWERPC_SVR_5534, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5553", "MPC5553", - CPU_POWERPC_MPC5553, POWERPC_SVR_5553, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5554", "MPC5554", - CPU_POWERPC_MPC5554, POWERPC_SVR_5554, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5561", "MPC5561", - CPU_POWERPC_MPC5561, POWERPC_SVR_5561, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5565", "MPC5565", - CPU_POWERPC_MPC5565, POWERPC_SVR_5565, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5566", "MPC5566", - CPU_POWERPC_MPC5566, POWERPC_SVR_5566, e200) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC5567", "MPC5567", - CPU_POWERPC_MPC5567, POWERPC_SVR_5567, e200) -#endif - /* e300 family */ - POWERPC_DEF("e300c1", CPU_POWERPC_e300c1, e300, - "PowerPC e300c1 core") - POWERPC_DEF("e300c2", CPU_POWERPC_e300c2, e300, - "PowerPC e300c2 core") - POWERPC_DEF("e300c3", CPU_POWERPC_e300c3, e300, - "PowerPC e300c3 core") - POWERPC_DEF("e300c4", CPU_POWERPC_e300c4, e300, - "PowerPC e300c4 core") - /* PowerPC e300 microcontrollers */ -#if defined(TODO) - POWERPC_DEF_SVR("MPC8313", "MPC8313", - CPU_POWERPC_MPC831x, POWERPC_SVR_8313, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8313E", "MPC8313E", - CPU_POWERPC_MPC831x, POWERPC_SVR_8313E, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8314", "MPC8314", - CPU_POWERPC_MPC831x, POWERPC_SVR_8314, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8314E", "MPC8314E", - CPU_POWERPC_MPC831x, POWERPC_SVR_8314E, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8315", "MPC8315", - CPU_POWERPC_MPC831x, POWERPC_SVR_8315, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8315E", "MPC8315E", - CPU_POWERPC_MPC831x, POWERPC_SVR_8315E, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8321", "MPC8321", - CPU_POWERPC_MPC832x, POWERPC_SVR_8321, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8321E", "MPC8321E", - CPU_POWERPC_MPC832x, POWERPC_SVR_8321E, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8323", "MPC8323", - CPU_POWERPC_MPC832x, POWERPC_SVR_8323, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8323E", "MPC8323E", - CPU_POWERPC_MPC832x, POWERPC_SVR_8323E, e300) -#endif - POWERPC_DEF_SVR("MPC8343", "MPC8343", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343, e300) - POWERPC_DEF_SVR("MPC8343A", "MPC8343A", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343A, e300) - POWERPC_DEF_SVR("MPC8343E", "MPC8343E", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343E, e300) - POWERPC_DEF_SVR("MPC8343EA", "MPC8343EA", - CPU_POWERPC_MPC834x, POWERPC_SVR_8343EA, e300) - POWERPC_DEF_SVR("MPC8347T", "MPC8347T", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347T, e300) - POWERPC_DEF_SVR("MPC8347P", "MPC8347P", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347P, e300) - POWERPC_DEF_SVR("MPC8347AT", "MPC8347AT", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347AT, e300) - POWERPC_DEF_SVR("MPC8347AP", "MPC8347AP", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347AP, e300) - POWERPC_DEF_SVR("MPC8347ET", "MPC8347ET", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347ET, e300) - POWERPC_DEF_SVR("MPC8347EP", "MPC8343EP", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EP, e300) - POWERPC_DEF_SVR("MPC8347EAT", "MPC8347EAT", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAT, e300) - POWERPC_DEF_SVR("MPC8347EAP", "MPC8343EAP", - CPU_POWERPC_MPC834x, POWERPC_SVR_8347EAP, e300) - POWERPC_DEF_SVR("MPC8349", "MPC8349", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349, e300) - POWERPC_DEF_SVR("MPC8349A", "MPC8349A", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349A, e300) - POWERPC_DEF_SVR("MPC8349E", "MPC8349E", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349E, e300) - POWERPC_DEF_SVR("MPC8349EA", "MPC8349EA", - CPU_POWERPC_MPC834x, POWERPC_SVR_8349EA, e300) -#if defined(TODO) - POWERPC_DEF_SVR("MPC8358E", "MPC8358E", - CPU_POWERPC_MPC835x, POWERPC_SVR_8358E, e300) -#endif -#if defined(TODO) - POWERPC_DEF_SVR("MPC8360E", "MPC8360E", - CPU_POWERPC_MPC836x, POWERPC_SVR_8360E, e300) -#endif - POWERPC_DEF_SVR("MPC8377", "MPC8377", - CPU_POWERPC_MPC837x, POWERPC_SVR_8377, e300) - POWERPC_DEF_SVR("MPC8377E", "MPC8377E", - CPU_POWERPC_MPC837x, POWERPC_SVR_8377E, e300) - POWERPC_DEF_SVR("MPC8378", "MPC8378", - CPU_POWERPC_MPC837x, POWERPC_SVR_8378, e300) - POWERPC_DEF_SVR("MPC8378E", "MPC8378E", - CPU_POWERPC_MPC837x, POWERPC_SVR_8378E, e300) - POWERPC_DEF_SVR("MPC8379", "MPC8379", - CPU_POWERPC_MPC837x, POWERPC_SVR_8379, e300) - POWERPC_DEF_SVR("MPC8379E", "MPC8379E", - CPU_POWERPC_MPC837x, POWERPC_SVR_8379E, e300) - /* e500 family */ - POWERPC_DEF("e500_v10", CPU_POWERPC_e500v1_v10, e500v1, - "PowerPC e500 v1.0 core") - POWERPC_DEF("e500_v20", CPU_POWERPC_e500v1_v20, e500v1, - "PowerPC e500 v2.0 core") - POWERPC_DEF("e500v2_v10", CPU_POWERPC_e500v2_v10, e500v2, - "PowerPC e500v2 v1.0 core") - POWERPC_DEF("e500v2_v20", CPU_POWERPC_e500v2_v20, e500v2, - "PowerPC e500v2 v2.0 core") - POWERPC_DEF("e500v2_v21", CPU_POWERPC_e500v2_v21, e500v2, - "PowerPC e500v2 v2.1 core") - POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2, - "PowerPC e500v2 v2.2 core") - POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2, - "PowerPC e500v2 v3.0 core") - POWERPC_DEF_SVR("e500mc", "e500mc", - CPU_POWERPC_e500mc, POWERPC_SVR_E500, e500mc) -#ifdef TARGET_PPC64 - POWERPC_DEF_SVR("e5500", "e5500", - CPU_POWERPC_e5500, POWERPC_SVR_E500, e5500) -#endif - /* PowerPC e500 microcontrollers */ - POWERPC_DEF_SVR("MPC8533_v10", "MPC8533 v1.0", - CPU_POWERPC_MPC8533_v10, POWERPC_SVR_8533_v10, e500v2) - POWERPC_DEF_SVR("MPC8533_v11", "MPC8533 v1.1", - CPU_POWERPC_MPC8533_v11, POWERPC_SVR_8533_v11, e500v2) - POWERPC_DEF_SVR("MPC8533E_v10", "MPC8533E v1.0", - CPU_POWERPC_MPC8533E_v10, POWERPC_SVR_8533E_v10, e500v2) - POWERPC_DEF_SVR("MPC8533E_v11", "MPC8533E v1.1", - CPU_POWERPC_MPC8533E_v11, POWERPC_SVR_8533E_v11, e500v2) - POWERPC_DEF_SVR("MPC8540_v10", "MPC8540 v1.0", - CPU_POWERPC_MPC8540_v10, POWERPC_SVR_8540_v10, e500v1) - POWERPC_DEF_SVR("MPC8540_v20", "MPC8540 v2.0", - CPU_POWERPC_MPC8540_v20, POWERPC_SVR_8540_v20, e500v1) - POWERPC_DEF_SVR("MPC8540_v21", "MPC8540 v2.1", - CPU_POWERPC_MPC8540_v21, POWERPC_SVR_8540_v21, e500v1) - POWERPC_DEF_SVR("MPC8541_v10", "MPC8541 v1.0", - CPU_POWERPC_MPC8541_v10, POWERPC_SVR_8541_v10, e500v1) - POWERPC_DEF_SVR("MPC8541_v11", "MPC8541 v1.1", - CPU_POWERPC_MPC8541_v11, POWERPC_SVR_8541_v11, e500v1) - POWERPC_DEF_SVR("MPC8541E_v10", "MPC8541E v1.0", - CPU_POWERPC_MPC8541E_v10, POWERPC_SVR_8541E_v10, e500v1) - POWERPC_DEF_SVR("MPC8541E_v11", "MPC8541E v1.1", - CPU_POWERPC_MPC8541E_v11, POWERPC_SVR_8541E_v11, e500v1) - POWERPC_DEF_SVR("MPC8543_v10", "MPC8543 v1.0", - CPU_POWERPC_MPC8543_v10, POWERPC_SVR_8543_v10, e500v2) - POWERPC_DEF_SVR("MPC8543_v11", "MPC8543 v1.1", - CPU_POWERPC_MPC8543_v11, POWERPC_SVR_8543_v11, e500v2) - POWERPC_DEF_SVR("MPC8543_v20", "MPC8543 v2.0", - CPU_POWERPC_MPC8543_v20, POWERPC_SVR_8543_v20, e500v2) - POWERPC_DEF_SVR("MPC8543_v21", "MPC8543 v2.1", - CPU_POWERPC_MPC8543_v21, POWERPC_SVR_8543_v21, e500v2) - POWERPC_DEF_SVR("MPC8543E_v10", "MPC8543E v1.0", - CPU_POWERPC_MPC8543E_v10, POWERPC_SVR_8543E_v10, e500v2) - POWERPC_DEF_SVR("MPC8543E_v11", "MPC8543E v1.1", - CPU_POWERPC_MPC8543E_v11, POWERPC_SVR_8543E_v11, e500v2) - POWERPC_DEF_SVR("MPC8543E_v20", "MPC8543E v2.0", - CPU_POWERPC_MPC8543E_v20, POWERPC_SVR_8543E_v20, e500v2) - POWERPC_DEF_SVR("MPC8543E_v21", "MPC8543E v2.1", - CPU_POWERPC_MPC8543E_v21, POWERPC_SVR_8543E_v21, e500v2) - POWERPC_DEF_SVR("MPC8544_v10", "MPC8544 v1.0", - CPU_POWERPC_MPC8544_v10, POWERPC_SVR_8544_v10, e500v2) - POWERPC_DEF_SVR("MPC8544_v11", "MPC8544 v1.1", - CPU_POWERPC_MPC8544_v11, POWERPC_SVR_8544_v11, e500v2) - POWERPC_DEF_SVR("MPC8544E_v10", "MPC8544E v1.0", - CPU_POWERPC_MPC8544E_v10, POWERPC_SVR_8544E_v10, e500v2) - POWERPC_DEF_SVR("MPC8544E_v11", "MPC8544E v1.1", - CPU_POWERPC_MPC8544E_v11, POWERPC_SVR_8544E_v11, e500v2) - POWERPC_DEF_SVR("MPC8545_v20", "MPC8545 v2.0", - CPU_POWERPC_MPC8545_v20, POWERPC_SVR_8545_v20, e500v2) - POWERPC_DEF_SVR("MPC8545_v21", "MPC8545 v2.1", - CPU_POWERPC_MPC8545_v21, POWERPC_SVR_8545_v21, e500v2) - POWERPC_DEF_SVR("MPC8545E_v20", "MPC8545E v2.0", - CPU_POWERPC_MPC8545E_v20, POWERPC_SVR_8545E_v20, e500v2) - POWERPC_DEF_SVR("MPC8545E_v21", "MPC8545E v2.1", - CPU_POWERPC_MPC8545E_v21, POWERPC_SVR_8545E_v21, e500v2) - POWERPC_DEF_SVR("MPC8547E_v20", "MPC8547E v2.0", - CPU_POWERPC_MPC8547E_v20, POWERPC_SVR_8547E_v20, e500v2) - POWERPC_DEF_SVR("MPC8547E_v21", "MPC8547E v2.1", - CPU_POWERPC_MPC8547E_v21, POWERPC_SVR_8547E_v21, e500v2) - POWERPC_DEF_SVR("MPC8548_v10", "MPC8548 v1.0", - CPU_POWERPC_MPC8548_v10, POWERPC_SVR_8548_v10, e500v2) - POWERPC_DEF_SVR("MPC8548_v11", "MPC8548 v1.1", - CPU_POWERPC_MPC8548_v11, POWERPC_SVR_8548_v11, e500v2) - POWERPC_DEF_SVR("MPC8548_v20", "MPC8548 v2.0", - CPU_POWERPC_MPC8548_v20, POWERPC_SVR_8548_v20, e500v2) - POWERPC_DEF_SVR("MPC8548_v21", "MPC8548 v2.1", - CPU_POWERPC_MPC8548_v21, POWERPC_SVR_8548_v21, e500v2) - POWERPC_DEF_SVR("MPC8548E_v10", "MPC8548E v1.0", - CPU_POWERPC_MPC8548E_v10, POWERPC_SVR_8548E_v10, e500v2) - POWERPC_DEF_SVR("MPC8548E_v11", "MPC8548E v1.1", - CPU_POWERPC_MPC8548E_v11, POWERPC_SVR_8548E_v11, e500v2) - POWERPC_DEF_SVR("MPC8548E_v20", "MPC8548E v2.0", - CPU_POWERPC_MPC8548E_v20, POWERPC_SVR_8548E_v20, e500v2) - POWERPC_DEF_SVR("MPC8548E_v21", "MPC8548E v2.1", - CPU_POWERPC_MPC8548E_v21, POWERPC_SVR_8548E_v21, e500v2) - POWERPC_DEF_SVR("MPC8555_v10", "MPC8555 v1.0", - CPU_POWERPC_MPC8555_v10, POWERPC_SVR_8555_v10, e500v2) - POWERPC_DEF_SVR("MPC8555_v11", "MPC8555 v1.1", - CPU_POWERPC_MPC8555_v11, POWERPC_SVR_8555_v11, e500v2) - POWERPC_DEF_SVR("MPC8555E_v10", "MPC8555E v1.0", - CPU_POWERPC_MPC8555E_v10, POWERPC_SVR_8555E_v10, e500v2) - POWERPC_DEF_SVR("MPC8555E_v11", "MPC8555E v1.1", - CPU_POWERPC_MPC8555E_v11, POWERPC_SVR_8555E_v11, e500v2) - POWERPC_DEF_SVR("MPC8560_v10", "MPC8560 v1.0", - CPU_POWERPC_MPC8560_v10, POWERPC_SVR_8560_v10, e500v2) - POWERPC_DEF_SVR("MPC8560_v20", "MPC8560 v2.0", - CPU_POWERPC_MPC8560_v20, POWERPC_SVR_8560_v20, e500v2) - POWERPC_DEF_SVR("MPC8560_v21", "MPC8560 v2.1", - CPU_POWERPC_MPC8560_v21, POWERPC_SVR_8560_v21, e500v2) - POWERPC_DEF_SVR("MPC8567", "MPC8567", - CPU_POWERPC_MPC8567, POWERPC_SVR_8567, e500v2) - POWERPC_DEF_SVR("MPC8567E", "MPC8567E", - CPU_POWERPC_MPC8567E, POWERPC_SVR_8567E, e500v2) - POWERPC_DEF_SVR("MPC8568", "MPC8568", - CPU_POWERPC_MPC8568, POWERPC_SVR_8568, e500v2) - POWERPC_DEF_SVR("MPC8568E", "MPC8568E", - CPU_POWERPC_MPC8568E, POWERPC_SVR_8568E, e500v2) - POWERPC_DEF_SVR("MPC8572", "MPC8572", - CPU_POWERPC_MPC8572, POWERPC_SVR_8572, e500v2) - POWERPC_DEF_SVR("MPC8572E", "MPC8572E", - CPU_POWERPC_MPC8572E, POWERPC_SVR_8572E, e500v2) - /* e600 family */ - POWERPC_DEF("e600", CPU_POWERPC_e600, 7400, - "PowerPC e600 core") - /* PowerPC e600 microcontrollers */ -#if defined(TODO) - POWERPC_DEF_SVR("MPC8610", "MPC8610", - CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400) -#endif - POWERPC_DEF_SVR("MPC8641", "MPC8641", - CPU_POWERPC_MPC8641, POWERPC_SVR_8641, 7400) - POWERPC_DEF_SVR("MPC8641D", "MPC8641D", - CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400) - /* 32 bits "classic" PowerPC */ - /* PowerPC 6xx family */ - POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601, - "PowerPC 601v0") - POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601, - "PowerPC 601v1") - POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v, - "PowerPC 601v2") - POWERPC_DEF("602", CPU_POWERPC_602, 602, - "PowerPC 602") - POWERPC_DEF("603", CPU_POWERPC_603, 603, - "PowerPC 603") - POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E, - "PowerPC 603e v1.1") - POWERPC_DEF("603e_v1.2", CPU_POWERPC_603E_v12, 603E, - "PowerPC 603e v1.2") - POWERPC_DEF("603e_v1.3", CPU_POWERPC_603E_v13, 603E, - "PowerPC 603e v1.3") - POWERPC_DEF("603e_v1.4", CPU_POWERPC_603E_v14, 603E, - "PowerPC 603e v1.4") - POWERPC_DEF("603e_v2.2", CPU_POWERPC_603E_v22, 603E, - "PowerPC 603e v2.2") - POWERPC_DEF("603e_v3", CPU_POWERPC_603E_v3, 603E, - "PowerPC 603e v3") - POWERPC_DEF("603e_v4", CPU_POWERPC_603E_v4, 603E, - "PowerPC 603e v4") - POWERPC_DEF("603e_v4.1", CPU_POWERPC_603E_v41, 603E, - "PowerPC 603e v4.1") - POWERPC_DEF("603e7", CPU_POWERPC_603E7, 603E, - "PowerPC 603e (aka PID7)") - POWERPC_DEF("603e7t", CPU_POWERPC_603E7t, 603E, - "PowerPC 603e7t") - POWERPC_DEF("603e7v", CPU_POWERPC_603E7v, 603E, - "PowerPC 603e7v") - POWERPC_DEF("603e7v1", CPU_POWERPC_603E7v1, 603E, - "PowerPC 603e7v1") - POWERPC_DEF("603e7v2", CPU_POWERPC_603E7v2, 603E, - "PowerPC 603e7v2") - POWERPC_DEF("603p", CPU_POWERPC_603P, 603E, - "PowerPC 603p (aka PID7v)") - POWERPC_DEF("604", CPU_POWERPC_604, 604, - "PowerPC 604") - POWERPC_DEF("604e_v1.0", CPU_POWERPC_604E_v10, 604E, - "PowerPC 604e v1.0") - POWERPC_DEF("604e_v2.2", CPU_POWERPC_604E_v22, 604E, - "PowerPC 604e v2.2") - POWERPC_DEF("604e_v2.4", CPU_POWERPC_604E_v24, 604E, - "PowerPC 604e v2.4") - POWERPC_DEF("604r", CPU_POWERPC_604R, 604E, - "PowerPC 604r (aka PIDA)") -#if defined(TODO) - POWERPC_DEF("604ev", CPU_POWERPC_604EV, 604E, - "PowerPC 604ev") -#endif - /* PowerPC 7xx family */ - POWERPC_DEF("740_v1.0", CPU_POWERPC_7x0_v10, 740, - "PowerPC 740 v1.0 (G3)") - POWERPC_DEF("750_v1.0", CPU_POWERPC_7x0_v10, 750, - "PowerPC 750 v1.0 (G3)") - POWERPC_DEF("740_v2.0", CPU_POWERPC_7x0_v20, 740, - "PowerPC 740 v2.0 (G3)") - POWERPC_DEF("750_v2.0", CPU_POWERPC_7x0_v20, 750, - "PowerPC 750 v2.0 (G3)") - POWERPC_DEF("740_v2.1", CPU_POWERPC_7x0_v21, 740, - "PowerPC 740 v2.1 (G3)") - POWERPC_DEF("750_v2.1", CPU_POWERPC_7x0_v21, 750, - "PowerPC 750 v2.1 (G3)") - POWERPC_DEF("740_v2.2", CPU_POWERPC_7x0_v22, 740, - "PowerPC 740 v2.2 (G3)") - POWERPC_DEF("750_v2.2", CPU_POWERPC_7x0_v22, 750, - "PowerPC 750 v2.2 (G3)") - POWERPC_DEF("740_v3.0", CPU_POWERPC_7x0_v30, 740, - "PowerPC 740 v3.0 (G3)") - POWERPC_DEF("750_v3.0", CPU_POWERPC_7x0_v30, 750, - "PowerPC 750 v3.0 (G3)") - POWERPC_DEF("740_v3.1", CPU_POWERPC_7x0_v31, 740, - "PowerPC 740 v3.1 (G3)") - POWERPC_DEF("750_v3.1", CPU_POWERPC_7x0_v31, 750, - "PowerPC 750 v3.1 (G3)") - POWERPC_DEF("740e", CPU_POWERPC_740E, 740, - "PowerPC 740E (G3)") - POWERPC_DEF("750e", CPU_POWERPC_750E, 750, - "PowerPC 750E (G3)") - POWERPC_DEF("740p", CPU_POWERPC_7x0P, 740, - "PowerPC 740P (G3)") - POWERPC_DEF("750p", CPU_POWERPC_7x0P, 750, - "PowerPC 750P (G3)") - POWERPC_DEF("750cl_v1.0", CPU_POWERPC_750CL_v10, 750cl, - "PowerPC 750CL v1.0") - POWERPC_DEF("750cl_v2.0", CPU_POWERPC_750CL_v20, 750cl, - "PowerPC 750CL v2.0") - POWERPC_DEF("750cx_v1.0", CPU_POWERPC_750CX_v10, 750cx, - "PowerPC 750CX v1.0 (G3 embedded)") - POWERPC_DEF("750cx_v2.0", CPU_POWERPC_750CX_v20, 750cx, - "PowerPC 750CX v2.1 (G3 embedded)") - POWERPC_DEF("750cx_v2.1", CPU_POWERPC_750CX_v21, 750cx, - "PowerPC 750CX v2.1 (G3 embedded)") - POWERPC_DEF("750cx_v2.2", CPU_POWERPC_750CX_v22, 750cx, - "PowerPC 750CX v2.2 (G3 embedded)") - POWERPC_DEF("750cxe_v2.1", CPU_POWERPC_750CXE_v21, 750cx, - "PowerPC 750CXe v2.1 (G3 embedded)") - POWERPC_DEF("750cxe_v2.2", CPU_POWERPC_750CXE_v22, 750cx, - "PowerPC 750CXe v2.2 (G3 embedded)") - POWERPC_DEF("750cxe_v2.3", CPU_POWERPC_750CXE_v23, 750cx, - "PowerPC 750CXe v2.3 (G3 embedded)") - POWERPC_DEF("750cxe_v2.4", CPU_POWERPC_750CXE_v24, 750cx, - "PowerPC 750CXe v2.4 (G3 embedded)") - POWERPC_DEF("750cxe_v2.4b", CPU_POWERPC_750CXE_v24b, 750cx, - "PowerPC 750CXe v2.4b (G3 embedded)") - POWERPC_DEF("750cxe_v3.0", CPU_POWERPC_750CXE_v30, 750cx, - "PowerPC 750CXe v3.0 (G3 embedded)") - POWERPC_DEF("750cxe_v3.1", CPU_POWERPC_750CXE_v31, 750cx, - "PowerPC 750CXe v3.1 (G3 embedded)") - POWERPC_DEF("750cxe_v3.1b", CPU_POWERPC_750CXE_v31b, 750cx, - "PowerPC 750CXe v3.1b (G3 embedded)") - POWERPC_DEF("750cxr", CPU_POWERPC_750CXR, 750cx, - "PowerPC 750CXr (G3 embedded)") - POWERPC_DEF("750fl", CPU_POWERPC_750FL, 750fx, - "PowerPC 750FL (G3 embedded)") - POWERPC_DEF("750fx_v1.0", CPU_POWERPC_750FX_v10, 750fx, - "PowerPC 750FX v1.0 (G3 embedded)") - POWERPC_DEF("750fx_v2.0", CPU_POWERPC_750FX_v20, 750fx, - "PowerPC 750FX v2.0 (G3 embedded)") - POWERPC_DEF("750fx_v2.1", CPU_POWERPC_750FX_v21, 750fx, - "PowerPC 750FX v2.1 (G3 embedded)") - POWERPC_DEF("750fx_v2.2", CPU_POWERPC_750FX_v22, 750fx, - "PowerPC 750FX v2.2 (G3 embedded)") - POWERPC_DEF("750fx_v2.3", CPU_POWERPC_750FX_v23, 750fx, - "PowerPC 750FX v2.3 (G3 embedded)") - POWERPC_DEF("750gl", CPU_POWERPC_750GL, 750gx, - "PowerPC 750GL (G3 embedded)") - POWERPC_DEF("750gx_v1.0", CPU_POWERPC_750GX_v10, 750gx, - "PowerPC 750GX v1.0 (G3 embedded)") - POWERPC_DEF("750gx_v1.1", CPU_POWERPC_750GX_v11, 750gx, - "PowerPC 750GX v1.1 (G3 embedded)") - POWERPC_DEF("750gx_v1.2", CPU_POWERPC_750GX_v12, 750gx, - "PowerPC 750GX v1.2 (G3 embedded)") - POWERPC_DEF("750l_v2.0", CPU_POWERPC_750L_v20, 750, - "PowerPC 750L v2.0 (G3 embedded)") - POWERPC_DEF("750l_v2.1", CPU_POWERPC_750L_v21, 750, - "PowerPC 750L v2.1 (G3 embedded)") - POWERPC_DEF("750l_v2.2", CPU_POWERPC_750L_v22, 750, - "PowerPC 750L v2.2 (G3 embedded)") - POWERPC_DEF("750l_v3.0", CPU_POWERPC_750L_v30, 750, - "PowerPC 750L v3.0 (G3 embedded)") - POWERPC_DEF("750l_v3.2", CPU_POWERPC_750L_v32, 750, - "PowerPC 750L v3.2 (G3 embedded)") - POWERPC_DEF("745_v1.0", CPU_POWERPC_7x5_v10, 745, - "PowerPC 745 v1.0") - POWERPC_DEF("755_v1.0", CPU_POWERPC_7x5_v10, 755, - "PowerPC 755 v1.0") - POWERPC_DEF("745_v1.1", CPU_POWERPC_7x5_v11, 745, - "PowerPC 745 v1.1") - POWERPC_DEF("755_v1.1", CPU_POWERPC_7x5_v11, 755, - "PowerPC 755 v1.1") - POWERPC_DEF("745_v2.0", CPU_POWERPC_7x5_v20, 745, - "PowerPC 745 v2.0") - POWERPC_DEF("755_v2.0", CPU_POWERPC_7x5_v20, 755, - "PowerPC 755 v2.0") - POWERPC_DEF("745_v2.1", CPU_POWERPC_7x5_v21, 745, - "PowerPC 745 v2.1") - POWERPC_DEF("755_v2.1", CPU_POWERPC_7x5_v21, 755, - "PowerPC 755 v2.1") - POWERPC_DEF("745_v2.2", CPU_POWERPC_7x5_v22, 745, - "PowerPC 745 v2.2") - POWERPC_DEF("755_v2.2", CPU_POWERPC_7x5_v22, 755, - "PowerPC 755 v2.2") - POWERPC_DEF("745_v2.3", CPU_POWERPC_7x5_v23, 745, - "PowerPC 745 v2.3") - POWERPC_DEF("755_v2.3", CPU_POWERPC_7x5_v23, 755, - "PowerPC 755 v2.3") - POWERPC_DEF("745_v2.4", CPU_POWERPC_7x5_v24, 745, - "PowerPC 745 v2.4") - POWERPC_DEF("755_v2.4", CPU_POWERPC_7x5_v24, 755, - "PowerPC 755 v2.4") - POWERPC_DEF("745_v2.5", CPU_POWERPC_7x5_v25, 745, - "PowerPC 745 v2.5") - POWERPC_DEF("755_v2.5", CPU_POWERPC_7x5_v25, 755, - "PowerPC 755 v2.5") - POWERPC_DEF("745_v2.6", CPU_POWERPC_7x5_v26, 745, - "PowerPC 745 v2.6") - POWERPC_DEF("755_v2.6", CPU_POWERPC_7x5_v26, 755, - "PowerPC 755 v2.6") - POWERPC_DEF("745_v2.7", CPU_POWERPC_7x5_v27, 745, - "PowerPC 745 v2.7") - POWERPC_DEF("755_v2.7", CPU_POWERPC_7x5_v27, 755, - "PowerPC 755 v2.7") - POWERPC_DEF("745_v2.8", CPU_POWERPC_7x5_v28, 745, - "PowerPC 745 v2.8") - POWERPC_DEF("755_v2.8", CPU_POWERPC_7x5_v28, 755, - "PowerPC 755 v2.8") -#if defined(TODO) - POWERPC_DEF("745p", CPU_POWERPC_7x5P, 745, - "PowerPC 745P (G3)") - POWERPC_DEF("755p", CPU_POWERPC_7x5P, 755, - "PowerPC 755P (G3)") -#endif - /* PowerPC 74xx family */ - POWERPC_DEF("7400_v1.0", CPU_POWERPC_7400_v10, 7400, - "PowerPC 7400 v1.0 (G4)") - POWERPC_DEF("7400_v1.1", CPU_POWERPC_7400_v11, 7400, - "PowerPC 7400 v1.1 (G4)") - POWERPC_DEF("7400_v2.0", CPU_POWERPC_7400_v20, 7400, - "PowerPC 7400 v2.0 (G4)") - POWERPC_DEF("7400_v2.1", CPU_POWERPC_7400_v21, 7400, - "PowerPC 7400 v2.1 (G4)") - POWERPC_DEF("7400_v2.2", CPU_POWERPC_7400_v22, 7400, - "PowerPC 7400 v2.2 (G4)") - POWERPC_DEF("7400_v2.6", CPU_POWERPC_7400_v26, 7400, - "PowerPC 7400 v2.6 (G4)") - POWERPC_DEF("7400_v2.7", CPU_POWERPC_7400_v27, 7400, - "PowerPC 7400 v2.7 (G4)") - POWERPC_DEF("7400_v2.8", CPU_POWERPC_7400_v28, 7400, - "PowerPC 7400 v2.8 (G4)") - POWERPC_DEF("7400_v2.9", CPU_POWERPC_7400_v29, 7400, - "PowerPC 7400 v2.9 (G4)") - POWERPC_DEF("7410_v1.0", CPU_POWERPC_7410_v10, 7410, - "PowerPC 7410 v1.0 (G4)") - POWERPC_DEF("7410_v1.1", CPU_POWERPC_7410_v11, 7410, - "PowerPC 7410 v1.1 (G4)") - POWERPC_DEF("7410_v1.2", CPU_POWERPC_7410_v12, 7410, - "PowerPC 7410 v1.2 (G4)") - POWERPC_DEF("7410_v1.3", CPU_POWERPC_7410_v13, 7410, - "PowerPC 7410 v1.3 (G4)") - POWERPC_DEF("7410_v1.4", CPU_POWERPC_7410_v14, 7410, - "PowerPC 7410 v1.4 (G4)") - POWERPC_DEF("7448_v1.0", CPU_POWERPC_7448_v10, 7400, - "PowerPC 7448 v1.0 (G4)") - POWERPC_DEF("7448_v1.1", CPU_POWERPC_7448_v11, 7400, - "PowerPC 7448 v1.1 (G4)") - POWERPC_DEF("7448_v2.0", CPU_POWERPC_7448_v20, 7400, - "PowerPC 7448 v2.0 (G4)") - POWERPC_DEF("7448_v2.1", CPU_POWERPC_7448_v21, 7400, - "PowerPC 7448 v2.1 (G4)") - POWERPC_DEF("7450_v1.0", CPU_POWERPC_7450_v10, 7450, - "PowerPC 7450 v1.0 (G4)") - POWERPC_DEF("7450_v1.1", CPU_POWERPC_7450_v11, 7450, - "PowerPC 7450 v1.1 (G4)") - POWERPC_DEF("7450_v1.2", CPU_POWERPC_7450_v12, 7450, - "PowerPC 7450 v1.2 (G4)") - POWERPC_DEF("7450_v2.0", CPU_POWERPC_7450_v20, 7450, - "PowerPC 7450 v2.0 (G4)") - POWERPC_DEF("7450_v2.1", CPU_POWERPC_7450_v21, 7450, - "PowerPC 7450 v2.1 (G4)") - POWERPC_DEF("7441_v2.1", CPU_POWERPC_7450_v21, 7440, - "PowerPC 7441 v2.1 (G4)") - POWERPC_DEF("7441_v2.3", CPU_POWERPC_74x1_v23, 7440, - "PowerPC 7441 v2.3 (G4)") - POWERPC_DEF("7451_v2.3", CPU_POWERPC_74x1_v23, 7450, - "PowerPC 7451 v2.3 (G4)") - POWERPC_DEF("7441_v2.10", CPU_POWERPC_74x1_v210, 7440, - "PowerPC 7441 v2.10 (G4)") - POWERPC_DEF("7451_v2.10", CPU_POWERPC_74x1_v210, 7450, - "PowerPC 7451 v2.10 (G4)") - POWERPC_DEF("7445_v1.0", CPU_POWERPC_74x5_v10, 7445, - "PowerPC 7445 v1.0 (G4)") - POWERPC_DEF("7455_v1.0", CPU_POWERPC_74x5_v10, 7455, - "PowerPC 7455 v1.0 (G4)") - POWERPC_DEF("7445_v2.1", CPU_POWERPC_74x5_v21, 7445, - "PowerPC 7445 v2.1 (G4)") - POWERPC_DEF("7455_v2.1", CPU_POWERPC_74x5_v21, 7455, - "PowerPC 7455 v2.1 (G4)") - POWERPC_DEF("7445_v3.2", CPU_POWERPC_74x5_v32, 7445, - "PowerPC 7445 v3.2 (G4)") - POWERPC_DEF("7455_v3.2", CPU_POWERPC_74x5_v32, 7455, - "PowerPC 7455 v3.2 (G4)") - POWERPC_DEF("7445_v3.3", CPU_POWERPC_74x5_v33, 7445, - "PowerPC 7445 v3.3 (G4)") - POWERPC_DEF("7455_v3.3", CPU_POWERPC_74x5_v33, 7455, - "PowerPC 7455 v3.3 (G4)") - POWERPC_DEF("7445_v3.4", CPU_POWERPC_74x5_v34, 7445, - "PowerPC 7445 v3.4 (G4)") - POWERPC_DEF("7455_v3.4", CPU_POWERPC_74x5_v34, 7455, - "PowerPC 7455 v3.4 (G4)") - POWERPC_DEF("7447_v1.0", CPU_POWERPC_74x7_v10, 7445, - "PowerPC 7447 v1.0 (G4)") - POWERPC_DEF("7457_v1.0", CPU_POWERPC_74x7_v10, 7455, - "PowerPC 7457 v1.0 (G4)") - POWERPC_DEF("7447_v1.1", CPU_POWERPC_74x7_v11, 7445, - "PowerPC 7447 v1.1 (G4)") - POWERPC_DEF("7457_v1.1", CPU_POWERPC_74x7_v11, 7455, - "PowerPC 7457 v1.1 (G4)") - POWERPC_DEF("7457_v1.2", CPU_POWERPC_74x7_v12, 7455, - "PowerPC 7457 v1.2 (G4)") - POWERPC_DEF("7447A_v1.0", CPU_POWERPC_74x7A_v10, 7445, - "PowerPC 7447A v1.0 (G4)") - POWERPC_DEF("7457A_v1.0", CPU_POWERPC_74x7A_v10, 7455, - "PowerPC 7457A v1.0 (G4)") - POWERPC_DEF("7447A_v1.1", CPU_POWERPC_74x7A_v11, 7445, - "PowerPC 7447A v1.1 (G4)") - POWERPC_DEF("7457A_v1.1", CPU_POWERPC_74x7A_v11, 7455, - "PowerPC 7457A v1.1 (G4)") - POWERPC_DEF("7447A_v1.2", CPU_POWERPC_74x7A_v12, 7445, - "PowerPC 7447A v1.2 (G4)") - POWERPC_DEF("7457A_v1.2", CPU_POWERPC_74x7A_v12, 7455, - "PowerPC 7457A v1.2 (G4)") - /* 64 bits PowerPC */ -#if defined (TARGET_PPC64) - POWERPC_DEF("620", CPU_POWERPC_620, 620, - "PowerPC 620") -#if defined(TODO) - POWERPC_DEF("630", CPU_POWERPC_630, 630, - "PowerPC 630 (POWER3)") -#endif -#if defined(TODO) - POWERPC_DEF("631", CPU_POWERPC_631, 631, - "PowerPC 631 (Power 3+)") -#endif -#if defined(TODO) - POWERPC_DEF("POWER4", CPU_POWERPC_POWER4, POWER4, - "POWER4") -#endif -#if defined(TODO) - POWERPC_DEF("POWER4+", CPU_POWERPC_POWER4P, POWER4P, - "POWER4p") -#endif -#if defined(TODO) - POWERPC_DEF("POWER5", CPU_POWERPC_POWER5, POWER5, - "POWER5") - POWERPC_DEF("POWER5gr", CPU_POWERPC_POWER5GR, POWER5, - "POWER5GR") -#endif -#if defined(TODO) - POWERPC_DEF("POWER5+", CPU_POWERPC_POWER5P, POWER5P, - "POWER5+") - POWERPC_DEF("POWER5gs", CPU_POWERPC_POWER5GS, POWER5P, - "POWER5GS") -#endif -#if defined(TODO) - POWERPC_DEF("POWER6", CPU_POWERPC_POWER6, POWER6, - "POWER6") - POWERPC_DEF("POWER6_5", CPU_POWERPC_POWER6_5, POWER5, - "POWER6 running in POWER5 mode") - POWERPC_DEF("POWER6A", CPU_POWERPC_POWER6A, POWER6, - "POWER6A") -#endif - POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7, - "POWER7 v2.0") - POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7, - "POWER7 v2.1") - POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, - "POWER7 v2.3") - POWERPC_DEF("970", CPU_POWERPC_970, 970, - "PowerPC 970") - POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX, - "PowerPC 970FX v1.0 (G5)") - POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970FX, - "PowerPC 970FX v2.0 (G5)") - POWERPC_DEF("970fx_v2.1", CPU_POWERPC_970FX_v21, 970FX, - "PowerPC 970FX v2.1 (G5)") - POWERPC_DEF("970fx_v3.0", CPU_POWERPC_970FX_v30, 970FX, - "PowerPC 970FX v3.0 (G5)") - POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX, - "PowerPC 970FX v3.1 (G5)") - POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX, - "PowerPC 970GX (G5)") - POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP, - "PowerPC 970MP v1.0") - POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP, - "PowerPC 970MP v1.1") -#if defined(TODO) - POWERPC_DEF("Cell", CPU_POWERPC_CELL, 970, - "PowerPC Cell") -#endif -#if defined(TODO) - POWERPC_DEF("Cell_v1.0", CPU_POWERPC_CELL_v10, 970, - "PowerPC Cell v1.0") -#endif -#if defined(TODO) - POWERPC_DEF("Cell_v2.0", CPU_POWERPC_CELL_v20, 970, - "PowerPC Cell v2.0") -#endif -#if defined(TODO) - POWERPC_DEF("Cell_v3.0", CPU_POWERPC_CELL_v30, 970, - "PowerPC Cell v3.0") -#endif -#if defined(TODO) - POWERPC_DEF("Cell_v3.1", CPU_POWERPC_CELL_v31, 970, - "PowerPC Cell v3.1") -#endif -#if defined(TODO) - POWERPC_DEF("Cell_v3.2", CPU_POWERPC_CELL_v32, 970, - "PowerPC Cell v3.2") -#endif -#if defined(TODO) - /* This one seems to support the whole POWER2 instruction set - * and the PowerPC 64 one. - */ - /* What about A10 & A30 ? */ - POWERPC_DEF("RS64", CPU_POWERPC_RS64, RS64, - "RS64 (Apache/A35)") -#endif -#if defined(TODO) - POWERPC_DEF("RS64-II", CPU_POWERPC_RS64II, RS64, - "RS64-II (NorthStar/A50)") -#endif -#if defined(TODO) - POWERPC_DEF("RS64-III", CPU_POWERPC_RS64III, RS64, - "RS64-III (Pulsar)") -#endif -#if defined(TODO) - POWERPC_DEF("RS64-IV", CPU_POWERPC_RS64IV, RS64, - "RS64-IV (IceStar/IStar/SStar)") -#endif -#endif /* defined (TARGET_PPC64) */ - /* POWER */ -#if defined(TODO) - POWERPC_DEF("POWER", CPU_POWERPC_POWER, POWER, - "Original POWER") -#endif -#if defined(TODO) - POWERPC_DEF("POWER2", CPU_POWERPC_POWER2, POWER, - "POWER2") -#endif - /* PA semi cores */ -#if defined(TODO) - POWERPC_DEF("PA6T", CPU_POWERPC_PA6T, PA6T, - "PA PA6T") -#endif typedef struct PowerPCCPUAlias { const char *alias; From cc4a04db05b083748b0ee9e642d68496a3d531ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:50 +0000 Subject: [PATCH 1464/1634] target-ppc: Fix remaining microcontroller typos among models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit controler -> controller Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/cpu-models.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index f0be585a4d..66408c0ceb 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -93,7 +93,7 @@ /* XXX: to be checked */ POWERPC_DEF("401G2", CPU_POWERPC_401G2, 401x2, "PowerPC 401G2") - /* PowerPC 401 microcontrolers */ + /* PowerPC 401 microcontrollers */ #if defined(TODO) POWERPC_DEF("401GF", CPU_POWERPC_401GF, 401, "PowerPC 401GF") @@ -107,7 +107,7 @@ NULL) #endif /* PowerPC 403 family */ - /* PowerPC 403 microcontrolers */ + /* PowerPC 403 microcontrollers */ POWERPC_DEF("403GA", CPU_POWERPC_403GA, 403, "PowerPC 403 GA") POWERPC_DEF("403GB", CPU_POWERPC_403GB, 403, @@ -174,7 +174,7 @@ POWERPC_DEF("405F6", CPU_POWERPC_405F6, 405, "PowerPC 405 F6") #endif - /* PowerPC 405 microcontrolers */ + /* PowerPC 405 microcontrollers */ POWERPC_DEF("405CRa", CPU_POWERPC_405CRa, 405, "PowerPC 405 CRa") POWERPC_DEF("405CRb", CPU_POWERPC_405CRb, 405, @@ -245,7 +245,7 @@ POWERPC_DEF("LC77700", CPU_POWERPC_LC77700, 405, "PowerPC LC77700 (Sanyo)") #endif - /* PowerPC 401/403/405 based set-top-box microcontrolers */ + /* PowerPC 401/403/405 based set-top-box microcontrollers */ #if defined(TODO) POWERPC_DEF("STB01000", CPU_POWERPC_STB01000, 401x2, "STB010000") @@ -337,7 +337,7 @@ POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5, "PowerPC 440H6") #endif - /* PowerPC 440 microcontrolers */ + /* PowerPC 440 microcontrollers */ POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP, "PowerPC 440 EPa") POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP, @@ -397,7 +397,7 @@ POWERPC_DEF("464", CPU_POWERPC_464, 460, "Generic PowerPC 464") #endif - /* PowerPC 464 microcontrolers */ + /* PowerPC 464 microcontrollers */ #if defined(TODO) POWERPC_DEF("464H90", CPU_POWERPC_464H90, 460, "PowerPC 464H90") From befa8af375acd52d7118fa8d4fdf15acee8d378a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 17 Feb 2013 23:16:51 +0000 Subject: [PATCH 1465/1634] target-ppc: Change "POWER7" CPU alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let it resolve to v2.3 rather than v2.0. Suggested-by: David Gibson Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b0d435735a..1015077df3 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7332,7 +7332,7 @@ static const PowerPCCPUAlias ppc_cpu_aliases[] = { { "Boxer", "POWER3" }, { "Dino", "POWER3" }, { "POWER3+", "631" }, - { "POWER7", "POWER7_v2.0" }, + { "POWER7", "POWER7_v2.3" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" }, { "Apache", "RS64" }, From 6bbd5dde9a10520eb069c4bff9f2e34b96b1cfee Mon Sep 17 00:00:00 2001 From: Erlon Cruz Date: Mon, 18 Feb 2013 05:00:32 +0000 Subject: [PATCH 1466/1634] pseries: Implement h_read hcall This h_call is useful for DLPAR in future amongst other things. Given an index it fetches the corresponding PTE stored in the htab. Signed-off-by: Erlon Cruz Acked-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_hcall.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index 7b8959488e..77c052fcb1 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -323,6 +323,36 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_SUCCESS; } +static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUPPCState *env = &cpu->env; + target_ulong flags = args[0]; + target_ulong pte_index = args[1]; + uint8_t *hpte; + int i, ridx, n_entries = 1; + + if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { + return H_PARAMETER; + } + + if (flags & H_READ_4) { + /* Clear the two low order bits */ + pte_index &= ~(3ULL); + n_entries = 4; + } + + hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); + + for (i = 0, ridx = 0; i < n_entries; i++) { + args[ridx++] = ldq_p(hpte); + args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2)); + hpte += HASH_PTE_SIZE_64; + } + + return H_SUCCESS; +} + static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -710,6 +740,7 @@ static void hypercall_register_types(void) spapr_register_hypercall(H_ENTER, h_enter); spapr_register_hypercall(H_REMOVE, h_remove); spapr_register_hypercall(H_PROTECT, h_protect); + spapr_register_hypercall(H_READ, h_read); /* hcall-bulk */ spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); From d60fa42e8bae39440f997ebfe8fe328269a57d16 Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Tue, 19 Feb 2013 04:41:11 +0000 Subject: [PATCH 1467/1634] Save memory allocation in the elf loader The current elf loader uses too much memory. For example, I have a executable with a bss section of 400 MB and I set the ram size to 512 MB. Qemu uses about 780MB of RAM (which is fine), but there's a peak at 1.6 GB during initialization (this is not fine). This patch fixes two things: 1) do not allocate each elf program twice. 2) do not allocate memory for areas that are only zeros. For this we need a new field in Rom: "datasize" which is the size of the allocated data. If datasize is less than romsize, it means that the area from datasize to romsize is filled with zeros. Signed-off-by: Fabien Chouteau Signed-off-by: Alexander Graf --- hw/elf_ops.h | 19 +++++++------ hw/loader.c | 75 +++++++++++++++++++++++++++++++++++++++++++--------- hw/loader.h | 2 ++ 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/hw/elf_ops.h b/hw/elf_ops.h index 531a42553b..acc701e3a4 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -197,7 +197,7 @@ static int glue(load_elf, SZ)(const char *name, int fd, struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; - elf_word mem_size; + elf_word mem_size, file_size; uint64_t addr, low = (uint64_t)-1, high = 0; uint8_t *data = NULL; char label[128]; @@ -252,14 +252,16 @@ static int glue(load_elf, SZ)(const char *name, int fd, for(i = 0; i < ehdr.e_phnum; i++) { ph = &phdr[i]; if (ph->p_type == PT_LOAD) { - mem_size = ph->p_memsz; - /* XXX: avoid allocating */ - data = g_malloc0(mem_size); + mem_size = ph->p_memsz; /* Size of the ROM */ + file_size = ph->p_filesz; /* Size of the allocated data */ + data = g_malloc0(file_size); if (ph->p_filesz > 0) { - if (lseek(fd, ph->p_offset, SEEK_SET) < 0) + if (lseek(fd, ph->p_offset, SEEK_SET) < 0) { goto fail; - if (read(fd, data, ph->p_filesz) != ph->p_filesz) + } + if (read(fd, data, file_size) != file_size) { goto fail; + } } /* address_offset is hack for kernel images that are linked at the wrong physical address. */ @@ -281,7 +283,9 @@ static int glue(load_elf, SZ)(const char *name, int fd, } snprintf(label, sizeof(label), "phdr #%d: %s", i, name); - rom_add_blob_fixed(label, data, mem_size, addr); + + /* rom_add_elf_program() seize the ownership of 'data' */ + rom_add_elf_program(label, data, file_size, mem_size, addr); total_size += mem_size; if (addr < low) @@ -289,7 +293,6 @@ static int glue(load_elf, SZ)(const char *name, int fd, if ((addr + mem_size) > high) high = addr + mem_size; - g_free(data); data = NULL; } } diff --git a/hw/loader.c b/hw/loader.c index 995edc3f98..bd2b52d14e 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -533,7 +533,14 @@ typedef struct Rom Rom; struct Rom { char *name; char *path; + + /* datasize is the amount of memory allocated in "data". If datasize is less + * than romsize, it means that the area from datasize to romsize is filled + * with zeros. + */ size_t romsize; + size_t datasize; + uint8_t *data; int isrom; char *fw_dir; @@ -589,14 +596,15 @@ int rom_add_file(const char *file, const char *fw_dir, rom->fw_dir = g_strdup(fw_dir); rom->fw_file = g_strdup(file); } - rom->addr = addr; - rom->romsize = lseek(fd, 0, SEEK_END); - rom->data = g_malloc0(rom->romsize); + rom->addr = addr; + rom->romsize = lseek(fd, 0, SEEK_END); + rom->datasize = rom->romsize; + rom->data = g_malloc0(rom->datasize); lseek(fd, 0, SEEK_SET); - rc = read(fd, rom->data, rom->romsize); - if (rc != rom->romsize) { + rc = read(fd, rom->data, rom->datasize); + if (rc != rom->datasize) { fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n", - rom->name, rc, rom->romsize); + rom->name, rc, rom->datasize); goto err; } close(fd); @@ -637,16 +645,37 @@ int rom_add_blob(const char *name, const void *blob, size_t len, { Rom *rom; - rom = g_malloc0(sizeof(*rom)); - rom->name = g_strdup(name); - rom->addr = addr; - rom->romsize = len; - rom->data = g_malloc0(rom->romsize); + rom = g_malloc0(sizeof(*rom)); + rom->name = g_strdup(name); + rom->addr = addr; + rom->romsize = len; + rom->datasize = len; + rom->data = g_malloc0(rom->datasize); memcpy(rom->data, blob, len); rom_insert(rom); return 0; } +/* This function is specific for elf program because we don't need to allocate + * all the rom. We just allocate the first part and the rest is just zeros. This + * is why romsize and datasize are different. Also, this function seize the + * memory ownership of "data", so we don't have to allocate and copy the buffer. + */ +int rom_add_elf_program(const char *name, void *data, size_t datasize, + size_t romsize, hwaddr addr) +{ + Rom *rom; + + rom = g_malloc0(sizeof(*rom)); + rom->name = g_strdup(name); + rom->addr = addr; + rom->datasize = datasize; + rom->romsize = romsize; + rom->data = data; + rom_insert(rom); + return 0; +} + int rom_add_vga(const char *file) { return rom_add_file(file, "vgaroms", 0, -1); @@ -668,7 +697,7 @@ static void rom_reset(void *unused) if (rom->data == NULL) { continue; } - cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize); + cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize); if (rom->isrom) { /* rom needs to be written only once */ g_free(rom->data); @@ -756,13 +785,33 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) d = dest + (rom->addr - addr); s = rom->data; - l = rom->romsize; + l = rom->datasize; if ((d + l) > (dest + size)) { l = dest - d; } memcpy(d, s, l); + + if (rom->romsize > rom->datasize) { + /* If datasize is less than romsize, it means that we didn't + * allocate all the ROM because the trailing data are only zeros. + */ + + d += l; + l = rom->romsize - rom->datasize; + + if ((d + l) > (dest + size)) { + /* Rom size doesn't fit in the destination area. Adjust to avoid + * overflow. + */ + l = dest - d; + } + + if (l > 0) { + memset(d, 0x0, l); + } + } } return (d + l) - dest; diff --git a/hw/loader.h b/hw/loader.h index 5e61c95b84..0958f06934 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -27,6 +27,8 @@ int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex); int rom_add_blob(const char *name, const void *blob, size_t len, hwaddr addr); +int rom_add_elf_program(const char *name, void *data, size_t datasize, + size_t romsize, hwaddr addr); int rom_load_all(void); void rom_set_fw(void *f); int rom_copy(uint8_t *dest, hwaddr addr, size_t size); From d67d40ea07577b0a952d3bea5a2f92edf0ee26a6 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 20 Feb 2013 16:41:50 +0000 Subject: [PATCH 1468/1634] target-ppc: Add mechanism for synchronizing SPRs with KVM Currently when runing under KVM on ppc, we synchronize a certain number of vital SPRs to KVM through the SET_SREGS call. This leaves out quite a lot of important SPRs which are maintained in KVM. It would be helpful to have their contents in qemu for debugging purposes, and when we implement migration it will be vital, since they include important guest state that will need to be restored on the target. This patch sets up for synchronization of any registers supported by the KVM ONE_REG calls. A new variant on spr_register() allows a ONE_REG id to be stored with the SPR information. When we set/get information to KVM we also synchronize any SPRs so registered. For now we set this mechanism up to synchronize a handful of important registers that already have ONE_REG IDs, notably the DAR and DSISR. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 6 ++ target-ppc/kvm.c | 115 +++++++++++++++++++++++++++++++++--- target-ppc/translate_init.c | 114 ++++++++++++++++++++--------------- 3 files changed, 178 insertions(+), 57 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index e4cf96ce2f..417abb0dd1 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -329,6 +329,12 @@ struct ppc_spr_t { void (*hea_write)(void *opaque, int spr_num, int gpr_num); #endif const char *name; +#ifdef CONFIG_KVM + /* We (ab)use the fact that all the SPRs will have ids for the + * ONE_REG interface will have KVM_REG_PPC to use 0 as meaning, + * don't sync this */ + uint64_t one_reg_id; +#endif }; /* Altivec registers (128 bits) */ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index a89c3cf7a5..02ab559836 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -61,6 +61,7 @@ static int cap_ppc_smt; static int cap_ppc_rma; static int cap_spapr_tce; static int cap_hior; +static int cap_one_reg; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -89,6 +90,7 @@ int kvm_arch_init(KVMState *s) cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); + cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG); cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); if (!cap_interrupt_level) { @@ -449,6 +451,76 @@ static void kvm_sw_tlb_put(PowerPCCPU *cpu) g_free(bitmap); } +static void kvm_get_one_spr(CPUState *cs, uint64_t id, int spr) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + union { + uint32_t u32; + uint64_t u64; + } val; + struct kvm_one_reg reg = { + .id = id, + .addr = (uintptr_t) &val, + }; + int ret; + + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret != 0) { + fprintf(stderr, "Warning: Unable to retrieve SPR %d from KVM: %s\n", + spr, strerror(errno)); + } else { + switch (id & KVM_REG_SIZE_MASK) { + case KVM_REG_SIZE_U32: + env->spr[spr] = val.u32; + break; + + case KVM_REG_SIZE_U64: + env->spr[spr] = val.u64; + break; + + default: + /* Don't handle this size yet */ + abort(); + } + } +} + +static void kvm_put_one_spr(CPUState *cs, uint64_t id, int spr) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + union { + uint32_t u32; + uint64_t u64; + } val; + struct kvm_one_reg reg = { + .id = id, + .addr = (uintptr_t) &val, + }; + int ret; + + switch (id & KVM_REG_SIZE_MASK) { + case KVM_REG_SIZE_U32: + val.u32 = env->spr[spr]; + break; + + case KVM_REG_SIZE_U64: + val.u64 = env->spr[spr]; + break; + + default: + /* Don't handle this size yet */ + abort(); + } + + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret != 0) { + fprintf(stderr, "Warning: Unable to set SPR %d to KVM: %s\n", + spr, strerror(errno)); + } +} + int kvm_arch_put_registers(CPUState *cs, int level) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -530,15 +602,22 @@ int kvm_arch_put_registers(CPUState *cs, int level) } if (cap_hior && (level >= KVM_PUT_RESET_STATE)) { - uint64_t hior = env->spr[SPR_HIOR]; - struct kvm_one_reg reg = { - .id = KVM_REG_PPC_HIOR, - .addr = (uintptr_t) &hior, - }; + kvm_put_one_spr(cs, KVM_REG_PPC_HIOR, SPR_HIOR); + } - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); - if (ret) { - return ret; + if (cap_one_reg) { + int i; + + /* We deliberately ignore errors here, for kernels which have + * the ONE_REG calls, but don't support the specific + * registers, there's a reasonable chance things will still + * work, at least until we try to migrate. */ + for (i = 0; i < 1024; i++) { + uint64_t id = env->spr_cb[i].one_reg_id; + + if (id != 0) { + kvm_put_one_spr(cs, id, i); + } } } @@ -721,6 +800,26 @@ int kvm_arch_get_registers(CPUState *cs) } } + if (cap_hior) { + kvm_get_one_spr(cs, KVM_REG_PPC_HIOR, SPR_HIOR); + } + + if (cap_one_reg) { + int i; + + /* We deliberately ignore errors here, for kernels which have + * the ONE_REG calls, but don't support the specific + * registers, there's a reasonable chance things will still + * work, at least until we try to migrate. */ + for (i = 0; i < 1024; i++) { + uint64_t id = env->spr_cb[i].one_reg_id; + + if (id != 0) { + kvm_get_one_spr(cs, id, i); + } + } + } + return 0; } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 1015077df3..7fb314c038 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -572,26 +572,42 @@ static inline void vscr_init (CPUPPCState *env, uint32_t val) set_flush_to_zero(vscr_nj, &env->vec_status); } -#if defined(CONFIG_USER_ONLY) -#define spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, initial_value) \ -do { \ - _spr_register(env, num, name, uea_read, uea_write, initial_value); \ -} while (0) -static inline void _spr_register (CPUPPCState *env, int num, - const char *name, - void (*uea_read)(void *opaque, int gprn, int sprn), - void (*uea_write)(void *opaque, int sprn, int gprn), - target_ulong initial_value) +#ifdef CONFIG_USER_ONLY +#define spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, initial_value) #else -static inline void spr_register (CPUPPCState *env, int num, +#if !defined(CONFIG_KVM) +#define spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, initial_value) +#else +#define spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, one_reg_id, initial_value) +#endif +#endif + +#define spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, initial_value) \ + spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, 0, initial_value) + +static inline void _spr_register(CPUPPCState *env, int num, const char *name, void (*uea_read)(void *opaque, int gprn, int sprn), void (*uea_write)(void *opaque, int sprn, int gprn), +#if !defined(CONFIG_USER_ONLY) + void (*oea_read)(void *opaque, int gprn, int sprn), void (*oea_write)(void *opaque, int sprn, int gprn), - target_ulong initial_value) #endif +#if defined(CONFIG_KVM) + uint64_t one_reg_id, +#endif + target_ulong initial_value) { ppc_spr_t *spr; @@ -667,14 +683,14 @@ static void gen_spr_generic (CPUPPCState *env) static void gen_spr_ne_601 (CPUPPCState *env) { /* Exception processing */ - spr_register(env, SPR_DSISR, "DSISR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_DAR, "DAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + spr_register_kvm(env, SPR_DSISR, "DSISR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DSISR, 0x00000000); + spr_register_kvm(env, SPR_DAR, "DAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DAR, 0x00000000); /* Timer */ spr_register(env, SPR_DECR, "DECR", SPR_NOACCESS, SPR_NOACCESS, @@ -918,10 +934,10 @@ static void gen_spr_7xx (CPUPPCState *env) { /* Breakpoints */ /* XXX : not implemented */ - spr_register(env, SPR_DABR, "DABR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + spr_register_kvm(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DABR, 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_IABR, "IABR", SPR_NOACCESS, SPR_NOACCESS, @@ -1047,10 +1063,10 @@ static void gen_spr_604 (CPUPPCState *env) &spr_read_generic, &spr_write_generic, 0x00000000); /* XXX : not implemented */ - spr_register(env, SPR_DABR, "DABR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + spr_register_kvm(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DABR, 0x00000000); /* Performance counters */ /* XXX : not implemented */ spr_register(env, SPR_MMCR0, "MMCR0", @@ -2305,14 +2321,14 @@ static void gen_spr_620 (CPUPPCState *env) static void gen_spr_5xx_8xx (CPUPPCState *env) { /* Exception processing */ - spr_register(env, SPR_DSISR, "DSISR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - spr_register(env, SPR_DAR, "DAR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + spr_register_kvm(env, SPR_DSISR, "DSISR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DSISR, 0x00000000); + spr_register_kvm(env, SPR_DAR, "DAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DAR, 0x00000000); /* Timer */ spr_register(env, SPR_DECR, "DECR", SPR_NOACCESS, SPR_NOACCESS, @@ -7036,22 +7052,22 @@ static void init_proc_POWER7 (CPUPPCState *env) 0x00000000); #if !defined(CONFIG_USER_ONLY) /* PURR & SPURR: Hack - treat these as aliases for the TB for now */ - spr_register(env, SPR_PURR, "PURR", - &spr_read_purr, SPR_NOACCESS, - &spr_read_purr, SPR_NOACCESS, - 0x00000000); - spr_register(env, SPR_SPURR, "SPURR", - &spr_read_purr, SPR_NOACCESS, - &spr_read_purr, SPR_NOACCESS, - 0x00000000); + spr_register_kvm(env, SPR_PURR, "PURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + KVM_REG_PPC_PURR, 0x00000000); + spr_register_kvm(env, SPR_SPURR, "SPURR", + &spr_read_purr, SPR_NOACCESS, + &spr_read_purr, SPR_NOACCESS, + KVM_REG_PPC_SPURR, 0x00000000); spr_register(env, SPR_CFAR, "SPR_CFAR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_cfar, &spr_write_cfar, 0x00000000); - spr_register(env, SPR_DSCR, "SPR_DSCR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); + spr_register_kvm(env, SPR_DSCR, "SPR_DSCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + KVM_REG_PPC_DSCR, 0x00000000); #endif /* !CONFIG_USER_ONLY */ /* Memory management */ /* XXX : not implemented */ From 70b79849b84510604e46299672e663a703ad5a4b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 20 Feb 2013 16:41:51 +0000 Subject: [PATCH 1469/1634] target-ppc: Synchronize FPU state with KVM Currently qemu does not get and put the state of the floating point and vector registers to KVM. This is obviously a problem for savevm, as well as possibly being problematic for debugging of FP-using guests. This patch fixes this by using new extensions to the ONE_REG interface to synchronize the qemu floating point state with KVM. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 02ab559836..44511592b4 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -521,6 +521,132 @@ static void kvm_put_one_spr(CPUState *cs, uint64_t id, int spr) } } +static int kvm_put_fp(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + struct kvm_one_reg reg; + int i; + int ret; + + if (env->insns_flags & PPC_FLOAT) { + uint64_t fpscr = env->fpscr; + bool vsx = !!(env->insns_flags2 & PPC2_VSX); + + reg.id = KVM_REG_PPC_FPSCR; + reg.addr = (uintptr_t)&fpscr; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to set FPSCR to KVM: %s\n", strerror(errno)); + return ret; + } + + for (i = 0; i < 32; i++) { + uint64_t vsr[2]; + + vsr[0] = float64_val(env->fpr[i]); + vsr[1] = env->vsr[i]; + reg.addr = (uintptr_t) &vsr; + reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i); + + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to set %s%d to KVM: %s\n", vsx ? "VSR" : "FPR", + i, strerror(errno)); + return ret; + } + } + } + + if (env->insns_flags & PPC_ALTIVEC) { + reg.id = KVM_REG_PPC_VSCR; + reg.addr = (uintptr_t)&env->vscr; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to set VSCR to KVM: %s\n", strerror(errno)); + return ret; + } + + for (i = 0; i < 32; i++) { + reg.id = KVM_REG_PPC_VR(i); + reg.addr = (uintptr_t)&env->avr[i]; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to set VR%d to KVM: %s\n", i, strerror(errno)); + return ret; + } + } + } + + return 0; +} + +static int kvm_get_fp(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + struct kvm_one_reg reg; + int i; + int ret; + + if (env->insns_flags & PPC_FLOAT) { + uint64_t fpscr; + bool vsx = !!(env->insns_flags2 & PPC2_VSX); + + reg.id = KVM_REG_PPC_FPSCR; + reg.addr = (uintptr_t)&fpscr; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to get FPSCR from KVM: %s\n", strerror(errno)); + return ret; + } else { + env->fpscr = fpscr; + } + + for (i = 0; i < 32; i++) { + uint64_t vsr[2]; + + reg.addr = (uintptr_t) &vsr; + reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i); + + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to get %s%d from KVM: %s\n", + vsx ? "VSR" : "FPR", i, strerror(errno)); + return ret; + } else { + env->fpr[i] = vsr[0]; + if (vsx) { + env->vsr[i] = vsr[1]; + } + } + } + } + + if (env->insns_flags & PPC_ALTIVEC) { + reg.id = KVM_REG_PPC_VSCR; + reg.addr = (uintptr_t)&env->vscr; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to get VSCR from KVM: %s\n", strerror(errno)); + return ret; + } + + for (i = 0; i < 32; i++) { + reg.id = KVM_REG_PPC_VR(i); + reg.addr = (uintptr_t)&env->avr[i]; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret < 0) { + dprintf("Unable to get VR%d from KVM: %s\n", + i, strerror(errno)); + return ret; + } + } + } + + return 0; +} + int kvm_arch_put_registers(CPUState *cs, int level) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -561,6 +687,8 @@ int kvm_arch_put_registers(CPUState *cs, int level) if (ret < 0) return ret; + kvm_put_fp(cs); + if (env->tlb_dirty) { kvm_sw_tlb_put(cpu); env->tlb_dirty = false; @@ -666,6 +794,8 @@ int kvm_arch_get_registers(CPUState *cs) for (i = 0;i < 32; i++) env->gpr[i] = regs.gpr[i]; + kvm_get_fp(cs); + if (cap_booke_sregs) { ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs); if (ret < 0) { From edbe35e0319c15ed2f373bcca626cbb4361f87c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 20 Feb 2013 18:24:57 +0000 Subject: [PATCH 1470/1634] target-ppc: Fix PPC_DUMP_SPR_ACCESS build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A victim of the d523dd00a7d73b28f2e99acf45a4b3f92e56e40a AREG0 conversion, insert the missing cpu_env arguments. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7fb314c038..1783c22d4d 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -54,7 +54,7 @@ static void spr_load_dump_spr(int sprn) { #ifdef PPC_DUMP_SPR_ACCESSES TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_load_dump_spr(t0); + gen_helper_load_dump_spr(cpu_env, t0); tcg_temp_free_i32(t0); #endif } @@ -69,7 +69,7 @@ static void spr_store_dump_spr(int sprn) { #ifdef PPC_DUMP_SPR_ACCESSES TCGv_i32 t0 = tcg_const_i32(sprn); - gen_helper_store_dump_spr(t0); + gen_helper_store_dump_spr(cpu_env, t0); tcg_temp_free_i32(t0); #endif } From e13da40448fabb0829d75b01dc57da5f44f391b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 21 Feb 2013 07:34:10 +0000 Subject: [PATCH 1471/1634] PPC: Fix dma interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In openbios (drivers/ide.c) they are set to 0000000d 00000000 00000002 00000000 0000000e 00000000 00000003 00000000 0000000f 00000000 00000004 00000000 (The last one seems to be not implemented in qemu) It follows convention of how they are set on real machines, both ide and dma ones are increased Real machine one: http://web.archive.org/web/20090107151044/http://penguinppc.org/historical/dev-trees-html/g4_agp_500_2.html 00000013 00000001 0000000b 00000000 00000014 00000001 0000000c 00000000 00000015 00000001 0000000d 00000000 Signed-off-by: Amadeusz Sławiński Signed-off-by: Alexander Graf --- hw/ppc/mac_newworld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 065ea871b3..a08a6b2086 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -370,7 +370,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */ qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ - qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */ + qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE DMA */ macio_init(macio, pic_mem, escc_bar); /* We only emulate 2 out of 3 IDE controllers for now */ From 987422bc4a4c6366ca6a7fbfa38a9920fd7ada2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 21 Feb 2013 07:34:11 +0000 Subject: [PATCH 1472/1634] PPC: xnu kernel expects FLUSH to be cleared on STOP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit otherwise it gets stuck in a loop so clear it when unsetting run when flush is set void IODBDMAStop( volatile IODBDMAChannelRegisters *registers) { IOSetDBDMAChannelControl( registers, IOClearDBDMAChannelControlBits( kdbdmaRun ) | IOSetDBDMAChannelControlBits( kdbdmaFlush )); DBDMA: writel 0x0000000000000b00 <= 0xa0002000 DBDMA: channel 0x16 reg 0x0 DBDMA: status 0x00002000 while( IOGetDBDMAChannelStatus( registers) & ( kdbdmaActive | kdbdmaFlush)) eieio(); DBDMA: readl 0x0000000000000b04 => 0x00002000 DBDMA: channel 0x16 reg 0x1 DBDMA: readl 0x0000000000000b04 => 0x00002000 DBDMA: channel 0x16 reg 0x1 DBDMA: readl 0x0000000000000b04 => 0x00002000 DBDMA: channel 0x16 reg 0x1 DBDMA: readl 0x0000000000000b04 => 0x00002000 DBDMA: channel 0x16 reg 0x1 it continues to get printed } Signed-off-by: Amadeusz Sławiński [agraf: replace tabs with spaces] Signed-off-by: Alexander Graf --- hw/mac_dbdma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index b894ab21aa..73d74c2c59 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -688,6 +688,10 @@ dbdma_control_write(DBDMA_channel *ch) if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) { /* RUN is cleared */ status &= ~(ACTIVE|DEAD); + if ((status & FLUSH) && ch->flush) { + ch->flush(&ch->io); + status &= ~FLUSH; + } } DBDMA_DPRINTF(" status 0x%08x\n", status); From 5ba4576b858c0d6056f59abb7e17a2b63f7905f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 23 Feb 2013 11:22:12 +0000 Subject: [PATCH 1473/1634] target-ppc: Make host CPU a subclass of the host's CPU model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids assigning individual class fields and contributors forgetting to add field assignments in KVM-only code. ppc_cpu_class_find_by_pvr() requires the CPU model classes to be registered, so defer host CPU type registration to kvm_arch_init(). Only register the host CPU type if there is a class with matching PVR. This lets us drop error handling from instance_init. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 66 +++++++++++++------------------------ target-ppc/translate_init.c | 15 +++++---- 2 files changed, 31 insertions(+), 50 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 44511592b4..9dff7607f1 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -81,6 +81,8 @@ static void kvm_kick_cpu(void *opaque) qemu_cpu_kick(CPU(cpu)); } +static int kvm_ppc_register_host_cpu_type(void); + int kvm_arch_init(KVMState *s) { cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ); @@ -98,6 +100,8 @@ int kvm_arch_init(KVMState *s) "VM to stall at times!\n"); } + kvm_ppc_register_host_cpu_type(); + return 0; } @@ -1488,44 +1492,15 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on) static void kvmppc_host_cpu_initfn(Object *obj) { - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(obj); - assert(kvm_enabled()); - - if (pcc->pvr != mfpvr()) { - fprintf(stderr, "Your host CPU is unsupported.\n" - "Please choose a supported model instead, see -cpu ?.\n"); - exit(1); - } } static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) { PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - uint32_t host_pvr = mfpvr(); - PowerPCCPUClass *pvr_pcc; uint32_t vmx = kvmppc_get_vmx(); uint32_t dfp = kvmppc_get_dfp(); - pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); - if (pvr_pcc != NULL) { - pcc->pvr = pvr_pcc->pvr; - pcc->svr = pvr_pcc->svr; - pcc->insns_flags = pvr_pcc->insns_flags; - pcc->insns_flags2 = pvr_pcc->insns_flags2; - pcc->msr_mask = pvr_pcc->msr_mask; - pcc->mmu_model = pvr_pcc->mmu_model; - pcc->excp_model = pvr_pcc->excp_model; - pcc->bus_model = pvr_pcc->bus_model; - pcc->flags = pvr_pcc->flags; - pcc->bfd_mach = pvr_pcc->bfd_mach; -#ifdef TARGET_PPC64 - pcc->sps = pvr_pcc->sps; -#endif - pcc->init_proc = pvr_pcc->init_proc; - pcc->check_pow = pvr_pcc->check_pow; - } - /* Now fix up the class with information we can query from the host */ if (vmx != -1) { @@ -1552,6 +1527,25 @@ int kvmppc_fixup_cpu(PowerPCCPU *cpu) return 0; } +static int kvm_ppc_register_host_cpu_type(void) +{ + TypeInfo type_info = { + .name = TYPE_HOST_POWERPC_CPU, + .instance_init = kvmppc_host_cpu_initfn, + .class_init = kvmppc_host_cpu_class_init, + }; + uint32_t host_pvr = mfpvr(); + PowerPCCPUClass *pvr_pcc; + + pvr_pcc = ppc_cpu_class_by_pvr(host_pvr); + if (pvr_pcc == NULL) { + return -1; + } + type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc)); + type_register(&type_info); + return 0; +} + bool kvm_arch_stop_on_emulation_error(CPUState *cpu) { @@ -1567,17 +1561,3 @@ int kvm_arch_on_sigbus(int code, void *addr) { return 1; } - -static const TypeInfo kvm_host_cpu_type_info = { - .name = TYPE_HOST_POWERPC_CPU, - .parent = TYPE_POWERPC_CPU, - .instance_init = kvmppc_host_cpu_initfn, - .class_init = kvmppc_host_cpu_class_init, -}; - -static void kvm_ppc_register_types(void) -{ - type_register_static(&kvm_host_cpu_type_info); -} - -type_init(kvm_ppc_register_types) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 1783c22d4d..521cdcca8c 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8298,13 +8298,6 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) const char *p; int i, len; - if (strcasecmp(name, "host") == 0) { - if (kvm_enabled()) { - ret = object_class_by_name(TYPE_HOST_POWERPC_CPU); - } - return ret; - } - /* Check if the given name is a PVR */ len = strlen(name); if (len == 10 && name[0] == '0' && name[1] == 'x') { @@ -8405,6 +8398,9 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) return; } #endif + if (unlikely(strcmp(typename, TYPE_HOST_POWERPC_CPU) == 0)) { + return; + } name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); @@ -8427,6 +8423,11 @@ void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) g_slist_foreach(list, ppc_cpu_list_entry, &s); g_slist_free(list); +#ifdef CONFIG_KVM + cpu_fprintf(f, "\n"); + cpu_fprintf(f, "PowerPC %-16s\n", "host"); +#endif + cpu_fprintf(f, "\n"); for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { ObjectClass *oc = ppc_cpu_class_by_name(ppc_cpu_aliases[i].model); From 55d3d1a4d1a8dca7a0f31dc0d212d7fb219563c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 23 Feb 2013 07:34:28 +0000 Subject: [PATCH 1474/1634] target-ppc: List alias names alongside CPU models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert adding a separate -cpu ? output section for aliases and list them per CPU subclass. Requested-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 521cdcca8c..6fbb7b3d52 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8392,6 +8392,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); const char *typename = object_class_get_name(oc); char *name; + int i; #if defined(TARGET_PPCEMB) if (pcc->mmu_model != POWERPC_MMU_BOOKE) { @@ -8406,6 +8407,16 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", name, pcc->pvr); + for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { + const PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; + ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model); + + if (alias_oc != oc) { + continue; + } + (*s->cpu_fprintf)(s->file, "PowerPC %-16s (alias for %s)\n", + alias->alias, name); + } g_free(name); } @@ -8416,7 +8427,6 @@ void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) .cpu_fprintf = cpu_fprintf, }; GSList *list; - int i; list = object_class_get_list(TYPE_POWERPC_CPU, false); list = g_slist_sort(list, ppc_cpu_list_compare); @@ -8427,17 +8437,6 @@ void ppc_cpu_list(FILE *f, fprintf_function cpu_fprintf) cpu_fprintf(f, "\n"); cpu_fprintf(f, "PowerPC %-16s\n", "host"); #endif - - cpu_fprintf(f, "\n"); - for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { - ObjectClass *oc = ppc_cpu_class_by_name(ppc_cpu_aliases[i].model); - if (oc == NULL) { - /* Hide aliases that point to a TODO or TODO_USER_ONLY model */ - continue; - } - cpu_fprintf(f, "PowerPC %-16s\n", - ppc_cpu_aliases[i].alias); - } } static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) From 35e21d3f53068911a98014577880f76c4734f31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 23 Feb 2013 07:52:24 +0000 Subject: [PATCH 1475/1634] target-ppc: Report CPU aliases for QMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QMP query-cpu-definitions implementation iterated over CPU classes only, which were getting less and less as aliases were extracted. Keep them in QMP as valid -cpu arguments even if not guaranteed stable. Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6fbb7b3d52..8ce9f7a464 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8469,11 +8469,32 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) { CpuDefinitionInfoList *cpu_list = NULL; GSList *list; + int i; list = object_class_get_list(TYPE_POWERPC_CPU, false); g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list); g_slist_free(list); + for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { + const PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; + ObjectClass *oc; + CpuDefinitionInfoList *entry; + CpuDefinitionInfo *info; + + oc = ppc_cpu_class_by_name(alias->model); + if (oc == NULL) { + continue; + } + + info = g_malloc0(sizeof(*info)); + info->name = g_strdup(alias->alias); + + entry = g_malloc0(sizeof(*entry)); + entry->value = info; + entry->next = cpu_list; + cpu_list = entry; + } + return cpu_list; } From e9a9607527746600a1af79ba63494ec596ec8584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 25 Feb 2013 03:43:17 +0000 Subject: [PATCH 1476/1634] target-ppc: Move CPU aliases out of translate_init.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move array of CPU aliases to cpu-models.c, alongside model definitions. This requires to zero-terminate the aliases array since ARRAY_SIZE() can no longer be used in translate_init.c then. Suggested-by: Alexander Graf Signed-off-by: Andreas Färber Signed-off-by: Alexander Graf --- target-ppc/cpu-models.c | 194 ++++++++++++++++++++++++++++++++++ target-ppc/cpu-models.h | 14 +++ target-ppc/translate_init.c | 201 +----------------------------------- 3 files changed, 211 insertions(+), 198 deletions(-) diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 66408c0ceb..20ca84e614 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -1223,3 +1223,197 @@ "PA PA6T") #endif + +/***************************************************************************/ +/* PowerPC CPU aliases */ + +const PowerPCCPUAlias ppc_cpu_aliases[] = { + { "403", "403GC" }, + { "405", "405D4" }, + { "405CR", "405CRc" }, + { "405GP", "405GPd" }, + { "405GPe", "405CRc" }, + { "x2vp7", "x2vp4" }, + { "x2vp50", "x2vp20" }, + + { "440EP", "440EPb" }, + { "440GP", "440GPc" }, + { "440GR", "440GRa" }, + { "440GX", "440GXf" }, + + { "RCPU", "MPC5xx" }, + /* MPC5xx microcontrollers */ + { "MGT560", "MPC5xx" }, + { "MPC509", "MPC5xx" }, + { "MPC533", "MPC5xx" }, + { "MPC534", "MPC5xx" }, + { "MPC555", "MPC5xx" }, + { "MPC556", "MPC5xx" }, + { "MPC560", "MPC5xx" }, + { "MPC561", "MPC5xx" }, + { "MPC562", "MPC5xx" }, + { "MPC563", "MPC5xx" }, + { "MPC564", "MPC5xx" }, + { "MPC565", "MPC5xx" }, + { "MPC566", "MPC5xx" }, + + { "PowerQUICC", "MPC8xx" }, + /* MPC8xx microcontrollers */ + { "MGT823", "MPC8xx" }, + { "MPC821", "MPC8xx" }, + { "MPC823", "MPC8xx" }, + { "MPC850", "MPC8xx" }, + { "MPC852T", "MPC8xx" }, + { "MPC855T", "MPC8xx" }, + { "MPC857", "MPC8xx" }, + { "MPC859", "MPC8xx" }, + { "MPC860", "MPC8xx" }, + { "MPC862", "MPC8xx" }, + { "MPC866", "MPC8xx" }, + { "MPC870", "MPC8xx" }, + { "MPC875", "MPC8xx" }, + { "MPC880", "MPC8xx" }, + { "MPC885", "MPC8xx" }, + + /* PowerPC MPC603 microcontrollers */ + { "MPC8240", "603" }, + + { "MPC52xx", "MPC5200" }, + { "MPC5200", "MPC5200_v12" }, + { "MPC5200B", "MPC5200B_v21" }, + + { "MPC82xx", "MPC8280" }, + { "PowerQUICC-II", "MPC82xx" }, + { "MPC8241", "G2HiP4" }, + { "MPC8245", "G2HiP4" }, + { "MPC8247", "G2leGP3" }, + { "MPC8248", "G2leGP3" }, + { "MPC8250", "MPC8250_HiP4" }, + { "MPC8250_HiP3", "G2HiP3" }, + { "MPC8250_HiP4", "G2HiP4" }, + { "MPC8255", "MPC8255_HiP4" }, + { "MPC8255_HiP3", "G2HiP3" }, + { "MPC8255_HiP4", "G2HiP4" }, + { "MPC8260", "MPC8260_HiP4" }, + { "MPC8260_HiP3", "G2HiP3" }, + { "MPC8260_HiP4", "G2HiP4" }, + { "MPC8264", "MPC8264_HiP4" }, + { "MPC8264_HiP3", "G2HiP3" }, + { "MPC8264_HiP4", "G2HiP4" }, + { "MPC8265", "MPC8265_HiP4" }, + { "MPC8265_HiP3", "G2HiP3" }, + { "MPC8265_HiP4", "G2HiP4" }, + { "MPC8266", "MPC8266_HiP4" }, + { "MPC8266_HiP3", "G2HiP3" }, + { "MPC8266_HiP4", "G2HiP4" }, + { "MPC8270", "G2leGP3" }, + { "MPC8271", "G2leGP3" }, + { "MPC8272", "G2leGP3" }, + { "MPC8275", "G2leGP3" }, + { "MPC8280", "G2leGP3" }, + { "e200", "e200z6" }, + { "e300", "e300c3" }, + { "MPC8347", "MPC8347T" }, + { "MPC8347A", "MPC8347AT" }, + { "MPC8347E", "MPC8347ET" }, + { "MPC8347EA", "MPC8347EAT" }, + { "e500", "e500v2_v22" }, + { "e500v1", "e500_v20" }, + { "e500v2", "e500v2_v22" }, + { "MPC8533", "MPC8533_v11" }, + { "MPC8533E", "MPC8533E_v11" }, + { "MPC8540", "MPC8540_v21" }, + { "MPC8541", "MPC8541_v11" }, + { "MPC8541E", "MPC8541E_v11" }, + { "MPC8543", "MPC8543_v21" }, + { "MPC8543E", "MPC8543E_v21" }, + { "MPC8544", "MPC8544_v11" }, + { "MPC8544E", "MPC8544E_v11" }, + { "MPC8545", "MPC8545_v21" }, + { "MPC8545E", "MPC8545E_v21" }, + { "MPC8547E", "MPC8547E_v21" }, + { "MPC8548", "MPC8548_v21" }, + { "MPC8548E", "MPC8548E_v21" }, + { "MPC8555", "MPC8555_v11" }, + { "MPC8555E", "MPC8555E_v11" }, + { "MPC8560", "MPC8560_v21" }, + { "601", "601_v2" }, + { "601v", "601_v2" }, + { "Vanilla", "603" }, + { "603e", "603e_v4.1" }, + { "Stretch", "603e" }, + { "Vaillant", "603e7v" }, + { "603r", "603e7t" }, + { "Goldeneye", "603r" }, + { "604e", "604e_v2.4" }, + { "Sirocco", "604e" }, + { "Mach5", "604r" }, + { "740", "740_v3.1" }, + { "Arthur", "740" }, + { "750", "750_v3.1" }, + { "Typhoon", "750" }, + { "G3", "750" }, + { "Conan/Doyle", "750p" }, + { "750cl", "750cl_v2.0" }, + { "750cx", "750cx_v2.2" }, + { "750cxe", "750cxe_v3.1b" }, + { "750fx", "750fx_v2.3" }, + { "750gx", "750gx_v1.2" }, + { "750l", "750l_v3.2" }, + { "LoneStar", "750l" }, + { "745", "745_v2.8" }, + { "755", "755_v2.8" }, + { "Goldfinger", "755" }, + { "7400", "7400_v2.9" }, + { "Max", "7400" }, + { "G4", "7400" }, + { "7410", "7410_v1.4" }, + { "Nitro", "7410" }, + { "7448", "7448_v2.1" }, + { "7450", "7450_v2.1" }, + { "Vger", "7450" }, + { "7441", "7441_v2.3" }, + { "7451", "7451_v2.3" }, + { "7445", "7445_v3.2" }, + { "7455", "7455_v3.2" }, + { "Apollo6", "7455" }, + { "7447", "7447_v1.2" }, + { "7457", "7457_v1.2" }, + { "Apollo7", "7457" }, + { "7447A", "7447A_v1.2" }, + { "7457A", "7457A_v1.2" }, + { "Apollo7PM", "7457A_v1.0" }, +#if defined(TARGET_PPC64) + { "Trident", "620" }, + { "POWER3", "630" }, + { "Boxer", "POWER3" }, + { "Dino", "POWER3" }, + { "POWER3+", "631" }, + { "POWER7", "POWER7_v2.3" }, + { "970fx", "970fx_v3.1" }, + { "970mp", "970mp_v1.1" }, + { "Apache", "RS64" }, + { "A35", "RS64" }, + { "NorthStar", "RS64-II" }, + { "A50", "RS64-II" }, + { "Pulsar", "RS64-III" }, + { "IceStar", "RS64-IV" }, + { "IStar", "RS64-IV" }, + { "SStar", "RS64-IV" }, +#endif + { "RIOS", "POWER" }, + { "RSC", "POWER" }, + { "RSC3308", "POWER" }, + { "RSC4608", "POWER" }, + { "RSC2", "POWER2" }, + { "P2SC", "POWER2" }, + + /* Generic PowerPCs */ +#if defined(TARGET_PPC64) + { "ppc64", "970fx" }, +#endif + { "ppc32", "604" }, + { "ppc", "ppc32" }, + { "default", "ppc" }, + { NULL, NULL } +}; diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index edff0f4c3c..a94f835121 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -21,6 +21,20 @@ #ifndef TARGET_PPC_CPU_MODELS_H #define TARGET_PPC_CPU_MODELS_H +/** + * PowerPCCPUAlias: + * @alias: The alias name. + * @model: The CPU model @alias refers to. + * + * A mapping entry from CPU @alias to CPU @model. + */ +typedef struct PowerPCCPUAlias { + const char *alias; + const char *model; +} PowerPCCPUAlias; + +extern const PowerPCCPUAlias ppc_cpu_aliases[]; + /*****************************************************************************/ /* PVR definitions for most known PowerPC */ enum { diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 8ce9f7a464..09ad4ba639 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7181,201 +7181,6 @@ POWERPC_FAMILY(620)(ObjectClass *oc, void *data) #endif /* defined (TARGET_PPC64) */ -typedef struct PowerPCCPUAlias { - const char *alias; - const char *model; -} PowerPCCPUAlias; - -static const PowerPCCPUAlias ppc_cpu_aliases[] = { - { "403", "403GC" }, - { "405", "405D4" }, - { "405CR", "405CRc" }, - { "405GP", "405GPd" }, - { "405GPe", "405CRc" }, - { "x2vp7", "x2vp4" }, - { "x2vp50", "x2vp20" }, - - { "440EP", "440EPb" }, - { "440GP", "440GPc" }, - { "440GR", "440GRa" }, - { "440GX", "440GXf" }, - - { "RCPU", "MPC5xx" }, - /* MPC5xx microcontrollers */ - { "MGT560", "MPC5xx" }, - { "MPC509", "MPC5xx" }, - { "MPC533", "MPC5xx" }, - { "MPC534", "MPC5xx" }, - { "MPC555", "MPC5xx" }, - { "MPC556", "MPC5xx" }, - { "MPC560", "MPC5xx" }, - { "MPC561", "MPC5xx" }, - { "MPC562", "MPC5xx" }, - { "MPC563", "MPC5xx" }, - { "MPC564", "MPC5xx" }, - { "MPC565", "MPC5xx" }, - { "MPC566", "MPC5xx" }, - - { "PowerQUICC", "MPC8xx" }, - /* MPC8xx microcontrollers */ - { "MGT823", "MPC8xx" }, - { "MPC821", "MPC8xx" }, - { "MPC823", "MPC8xx" }, - { "MPC850", "MPC8xx" }, - { "MPC852T", "MPC8xx" }, - { "MPC855T", "MPC8xx" }, - { "MPC857", "MPC8xx" }, - { "MPC859", "MPC8xx" }, - { "MPC860", "MPC8xx" }, - { "MPC862", "MPC8xx" }, - { "MPC866", "MPC8xx" }, - { "MPC870", "MPC8xx" }, - { "MPC875", "MPC8xx" }, - { "MPC880", "MPC8xx" }, - { "MPC885", "MPC8xx" }, - - /* PowerPC MPC603 microcontrollers */ - { "MPC8240", "603" }, - - { "MPC52xx", "MPC5200" }, - { "MPC5200", "MPC5200_v12" }, - { "MPC5200B", "MPC5200B_v21" }, - - { "MPC82xx", "MPC8280" }, - { "PowerQUICC-II", "MPC82xx" }, - { "MPC8241", "G2HiP4" }, - { "MPC8245", "G2HiP4" }, - { "MPC8247", "G2leGP3" }, - { "MPC8248", "G2leGP3" }, - { "MPC8250", "MPC8250_HiP4" }, - { "MPC8250_HiP3", "G2HiP3" }, - { "MPC8250_HiP4", "G2HiP4" }, - { "MPC8255", "MPC8255_HiP4" }, - { "MPC8255_HiP3", "G2HiP3" }, - { "MPC8255_HiP4", "G2HiP4" }, - { "MPC8260", "MPC8260_HiP4" }, - { "MPC8260_HiP3", "G2HiP3" }, - { "MPC8260_HiP4", "G2HiP4" }, - { "MPC8264", "MPC8264_HiP4" }, - { "MPC8264_HiP3", "G2HiP3" }, - { "MPC8264_HiP4", "G2HiP4" }, - { "MPC8265", "MPC8265_HiP4" }, - { "MPC8265_HiP3", "G2HiP3" }, - { "MPC8265_HiP4", "G2HiP4" }, - { "MPC8266", "MPC8266_HiP4" }, - { "MPC8266_HiP3", "G2HiP3" }, - { "MPC8266_HiP4", "G2HiP4" }, - { "MPC8270", "G2leGP3" }, - { "MPC8271", "G2leGP3" }, - { "MPC8272", "G2leGP3" }, - { "MPC8275", "G2leGP3" }, - { "MPC8280", "G2leGP3" }, - { "e200", "e200z6" }, - { "e300", "e300c3" }, - { "MPC8347", "MPC8347T" }, - { "MPC8347A", "MPC8347AT" }, - { "MPC8347E", "MPC8347ET" }, - { "MPC8347EA", "MPC8347EAT" }, - { "e500", "e500v2_v22" }, - { "e500v1", "e500_v20" }, - { "e500v2", "e500v2_v22" }, - { "MPC8533", "MPC8533_v11" }, - { "MPC8533E", "MPC8533E_v11" }, - { "MPC8540", "MPC8540_v21" }, - { "MPC8541", "MPC8541_v11" }, - { "MPC8541E", "MPC8541E_v11" }, - { "MPC8543", "MPC8543_v21" }, - { "MPC8543E", "MPC8543E_v21" }, - { "MPC8544", "MPC8544_v11" }, - { "MPC8544E", "MPC8544E_v11" }, - { "MPC8545", "MPC8545_v21" }, - { "MPC8545E", "MPC8545E_v21" }, - { "MPC8547E", "MPC8547E_v21" }, - { "MPC8548", "MPC8548_v21" }, - { "MPC8548E", "MPC8548E_v21" }, - { "MPC8555", "MPC8555_v11" }, - { "MPC8555E", "MPC8555E_v11" }, - { "MPC8560", "MPC8560_v21" }, - { "601", "601_v2" }, - { "601v", "601_v2" }, - { "Vanilla", "603" }, - { "603e", "603e_v4.1" }, - { "Stretch", "603e" }, - { "Vaillant", "603e7v" }, - { "603r", "603e7t" }, - { "Goldeneye", "603r" }, - { "604e", "604e_v2.4" }, - { "Sirocco", "604e" }, - { "Mach5", "604r" }, - { "740", "740_v3.1" }, - { "Arthur", "740" }, - { "750", "750_v3.1" }, - { "Typhoon", "750" }, - { "G3", "750" }, - { "Conan/Doyle", "750p" }, - { "750cl", "750cl_v2.0" }, - { "750cx", "750cx_v2.2" }, - { "750cxe", "750cxe_v3.1b" }, - { "750fx", "750fx_v2.3" }, - { "750gx", "750gx_v1.2" }, - { "750l", "750l_v3.2" }, - { "LoneStar", "750l" }, - { "745", "745_v2.8" }, - { "755", "755_v2.8" }, - { "Goldfinger", "755" }, - { "7400", "7400_v2.9" }, - { "Max", "7400" }, - { "G4", "7400" }, - { "7410", "7410_v1.4" }, - { "Nitro", "7410" }, - { "7448", "7448_v2.1" }, - { "7450", "7450_v2.1" }, - { "Vger", "7450" }, - { "7441", "7441_v2.3" }, - { "7451", "7451_v2.3" }, - { "7445", "7445_v3.2" }, - { "7455", "7455_v3.2" }, - { "Apollo6", "7455" }, - { "7447", "7447_v1.2" }, - { "7457", "7457_v1.2" }, - { "Apollo7", "7457" }, - { "7447A", "7447A_v1.2" }, - { "7457A", "7457A_v1.2" }, - { "Apollo7PM", "7457A_v1.0" }, -#if defined(TARGET_PPC64) - { "Trident", "620" }, - { "POWER3", "630" }, - { "Boxer", "POWER3" }, - { "Dino", "POWER3" }, - { "POWER3+", "631" }, - { "POWER7", "POWER7_v2.3" }, - { "970fx", "970fx_v3.1" }, - { "970mp", "970mp_v1.1" }, - { "Apache", "RS64" }, - { "A35", "RS64" }, - { "NorthStar", "RS64-II" }, - { "A50", "RS64-II" }, - { "Pulsar", "RS64-III" }, - { "IceStar", "RS64-IV" }, - { "IStar", "RS64-IV" }, - { "SStar", "RS64-IV" }, -#endif - { "RIOS", "POWER" }, - { "RSC", "POWER" }, - { "RSC3308", "POWER" }, - { "RSC4608", "POWER" }, - { "RSC2", "POWER2" }, - { "P2SC", "POWER2" }, - - /* Generic PowerPCs */ -#if defined(TARGET_PPC64) - { "ppc64", "970fx" }, -#endif - { "ppc32", "604" }, - { "ppc", "ppc32" }, - { "default", "ppc" }, -}; - /*****************************************************************************/ /* Generic CPU instantiation routine */ static void init_ppc_proc(PowerPCCPU *cpu) @@ -8316,7 +8121,7 @@ static ObjectClass *ppc_cpu_class_by_name(const char *name) } } - for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { + 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); } @@ -8407,7 +8212,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) strlen(typename) - strlen("-" TYPE_POWERPC_CPU)); (*s->cpu_fprintf)(s->file, "PowerPC %-16s PVR %08x\n", name, pcc->pvr); - for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { + 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); @@ -8475,7 +8280,7 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp) g_slist_foreach(list, ppc_cpu_defs_entry, &cpu_list); g_slist_free(list); - for (i = 0; i < ARRAY_SIZE(ppc_cpu_aliases); i++) { + for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { const PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; ObjectClass *oc; CpuDefinitionInfoList *entry; From d63919c93e6fb0587632adafba82c21e55ea4396 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 25 Feb 2013 19:27:12 +0000 Subject: [PATCH 1477/1634] pseries: Add compatible property to root of device tree Currently, for the pseries machine the device tree supplied by qemu to SLOF and from there to the guest does not include a 'compatible property' at the root level. Usually that works fine, since in this case the compatible property doesn't really give any information not already found in the 'device_type' or 'model' properties. However, the lack of 'compatible' confuses the bootloader install in the SLES11 SP2 and SLES11 SP3 installers. This patch therefore adds a token 'compatible' property to work around that. Signed-off-by: David Gibson Cc: qemu-stable@nongnu.org Signed-off-by: Alexander Graf --- hw/spapr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/spapr.c b/hw/spapr.c index e88a27aa71..fadf70f952 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -260,6 +260,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_begin_node(fdt, ""))); _FDT((fdt_property_string(fdt, "device_type", "chrp"))); _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); + _FDT((fdt_property_string(fdt, "compatible", "qemu,pseries"))); _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); From 1c9d2a1d3c63ab7cee37acdcab92aafad3d6b3fe Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 4 Feb 2013 22:53:25 +0000 Subject: [PATCH 1478/1634] s390: simplify kvm cpu init There is no special code right now and the reset ioctl is done later on in the the reset handler anyway. Lets simplify the cpu init. Signed-off-by: Christian Borntraeger Signed-off-by: Alexander Graf --- target-s390x/kvm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 3929771182..8f111ae732 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -103,13 +103,8 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) int kvm_arch_init_vcpu(CPUState *cpu) { - int ret = 0; - - if (kvm_vcpu_ioctl(cpu, KVM_S390_INITIAL_RESET, NULL) < 0) { - perror("cannot init reset vcpu"); - } - - return ret; + /* nothing todo yet */ + return 0; } void kvm_arch_reset_vcpu(CPUState *cpu) From dd4ad64ada4316d2f61af0e0489e89fe620244db Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 5 Mar 2013 02:22:01 +0000 Subject: [PATCH 1479/1634] s390: virtio-ccw maintainer Add myself as maintainer for virtio-ccw and the s390-ccw-virtio machine. Signed-off-by: Cornelia Huck [agraf: add myself for virtio-ccw machine] Signed-off-by: Alexander Graf --- MAINTAINERS | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2439614ad2..0ca7e1da8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -454,6 +454,14 @@ M: Alexander Graf S: Maintained F: hw/s390-*.c +S390 Virtio-ccw +M: Cornelia Huck +M: Alexander Graf +S: Supported +F: hw/s390x/s390-virtio-ccw.c +F: hw/s390x/css.[hc] +T: git git://github.com/cohuck/qemu virtio-ccw-upstr + UniCore32 Machines ------------- PKUnity-3 SoC initramfs-with-busybox @@ -565,6 +573,12 @@ M: Stefan Hajnoczi S: Supported F: hw/virtio-blk* +virtio-ccw +M: Cornelia Huck +S: Supported +F: hw/s390x/virtio-ccw.[hc] +T: git git://github.com/cohuck/qemu virtio-ccw-upstr + virtio-serial M: Amit Shah S: Supported From 35569cea79fd3f5ccb5b23ca024c7d3aa4d24e75 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 7 Mar 2013 17:21:41 +0100 Subject: [PATCH 1480/1634] Allow virtio-net features for legacy s390 virtio bus Enable all virtio-net features for the legacy s390 virtio bus. This also fixes kernel BUG at /usr/src/packages/BUILD/kernel-default-3.0.58/linux-3.0/drivers/s390/kvm/kvm_virtio.c:121! Signed-off-by: Christian Borntraeger Cc: qemu-stable@nongnu.org Signed-off-by: Alexander Graf --- hw/s390x/s390-virtio-bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 089ed92006..d9b7f83878 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -402,6 +402,7 @@ static const VirtIOBindings virtio_s390_bindings = { static Property s390_virtio_net_properties[] = { DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic), + DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features), DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device, net.txtimer, TX_TIMER_INTERVAL), DEFINE_PROP_INT32("x-txburst", VirtIOS390Device, From 38dd7cc776bbde7edbe60ba5d0abbd156e7e0f2f Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 22 Feb 2013 09:01:32 +0000 Subject: [PATCH 1481/1634] s390/css: Fix subchannel detection We have to consider the m bit to find the real channel subsystem when determining the last subchannel. If we fail to take this into account, removal of a subchannel in the middle of a big list of devices will stop device detection after a reboot. Signed-off-by: Christian Borntraeger Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck Signed-off-by: Alexander Graf --- hw/s390x/css.c | 11 +++++++---- target-s390x/cpu.h | 2 +- target-s390x/ioinst.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 85f6f22a7f..e526a1c86c 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -988,15 +988,18 @@ int css_do_rchp(uint8_t cssid, uint8_t chpid) return 0; } -bool css_schid_final(uint8_t cssid, uint8_t ssid, uint16_t schid) +bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid) { SubchSet *set; + uint8_t real_cssid; - if (cssid > MAX_CSSID || ssid > MAX_SSID || !channel_subsys->css[cssid] || - !channel_subsys->css[cssid]->sch_set[ssid]) { + real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid; + if (real_cssid > MAX_CSSID || ssid > MAX_SSID || + !channel_subsys->css[real_cssid] || + !channel_subsys->css[real_cssid]->sch_set[ssid]) { return true; } - set = channel_subsys->css[cssid]->sch_set[ssid]; + set = channel_subsys->css[real_cssid]->sch_set[ssid]; return schid > find_last_bit(set->schids_used, (MAX_SCHID + 1) / sizeof(unsigned long)); } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index e450db74a2..9cb739da1e 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -404,7 +404,7 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, bool css_subch_visible(SubchDev *sch); void css_conditional_io_interrupt(SubchDev *sch); int css_do_stsch(SubchDev *sch, SCHIB *schib); -bool css_schid_final(uint8_t cssid, uint8_t ssid, uint16_t schid); +bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid); int css_do_msch(SubchDev *sch, SCHIB *schib); int css_do_xsch(SubchDev *sch); int css_do_csch(SubchDev *sch); diff --git a/target-s390x/ioinst.c b/target-s390x/ioinst.c index e3531f365e..28c508d541 100644 --- a/target-s390x/ioinst.c +++ b/target-s390x/ioinst.c @@ -316,7 +316,7 @@ int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb) cc = 3; } } else { - if (css_schid_final(cssid, ssid, schid)) { + if (css_schid_final(m, cssid, ssid, schid)) { cc = 3; /* No more subchannels in this css/ss */ } else { /* Store an empty schib. */ From 8a7df84f9ff4342cae30f4e515e6ac82a0eb0bea Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 22 Feb 2013 09:01:33 +0000 Subject: [PATCH 1482/1634] s390/virtio-ccw: remove redundant call to blockdev_mark_auto_del blockdev_mark_auto_del is already called in virtio-blk-exit. Remove the redundant call. Signed-off-by: Christian Borntraeger Signed-off-by: Jens Freimann Signed-off-by: Alexander Graf --- hw/s390x/virtio-ccw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index d92e42735c..a9cf703d53 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -585,7 +585,6 @@ static int virtio_ccw_blk_init(VirtioCcwDevice *dev) static int virtio_ccw_blk_exit(VirtioCcwDevice *dev) { virtio_blk_exit(dev->vdev); - blockdev_mark_auto_del(dev->blk.conf.bs); return virtio_ccw_exit(dev); } From 1b3048170ad0dad83186a39cbf22471fc32583ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 21 Feb 2013 16:26:45 +0100 Subject: [PATCH 1483/1634] Revert "make_device_config.sh: Fix target path in generated dependency file" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 23bf49b5eca716aaad073f2b47613434e1515cb5. While *-softmmu/config-devices.mak.d is included through *.d pattern via Makefile.target, the make_devices_config.sh call these dependencies are for is in ./Makefile. Therefore revert to original behavior. This should unbreak pci.mak dependencies not propagating. Reported-by: Peter Maydell Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- scripts/make_device_config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh index 81fe94259d..28efd36286 100644 --- a/scripts/make_device_config.sh +++ b/scripts/make_device_config.sh @@ -25,4 +25,4 @@ done process_includes $src > $dest cat $src $all_includes | grep -v '^include' > $dest -echo "`basename $1`: $all_includes" > $dep +echo "$1: $all_includes" > $dep From 880708013357fa5d1c077e2a4a364b65706e09e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 21 Feb 2013 16:26:46 +0100 Subject: [PATCH 1484/1634] make_device_config.sh: Emit dependency file to directory where included MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Placing the config-devices.mak.d file alongside the config-devices.mak file in *-softmmu/ lead to it getting included into through *-softmmu/Makefile in addition to ./Makefile, leading to confusion. Instead, emit it to ./%-config-devices.mak.d, where it is included. Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- Makefile | 2 +- scripts/make_device_config.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2262410f0f..ae22a0f518 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ endif SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR) SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS)) -SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS)) +SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS)) ifeq ($(SUBDIR_DEVICES_MAK),) config-all-devices.mak: diff --git a/scripts/make_device_config.sh b/scripts/make_device_config.sh index 28efd36286..7242707819 100644 --- a/scripts/make_device_config.sh +++ b/scripts/make_device_config.sh @@ -3,7 +3,7 @@ # files from include directives. dest=$1.tmp -dep=$1.d +dep=`dirname $1`-`basename $1`.d src=$2 src_dir=`dirname $src` all_includes= From 916359f66f838481b4a37a45ab27ccd0474ae487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 21 Feb 2013 16:26:47 +0100 Subject: [PATCH 1485/1634] Makefile: Add subdir dependency on config-devices-all.mak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What 23bf49b5eca716aaad073f2b47613434e1515cb5 really seemed to try to fix is that Makefile could recurse into *-softmmu/ subdirectories before a new *-softmmu/config-devices.mak was generated from pci.mak. Fix this by adding a dependency on config-all-devices.mak, which in turn has dependencies on *-softmmu/config-devices.mak. Reported-by: Gerhard Wiesinger Signed-off-by: Andreas Färber Signed-off-by: Blue Swirl --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index ae22a0f518..12c7662667 100644 --- a/Makefile +++ b/Makefile @@ -123,6 +123,9 @@ qemu-options.def: $(SRC_PATH)/qemu-options.hx $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $@") SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS)) +SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES)) + +$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak subdir-%: $(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,) From a4960ef34829c355fdf25b8ee6b869c92393e366 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 5 Mar 2013 08:54:41 -0800 Subject: [PATCH 1486/1634] tcg: Don't make exitreq flag a local temporary The value is not actually live across basic blocks, so there's no need for the local property. This eliminates storing the temporary to its home location at the branch. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- include/exec/gen-icount.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 4e3b17b083..4fc7b2981d 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -15,7 +15,7 @@ static inline void gen_tb_start(void) TCGv_i32 flag; exitreq_label = gen_new_label(); - flag = tcg_temp_local_new_i32(); + flag = tcg_temp_new_i32(); tcg_gen_ld_i32(flag, cpu_env, offsetof(CPUState, tcg_exit_req) - ENV_OFFSET); tcg_gen_brcondi_i32(TCG_COND_NE, flag, 0, exitreq_label); From 7830cf78ac00643930503732834c00387e9e75ff Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 9 Mar 2013 09:56:03 +0000 Subject: [PATCH 1487/1634] baum: fix build 08744c98115cfa144ed3493556024e400b2e2573 removed hw/baum.h but did not adjust hw/baum.c, breaking build. Fix. Signed-off-by: Blue Swirl Message-id: c50406bda98f8b277e8b9004a0012fa5e5c124d0.1362822910.git.blauwirbel@gmail.com Signed-off-by: Anthony Liguori --- hw/baum.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/baum.c b/hw/baum.c index d75b15007d..d8919d54de 100644 --- a/hw/baum.c +++ b/hw/baum.c @@ -25,7 +25,6 @@ #include "char/char.h" #include "qemu/timer.h" #include "usb.h" -#include "baum.h" #include #include #include From 44ab9ed4f859fc6f691ba433c24d354ba93f056f Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 9 Mar 2013 09:56:04 +0000 Subject: [PATCH 1488/1634] qemu-char: fix win32 build 96c6384776d631839a9c8fe02bf135f9ba22586c did not adjust Win32 #ifdeffery properly, breaking build in later commits. Fix. Signed-off-by: Blue Swirl Tested-by: Igor Mitsyanko Message-id: 0ba5565b1ed44380c57d4a5fab86e9549f581ebf.1362822910.git.blauwirbel@gmail.com Signed-off-by: Anthony Liguori --- qemu-char.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index b82d6433d2..04aa589c7e 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -535,8 +535,6 @@ int send_all(int fd, const void *_buf, int len1) } #endif /* !_WIN32 */ -#ifndef _WIN32 - typedef struct IOWatchPoll { GSource *src; @@ -634,6 +632,7 @@ static guint io_add_watch_poll(GIOChannel *channel, return tag; } +#ifndef _WIN32 static GIOChannel *io_channel_from_fd(int fd) { GIOChannel *chan; @@ -649,6 +648,7 @@ static GIOChannel *io_channel_from_fd(int fd) return chan; } +#endif static GIOChannel *io_channel_from_socket(int fd) { @@ -699,6 +699,8 @@ static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1) return len1 - len; } +#ifndef _WIN32 + typedef struct FDCharDriver { CharDriverState *chr; GIOChannel *fd_in, *fd_out; From ec00b51a6c3e6c515c52e6e4564d915ee1f19022 Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Wed, 2 Jan 2013 21:06:35 -0500 Subject: [PATCH 1489/1634] linux-user: Add Alpha socket constants Without these, some networking programs will not work Signed-off-by: Dillon Amburgey Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/socket.h | 69 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/linux-user/socket.h b/linux-user/socket.h index 93d47823d8..339cae5a16 100644 --- a/linux-user/socket.h +++ b/linux-user/socket.h @@ -87,6 +87,75 @@ #define TARGET_SOCK_MAX (SOCK_PACKET + 1) +#elif defined(TARGET_ALPHA) + + /* For setsockopt(2) */ + #define TARGET_SOL_SOCKET 0xffff + + #define TARGET_SO_DEBUG 0x0001 + #define TARGET_SO_REUSEADDR 0x0004 + #define TARGET_SO_KEEPALIVE 0x0008 + #define TARGET_SO_DONTROUTE 0x0010 + #define TARGET_SO_BROADCAST 0x0020 + #define TARGET_SO_LINGER 0x0080 + #define TARGET_SO_OOBINLINE 0x0100 + /* To add :#define TARGET_SO_REUSEPORT 0x0200 */ + + #define TARGET_SO_TYPE 0x1008 + #define TARGET_SO_ERROR 0x1007 + #define TARGET_SO_SNDBUF 0x1001 + #define TARGET_SO_RCVBUF 0x1002 + #define TARGET_SO_SNDBUFFORCE 0x100a + #define TARGET_SO_RCVBUFFORCE 0x100b + #define TARGET_SO_RCVLOWAT 0x1010 + #define TARGET_SO_SNDLOWAT 0x1011 + #define TARGET_SO_RCVTIMEO 0x1012 + #define TARGET_SO_SNDTIMEO 0x1013 + #define TARGET_SO_ACCEPTCONN 0x1014 + #define TARGET_SO_PROTOCOL 0x1028 + #define TARGET_SO_DOMAIN 0x1029 + + /* linux-specific, might as well be the same as on i386 */ + #define TARGET_SO_NO_CHECK 11 + #define TARGET_SO_PRIORITY 12 + #define TARGET_SO_BSDCOMPAT 14 + + #define TARGET_SO_PASSCRED 17 + #define TARGET_SO_PEERCRED 18 + #define TARGET_SO_BINDTODEVICE 25 + + /* Socket filtering */ + #define TARGET_SO_ATTACH_FILTER 26 + #define TARGET_SO_DETACH_FILTER 27 + + #define TARGET_SO_PEERNAME 28 + #define TARGET_SO_TIMESTAMP 29 + #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP + + #define TARGET_SO_PEERSEC 30 + #define TARGET_SO_PASSSEC 34 + #define TARGET_SO_TIMESTAMPNS 35 + #define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS + + /* Security levels - as per NRL IPv6 - don't actually do anything */ + #define TARGET_SO_SECURITY_AUTHENTICATION 19 + #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 20 + #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 21 + + #define TARGET_SO_MARK 36 + + #define TARGET_SO_TIMESTAMPING 37 + #define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING + + #define TARGET_SO_RXQ_OVFL 40 + + #define TARGET_SO_WIFI_STATUS 41 + #define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS + #define TARGET_SO_PEEK_OFF 42 + + /* Instruct lower device to use last 4-bytes of skb data as FCS */ + #define TARGET_SO_NOFCS 43 + #else /* For setsockopt(2) */ From d95ec14fd20ff69881ab26e7ebd1dab4eb851d97 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 31 Dec 2012 21:00:11 +0100 Subject: [PATCH 1490/1634] linux-user: improve print_fcntl() Signed-off-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/strace.c | 97 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 18 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 4e91a6eb9c..9a181460ec 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -462,18 +462,6 @@ UNUSED static struct flags mmap_flags[] = { FLAG_END, }; -UNUSED static struct flags fcntl_flags[] = { - FLAG_TARGET(F_DUPFD), - FLAG_TARGET(F_GETFD), - FLAG_TARGET(F_SETFD), - FLAG_TARGET(F_GETFL), - FLAG_TARGET(F_SETFL), - FLAG_TARGET(F_GETLK), - FLAG_TARGET(F_SETLK), - FLAG_TARGET(F_SETLKW), - FLAG_END, -}; - UNUSED static struct flags clone_flags[] = { FLAG_GENERIC(CLONE_VM), FLAG_GENERIC(CLONE_FS), @@ -867,12 +855,85 @@ print_fcntl(const struct syscallname *name, { print_syscall_prologue(name); print_raw_param("%d", arg0, 0); - print_flags(fcntl_flags, arg1, 0); - /* - * TODO: check flags and print following argument only - * when needed. - */ - print_pointer(arg2, 1); + switch(arg1) { + case TARGET_F_DUPFD: + gemu_log("F_DUPFD,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); + break; + case TARGET_F_GETFD: + gemu_log("F_GETFD"); + break; + case TARGET_F_SETFD: + gemu_log("F_SETFD,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); + break; + case TARGET_F_GETFL: + gemu_log("F_GETFL"); + break; + case TARGET_F_SETFL: + gemu_log("F_SETFL,"); + print_open_flags(arg2, 1); + break; + case TARGET_F_GETLK: + gemu_log("F_GETLK,"); + print_pointer(arg2, 1); + break; + case TARGET_F_SETLK: + gemu_log("F_SETLK,"); + print_pointer(arg2, 1); + break; + case TARGET_F_SETLKW: + gemu_log("F_SETLKW,"); + print_pointer(arg2, 1); + break; + case TARGET_F_GETOWN: + gemu_log("F_GETOWN"); + break; + case TARGET_F_SETOWN: + gemu_log("F_SETOWN,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + break; + case TARGET_F_GETSIG: + gemu_log("F_GETSIG"); + break; + case TARGET_F_SETSIG: + gemu_log("F_SETSIG,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + break; +#if TARGET_ABI_BITS == 32 + case TARGET_F_GETLK64: + gemu_log("F_GETLK64,"); + print_pointer(arg2, 1); + break; + case TARGET_F_SETLK64: + gemu_log("F_SETLK64,"); + print_pointer(arg2, 1); + break; + case TARGET_F_SETLKW64: + gemu_log("F_SETLKW64,"); + print_pointer(arg2, 1); + break; +#endif + case TARGET_F_SETLEASE: + gemu_log("F_SETLEASE,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + break; + case TARGET_F_GETLEASE: + gemu_log("F_GETLEASE"); + break; + case TARGET_F_DUPFD_CLOEXEC: + gemu_log("F_DUPFD_CLOEXEC,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); + break; + case TARGET_F_NOTIFY: + gemu_log("F_NOTIFY,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + break; + default: + print_raw_param(TARGET_ABI_FMT_ld, arg1, 0); + print_pointer(arg2, 1); + break; + } print_syscall_epilogue(name); } #define print_fcntl64 print_fcntl From cce246e0a21577bb2372ab3a7d6789371e087de9 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Sat, 23 Feb 2013 16:14:07 -0700 Subject: [PATCH 1491/1634] linux-user/syscall.c: handle FUTEX_WAIT_BITSET in do_futex Upstream libc has recently changed to start using FUTEX_WAIT_BITSET instead of FUTEX_WAIT and this is causing do_futex to return -TARGET_ENOSYS. Pass bitset in val3 to sys_futex which will be ignored by kernel for the FUTEX_WAIT case. Signed-off-by: John Rigby Signed-off-by: Riku Voipio --- linux-user/syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 19630eaf20..c7fcfc02c6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4922,6 +4922,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, #endif switch (base_op) { case FUTEX_WAIT: + case FUTEX_WAIT_BITSET: if (timeout) { pts = &ts; target_to_host_timespec(pts, timeout); @@ -4929,7 +4930,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout, pts = NULL; } return get_errno(sys_futex(g2h(uaddr), op, tswap32(val), - pts, NULL, 0)); + pts, NULL, val3)); case FUTEX_WAKE: return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0)); case FUTEX_FD: From bfb669f39f2ecd854992924ced20b00163509043 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Sat, 23 Feb 2013 16:14:08 -0700 Subject: [PATCH 1492/1634] linux-user: fix futex strace of FUTEX_CLOCK_REALTIME Handle same as existing FUTEX_PRIVATE_FLAG. Signed-off-by: John Rigby Signed-off-by: Riku Voipio --- linux-user/strace.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/strace.c b/linux-user/strace.c index 9a181460ec..0fbae3c2f6 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1497,6 +1497,12 @@ if( cmd == val ) { \ gemu_log("FUTEX_PRIVATE_FLAG|"); cmd &= ~FUTEX_PRIVATE_FLAG; } +#endif +#ifdef FUTEX_CLOCK_REALTIME + if (cmd & FUTEX_CLOCK_REALTIME) { + gemu_log("FUTEX_CLOCK_REALTIME|"); + cmd &= ~FUTEX_CLOCK_REALTIME; + } #endif print_op(FUTEX_WAIT) print_op(FUTEX_WAKE) From f2b79ce9dc65753c6833921dd5ef6fa59632851f Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Sat, 2 Feb 2013 18:04:48 -0500 Subject: [PATCH 1493/1634] linux-user: Support setgroups syscall with no groups Signed-off-by: Dillon Amburgey Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c7fcfc02c6..1729446840 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7680,18 +7680,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { int gidsetsize = arg1; target_id *target_grouplist; - gid_t *grouplist; + gid_t *grouplist = NULL; int i; - - grouplist = alloca(gidsetsize * sizeof(gid_t)); - target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1); - if (!target_grouplist) { - ret = -TARGET_EFAULT; - goto fail; + if (gidsetsize) { + grouplist = alloca(gidsetsize * sizeof(gid_t)); + target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1); + if (!target_grouplist) { + ret = -TARGET_EFAULT; + goto fail; + } + for (i = 0; i < gidsetsize; i++) { + grouplist[i] = low2highgid(tswapid(target_grouplist[i])); + } + unlock_user(target_grouplist, arg2, 0); } - for(i = 0;i < gidsetsize; i++) - grouplist[i] = low2highgid(tswapid(target_grouplist[i])); - unlock_user(target_grouplist, arg2, 0); ret = get_errno(setgroups(gidsetsize, grouplist)); } break; From 0d95fda86b0d69fc4010f6bb37aa4fd38f1addff Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Thu, 3 Jan 2013 22:10:26 -0500 Subject: [PATCH 1494/1634] linux-user: Add more sparc syscall numbers Signed-off-by: Dillon Amburgey Signed-off-by: Riku Voipio --- linux-user/sparc/syscall_nr.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index 061711cc03..534e6e9963 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -200,6 +200,8 @@ #define TARGET_NR__newselect 230 /* Linux Specific */ #define TARGET_NR_time 231 /* Linux Specific */ #define TARGET_NR_stime 233 /* Linux Specific */ +#define TARGET_NR_statfs64 234 /* Linux Specific */ +#define TARGET_NR_fstatfs64 235 /* Linux Specific */ #define TARGET_NR__llseek 236 /* Linux Specific */ #define TARGET_NR_mlock 237 #define TARGET_NR_munlock 238 From 5da5aad068def65b5e278a6380192d4bfe279585 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:07 +0100 Subject: [PATCH 1495/1634] migration: simplify while loop Unify the goto around the loop, with the exit condition at the end of it. Both can be expressed as "while (ret >= 0)". Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/migration.c b/migration.c index 11725ae3fc..ba8b647dce 100644 --- a/migration.c +++ b/migration.c @@ -666,14 +666,9 @@ static void *buffered_file_thread(void *opaque) qemu_mutex_lock_iothread(); DPRINTF("beginning savevm\n"); ret = qemu_savevm_state_begin(s->file, &s->params); - if (ret < 0) { - DPRINTF("failed, %d\n", ret); - qemu_mutex_unlock_iothread(); - goto out; - } qemu_mutex_unlock_iothread(); - while (true) { + while (ret >= 0) { int64_t current_time; uint64_t pending_size; @@ -754,12 +749,8 @@ static void *buffered_file_thread(void *opaque) sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } ret = buffered_flush(s); - if (ret < 0) { - break; - } } -out: if (ret < 0) { migrate_fd_error(s); } From 891518abd804401978e402d588733e282be960ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:08 +0100 Subject: [PATCH 1496/1634] migration: always use vm_stop_force_state vm_stop_force_state does: if (runstate_is_running()) { vm_stop(state); } else { runstate_set(state); } migration.c does: if (runstate_is_running()) { vm_stop(state); } else { vm_stop_force_state(state); } The code run is the same even if we always use vm_stop_force_state in migration.c. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/migration.c b/migration.c index ba8b647dce..65e8583517 100644 --- a/migration.c +++ b/migration.c @@ -699,11 +699,7 @@ static void *buffered_file_thread(void *opaque) DPRINTF("done iterating\n"); start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - if (old_vm_running) { - vm_stop(RUN_STATE_FINISH_MIGRATE); - } else { - vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - } + vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); ret = qemu_savevm_state_complete(s->file); if (ret < 0) { qemu_mutex_unlock_iothread(); From 7a2c17216cd5ae4c22844123b8e9360d517932f8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:09 +0100 Subject: [PATCH 1497/1634] migration: move more error handling to migrate_fd_cleanup The next patch will add more cases where qemu_savevm_state_cancel needs to be called; prepare for that already, the function can be called twice with no ill effect. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/migration.c b/migration.c index 65e8583517..10ce9fe6a2 100644 --- a/migration.c +++ b/migration.c @@ -260,7 +260,7 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, /* shared migration helpers */ -static int migrate_fd_cleanup(MigrationState *s) +static void migrate_fd_cleanup(MigrationState *s) { int ret = 0; @@ -271,7 +271,13 @@ static int migrate_fd_cleanup(MigrationState *s) } assert(s->fd == -1); - return ret; + if (ret < 0 && s->state == MIG_STATE_ACTIVE) { + s->state = MIG_STATE_ERROR; + } + + if (s->state != MIG_STATE_ACTIVE) { + qemu_savevm_state_cancel(); + } } void migrate_fd_error(MigrationState *s) @@ -285,9 +291,8 @@ void migrate_fd_error(MigrationState *s) static void migrate_fd_completed(MigrationState *s) { DPRINTF("setting completed state\n"); - if (migrate_fd_cleanup(s) < 0) { - s->state = MIG_STATE_ERROR; - } else { + migrate_fd_cleanup(s); + if (s->state == MIG_STATE_ACTIVE) { s->state = MIG_STATE_COMPLETED; runstate_set(RUN_STATE_POSTMIGRATE); } @@ -322,7 +327,6 @@ static void migrate_fd_cancel(MigrationState *s) s->state = MIG_STATE_CANCELLED; notifier_list_notify(&migration_state_notifiers, s); - qemu_savevm_state_cancel(); migrate_fd_cleanup(s); } From 04943ebaa9e4f5f9ac080198a7b0d25c6d7ac444 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:10 +0100 Subject: [PATCH 1498/1634] migration: push qemu_savevm_state_cancel out of qemu_savevm_state_* This is useful, because it lets us keep the cancellation callbacks inside the big lock while pushing the others out. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- savevm.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/savevm.c b/savevm.c index a8a53efc9b..4302903e7c 100644 --- a/savevm.c +++ b/savevm.c @@ -1621,17 +1621,11 @@ int qemu_savevm_state_begin(QEMUFile *f, ret = se->ops->save_live_setup(f, se->opaque); if (ret < 0) { - qemu_savevm_state_cancel(); return ret; } } ret = qemu_file_get_error(f); - if (ret != 0) { - qemu_savevm_state_cancel(); - } - return ret; - } /* @@ -1677,9 +1671,6 @@ int qemu_savevm_state_iterate(QEMUFile *f) return ret; } ret = qemu_file_get_error(f); - if (ret != 0) { - qemu_savevm_state_cancel(); - } return ret; } @@ -1778,8 +1769,7 @@ static int qemu_savevm_state(QEMUFile *f) }; if (qemu_savevm_state_blocked(NULL)) { - ret = -EINVAL; - goto out; + return -EINVAL; } ret = qemu_savevm_state_begin(f, ¶ms); @@ -1798,6 +1788,9 @@ out: if (ret == 0) { ret = qemu_file_get_error(f); } + if (ret != 0) { + qemu_savevm_state_cancel(); + } return ret; } From d418cf57a3e699746ef0bfa772bbe8c7e17cebb5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:11 +0100 Subject: [PATCH 1499/1634] block-migration: remove useless calls to blk_mig_cleanup Now that the cancel callback is called consistently for all errors, we can avoid doing its work in the other callbacks. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- block-migration.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/block-migration.c b/block-migration.c index 43ab2028c0..e6c917d952 100644 --- a/block-migration.c +++ b/block-migration.c @@ -524,16 +524,10 @@ static int block_save_setup(QEMUFile *f, void *opaque) set_dirty_tracking(1); ret = flush_blks(f); - if (ret) { - blk_mig_cleanup(); - return ret; - } - blk_mig_reset_dirty_cursor(); - qemu_put_be64(f, BLK_MIG_FLAG_EOS); - return 0; + return ret; } static int block_save_iterate(QEMUFile *f, void *opaque) @@ -546,7 +540,6 @@ static int block_save_iterate(QEMUFile *f, void *opaque) ret = flush_blks(f); if (ret) { - blk_mig_cleanup(); return ret; } @@ -564,20 +557,18 @@ static int block_save_iterate(QEMUFile *f, void *opaque) } } else { ret = blk_mig_save_dirty_block(f, 1); + if (ret < 0) { + return ret; + } if (ret != 0) { /* no more dirty blocks */ break; } } } - if (ret < 0) { - blk_mig_cleanup(); - return ret; - } ret = flush_blks(f); if (ret) { - blk_mig_cleanup(); return ret; } @@ -595,7 +586,6 @@ static int block_save_complete(QEMUFile *f, void *opaque) ret = flush_blks(f); if (ret) { - blk_mig_cleanup(); return ret; } @@ -607,12 +597,11 @@ static int block_save_complete(QEMUFile *f, void *opaque) do { ret = blk_mig_save_dirty_block(f, 0); + if (ret < 0) { + return ret; + } } while (ret == 0); - blk_mig_cleanup(); - if (ret < 0) { - return ret; - } /* report completion */ qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS); @@ -620,6 +609,7 @@ static int block_save_complete(QEMUFile *f, void *opaque) qemu_put_be64(f, BLK_MIG_FLAG_EOS); + blk_mig_cleanup(); return 0; } From 93bf21044c38134bc7d35577b675d9f2bdcb8419 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:12 +0100 Subject: [PATCH 1500/1634] qemu-file: pass errno from qemu_fflush via f->last_error This is done by almost all callers of qemu_fflush, move the code directly to qemu_fflush. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- savevm.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/savevm.c b/savevm.c index 4302903e7c..a681177964 100644 --- a/savevm.c +++ b/savevm.c @@ -453,13 +453,13 @@ static void qemu_file_set_error(QEMUFile *f, int ret) /** Flushes QEMUFile buffer * */ -static int qemu_fflush(QEMUFile *f) +static void qemu_fflush(QEMUFile *f) { int ret = 0; - if (!f->ops->put_buffer) - return 0; - + if (!f->ops->put_buffer) { + return; + } if (f->is_write && f->buf_index > 0) { ret = f->ops->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); if (ret >= 0) { @@ -467,7 +467,9 @@ static int qemu_fflush(QEMUFile *f) } f->buf_index = 0; } - return ret; + if (ret < 0) { + qemu_file_set_error(f, ret); + } } static void qemu_fill_buffer(QEMUFile *f) @@ -518,7 +520,8 @@ int qemu_get_fd(QEMUFile *f) int qemu_fclose(QEMUFile *f) { int ret; - ret = qemu_fflush(f); + qemu_fflush(f); + ret = qemu_file_get_error(f); if (f->ops->close) { int ret2 = f->ops->close(f->opaque); @@ -560,9 +563,8 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) buf += l; size -= l; if (f->buf_index >= IO_BUF_SIZE) { - int ret = qemu_fflush(f); - if (ret < 0) { - qemu_file_set_error(f, ret); + qemu_fflush(f); + if (qemu_file_get_error(f)) { break; } } @@ -584,10 +586,7 @@ void qemu_put_byte(QEMUFile *f, int v) f->buf[f->buf_index++] = v; f->is_write = 1; if (f->buf_index >= IO_BUF_SIZE) { - int ret = qemu_fflush(f); - if (ret < 0) { - qemu_file_set_error(f, ret); - } + qemu_fflush(f); } } From 47c8c17af883b5bd0f147cfcec8d7ef8ff76023b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:13 +0100 Subject: [PATCH 1501/1634] migration: use qemu_file_set_error to pass error codes back to qemu_savevm_state Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/sysemu/sysemu.h | 6 +++--- savevm.c | 44 +++++++++++++++++------------------------ 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index b19ec952b4..6578782fc3 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -73,10 +73,10 @@ void do_info_snapshots(Monitor *mon, const QDict *qdict); void qemu_announce_self(void); bool qemu_savevm_state_blocked(Error **errp); -int qemu_savevm_state_begin(QEMUFile *f, - const MigrationParams *params); +void qemu_savevm_state_begin(QEMUFile *f, + const MigrationParams *params); int qemu_savevm_state_iterate(QEMUFile *f); -int qemu_savevm_state_complete(QEMUFile *f); +void qemu_savevm_state_complete(QEMUFile *f); void qemu_savevm_state_cancel(void); uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size); int qemu_loadvm_state(QEMUFile *f); diff --git a/savevm.c b/savevm.c index a681177964..a1690b4ddc 100644 --- a/savevm.c +++ b/savevm.c @@ -1579,8 +1579,8 @@ bool qemu_savevm_state_blocked(Error **errp) return false; } -int qemu_savevm_state_begin(QEMUFile *f, - const MigrationParams *params) +void qemu_savevm_state_begin(QEMUFile *f, + const MigrationParams *params) { SaveStateEntry *se; int ret; @@ -1620,11 +1620,10 @@ int qemu_savevm_state_begin(QEMUFile *f, ret = se->ops->save_live_setup(f, se->opaque); if (ret < 0) { - return ret; + qemu_file_set_error(f, ret); + break; } } - ret = qemu_file_get_error(f); - return ret; } /* @@ -1658,6 +1657,9 @@ int qemu_savevm_state_iterate(QEMUFile *f) ret = se->ops->save_live_iterate(f, se->opaque); trace_savevm_section_end(se->section_id); + if (ret < 0) { + qemu_file_set_error(f, ret); + } if (ret <= 0) { /* Do not proceed to the next vmstate before this one reported completion of the current stage. This serializes the migration @@ -1666,14 +1668,10 @@ int qemu_savevm_state_iterate(QEMUFile *f) break; } } - if (ret != 0) { - return ret; - } - ret = qemu_file_get_error(f); return ret; } -int qemu_savevm_state_complete(QEMUFile *f) +void qemu_savevm_state_complete(QEMUFile *f) { SaveStateEntry *se; int ret; @@ -1697,7 +1695,8 @@ int qemu_savevm_state_complete(QEMUFile *f) ret = se->ops->save_live_complete(f, se->opaque); trace_savevm_section_end(se->section_id); if (ret < 0) { - return ret; + qemu_file_set_error(f, ret); + return; } } @@ -1725,8 +1724,6 @@ int qemu_savevm_state_complete(QEMUFile *f) } qemu_put_byte(f, QEMU_VM_EOF); - - return qemu_file_get_error(f); } uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size) @@ -1771,26 +1768,21 @@ static int qemu_savevm_state(QEMUFile *f) return -EINVAL; } - ret = qemu_savevm_state_begin(f, ¶ms); - if (ret < 0) - goto out; + qemu_savevm_state_begin(f, ¶ms); + while (qemu_file_get_error(f) == 0) { + if (qemu_savevm_state_iterate(f) > 0) { + break; + } + } - do { - ret = qemu_savevm_state_iterate(f); - if (ret < 0) - goto out; - } while (ret == 0); - - ret = qemu_savevm_state_complete(f); - -out: + ret = qemu_file_get_error(f); if (ret == 0) { + qemu_savevm_state_complete(f); ret = qemu_file_get_error(f); } if (ret != 0) { qemu_savevm_state_cancel(); } - return ret; } From 4eb938102b3d533e142de23e255e46da1326fc5a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:14 +0100 Subject: [PATCH 1502/1634] qemu-file: temporarily expose qemu_file_set_error and qemu_fflush Right now, migration cannot entirely rely on QEMUFile's automatic drop of I/O after an error, because it does its "real" I/O outside the put_buffer callback. To fix this until buffering is gone, expose qemu_file_set_error which we will use in buffered_flush. Similarly, buffered_flush is not a complete flush because some data may still reside in the QEMUFile's own buffer. This somewhat complicates the process of closing the migration thread. Again, when buffering is gone buffered_flush will disappear and calling qemu_fflush will not be needed; in the meanwhile, we expose the function for use in migration.c. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/qemu-file.h | 2 ++ savevm.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 46fc11dc99..5e0c287793 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -82,6 +82,7 @@ QEMUFile *qemu_popen_cmd(const char *command, const char *mode); int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); int64_t qemu_ftell(QEMUFile *f); +void qemu_fflush(QEMUFile *f); void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); void qemu_put_byte(QEMUFile *f, int v); @@ -113,6 +114,7 @@ int qemu_file_rate_limit(QEMUFile *f); int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_get_error(QEMUFile *f); +void qemu_file_set_error(QEMUFile *f, int ret); static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) { diff --git a/savevm.c b/savevm.c index a1690b4ddc..e10a045df6 100644 --- a/savevm.c +++ b/savevm.c @@ -443,7 +443,7 @@ int qemu_file_get_error(QEMUFile *f) return f->last_error; } -static void qemu_file_set_error(QEMUFile *f, int ret) +void qemu_file_set_error(QEMUFile *f, int ret) { if (f->last_error == 0) { f->last_error = ret; @@ -453,7 +453,7 @@ static void qemu_file_set_error(QEMUFile *f, int ret) /** Flushes QEMUFile buffer * */ -static void qemu_fflush(QEMUFile *f) +void qemu_fflush(QEMUFile *f) { int ret = 0; From f5821518ed6d49aae9fd0aa6169d2d74bb83054c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:15 +0100 Subject: [PATCH 1503/1634] migration: flush all data to fd when buffered_flush is called Including data that resided in the QEMUFile's own buffer. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/migration.c b/migration.c index 10ce9fe6a2..c5a7f29eb7 100644 --- a/migration.c +++ b/migration.c @@ -525,6 +525,8 @@ static ssize_t buffered_flush(MigrationState *s) DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); + qemu_fflush(s->file); + while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { size_t to_send = MIN(s->buffer_size - offset, s->xfer_limit - s->bytes_xfer); ret = migrate_fd_put_buffer(s, s->buffer + offset, to_send); From 63dfbd7ee03185c181a0791958ec9c8337089b55 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:16 +0100 Subject: [PATCH 1504/1634] migration: use qemu_file_set_error Remove the return value of buffered_flush, pass it via the error code of s->file. Once this is done, the error can be retrieved simply via migrate_fd_close's call to qemu_fclose. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/migration.c b/migration.c index c5a7f29eb7..939c3f7640 100644 --- a/migration.c +++ b/migration.c @@ -518,7 +518,7 @@ int64_t migrate_xbzrle_cache_size(void) /* migration thread support */ -static ssize_t buffered_flush(MigrationState *s) +static void buffered_flush(MigrationState *s) { size_t offset = 0; ssize_t ret = 0; @@ -545,9 +545,8 @@ static ssize_t buffered_flush(MigrationState *s) s->buffer_size -= offset; if (ret < 0) { - return ret; + qemu_file_set_error(s->file, ret); } - return offset; } static int buffered_put_buffer(void *opaque, const uint8_t *buf, @@ -586,25 +585,15 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, static int buffered_close(void *opaque) { MigrationState *s = opaque; - ssize_t ret = 0; - int ret2; DPRINTF("closing\n"); s->xfer_limit = INT_MAX; while (!qemu_file_get_error(s->file) && s->buffer_size) { - ret = buffered_flush(s); - if (ret < 0) { - break; - } - } - - ret2 = migrate_fd_close(s); - if (ret >= 0) { - ret = ret2; + buffered_flush(s); } s->complete = true; - return ret; + return migrate_fd_close(s); } static int buffered_get_fd(void *opaque) @@ -750,7 +739,8 @@ static void *buffered_file_thread(void *opaque) g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } - ret = buffered_flush(s); + buffered_flush(s); + ret = qemu_file_get_error(s->file); } if (ret < 0) { From dba433c03a0f5dc22a459435dd89557886298921 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:17 +0100 Subject: [PATCH 1505/1634] migration: simplify error handling Always use qemu_file_get_error to detect errors, since that is how QEMUFile itself drops I/O after an error occurs. There is no need to propagate and check return values all the time. Also remove the "complete" member, since we know that it is set (via migrate_fd_cleanup) only when the state changes. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/migration.h | 1 - migration.c | 46 +++++++++++------------------------ 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index d1214097fe..3e680af7f6 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -54,7 +54,6 @@ struct MigrationState int64_t dirty_bytes_rate; bool enabled_capabilities[MIGRATION_CAPABILITY_MAX]; int64_t xbzrle_cache_size; - bool complete; }; void process_incoming_migration(QEMUFile *f); diff --git a/migration.c b/migration.c index 939c3f7640..18f97cfed3 100644 --- a/migration.c +++ b/migration.c @@ -525,6 +525,10 @@ static void buffered_flush(MigrationState *s) DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); + if (qemu_file_get_error(s->file)) { + s->buffer_size = 0; + return; + } qemu_fflush(s->file); while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { @@ -592,7 +596,6 @@ static int buffered_close(void *opaque) while (!qemu_file_get_error(s->file) && s->buffer_size) { buffered_flush(s); } - s->complete = true; return migrate_fd_close(s); } @@ -656,37 +659,21 @@ static void *buffered_file_thread(void *opaque) int64_t sleep_time = 0; int64_t max_size = 0; bool last_round = false; - int ret; qemu_mutex_lock_iothread(); DPRINTF("beginning savevm\n"); - ret = qemu_savevm_state_begin(s->file, &s->params); - qemu_mutex_unlock_iothread(); + qemu_savevm_state_begin(s->file, &s->params); - while (ret >= 0) { + while (s->state == MIG_STATE_ACTIVE) { int64_t current_time; uint64_t pending_size; - qemu_mutex_lock_iothread(); - if (s->state != MIG_STATE_ACTIVE) { - DPRINTF("put_ready returning because of non-active state\n"); - qemu_mutex_unlock_iothread(); - break; - } - if (s->complete) { - qemu_mutex_unlock_iothread(); - break; - } if (s->bytes_xfer < s->xfer_limit) { DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); DPRINTF("pending size %lu max %lu\n", pending_size, max_size); if (pending_size && pending_size >= max_size) { - ret = qemu_savevm_state_iterate(s->file); - if (ret < 0) { - qemu_mutex_unlock_iothread(); - break; - } + qemu_savevm_state_iterate(s->file); } else { int old_vm_running = runstate_is_running(); int64_t start_time, end_time; @@ -695,13 +682,8 @@ static void *buffered_file_thread(void *opaque) start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - ret = qemu_savevm_state_complete(s->file); - if (ret < 0) { - qemu_mutex_unlock_iothread(); - break; - } else { - migrate_fd_completed(s); - } + qemu_savevm_state_complete(s->file); + migrate_fd_completed(s); end_time = qemu_get_clock_ms(rt_clock); s->total_time = end_time - s->total_time; s->downtime = end_time - start_time; @@ -740,12 +722,13 @@ static void *buffered_file_thread(void *opaque) sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } buffered_flush(s); - ret = qemu_file_get_error(s->file); + qemu_mutex_lock_iothread(); + if (qemu_file_get_error(s->file)) { + migrate_fd_error(s); + } } - if (ret < 0) { - migrate_fd_error(s); - } + qemu_mutex_unlock_iothread(); g_free(s->buffer); return NULL; } @@ -770,7 +753,6 @@ void migrate_fd_connect(MigrationState *s) s->expected_downtime = max_downtime/1000000; s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; - s->complete = false; s->file = qemu_fopen_ops(s, &buffered_file_ops); From a3fa1d78cbae2259491b17689812edcb643a3b30 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:18 +0100 Subject: [PATCH 1506/1634] migration: do not nest flushing of device data Completion of migration is currently done with a "nested" loop that invokes buffered_flush: migrate_fd_completed is called by buffered_file_thread, which calls migrate_fd_cleanup, which calls buffered_close (via qemu_fclose), which flushes the buffer. Simplify this, by reusing the buffered_flush call of buffered_file_thread. Then if qemu_savevm_state_complete was called, and the buffer is empty (including the QEMUFile buffer, for which we need the previous patch), we are done. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 55 +++++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/migration.c b/migration.c index 18f97cfed3..9a234c7b08 100644 --- a/migration.c +++ b/migration.c @@ -262,41 +262,34 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, static void migrate_fd_cleanup(MigrationState *s) { - int ret = 0; - if (s->file) { DPRINTF("closing file\n"); - ret = qemu_fclose(s->file); + qemu_fclose(s->file); s->file = NULL; } assert(s->fd == -1); - if (ret < 0 && s->state == MIG_STATE_ACTIVE) { - s->state = MIG_STATE_ERROR; - } + assert(s->state != MIG_STATE_ACTIVE); - if (s->state != MIG_STATE_ACTIVE) { + if (s->state != MIG_STATE_COMPLETED) { qemu_savevm_state_cancel(); } + + notifier_list_notify(&migration_state_notifiers, s); } void migrate_fd_error(MigrationState *s) { DPRINTF("setting error state\n"); s->state = MIG_STATE_ERROR; - notifier_list_notify(&migration_state_notifiers, s); migrate_fd_cleanup(s); } static void migrate_fd_completed(MigrationState *s) { DPRINTF("setting completed state\n"); + s->state = MIG_STATE_COMPLETED; migrate_fd_cleanup(s); - if (s->state == MIG_STATE_ACTIVE) { - s->state = MIG_STATE_COMPLETED; - runstate_set(RUN_STATE_POSTMIGRATE); - } - notifier_list_notify(&migration_state_notifiers, s); } static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, @@ -326,8 +319,6 @@ static void migrate_fd_cancel(MigrationState *s) DPRINTF("cancelling migration\n"); s->state = MIG_STATE_CANCELLED; - notifier_list_notify(&migration_state_notifiers, s); - migrate_fd_cleanup(s); } @@ -592,10 +583,6 @@ static int buffered_close(void *opaque) DPRINTF("closing\n"); - s->xfer_limit = INT_MAX; - while (!qemu_file_get_error(s->file) && s->buffer_size) { - buffered_flush(s); - } return migrate_fd_close(s); } @@ -658,6 +645,8 @@ static void *buffered_file_thread(void *opaque) int64_t initial_time = qemu_get_clock_ms(rt_clock); int64_t sleep_time = 0; int64_t max_size = 0; + int64_t start_time = initial_time; + bool old_vm_running = false; bool last_round = false; qemu_mutex_lock_iothread(); @@ -675,23 +664,13 @@ static void *buffered_file_thread(void *opaque) if (pending_size && pending_size >= max_size) { qemu_savevm_state_iterate(s->file); } else { - int old_vm_running = runstate_is_running(); - int64_t start_time, end_time; - DPRINTF("done iterating\n"); start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + old_vm_running = runstate_is_running(); vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + s->xfer_limit = INT_MAX; qemu_savevm_state_complete(s->file); - migrate_fd_completed(s); - end_time = qemu_get_clock_ms(rt_clock); - s->total_time = end_time - s->total_time; - s->downtime = end_time - start_time; - if (s->state != MIG_STATE_COMPLETED) { - if (old_vm_running) { - vm_start(); - } - } last_round = true; } } @@ -725,6 +704,20 @@ static void *buffered_file_thread(void *opaque) qemu_mutex_lock_iothread(); if (qemu_file_get_error(s->file)) { migrate_fd_error(s); + } else if (last_round && s->buffer_size == 0) { + migrate_fd_completed(s); + } + } + + if (s->state == MIG_STATE_COMPLETED) { + int64_t end_time = qemu_get_clock_ms(rt_clock); + s->total_time = end_time - s->total_time; + s->downtime = end_time - start_time; + runstate_set(RUN_STATE_POSTMIGRATE); + } else { + if (old_vm_running) { + assert(last_round); + vm_start(); } } From c09e5bb1d88ef38986bac7c6ed59dbd732cc4771 Mon Sep 17 00:00:00 2001 From: Kazuya Saito Date: Fri, 22 Feb 2013 17:36:19 +0100 Subject: [PATCH 1507/1634] migration: add migrate_set_state tracepoint Signed-off-by: Kazuya Saito Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 9 ++++++++- trace-events | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index 9a234c7b08..b091532152 100644 --- a/migration.c +++ b/migration.c @@ -23,6 +23,7 @@ #include "migration/block.h" #include "qemu/thread.h" #include "qmp-commands.h" +#include "trace.h" //#define DEBUG_MIGRATION @@ -282,6 +283,7 @@ void migrate_fd_error(MigrationState *s) { DPRINTF("setting error state\n"); s->state = MIG_STATE_ERROR; + trace_migrate_set_state(MIG_STATE_ERROR); migrate_fd_cleanup(s); } @@ -289,6 +291,7 @@ static void migrate_fd_completed(MigrationState *s) { DPRINTF("setting completed state\n"); s->state = MIG_STATE_COMPLETED; + trace_migrate_set_state(MIG_STATE_COMPLETED); migrate_fd_cleanup(s); } @@ -319,6 +322,7 @@ static void migrate_fd_cancel(MigrationState *s) DPRINTF("cancelling migration\n"); s->state = MIG_STATE_CANCELLED; + trace_migrate_set_state(MIG_STATE_CANCELLED); migrate_fd_cleanup(s); } @@ -377,8 +381,9 @@ static MigrationState *migrate_init(const MigrationParams *params) s->bandwidth_limit = bandwidth_limit; s->state = MIG_STATE_SETUP; - s->total_time = qemu_get_clock_ms(rt_clock); + trace_migrate_set_state(MIG_STATE_SETUP); + s->total_time = qemu_get_clock_ms(rt_clock); return s; } @@ -738,6 +743,8 @@ static const QEMUFileOps buffered_file_ops = { void migrate_fd_connect(MigrationState *s) { s->state = MIG_STATE_ACTIVE; + trace_migrate_set_state(MIG_STATE_ACTIVE); + s->bytes_xfer = 0; s->buffer = NULL; s->buffer_size = 0; diff --git a/trace-events b/trace-events index 3064fc7767..8389d83568 100644 --- a/trace-events +++ b/trace-events @@ -1091,3 +1091,6 @@ css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, # hw/s390x/virtio-ccw.c virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x" virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)" + +# migration.c +migrate_set_state(int new_state) "new state %d" From f4410a5d9926886c36d9fa9fdd969d0469d62724 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:20 +0100 Subject: [PATCH 1508/1634] migration: prepare to access s->state outside critical sections Accessing s->state outside the big QEMU lock will simplify a bit the locking/unlocking of the iothread lock. We need to keep the lock in migrate_fd_error and migrate_fd_completed, however, because they call migrate_fd_cleanup. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/migration.c b/migration.c index b091532152..b40755f8ad 100644 --- a/migration.c +++ b/migration.c @@ -279,19 +279,25 @@ static void migrate_fd_cleanup(MigrationState *s) notifier_list_notify(&migration_state_notifiers, s); } +static void migrate_finish_set_state(MigrationState *s, int new_state) +{ + if (__sync_val_compare_and_swap(&s->state, MIG_STATE_ACTIVE, + new_state) == new_state) { + trace_migrate_set_state(new_state); + } +} + void migrate_fd_error(MigrationState *s) { DPRINTF("setting error state\n"); - s->state = MIG_STATE_ERROR; - trace_migrate_set_state(MIG_STATE_ERROR); + migrate_finish_set_state(s, MIG_STATE_ERROR); migrate_fd_cleanup(s); } static void migrate_fd_completed(MigrationState *s) { DPRINTF("setting completed state\n"); - s->state = MIG_STATE_COMPLETED; - trace_migrate_set_state(MIG_STATE_COMPLETED); + migrate_finish_set_state(s, MIG_STATE_COMPLETED); migrate_fd_cleanup(s); } @@ -316,13 +322,9 @@ static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, static void migrate_fd_cancel(MigrationState *s) { - if (s->state != MIG_STATE_ACTIVE) - return; - DPRINTF("cancelling migration\n"); - s->state = MIG_STATE_CANCELLED; - trace_migrate_set_state(MIG_STATE_CANCELLED); + migrate_finish_set_state(s, MIG_STATE_CANCELLED); migrate_fd_cleanup(s); } @@ -657,12 +659,14 @@ static void *buffered_file_thread(void *opaque) qemu_mutex_lock_iothread(); DPRINTF("beginning savevm\n"); qemu_savevm_state_begin(s->file, &s->params); + qemu_mutex_unlock_iothread(); while (s->state == MIG_STATE_ACTIVE) { int64_t current_time; uint64_t pending_size; if (s->bytes_xfer < s->xfer_limit) { + qemu_mutex_lock_iothread(); DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); DPRINTF("pending size %lu max %lu\n", pending_size, max_size); @@ -678,8 +682,9 @@ static void *buffered_file_thread(void *opaque) qemu_savevm_state_complete(s->file); last_round = true; } + qemu_mutex_unlock_iothread(); } - qemu_mutex_unlock_iothread(); + current_time = qemu_get_clock_ms(rt_clock); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = s->bytes_xfer; @@ -706,14 +711,18 @@ static void *buffered_file_thread(void *opaque) sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } buffered_flush(s); - qemu_mutex_lock_iothread(); if (qemu_file_get_error(s->file)) { + qemu_mutex_lock_iothread(); migrate_fd_error(s); + qemu_mutex_unlock_iothread(); } else if (last_round && s->buffer_size == 0) { + qemu_mutex_lock_iothread(); migrate_fd_completed(s); + qemu_mutex_unlock_iothread(); } } + qemu_mutex_lock_iothread(); if (s->state == MIG_STATE_COMPLETED) { int64_t end_time = qemu_get_clock_ms(rt_clock); s->total_time = end_time - s->total_time; @@ -725,8 +734,8 @@ static void *buffered_file_thread(void *opaque) vm_start(); } } - qemu_mutex_unlock_iothread(); + g_free(s->buffer); return NULL; } From bb1fadc444ff967554c41d96cb9dde110e8aece9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:21 +0100 Subject: [PATCH 1509/1634] migration: cleanup migration (including thread) in the iothread Perform final cleanup in a bottom half, and add joining the thread to the series of cleanup actions. migrate_fd_error remains for connection error, but it doesn't need to cleanup anything anymore. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/migration.h | 1 + migration.c | 38 ++++++++++++++++++----------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index 3e680af7f6..ed20bed03c 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -38,6 +38,7 @@ struct MigrationState size_t buffer_size; size_t buffer_capacity; QemuThread thread; + QEMUBH *cleanup_bh; QEMUFile *file; int fd; diff --git a/migration.c b/migration.c index b40755f8ad..729578b730 100644 --- a/migration.c +++ b/migration.c @@ -261,8 +261,13 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params, /* shared migration helpers */ -static void migrate_fd_cleanup(MigrationState *s) +static void migrate_fd_cleanup(void *opaque) { + MigrationState *s = opaque; + + qemu_bh_delete(s->cleanup_bh); + s->cleanup_bh = NULL; + if (s->file) { DPRINTF("closing file\n"); qemu_fclose(s->file); @@ -290,15 +295,10 @@ static void migrate_finish_set_state(MigrationState *s, int new_state) void migrate_fd_error(MigrationState *s) { DPRINTF("setting error state\n"); - migrate_finish_set_state(s, MIG_STATE_ERROR); - migrate_fd_cleanup(s); -} - -static void migrate_fd_completed(MigrationState *s) -{ - DPRINTF("setting completed state\n"); - migrate_finish_set_state(s, MIG_STATE_COMPLETED); - migrate_fd_cleanup(s); + assert(s->file == NULL); + s->state = MIG_STATE_ERROR; + trace_migrate_set_state(MIG_STATE_ERROR); + notifier_list_notify(&migration_state_notifiers, s); } static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, @@ -325,7 +325,6 @@ static void migrate_fd_cancel(MigrationState *s) DPRINTF("cancelling migration\n"); migrate_finish_set_state(s, MIG_STATE_CANCELLED); - migrate_fd_cleanup(s); } int migrate_fd_close(MigrationState *s) @@ -590,6 +589,11 @@ static int buffered_close(void *opaque) DPRINTF("closing\n"); + qemu_mutex_unlock_iothread(); + qemu_thread_join(&s->thread); + qemu_mutex_lock_iothread(); + assert(s->state != MIG_STATE_ACTIVE); + return migrate_fd_close(s); } @@ -712,13 +716,9 @@ static void *buffered_file_thread(void *opaque) } buffered_flush(s); if (qemu_file_get_error(s->file)) { - qemu_mutex_lock_iothread(); - migrate_fd_error(s); - qemu_mutex_unlock_iothread(); + migrate_finish_set_state(s, MIG_STATE_ERROR); } else if (last_round && s->buffer_size == 0) { - qemu_mutex_lock_iothread(); - migrate_fd_completed(s); - qemu_mutex_unlock_iothread(); + migrate_finish_set_state(s, MIG_STATE_COMPLETED); } } @@ -734,6 +734,7 @@ static void *buffered_file_thread(void *opaque) vm_start(); } } + qemu_bh_schedule(s->cleanup_bh); qemu_mutex_unlock_iothread(); g_free(s->buffer); @@ -763,9 +764,10 @@ void migrate_fd_connect(MigrationState *s) s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; + s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); s->file = qemu_fopen_ops(s, &buffered_file_ops); qemu_thread_create(&s->thread, buffered_file_thread, s, - QEMU_THREAD_DETACHED); + QEMU_THREAD_JOINABLE); notifier_list_notify(&migration_state_notifiers, s); } From a55ce1c851b5802569fb00b2a645a73c03fd7c86 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:22 +0100 Subject: [PATCH 1510/1634] block-migration: remove variables that are never read Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- block-migration.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/block-migration.c b/block-migration.c index e6c917d952..e72f322bc7 100644 --- a/block-migration.c +++ b/block-migration.c @@ -50,7 +50,6 @@ typedef struct BlkMigDevState { int64_t cur_dirty; int64_t completed_sectors; int64_t total_sectors; - int64_t dirty; QSIMPLEQ_ENTRY(BlkMigDevState) entry; unsigned long *aio_bitmap; } BlkMigDevState; @@ -78,7 +77,6 @@ typedef struct BlkMigState { int64_t total_sector_sum; int prev_progress; int bulk_completed; - long double prev_time_offset; } BlkMigState; static BlkMigState block_mig_state; @@ -179,13 +177,10 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds) static void blk_mig_read_cb(void *opaque, int ret) { - long double curr_time = qemu_get_clock_ns(rt_clock); BlkMigBlock *blk = opaque; blk->ret = ret; - block_mig_state.prev_time_offset = curr_time; - QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); bmds_set_aio_inflight(blk->bmds, blk->sector, blk->nr_sectors, 0); @@ -236,10 +231,6 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); - if (block_mig_state.submitted == 0) { - block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock); - } - blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); block_mig_state.submitted++; @@ -382,10 +373,6 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); - if (block_mig_state.submitted == 0) { - block_mig_state.prev_time_offset = qemu_get_clock_ns(rt_clock); - } - blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); block_mig_state.submitted++; From 13197e3cbaba0ba693dd2855a32182ca584fa97e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:23 +0100 Subject: [PATCH 1511/1634] block-migration: small preparatory changes for locking Some small changes that will simplify the positioning of lock/unlock primitives. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- block-migration.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/block-migration.c b/block-migration.c index e72f322bc7..9a40edd457 100644 --- a/block-migration.c +++ b/block-migration.c @@ -231,9 +231,10 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); + block_mig_state.submitted++; + blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); - block_mig_state.submitted++; bdrv_reset_dirty(bs, cur_sector, nr_sectors); bmds->cur_sector = cur_sector + nr_sectors; @@ -440,9 +441,10 @@ static int flush_blks(QEMUFile *f) ret = blk->ret; break; } - blk_send(f, blk); QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry); + blk_send(f, blk); + g_free(blk->buf); g_free(blk); @@ -542,15 +544,16 @@ static int block_save_iterate(QEMUFile *f, void *opaque) /* finished saving bulk on all devices */ block_mig_state.bulk_completed = 1; } + ret = 0; } else { ret = blk_mig_save_dirty_block(f, 1); - if (ret < 0) { - return ret; - } - if (ret != 0) { - /* no more dirty blocks */ - break; - } + } + if (ret < 0) { + return ret; + } + if (ret != 0) { + /* no more dirty blocks */ + break; } } @@ -560,7 +563,6 @@ static int block_save_iterate(QEMUFile *f, void *opaque) } qemu_put_be64(f, BLK_MIG_FLAG_EOS); - return qemu_ftell(f) - last_ftell; } @@ -603,7 +605,9 @@ static int block_save_complete(QEMUFile *f, void *opaque) static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) { /* Estimate pending number of bytes to send */ - uint64_t pending = get_remaining_dirty() + + uint64_t pending; + + pending = get_remaining_dirty() + block_mig_state.submitted * BLOCK_SIZE + block_mig_state.read_done * BLOCK_SIZE; From 323920c4eac01de74cf2b5e941c97ca9b2d36b7f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:24 +0100 Subject: [PATCH 1512/1634] block-migration: document usage of state across threads Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- block-migration.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/block-migration.c b/block-migration.c index 9a40edd457..d62a8b80ba 100644 --- a/block-migration.c +++ b/block-migration.c @@ -43,18 +43,24 @@ #endif typedef struct BlkMigDevState { + /* Written during setup phase. Can be read without a lock. */ BlockDriverState *bs; - int bulk_completed; int shared_base; - int64_t cur_sector; - int64_t cur_dirty; - int64_t completed_sectors; int64_t total_sectors; QSIMPLEQ_ENTRY(BlkMigDevState) entry; + + /* Only used by migration thread. Does not need a lock. */ + int bulk_completed; + int64_t cur_sector; + int64_t cur_dirty; + + /* Protected by iothread lock. */ unsigned long *aio_bitmap; + int64_t completed_sectors; } BlkMigDevState; typedef struct BlkMigBlock { + /* Only used by migration thread. */ uint8_t *buf; BlkMigDevState *bmds; int64_t sector; @@ -62,19 +68,26 @@ typedef struct BlkMigBlock { struct iovec iov; QEMUIOVector qiov; BlockDriverAIOCB *aiocb; + + /* Protected by iothread lock. */ int ret; QSIMPLEQ_ENTRY(BlkMigBlock) entry; } BlkMigBlock; typedef struct BlkMigState { + /* Written during setup phase. Can be read without a lock. */ int blk_enable; int shared_base; QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list; + int64_t total_sector_sum; + + /* Protected by iothread lock. */ QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list; int submitted; int read_done; + + /* Only used by migration thread. Does not need a lock. */ int transferred; - int64_t total_sector_sum; int prev_progress; int bulk_completed; } BlkMigState; From 52e850dea988585c3d693fd9cd4a4c38968d89b8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:25 +0100 Subject: [PATCH 1513/1634] block-migration: add lock Some state is shared between the block migration code and its AIO callbacks. Once block migration will run outside the iothread, the block migration code and the AIO callbacks will be able to run concurrently. Protect the critical sections with a separate lock. Do the same for completed_sectors, which can be used from the monitor. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- block-migration.c | 54 ++++++++++++++++++++++++++++++++++++++++--- include/qemu/atomic.h | 1 + 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/block-migration.c b/block-migration.c index d62a8b80ba..b726c6c002 100644 --- a/block-migration.c +++ b/block-migration.c @@ -54,7 +54,7 @@ typedef struct BlkMigDevState { int64_t cur_sector; int64_t cur_dirty; - /* Protected by iothread lock. */ + /* Protected by block migration lock. */ unsigned long *aio_bitmap; int64_t completed_sectors; } BlkMigDevState; @@ -69,7 +69,7 @@ typedef struct BlkMigBlock { QEMUIOVector qiov; BlockDriverAIOCB *aiocb; - /* Protected by iothread lock. */ + /* Protected by block migration lock. */ int ret; QSIMPLEQ_ENTRY(BlkMigBlock) entry; } BlkMigBlock; @@ -81,7 +81,7 @@ typedef struct BlkMigState { QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list; int64_t total_sector_sum; - /* Protected by iothread lock. */ + /* Protected by lock. */ QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list; int submitted; int read_done; @@ -90,10 +90,23 @@ typedef struct BlkMigState { int transferred; int prev_progress; int bulk_completed; + + /* Lock must be taken _inside_ the iothread lock. */ + QemuMutex lock; } BlkMigState; static BlkMigState block_mig_state; +static void blk_mig_lock(void) +{ + qemu_mutex_lock(&block_mig_state.lock); +} + +static void blk_mig_unlock(void) +{ + qemu_mutex_unlock(&block_mig_state.lock); +} + static void blk_send(QEMUFile *f, BlkMigBlock * blk) { int len; @@ -120,9 +133,11 @@ uint64_t blk_mig_bytes_transferred(void) BlkMigDevState *bmds; uint64_t sum = 0; + blk_mig_lock(); QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { sum += bmds->completed_sectors; } + blk_mig_unlock(); return sum << BDRV_SECTOR_BITS; } @@ -142,6 +157,9 @@ uint64_t blk_mig_bytes_total(void) return sum << BDRV_SECTOR_BITS; } + +/* Called with migration lock held. */ + static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector) { int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK; @@ -154,6 +172,8 @@ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector) } } +/* Called with migration lock held. */ + static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num, int nb_sectors, int set) { @@ -188,10 +208,13 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds) bmds->aio_bitmap = g_malloc0(bitmap_size); } +/* Never hold migration lock when yielding to the main loop! */ + static void blk_mig_read_cb(void *opaque, int ret) { BlkMigBlock *blk = opaque; + blk_mig_lock(); blk->ret = ret; QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry); @@ -200,6 +223,7 @@ static void blk_mig_read_cb(void *opaque, int ret) block_mig_state.submitted--; block_mig_state.read_done++; assert(block_mig_state.submitted >= 0); + blk_mig_unlock(); } static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) @@ -244,7 +268,9 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&blk->qiov, &blk->iov, 1); + blk_mig_lock(); block_mig_state.submitted++; + blk_mig_unlock(); blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); @@ -366,8 +392,12 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, int ret = -EIO; for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) { + blk_mig_lock(); if (bmds_aio_inflight(bmds, sector)) { + blk_mig_unlock(); bdrv_drain_all(); + } else { + blk_mig_unlock(); } if (bdrv_get_dirty(bmds->bs, sector)) { @@ -389,8 +419,11 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, blk->aiocb = bdrv_aio_readv(bmds->bs, sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); + + blk_mig_lock(); block_mig_state.submitted++; bmds_set_aio_inflight(bmds, sector, nr_sectors, 1); + blk_mig_unlock(); } else { ret = bdrv_read(bmds->bs, sector, blk->buf, nr_sectors); if (ret < 0) { @@ -446,6 +479,7 @@ static int flush_blks(QEMUFile *f) __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, block_mig_state.transferred); + blk_mig_lock(); while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) { if (qemu_file_rate_limit(f)) { break; @@ -456,7 +490,9 @@ static int flush_blks(QEMUFile *f) } QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry); + blk_mig_unlock(); blk_send(f, blk); + blk_mig_lock(); g_free(blk->buf); g_free(blk); @@ -465,6 +501,7 @@ static int flush_blks(QEMUFile *f) block_mig_state.transferred++; assert(block_mig_state.read_done >= 0); } + blk_mig_unlock(); DPRINTF("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__, block_mig_state.submitted, block_mig_state.read_done, @@ -493,6 +530,7 @@ static void blk_mig_cleanup(void) set_dirty_tracking(0); + blk_mig_lock(); while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) { QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry); bdrv_set_in_use(bmds->bs, 0); @@ -506,6 +544,7 @@ static void blk_mig_cleanup(void) g_free(blk->buf); g_free(blk); } + blk_mig_unlock(); } static void block_migration_cancel(void *opaque) @@ -548,9 +587,11 @@ static int block_save_iterate(QEMUFile *f, void *opaque) blk_mig_reset_dirty_cursor(); /* control the rate of transfer */ + blk_mig_lock(); while ((block_mig_state.submitted + block_mig_state.read_done) * BLOCK_SIZE < qemu_file_get_rate_limit(f)) { + blk_mig_unlock(); if (block_mig_state.bulk_completed == 0) { /* first finish the bulk phase */ if (blk_mig_save_bulked_block(f) == 0) { @@ -564,11 +605,13 @@ static int block_save_iterate(QEMUFile *f, void *opaque) if (ret < 0) { return ret; } + blk_mig_lock(); if (ret != 0) { /* no more dirty blocks */ break; } } + blk_mig_unlock(); ret = flush_blks(f); if (ret) { @@ -595,7 +638,9 @@ static int block_save_complete(QEMUFile *f, void *opaque) /* we know for sure that save bulk is completed and all async read completed */ + blk_mig_lock(); assert(block_mig_state.submitted == 0); + blk_mig_unlock(); do { ret = blk_mig_save_dirty_block(f, 0); @@ -620,6 +665,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) /* Estimate pending number of bytes to send */ uint64_t pending; + blk_mig_lock(); pending = get_remaining_dirty() + block_mig_state.submitted * BLOCK_SIZE + block_mig_state.read_done * BLOCK_SIZE; @@ -628,6 +674,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) if (pending == 0 && !block_mig_state.bulk_completed) { pending = BLOCK_SIZE; } + blk_mig_unlock(); DPRINTF("Enter save live pending %" PRIu64 "\n", pending); return pending; @@ -739,6 +786,7 @@ void blk_mig_init(void) { QSIMPLEQ_INIT(&block_mig_state.bmds_list); QSIMPLEQ_INIT(&block_mig_state.blk_list); + qemu_mutex_init(&block_mig_state.lock); register_savevm_live(NULL, "block", 0, 1, &savevm_block_handlers, &block_mig_state); diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h index 96a194bbee..10becb6101 100644 --- a/include/qemu/atomic.h +++ b/include/qemu/atomic.h @@ -16,6 +16,7 @@ */ #define smp_wmb() barrier() #define smp_rmb() barrier() + /* * We use GCC builtin if it's available, as that can use * mfence on 32 bit as well, e.g. if built with -march=pentium-m. From 8c8de19d93444536d3291e6ab83e2bcf61dd2d0c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:26 +0100 Subject: [PATCH 1514/1634] migration: reorder SaveVMHandlers members This groups together the callbacks that later will have similar locking rules. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/vmstate.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 94a409b708..fdf4e651ad 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -34,13 +34,15 @@ typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); typedef struct SaveVMHandlers { void (*set_params)(const MigrationParams *params, void * opaque); SaveStateHandler *save_state; + int (*save_live_setup)(QEMUFile *f, void *opaque); - int (*save_live_iterate)(QEMUFile *f, void *opaque); - int (*save_live_complete)(QEMUFile *f, void *opaque); - uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size); void (*cancel)(void *opaque); - LoadStateHandler *load_state; + int (*save_live_complete)(QEMUFile *f, void *opaque); bool (*is_active)(void *opaque); + int (*save_live_iterate)(QEMUFile *f, void *opaque); + uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size); + + LoadStateHandler *load_state; } SaveVMHandlers; int register_savevm(DeviceState *dev, From 32c835ba3984728c22d4e73cdb595090a60f437e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:27 +0100 Subject: [PATCH 1515/1634] migration: run pending/iterate callbacks out of big lock This makes it possible to do blocking writes directly to the socket, with no buffer in the middle. For RAM, only the migration_bitmap_sync() call needs the iothread lock. For block migration, it is needed by the block layer (including bdrv_drain_all and dirty bitmap access), but because some code is shared between iterate and complete, all of mig_save_device_dirty is run with the lock taken. In the savevm case, the iterate callback runs within the big lock. This is annoying because it complicates the rules. Luckily we do not need to do anything about it: the RAM iterate callback does not need the iothread lock, and block migration never runs during savevm. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- arch_init.c | 4 ++++ block-migration.c | 37 +++++++++++++++++++++++++++++++++++-- include/migration/vmstate.h | 11 +++++++++++ migration.c | 4 ++-- 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/arch_init.c b/arch_init.c index 8daeafaf5c..32b437897c 100644 --- a/arch_init.c +++ b/arch_init.c @@ -379,6 +379,8 @@ static inline bool migration_bitmap_set_dirty(MemoryRegion *mr, return ret; } +/* Needs iothread lock! */ + static void migration_bitmap_sync(void) { RAMBlock *block; @@ -690,7 +692,9 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE; if (remaining_size < max_size) { + qemu_mutex_lock_iothread(); migration_bitmap_sync(); + qemu_mutex_unlock_iothread(); remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE; } return remaining_size; diff --git a/block-migration.c b/block-migration.c index b726c6c002..8da5f868af 100644 --- a/block-migration.c +++ b/block-migration.c @@ -107,6 +107,10 @@ static void blk_mig_unlock(void) qemu_mutex_unlock(&block_mig_state.lock); } +/* Must run outside of the iothread lock during the bulk phase, + * or the VM will stall. + */ + static void blk_send(QEMUFile *f, BlkMigBlock * blk) { int len; @@ -226,6 +230,8 @@ static void blk_mig_read_cb(void *opaque, int ret) blk_mig_unlock(); } +/* Called with no lock taken. */ + static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) { int64_t total_sectors = bmds->total_sectors; @@ -235,11 +241,13 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) int nr_sectors; if (bmds->shared_base) { + qemu_mutex_lock_iothread(); while (cur_sector < total_sectors && !bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH, &nr_sectors)) { cur_sector += nr_sectors; } + qemu_mutex_unlock_iothread(); } if (cur_sector >= total_sectors) { @@ -272,15 +280,19 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds) block_mig_state.submitted++; blk_mig_unlock(); + qemu_mutex_lock_iothread(); blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov, nr_sectors, blk_mig_read_cb, blk); bdrv_reset_dirty(bs, cur_sector, nr_sectors); - bmds->cur_sector = cur_sector + nr_sectors; + qemu_mutex_unlock_iothread(); + bmds->cur_sector = cur_sector + nr_sectors; return (bmds->cur_sector >= total_sectors); } +/* Called with iothread lock taken. */ + static void set_dirty_tracking(int enable) { BlkMigDevState *bmds; @@ -336,6 +348,8 @@ static void init_blk_migration(QEMUFile *f) bdrv_iterate(init_blk_migration_it, NULL); } +/* Called with no lock taken. */ + static int blk_mig_save_bulked_block(QEMUFile *f) { int64_t completed_sector_sum = 0; @@ -382,6 +396,8 @@ static void blk_mig_reset_dirty_cursor(void) } } +/* Called with iothread lock taken. */ + static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds, int is_async) { @@ -451,7 +467,9 @@ error: return ret; } -/* return value: +/* Called with iothread lock taken. + * + * return value: * 0: too much data for max_downtime * 1: few enough data for max_downtime */ @@ -470,6 +488,8 @@ static int blk_mig_save_dirty_block(QEMUFile *f, int is_async) return ret; } +/* Called with no locks taken. */ + static int flush_blks(QEMUFile *f) { BlkMigBlock *blk; @@ -509,6 +529,8 @@ static int flush_blks(QEMUFile *f) return ret; } +/* Called with iothread lock taken. */ + static int64_t get_remaining_dirty(void) { BlkMigDevState *bmds; @@ -521,6 +543,8 @@ static int64_t get_remaining_dirty(void) return dirty << BDRV_SECTOR_BITS; } +/* Called with iothread lock taken. */ + static void blk_mig_cleanup(void) { BlkMigDevState *bmds; @@ -600,7 +624,12 @@ static int block_save_iterate(QEMUFile *f, void *opaque) } ret = 0; } else { + /* Always called with iothread lock taken for + * simplicity, block_save_complete also calls it. + */ + qemu_mutex_lock_iothread(); ret = blk_mig_save_dirty_block(f, 1); + qemu_mutex_unlock_iothread(); } if (ret < 0) { return ret; @@ -622,6 +651,8 @@ static int block_save_iterate(QEMUFile *f, void *opaque) return qemu_ftell(f) - last_ftell; } +/* Called with iothread lock taken. */ + static int block_save_complete(QEMUFile *f, void *opaque) { int ret; @@ -665,6 +696,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) /* Estimate pending number of bytes to send */ uint64_t pending; + qemu_mutex_lock_iothread(); blk_mig_lock(); pending = get_remaining_dirty() + block_mig_state.submitted * BLOCK_SIZE + @@ -675,6 +707,7 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size) pending = BLOCK_SIZE; } blk_mig_unlock(); + qemu_mutex_unlock_iothread(); DPRINTF("Enter save live pending %" PRIu64 "\n", pending); return pending; diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index fdf4e651ad..a816ac3243 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -32,14 +32,25 @@ typedef void SaveStateHandler(QEMUFile *f, void *opaque); typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); typedef struct SaveVMHandlers { + /* This runs inside the iothread lock. */ void (*set_params)(const MigrationParams *params, void * opaque); SaveStateHandler *save_state; int (*save_live_setup)(QEMUFile *f, void *opaque); void (*cancel)(void *opaque); int (*save_live_complete)(QEMUFile *f, void *opaque); + + /* This runs both outside and inside the iothread lock. */ bool (*is_active)(void *opaque); + + /* This runs outside the iothread lock in the migration case, and + * within the lock in the savevm case. The callback had better only + * use data that is local to the migration thread or protected + * by other locks. + */ int (*save_live_iterate)(QEMUFile *f, void *opaque); + + /* This runs outside the iothread lock! */ uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size); LoadStateHandler *load_state; diff --git a/migration.c b/migration.c index 729578b730..92a7152d67 100644 --- a/migration.c +++ b/migration.c @@ -670,7 +670,6 @@ static void *buffered_file_thread(void *opaque) uint64_t pending_size; if (s->bytes_xfer < s->xfer_limit) { - qemu_mutex_lock_iothread(); DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); DPRINTF("pending size %lu max %lu\n", pending_size, max_size); @@ -678,6 +677,7 @@ static void *buffered_file_thread(void *opaque) qemu_savevm_state_iterate(s->file); } else { DPRINTF("done iterating\n"); + qemu_mutex_lock_iothread(); start_time = qemu_get_clock_ms(rt_clock); qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); old_vm_running = runstate_is_running(); @@ -685,8 +685,8 @@ static void *buffered_file_thread(void *opaque) s->xfer_limit = INT_MAX; qemu_savevm_state_complete(s->file); last_round = true; + qemu_mutex_unlock_iothread(); } - qemu_mutex_unlock_iothread(); } current_time = qemu_get_clock_ms(rt_clock); From 9b0950375277467fd74a9075624477ae43b9bb22 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:28 +0100 Subject: [PATCH 1516/1634] migration: run setup callbacks out of big lock Only the migration_bitmap_sync() call needs the iothread lock. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- arch_init.c | 10 ++++++---- block-migration.c | 2 ++ include/migration/vmstate.h | 2 +- migration.c | 2 -- savevm.c | 3 +++ 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/arch_init.c b/arch_init.c index 32b437897c..6089c53386 100644 --- a/arch_init.c +++ b/arch_init.c @@ -570,10 +570,6 @@ static int ram_save_setup(QEMUFile *f, void *opaque) bitmap_set(migration_bitmap, 0, ram_pages); migration_dirty_pages = ram_pages; - qemu_mutex_lock_ramlist(); - bytes_transferred = 0; - reset_ram_globals(); - if (migrate_use_xbzrle()) { XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() / TARGET_PAGE_SIZE, @@ -587,8 +583,14 @@ static int ram_save_setup(QEMUFile *f, void *opaque) acct_clear(); } + qemu_mutex_lock_iothread(); + qemu_mutex_lock_ramlist(); + bytes_transferred = 0; + reset_ram_globals(); + memory_global_dirty_log_start(); migration_bitmap_sync(); + qemu_mutex_unlock_iothread(); qemu_put_be64(f, ram_bytes_total() | RAM_SAVE_FLAG_MEM_SIZE); diff --git a/block-migration.c b/block-migration.c index 8da5f868af..2fd7699794 100644 --- a/block-migration.c +++ b/block-migration.c @@ -583,10 +583,12 @@ static int block_save_setup(QEMUFile *f, void *opaque) DPRINTF("Enter save live setup submitted %d transferred %d\n", block_mig_state.submitted, block_mig_state.transferred); + qemu_mutex_lock_iothread(); init_blk_migration(f); /* start track dirty blocks */ set_dirty_tracking(1); + qemu_mutex_unlock_iothread(); ret = flush_blks(f); blk_mig_reset_dirty_cursor(); diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index a816ac3243..a64db941bc 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -36,7 +36,6 @@ typedef struct SaveVMHandlers { void (*set_params)(const MigrationParams *params, void * opaque); SaveStateHandler *save_state; - int (*save_live_setup)(QEMUFile *f, void *opaque); void (*cancel)(void *opaque); int (*save_live_complete)(QEMUFile *f, void *opaque); @@ -51,6 +50,7 @@ typedef struct SaveVMHandlers { int (*save_live_iterate)(QEMUFile *f, void *opaque); /* This runs outside the iothread lock! */ + int (*save_live_setup)(QEMUFile *f, void *opaque); uint64_t (*save_live_pending)(QEMUFile *f, void *opaque, uint64_t max_size); LoadStateHandler *load_state; diff --git a/migration.c b/migration.c index 92a7152d67..e64c92d75b 100644 --- a/migration.c +++ b/migration.c @@ -660,10 +660,8 @@ static void *buffered_file_thread(void *opaque) bool old_vm_running = false; bool last_round = false; - qemu_mutex_lock_iothread(); DPRINTF("beginning savevm\n"); qemu_savevm_state_begin(s->file, &s->params); - qemu_mutex_unlock_iothread(); while (s->state == MIG_STATE_ACTIVE) { int64_t current_time; diff --git a/savevm.c b/savevm.c index e10a045df6..7c7774e932 100644 --- a/savevm.c +++ b/savevm.c @@ -1768,7 +1768,10 @@ static int qemu_savevm_state(QEMUFile *f) return -EINVAL; } + qemu_mutex_unlock_iothread(); qemu_savevm_state_begin(f, ¶ms); + qemu_mutex_lock_iothread(); + while (qemu_file_get_error(f) == 0) { if (qemu_savevm_state_iterate(f) > 0) { break; From edaae611f6df0d66a8b5a90c84123b72980c7a22 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:29 +0100 Subject: [PATCH 1517/1634] migration: yay, buffering is gone Buffering was needed because blocking writes could take a long time and starve other threads seeking to grab the big QEMU mutex. Now that all writes (except within _complete callbacks) are done outside the big QEMU mutex, we do not need buffering at all. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/migration.h | 3 -- migration.c | 79 ++++++++++------------------------- savevm.c | 1 + 3 files changed, 22 insertions(+), 61 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index ed20bed03c..cec8643870 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -34,9 +34,6 @@ struct MigrationState int64_t bandwidth_limit; size_t bytes_xfer; size_t xfer_limit; - uint8_t *buffer; - size_t buffer_size; - size_t buffer_capacity; QemuThread thread; QEMUBH *cleanup_bh; diff --git a/migration.c b/migration.c index e64c92d75b..4c8d576701 100644 --- a/migration.c +++ b/migration.c @@ -514,73 +514,41 @@ int64_t migrate_xbzrle_cache_size(void) /* migration thread support */ - -static void buffered_flush(MigrationState *s) -{ - size_t offset = 0; - ssize_t ret = 0; - - DPRINTF("flushing %zu byte(s) of data\n", s->buffer_size); - - if (qemu_file_get_error(s->file)) { - s->buffer_size = 0; - return; - } - qemu_fflush(s->file); - - while (s->bytes_xfer < s->xfer_limit && offset < s->buffer_size) { - size_t to_send = MIN(s->buffer_size - offset, s->xfer_limit - s->bytes_xfer); - ret = migrate_fd_put_buffer(s, s->buffer + offset, to_send); - if (ret <= 0) { - DPRINTF("error flushing data, %zd\n", ret); - break; - } else { - DPRINTF("flushed %zd byte(s)\n", ret); - offset += ret; - s->bytes_xfer += ret; - } - } - - DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size); - memmove(s->buffer, s->buffer + offset, s->buffer_size - offset); - s->buffer_size -= offset; - - if (ret < 0) { - qemu_file_set_error(s->file, ret); - } -} - static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { MigrationState *s = opaque; - ssize_t error; + ssize_t ret; + size_t sent; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); - error = qemu_file_get_error(s->file); - if (error) { - DPRINTF("flush when error, bailing: %s\n", strerror(-error)); - return error; + ret = qemu_file_get_error(s->file); + if (ret) { + DPRINTF("flush when error, bailing: %s\n", strerror(-ret)); + return ret; } if (size <= 0) { return size; } - if (size > (s->buffer_capacity - s->buffer_size)) { - DPRINTF("increasing buffer capacity from %zu by %zu\n", - s->buffer_capacity, size + 1024); - - s->buffer_capacity += size + 1024; - - s->buffer = g_realloc(s->buffer, s->buffer_capacity); + sent = 0; + while (size) { + ret = migrate_fd_put_buffer(s, buf, size); + if (ret <= 0) { + DPRINTF("error flushing data, %zd\n", ret); + return ret; + } else { + DPRINTF("flushed %zd byte(s)\n", ret); + sent += ret; + buf += ret; + size -= ret; + s->bytes_xfer += ret; + } } - memcpy(s->buffer + s->buffer_size, buf, size); - s->buffer_size += size; - - return size; + return sent; } static int buffered_close(void *opaque) @@ -712,10 +680,9 @@ static void *buffered_file_thread(void *opaque) g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } - buffered_flush(s); if (qemu_file_get_error(s->file)) { migrate_finish_set_state(s, MIG_STATE_ERROR); - } else if (last_round && s->buffer_size == 0) { + } else if (last_round) { migrate_finish_set_state(s, MIG_STATE_COMPLETED); } } @@ -735,7 +702,6 @@ static void *buffered_file_thread(void *opaque) qemu_bh_schedule(s->cleanup_bh); qemu_mutex_unlock_iothread(); - g_free(s->buffer); return NULL; } @@ -754,9 +720,6 @@ void migrate_fd_connect(MigrationState *s) trace_migrate_set_state(MIG_STATE_ACTIVE); s->bytes_xfer = 0; - s->buffer = NULL; - s->buffer_size = 0; - s->buffer_capacity = 0; /* This is a best 1st approximation. ns to ms */ s->expected_downtime = max_downtime/1000000; diff --git a/savevm.c b/savevm.c index 7c7774e932..ce10295f5c 100644 --- a/savevm.c +++ b/savevm.c @@ -1724,6 +1724,7 @@ void qemu_savevm_state_complete(QEMUFile *f) } qemu_put_byte(f, QEMU_VM_EOF); + qemu_fflush(f); } uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size) From 5f496a1be3d15f192be1ab1fed3a3278fd5a91a1 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 22 Feb 2013 17:36:30 +0100 Subject: [PATCH 1518/1634] Rename buffered_ to migration_ This is consistent once that we have moved everything to migration.c Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/migration.c b/migration.c index 4c8d576701..861b1245b0 100644 --- a/migration.c +++ b/migration.c @@ -514,7 +514,7 @@ int64_t migrate_xbzrle_cache_size(void) /* migration thread support */ -static int buffered_put_buffer(void *opaque, const uint8_t *buf, +static int migration_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { MigrationState *s = opaque; @@ -551,7 +551,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, return sent; } -static int buffered_close(void *opaque) +static int migration_close(void *opaque) { MigrationState *s = opaque; @@ -565,7 +565,7 @@ static int buffered_close(void *opaque) return migrate_fd_close(s); } -static int buffered_get_fd(void *opaque) +static int migration_get_fd(void *opaque) { MigrationState *s = opaque; @@ -578,7 +578,7 @@ static int buffered_get_fd(void *opaque) * 1: Time to stop * negative: There has been an error */ -static int buffered_rate_limit(void *opaque) +static int migration_rate_limit(void *opaque) { MigrationState *s = opaque; int ret; @@ -595,7 +595,7 @@ static int buffered_rate_limit(void *opaque) return 0; } -static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate) +static int64_t migration_set_rate_limit(void *opaque, int64_t new_rate) { MigrationState *s = opaque; if (qemu_file_get_error(s->file)) { @@ -611,14 +611,14 @@ out: return s->xfer_limit; } -static int64_t buffered_get_rate_limit(void *opaque) +static int64_t migration_get_rate_limit(void *opaque) { MigrationState *s = opaque; return s->xfer_limit; } -static void *buffered_file_thread(void *opaque) +static void *migration_thread(void *opaque) { MigrationState *s = opaque; int64_t initial_time = qemu_get_clock_ms(rt_clock); @@ -705,13 +705,13 @@ static void *buffered_file_thread(void *opaque) return NULL; } -static const QEMUFileOps buffered_file_ops = { - .get_fd = buffered_get_fd, - .put_buffer = buffered_put_buffer, - .close = buffered_close, - .rate_limit = buffered_rate_limit, - .get_rate_limit = buffered_get_rate_limit, - .set_rate_limit = buffered_set_rate_limit, +static const QEMUFileOps migration_file_ops = { + .get_fd = migration_get_fd, + .put_buffer = migration_put_buffer, + .close = migration_close, + .rate_limit = migration_rate_limit, + .get_rate_limit = migration_get_rate_limit, + .set_rate_limit = migration_set_rate_limit, }; void migrate_fd_connect(MigrationState *s) @@ -726,9 +726,9 @@ void migrate_fd_connect(MigrationState *s) s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); - s->file = qemu_fopen_ops(s, &buffered_file_ops); + s->file = qemu_fopen_ops(s, &migration_file_ops); - qemu_thread_create(&s->thread, buffered_file_thread, s, + qemu_thread_create(&s->thread, migration_thread, s, QEMU_THREAD_JOINABLE); notifier_list_notify(&migration_state_notifiers, s); } From 05f28b837c6bd6124abab2496ce15c07a334a5ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:31 +0100 Subject: [PATCH 1519/1634] qemu-file: make qemu_fflush and qemu_file_set_error private again Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/qemu-file.h | 2 -- savevm.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 5e0c287793..46fc11dc99 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -82,7 +82,6 @@ QEMUFile *qemu_popen_cmd(const char *command, const char *mode); int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); int64_t qemu_ftell(QEMUFile *f); -void qemu_fflush(QEMUFile *f); void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); void qemu_put_byte(QEMUFile *f, int v); @@ -114,7 +113,6 @@ int qemu_file_rate_limit(QEMUFile *f); int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_get_error(QEMUFile *f); -void qemu_file_set_error(QEMUFile *f, int ret); static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) { diff --git a/savevm.c b/savevm.c index ce10295f5c..fef2ab9beb 100644 --- a/savevm.c +++ b/savevm.c @@ -443,7 +443,7 @@ int qemu_file_get_error(QEMUFile *f) return f->last_error; } -void qemu_file_set_error(QEMUFile *f, int ret) +static void qemu_file_set_error(QEMUFile *f, int ret) { if (f->last_error == 0) { f->last_error = ret; @@ -453,7 +453,7 @@ void qemu_file_set_error(QEMUFile *f, int ret) /** Flushes QEMUFile buffer * */ -void qemu_fflush(QEMUFile *f) +static void qemu_fflush(QEMUFile *f) { int ret = 0; From 059f896cefb2776181e39d9ba69345bd9d07d52b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:32 +0100 Subject: [PATCH 1520/1634] migration: eliminate last_round We will go around the loop exactly once after setting last_round. Eliminate the variable altogether. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/migration.c b/migration.c index 861b1245b0..612ffa7438 100644 --- a/migration.c +++ b/migration.c @@ -626,7 +626,6 @@ static void *migration_thread(void *opaque) int64_t max_size = 0; int64_t start_time = initial_time; bool old_vm_running = false; - bool last_round = false; DPRINTF("beginning savevm\n"); qemu_savevm_state_begin(s->file, &s->params); @@ -650,8 +649,11 @@ static void *migration_thread(void *opaque) vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); s->xfer_limit = INT_MAX; qemu_savevm_state_complete(s->file); - last_round = true; qemu_mutex_unlock_iothread(); + if (!qemu_file_get_error(s->file)) { + migrate_finish_set_state(s, MIG_STATE_COMPLETED); + break; + } } } @@ -675,15 +677,13 @@ static void *migration_thread(void *opaque) sleep_time = 0; initial_time = current_time; } - if (!last_round && (s->bytes_xfer >= s->xfer_limit)) { + if (s->bytes_xfer >= s->xfer_limit) { /* usleep expects microseconds */ g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } if (qemu_file_get_error(s->file)) { migrate_finish_set_state(s, MIG_STATE_ERROR); - } else if (last_round) { - migrate_finish_set_state(s, MIG_STATE_COMPLETED); } } @@ -695,7 +695,6 @@ static void *migration_thread(void *opaque) runstate_set(RUN_STATE_POSTMIGRATE); } else { if (old_vm_running) { - assert(last_round); vm_start(); } } From fd45ee2c643bb3d55de5c54b50c23859ca631a9f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:33 +0100 Subject: [PATCH 1521/1634] migration: detect error before sleeping Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/migration.c b/migration.c index 612ffa7438..414e0f9023 100644 --- a/migration.c +++ b/migration.c @@ -657,6 +657,10 @@ static void *migration_thread(void *opaque) } } + if (qemu_file_get_error(s->file)) { + migrate_finish_set_state(s, MIG_STATE_ERROR); + break; + } current_time = qemu_get_clock_ms(rt_clock); if (current_time >= initial_time + BUFFER_DELAY) { uint64_t transferred_bytes = s->bytes_xfer; @@ -682,9 +686,6 @@ static void *migration_thread(void *opaque) g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); sleep_time += qemu_get_clock_ms(rt_clock) - current_time; } - if (qemu_file_get_error(s->file)) { - migrate_finish_set_state(s, MIG_STATE_ERROR); - } } qemu_mutex_lock_iothread(); From db2f25309af1af0f27e0ddec4acc3b66837fa668 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:34 +0100 Subject: [PATCH 1522/1634] migration: remove useless qemu_file_get_error check migration_put_buffer is never called if there has been an error. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/migration.c b/migration.c index 414e0f9023..5d99999e47 100644 --- a/migration.c +++ b/migration.c @@ -523,12 +523,6 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf, DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); - ret = qemu_file_get_error(s->file); - if (ret) { - DPRINTF("flush when error, bailing: %s\n", strerror(-ret)); - return ret; - } - if (size <= 0) { return size; } From a0ff044b8ea81908cd8fe5819ce33780f53f58ee Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:35 +0100 Subject: [PATCH 1523/1634] migration: use qemu_file_rate_limit consistently Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration.c b/migration.c index 5d99999e47..f35728da8d 100644 --- a/migration.c +++ b/migration.c @@ -628,7 +628,7 @@ static void *migration_thread(void *opaque) int64_t current_time; uint64_t pending_size; - if (s->bytes_xfer < s->xfer_limit) { + if (!qemu_file_rate_limit(s->file)) { DPRINTF("iterate\n"); pending_size = qemu_savevm_state_pending(s->file, max_size); DPRINTF("pending size %lu max %lu\n", pending_size, max_size); @@ -675,7 +675,7 @@ static void *migration_thread(void *opaque) sleep_time = 0; initial_time = current_time; } - if (s->bytes_xfer >= s->xfer_limit) { + if (qemu_file_rate_limit(s->file)) { /* usleep expects microseconds */ g_usleep((initial_time + BUFFER_DELAY - current_time)*1000); sleep_time += qemu_get_clock_ms(rt_clock) - current_time; From 817b9ed5eb300dbb434d752da416441028539a96 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:36 +0100 Subject: [PATCH 1524/1634] migration: merge qemu_popen_cmd with qemu_popen There is no reason for outgoing exec migration to do popen manually anymore (the reason used to be that we needed the FILE* to make it non-blocking). Use qemu_popen_cmd. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/qemu-file.h | 1 - migration-exec.c | 10 ++++------ savevm.c | 22 ++++++++-------------- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 46fc11dc99..987e719173 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -77,7 +77,6 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops); QEMUFile *qemu_fopen(const char *filename, const char *mode); QEMUFile *qemu_fdopen(int fd, const char *mode); QEMUFile *qemu_fopen_socket(int fd); -QEMUFile *qemu_popen(FILE *popen_file, const char *mode); QEMUFile *qemu_popen_cmd(const char *command, const char *mode); int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); diff --git a/migration-exec.c b/migration-exec.c index a051a6e668..5dc73139a4 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -59,19 +59,17 @@ static int exec_close(MigrationState *s) void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp) { - FILE *f; - - f = popen(command, "w"); + QEMUFile *f; + f = qemu_popen_cmd(command, "w"); if (f == NULL) { error_setg_errno(errp, errno, "failed to popen the migration target"); return; } - s->fd = fileno(f); + s->opaque = f; + s->fd = qemu_get_fd(f); assert(s->fd != -1); - s->opaque = qemu_popen(f, "w"); - s->close = exec_close; s->get_error = file_errno; s->write = file_write; diff --git a/savevm.c b/savevm.c index fef2ab9beb..38699de4a3 100644 --- a/savevm.c +++ b/savevm.c @@ -275,11 +275,17 @@ static const QEMUFileOps stdio_pipe_write_ops = { .close = stdio_pclose }; -QEMUFile *qemu_popen(FILE *stdio_file, const char *mode) +QEMUFile *qemu_popen_cmd(const char *command, const char *mode) { + FILE *stdio_file; QEMUFileStdio *s; - if (stdio_file == NULL || mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { + stdio_file = popen(command, mode); + if (stdio_file == NULL) { + return NULL; + } + + if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) { fprintf(stderr, "qemu_popen: Argument validity check failed\n"); return NULL; } @@ -296,18 +302,6 @@ QEMUFile *qemu_popen(FILE *stdio_file, const char *mode) return s->file; } -QEMUFile *qemu_popen_cmd(const char *command, const char *mode) -{ - FILE *popen_file; - - popen_file = popen(command, mode); - if(popen_file == NULL) { - return NULL; - } - - return qemu_popen(popen_file, mode); -} - static const QEMUFileOps stdio_file_read_ops = { .get_fd = stdio_get_fd, .get_buffer = stdio_get_buffer, From ce39ee3184a02eca7f9529cc19b1582f6f704c70 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:37 +0100 Subject: [PATCH 1525/1634] qemu-file: fsync a writable stdio QEMUFile This is what fd_close does. Prepare for switching to a QEMUFile. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- savevm.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/savevm.c b/savevm.c index 38699de4a3..1d49fde68b 100644 --- a/savevm.c +++ b/savevm.c @@ -256,6 +256,24 @@ static int stdio_fclose(void *opaque) { QEMUFileStdio *s = opaque; int ret = 0; + + if (s->file->ops->put_buffer) { + int fd = fileno(s->stdio_file); + struct stat st; + + ret = fstat(fd, &st); + if (ret == 0 && S_ISREG(st.st_mode)) { + /* + * If the file handle is a regular file make sure the + * data is flushed to disk before signaling success. + */ + ret = fsync(fd); + if (ret != 0) { + ret = -errno; + return ret; + } + } + } if (fclose(s->stdio_file) == EOF) { ret = -errno; } From 13c7b2da073ec83cb47f9582149c8d28bb038e73 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:38 +0100 Subject: [PATCH 1526/1634] qemu-file: check exit status when closing a pipe QEMUFile This is what exec_close does. Move this to the underlying QEMUFile. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/qemu/osdep.h | 7 +++++++ migration-exec.c | 4 ---- savevm.c | 3 +++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 87d3b9cfa8..df244006c7 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -9,6 +9,13 @@ #include #endif +#ifndef _WIN32 +#include +#else +#define WIFEXITED(x) 1 +#define WEXITSTATUS(x) (x) +#endif + #include #if defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10 diff --git a/migration-exec.c b/migration-exec.c index 5dc73139a4..a2b5f8d729 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -50,10 +50,6 @@ static int exec_close(MigrationState *s) ret = qemu_fclose(s->opaque); s->opaque = NULL; s->fd = -1; - if (ret >= 0 && !(WIFEXITED(ret) && WEXITSTATUS(ret) == 0)) { - /* close succeeded, but non-zero exit code: */ - ret = -EIO; /* fake errno value */ - } return ret; } diff --git a/savevm.c b/savevm.c index 1d49fde68b..6d6f1f1ca6 100644 --- a/savevm.c +++ b/savevm.c @@ -247,6 +247,9 @@ static int stdio_pclose(void *opaque) ret = pclose(s->stdio_file); if (ret == -1) { ret = -errno; + } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) { + /* close succeeded, but non-zero exit code: */ + ret = -EIO; /* fake errno value */ } g_free(s); return ret; From 0cc3f3ccc9d29acc94b995430518bda1c7c01bef Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:39 +0100 Subject: [PATCH 1527/1634] qemu-file: add writable socket QEMUFile Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/qemu-file.h | 2 +- migration-tcp.c | 2 +- migration-unix.c | 2 +- savevm.c | 33 +++++++++++++++++++++++++++++++-- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 987e719173..25e84613fa 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -76,7 +76,7 @@ typedef struct QEMUFileOps { QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops); QEMUFile *qemu_fopen(const char *filename, const char *mode); QEMUFile *qemu_fdopen(int fd, const char *mode); -QEMUFile *qemu_fopen_socket(int fd); +QEMUFile *qemu_fopen_socket(int fd, const char *mode); QEMUFile *qemu_popen_cmd(const char *command, const char *mode); int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); diff --git a/migration-tcp.c b/migration-tcp.c index e78a296137..7d975b5e80 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -95,7 +95,7 @@ static void tcp_accept_incoming_migration(void *opaque) goto out; } - f = qemu_fopen_socket(c); + f = qemu_fopen_socket(c, "rb"); if (f == NULL) { fprintf(stderr, "could not qemu_fopen socket\n"); goto out; diff --git a/migration-unix.c b/migration-unix.c index 218835a7a4..4693b43d90 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -95,7 +95,7 @@ static void unix_accept_incoming_migration(void *opaque) goto out; } - f = qemu_fopen_socket(c); + f = qemu_fopen_socket(c, "rb"); if (f == NULL) { fprintf(stderr, "could not qemu_fopen socket\n"); goto out; diff --git a/savevm.c b/savevm.c index 6d6f1f1ca6..76c88c7960 100644 --- a/savevm.c +++ b/savevm.c @@ -198,6 +198,18 @@ static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) return len; } +static int socket_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) +{ + QEMUFileSocket *s = opaque; + ssize_t len; + + len = qemu_send_full(s->fd, buf, size, 0); + if (len < size) { + len = -socket_error(); + } + return len; +} + static int socket_close(void *opaque) { QEMUFileSocket *s = opaque; @@ -369,12 +381,29 @@ static const QEMUFileOps socket_read_ops = { .close = socket_close }; -QEMUFile *qemu_fopen_socket(int fd) +static const QEMUFileOps socket_write_ops = { + .get_fd = socket_get_fd, + .put_buffer = socket_put_buffer, + .close = socket_close +}; + +QEMUFile *qemu_fopen_socket(int fd, const char *mode) { QEMUFileSocket *s = g_malloc0(sizeof(QEMUFileSocket)); + if (mode == NULL || + (mode[0] != 'r' && mode[0] != 'w') || + mode[1] != 'b' || mode[2] != 0) { + fprintf(stderr, "qemu_fopen: Argument validity check failed\n"); + return NULL; + } + s->fd = fd; - s->file = qemu_fopen_ops(s, &socket_read_ops); + if (mode[0] == 'w') { + s->file = qemu_fopen_ops(s, &socket_write_ops); + } else { + s->file = qemu_fopen_ops(s, &socket_read_ops); + } return s->file; } From 3f2d38faab97f4d676c41868a8243997b2aab7cb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:40 +0100 Subject: [PATCH 1528/1634] qemu-file: simplify and export qemu_ftell Force a flush when qemu_ftell is called. This simplifies the buffer magic (it also breaks qemu_ftell for input QEMUFiles, but we never use it). Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- savevm.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/savevm.c b/savevm.c index 76c88c7960..c60ace3218 100644 --- a/savevm.c +++ b/savevm.c @@ -119,8 +119,8 @@ struct QEMUFile { void *opaque; int is_write; - int64_t buf_offset; /* start of buffer when writing, end of buffer - when reading */ + int64_t pos; /* start of buffer when writing, end of buffer + when reading */ int buf_index; int buf_size; /* 0 when writing */ uint8_t buf[IO_BUF_SIZE]; @@ -505,9 +505,9 @@ static void qemu_fflush(QEMUFile *f) return; } if (f->is_write && f->buf_index > 0) { - ret = f->ops->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); + ret = f->ops->put_buffer(f->opaque, f->buf, f->pos, f->buf_index); if (ret >= 0) { - f->buf_offset += f->buf_index; + f->pos += f->buf_index; } f->buf_index = 0; } @@ -534,11 +534,11 @@ static void qemu_fill_buffer(QEMUFile *f) f->buf_index = 0; f->buf_size = pending; - len = f->ops->get_buffer(f->opaque, f->buf + pending, f->buf_offset, + len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, IO_BUF_SIZE - pending); if (len > 0) { f->buf_size += len; - f->buf_offset += len; + f->pos += len; } else if (len == 0) { qemu_file_set_error(f, -EIO); } else if (len != -EAGAIN) @@ -718,12 +718,8 @@ int qemu_get_byte(QEMUFile *f) int64_t qemu_ftell(QEMUFile *f) { - /* buf_offset excludes buffer for writing but includes it for reading */ - if (f->is_write) { - return f->buf_offset + f->buf_index; - } else { - return f->buf_offset - f->buf_size + f->buf_index; - } + qemu_fflush(f); + return f->pos; } int qemu_file_rate_limit(QEMUFile *f) From f8bbc1286337a8506162b5785babe6f2a7de2476 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:41 +0100 Subject: [PATCH 1529/1634] migration: use QEMUFile for migration channel lifetime As a start, use QEMUFile to store the destination and close it. qemu_get_fd gets a file descriptor that will be used by the write callbacks. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/migration.h | 7 ++++--- migration-exec.c | 21 ++------------------- migration-fd.c | 35 +++-------------------------------- migration-tcp.c | 19 +++---------------- migration-unix.c | 19 +++---------------- migration.c | 8 +++++--- savevm.c | 1 + 7 files changed, 21 insertions(+), 89 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index cec8643870..1f8f305ac9 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -38,12 +38,13 @@ struct MigrationState QEMUBH *cleanup_bh; QEMUFile *file; + QEMUFile *migration_file; + int fd; - int state; int (*get_error)(MigrationState *s); - int (*close)(MigrationState *s); int (*write)(MigrationState *s, const void *buff, size_t size); - void *opaque; + + int state; MigrationParams params; int64_t total_time; int64_t downtime; diff --git a/migration-exec.c b/migration-exec.c index a2b5f8d729..8c3f72050a 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -43,33 +43,16 @@ static int file_write(MigrationState *s, const void * buf, size_t size) return write(s->fd, buf, size); } -static int exec_close(MigrationState *s) -{ - int ret = 0; - DPRINTF("exec_close\n"); - ret = qemu_fclose(s->opaque); - s->opaque = NULL; - s->fd = -1; - return ret; -} - void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp) { - QEMUFile *f; - f = qemu_popen_cmd(command, "w"); - if (f == NULL) { + s->migration_file = qemu_popen_cmd(command, "w"); + if (s->migration_file == NULL) { error_setg_errno(errp, errno, "failed to popen the migration target"); return; } - s->opaque = f; - s->fd = qemu_get_fd(f); - assert(s->fd != -1); - - s->close = exec_close; s->get_error = file_errno; s->write = file_write; - migrate_fd_connect(s); } diff --git a/migration-fd.c b/migration-fd.c index a99e0e3971..463645794c 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -40,45 +40,16 @@ static int fd_write(MigrationState *s, const void * buf, size_t size) return write(s->fd, buf, size); } -static int fd_close(MigrationState *s) -{ - struct stat st; - int ret; - - DPRINTF("fd_close\n"); - ret = fstat(s->fd, &st); - if (ret == 0 && S_ISREG(st.st_mode)) { - /* - * If the file handle is a regular file make sure the - * data is flushed to disk before signaling success. - */ - ret = fsync(s->fd); - if (ret != 0) { - ret = -errno; - perror("migration-fd: fsync"); - return ret; - } - } - ret = close(s->fd); - s->fd = -1; - if (ret != 0) { - ret = -errno; - perror("migration-fd: close"); - } - return ret; -} - void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp) { - s->fd = monitor_get_fd(cur_mon, fdname, errp); - if (s->fd == -1) { + int fd = monitor_get_fd(cur_mon, fdname, errp); + if (fd == -1) { return; } + s->migration_file = qemu_fdopen(fd, "wb"); s->get_error = fd_errno; s->write = fd_write; - s->close = fd_close; - migrate_fd_connect(s); } diff --git a/migration-tcp.c b/migration-tcp.c index 7d975b5e80..1e8e00411b 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -39,28 +39,17 @@ static int socket_write(MigrationState *s, const void * buf, size_t size) return send(s->fd, buf, size, 0); } -static int tcp_close(MigrationState *s) -{ - int r = 0; - DPRINTF("tcp_close\n"); - if (closesocket(s->fd) < 0) { - r = -socket_error(); - } - return r; -} - static void tcp_wait_for_connect(int fd, void *opaque) { MigrationState *s = opaque; if (fd < 0) { DPRINTF("migrate connect error\n"); - s->fd = -1; + s->migration_file = NULL; migrate_fd_error(s); } else { DPRINTF("migrate connect success\n"); - s->fd = fd; - socket_set_block(s->fd); + s->migration_file = qemu_fopen_socket(fd, "wb"); migrate_fd_connect(s); } } @@ -69,9 +58,7 @@ void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Erro { s->get_error = socket_errno; s->write = socket_write; - s->close = tcp_close; - - s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp); + inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp); } static void tcp_accept_incoming_migration(void *opaque) diff --git a/migration-unix.c b/migration-unix.c index 4693b43d90..11917f4f2a 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -39,28 +39,17 @@ static int unix_write(MigrationState *s, const void * buf, size_t size) return write(s->fd, buf, size); } -static int unix_close(MigrationState *s) -{ - int r = 0; - DPRINTF("unix_close\n"); - if (close(s->fd) < 0) { - r = -errno; - } - return r; -} - static void unix_wait_for_connect(int fd, void *opaque) { MigrationState *s = opaque; if (fd < 0) { DPRINTF("migrate connect error\n"); - s->fd = -1; + s->migration_file = NULL; migrate_fd_error(s); } else { DPRINTF("migrate connect success\n"); - s->fd = fd; - socket_set_block(s->fd); + s->migration_file = qemu_fopen_socket(fd, "wb"); migrate_fd_connect(s); } } @@ -69,9 +58,7 @@ void unix_start_outgoing_migration(MigrationState *s, const char *path, Error ** { s->get_error = unix_errno; s->write = unix_write; - s->close = unix_close; - - s->fd = unix_nonblocking_connect(path, unix_wait_for_connect, s, errp); + unix_nonblocking_connect(path, unix_wait_for_connect, s, errp); } static void unix_accept_incoming_migration(void *opaque) diff --git a/migration.c b/migration.c index f35728da8d..52126d86cc 100644 --- a/migration.c +++ b/migration.c @@ -274,7 +274,7 @@ static void migrate_fd_cleanup(void *opaque) s->file = NULL; } - assert(s->fd == -1); + assert(s->migration_file == NULL); assert(s->state != MIG_STATE_ACTIVE); if (s->state != MIG_STATE_COMPLETED) { @@ -330,8 +330,9 @@ static void migrate_fd_cancel(MigrationState *s) int migrate_fd_close(MigrationState *s) { int rc = 0; - if (s->fd != -1) { - rc = s->close(s); + if (s->migration_file != NULL) { + rc = qemu_fclose(s->migration_file); + s->migration_file = NULL; s->fd = -1; } return rc; @@ -720,6 +721,7 @@ void migrate_fd_connect(MigrationState *s) s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); + s->fd = qemu_get_fd(s->migration_file); s->file = qemu_fopen_ops(s, &migration_file_ops); qemu_thread_create(&s->thread, migration_thread, s, diff --git a/savevm.c b/savevm.c index c60ace3218..1414f08c1a 100644 --- a/savevm.c +++ b/savevm.c @@ -400,6 +400,7 @@ QEMUFile *qemu_fopen_socket(int fd, const char *mode) s->fd = fd; if (mode[0] == 'w') { + socket_set_block(s->fd); s->file = qemu_fopen_ops(s, &socket_write_ops); } else { s->file = qemu_fopen_ops(s, &socket_read_ops); From e6a1cf21328802f3a83e84e893b8cb8a468141cc Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:42 +0100 Subject: [PATCH 1530/1634] migration: use QEMUFile for writing outgoing migration data Second, drop the file descriptor indirection, and write directly to the QEMUFile. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/migration.h | 4 --- migration-exec.c | 12 --------- migration-fd.c | 12 --------- migration-tcp.c | 12 --------- migration-unix.c | 12 --------- migration.c | 46 ++++++----------------------------- 6 files changed, 8 insertions(+), 90 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index 1f8f305ac9..ae94706bdf 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -40,10 +40,6 @@ struct MigrationState QEMUFile *file; QEMUFile *migration_file; - int fd; - int (*get_error)(MigrationState *s); - int (*write)(MigrationState *s, const void *buff, size_t size); - int state; MigrationParams params; int64_t total_time; diff --git a/migration-exec.c b/migration-exec.c index 8c3f72050a..1c539de931 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -33,16 +33,6 @@ do { } while (0) #endif -static int file_errno(MigrationState *s) -{ - return errno; -} - -static int file_write(MigrationState *s, const void * buf, size_t size) -{ - return write(s->fd, buf, size); -} - void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp) { s->migration_file = qemu_popen_cmd(command, "w"); @@ -51,8 +41,6 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error return; } - s->get_error = file_errno; - s->write = file_write; migrate_fd_connect(s); } diff --git a/migration-fd.c b/migration-fd.c index 463645794c..07c758ab6b 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -30,16 +30,6 @@ do { } while (0) #endif -static int fd_errno(MigrationState *s) -{ - return errno; -} - -static int fd_write(MigrationState *s, const void * buf, size_t size) -{ - return write(s->fd, buf, size); -} - void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp) { int fd = monitor_get_fd(cur_mon, fdname, errp); @@ -48,8 +38,6 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error ** } s->migration_file = qemu_fdopen(fd, "wb"); - s->get_error = fd_errno; - s->write = fd_write; migrate_fd_connect(s); } diff --git a/migration-tcp.c b/migration-tcp.c index 1e8e00411b..5ea4f3d2b6 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -29,16 +29,6 @@ do { } while (0) #endif -static int socket_errno(MigrationState *s) -{ - return socket_error(); -} - -static int socket_write(MigrationState *s, const void * buf, size_t size) -{ - return send(s->fd, buf, size, 0); -} - static void tcp_wait_for_connect(int fd, void *opaque) { MigrationState *s = opaque; @@ -56,8 +46,6 @@ static void tcp_wait_for_connect(int fd, void *opaque) void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp) { - s->get_error = socket_errno; - s->write = socket_write; inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp); } diff --git a/migration-unix.c b/migration-unix.c index 11917f4f2a..64bfa31e35 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -29,16 +29,6 @@ do { } while (0) #endif -static int unix_errno(MigrationState *s) -{ - return errno; -} - -static int unix_write(MigrationState *s, const void * buf, size_t size) -{ - return write(s->fd, buf, size); -} - static void unix_wait_for_connect(int fd, void *opaque) { MigrationState *s = opaque; @@ -56,8 +46,6 @@ static void unix_wait_for_connect(int fd, void *opaque) void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp) { - s->get_error = unix_errno; - s->write = unix_write; unix_nonblocking_connect(path, unix_wait_for_connect, s, errp); } diff --git a/migration.c b/migration.c index 52126d86cc..681a459812 100644 --- a/migration.c +++ b/migration.c @@ -301,25 +301,6 @@ void migrate_fd_error(MigrationState *s) notifier_list_notify(&migration_state_notifiers, s); } -static ssize_t migrate_fd_put_buffer(MigrationState *s, const void *data, - size_t size) -{ - ssize_t ret; - - if (s->state != MIG_STATE_ACTIVE) { - return -EIO; - } - - do { - ret = s->write(s, data, size); - } while (ret == -1 && ((s->get_error(s)) == EINTR)); - - if (ret == -1) - ret = -(s->get_error(s)); - - return ret; -} - static void migrate_fd_cancel(MigrationState *s) { DPRINTF("cancelling migration\n"); @@ -333,7 +314,6 @@ int migrate_fd_close(MigrationState *s) if (s->migration_file != NULL) { rc = qemu_fclose(s->migration_file); s->migration_file = NULL; - s->fd = -1; } return rc; } @@ -519,8 +499,7 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, int size) { MigrationState *s = opaque; - ssize_t ret; - size_t sent; + int ret; DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); @@ -528,22 +507,14 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf, return size; } - sent = 0; - while (size) { - ret = migrate_fd_put_buffer(s, buf, size); - if (ret <= 0) { - DPRINTF("error flushing data, %zd\n", ret); - return ret; - } else { - DPRINTF("flushed %zd byte(s)\n", ret); - sent += ret; - buf += ret; - size -= ret; - s->bytes_xfer += ret; - } + qemu_put_buffer(s->migration_file, buf, size); + ret = qemu_file_get_error(s->migration_file); + if (ret) { + return ret; } - return sent; + s->bytes_xfer += size; + return size; } static int migration_close(void *opaque) @@ -564,7 +535,7 @@ static int migration_get_fd(void *opaque) { MigrationState *s = opaque; - return s->fd; + return qemu_get_fd(s->migration_file); } /* @@ -721,7 +692,6 @@ void migrate_fd_connect(MigrationState *s) s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); - s->fd = qemu_get_fd(s->migration_file); s->file = qemu_fopen_ops(s, &migration_file_ops); qemu_thread_create(&s->thread, migration_thread, s, From be7172e22a9c3bc448894e57f6c2d1af6ffd47fd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:43 +0100 Subject: [PATCH 1531/1634] migration: use qemu_ftell to compute bandwidth Prepare for when s->bytes_xfer will be removed. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/migration.c b/migration.c index 681a459812..6da17461f3 100644 --- a/migration.c +++ b/migration.c @@ -589,6 +589,7 @@ static void *migration_thread(void *opaque) MigrationState *s = opaque; int64_t initial_time = qemu_get_clock_ms(rt_clock); int64_t sleep_time = 0; + int64_t initial_bytes = 0; int64_t max_size = 0; int64_t start_time = initial_time; bool old_vm_running = false; @@ -629,7 +630,7 @@ static void *migration_thread(void *opaque) } current_time = qemu_get_clock_ms(rt_clock); if (current_time >= initial_time + BUFFER_DELAY) { - uint64_t transferred_bytes = s->bytes_xfer; + uint64_t transferred_bytes = qemu_ftell(s->file) - initial_bytes; uint64_t time_spent = current_time - initial_time - sleep_time; double bandwidth = transferred_bytes / time_spent; max_size = bandwidth * migrate_max_downtime() / 1000000; @@ -646,6 +647,7 @@ static void *migration_thread(void *opaque) s->bytes_xfer = 0; sleep_time = 0; initial_time = current_time; + initial_bytes = qemu_ftell(s->file); } if (qemu_file_rate_limit(s->file)) { /* usleep expects microseconds */ From 442773cef15092b5927851237850760345d2cf16 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:44 +0100 Subject: [PATCH 1532/1634] migration: small changes around rate-limiting This patch extracts a few small changes from the next patch, which are unrelated to adding generic rate-limiting functionality to QEMUFile. Make migration_set_rate_limit a simple accessor, and use qemu_file_set_rate_limit consistently. Also fix a typo where INT_MAX should have been SIZE_MAX. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/migration.c b/migration.c index 6da17461f3..1f58d77f76 100644 --- a/migration.c +++ b/migration.c @@ -462,10 +462,15 @@ void qmp_migrate_set_speed(int64_t value, Error **errp) if (value < 0) { value = 0; } + if (value > SIZE_MAX) { + value = SIZE_MAX; + } s = migrate_get_current(); s->bandwidth_limit = value; - qemu_file_set_rate_limit(s->file, s->bandwidth_limit); + if (s->file) { + qemu_file_set_rate_limit(s->file, s->bandwidth_limit / XFER_LIMIT_RATIO); + } } void qmp_migrate_set_downtime(double value, Error **errp) @@ -567,11 +572,8 @@ static int64_t migration_set_rate_limit(void *opaque, int64_t new_rate) if (qemu_file_get_error(s->file)) { goto out; } - if (new_rate > SIZE_MAX) { - new_rate = SIZE_MAX; - } - s->xfer_limit = new_rate / XFER_LIMIT_RATIO; + s->xfer_limit = new_rate; out: return s->xfer_limit; @@ -614,7 +616,7 @@ static void *migration_thread(void *opaque) qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); old_vm_running = runstate_is_running(); vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - s->xfer_limit = INT_MAX; + qemu_file_set_rate_limit(s->file, INT_MAX); qemu_savevm_state_complete(s->file); qemu_mutex_unlock_iothread(); if (!qemu_file_get_error(s->file)) { @@ -691,11 +693,12 @@ void migrate_fd_connect(MigrationState *s) /* This is a best 1st approximation. ns to ms */ s->expected_downtime = max_downtime/1000000; - s->xfer_limit = s->bandwidth_limit / XFER_LIMIT_RATIO; - s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); s->file = qemu_fopen_ops(s, &migration_file_ops); + qemu_file_set_rate_limit(s->file, + s->bandwidth_limit / XFER_LIMIT_RATIO); + qemu_thread_create(&s->thread, migration_thread, s, QEMU_THREAD_JOINABLE); notifier_list_notify(&migration_state_notifiers, s); From 1964a397063967acc5ce71a2a24ed26e74824ee1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:45 +0100 Subject: [PATCH 1533/1634] migration: move rate limiting to QEMUFile Rate limiting is now simply a byte counter; client call qemu_file_rate_limit() manually to determine if they have to exit. So it is possible and simple to move the functionality to QEMUFile. This makes the remaining functionality of s->file redundant; in the next patch we can remove it and write directly to s->migration_file. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- docs/migration.txt | 20 +------------- include/migration/qemu-file.h | 18 ++----------- migration.c | 51 +---------------------------------- savevm.c | 31 +++++++++++---------- 4 files changed, 21 insertions(+), 99 deletions(-) diff --git a/docs/migration.txt b/docs/migration.txt index f3ddd2f1a8..0719a55002 100644 --- a/docs/migration.txt +++ b/docs/migration.txt @@ -55,10 +55,7 @@ QEMUFile with: QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, QEMUFileGetBufferFunc *get_buffer, - QEMUFileCloseFunc *close, - QEMUFileRateLimit *rate_limit, - QEMUFileSetRateLimit *set_rate_limit, - QEMUFileGetRateLimit *get_rate_limit); + QEMUFileCloseFunc *close); The functions have the following functionality: @@ -80,24 +77,9 @@ Close a file and return an error code. typedef int (QEMUFileCloseFunc)(void *opaque); -Called to determine if the file has exceeded its bandwidth allocation. The -bandwidth capping is a soft limit, not a hard limit. - -typedef int (QEMUFileRateLimit)(void *opaque); - -Called to change the current bandwidth allocation. This function must return -the new actual bandwidth. It should be new_rate if everything goes OK, and -the old rate otherwise. - -typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate); -typedef size_t (QEMUFileGetRateLimit)(void *opaque); - You can use any internal state that you need using the opaque void * pointer that is passed to all functions. -The rate limiting functions are used to limit the bandwidth used by -QEMU migration. - The important functions for us are put_buffer()/get_buffer() that allow to write/read a buffer into the QEMUFile. diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index 25e84613fa..df812617f8 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -51,26 +51,11 @@ typedef int (QEMUFileCloseFunc)(void *opaque); */ typedef int (QEMUFileGetFD)(void *opaque); -/* Called to determine if the file has exceeded its bandwidth allocation. The - * bandwidth capping is a soft limit, not a hard limit. - */ -typedef int (QEMUFileRateLimit)(void *opaque); - -/* Called to change the current bandwidth allocation. This function must return - * the new actual bandwidth. It should be new_rate if everything goes ok, and - * the old rate otherwise - */ -typedef int64_t (QEMUFileSetRateLimit)(void *opaque, int64_t new_rate); -typedef int64_t (QEMUFileGetRateLimit)(void *opaque); - typedef struct QEMUFileOps { QEMUFilePutBufferFunc *put_buffer; QEMUFileGetBufferFunc *get_buffer; QEMUFileCloseFunc *close; QEMUFileGetFD *get_fd; - QEMUFileRateLimit *rate_limit; - QEMUFileSetRateLimit *set_rate_limit; - QEMUFileGetRateLimit *get_rate_limit; } QEMUFileOps; QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops); @@ -109,7 +94,8 @@ unsigned int qemu_get_be32(QEMUFile *f); uint64_t qemu_get_be64(QEMUFile *f); int qemu_file_rate_limit(QEMUFile *f); -int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); +void qemu_file_reset_rate_limit(QEMUFile *f); +void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_get_error(QEMUFile *f); diff --git a/migration.c b/migration.c index 1f58d77f76..4b04d50d58 100644 --- a/migration.c +++ b/migration.c @@ -518,7 +518,6 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf, return ret; } - s->bytes_xfer += size; return size; } @@ -543,49 +542,6 @@ static int migration_get_fd(void *opaque) return qemu_get_fd(s->migration_file); } -/* - * The meaning of the return values is: - * 0: We can continue sending - * 1: Time to stop - * negative: There has been an error - */ -static int migration_rate_limit(void *opaque) -{ - MigrationState *s = opaque; - int ret; - - ret = qemu_file_get_error(s->file); - if (ret) { - return ret; - } - - if (s->bytes_xfer >= s->xfer_limit) { - return 1; - } - - return 0; -} - -static int64_t migration_set_rate_limit(void *opaque, int64_t new_rate) -{ - MigrationState *s = opaque; - if (qemu_file_get_error(s->file)) { - goto out; - } - - s->xfer_limit = new_rate; - -out: - return s->xfer_limit; -} - -static int64_t migration_get_rate_limit(void *opaque) -{ - MigrationState *s = opaque; - - return s->xfer_limit; -} - static void *migration_thread(void *opaque) { MigrationState *s = opaque; @@ -646,7 +602,7 @@ static void *migration_thread(void *opaque) s->expected_downtime = s->dirty_bytes_rate / bandwidth; } - s->bytes_xfer = 0; + qemu_file_reset_rate_limit(s->file); sleep_time = 0; initial_time = current_time; initial_bytes = qemu_ftell(s->file); @@ -679,9 +635,6 @@ static const QEMUFileOps migration_file_ops = { .get_fd = migration_get_fd, .put_buffer = migration_put_buffer, .close = migration_close, - .rate_limit = migration_rate_limit, - .get_rate_limit = migration_get_rate_limit, - .set_rate_limit = migration_set_rate_limit, }; void migrate_fd_connect(MigrationState *s) @@ -689,10 +642,8 @@ void migrate_fd_connect(MigrationState *s) s->state = MIG_STATE_ACTIVE; trace_migrate_set_state(MIG_STATE_ACTIVE); - s->bytes_xfer = 0; /* This is a best 1st approximation. ns to ms */ s->expected_downtime = max_downtime/1000000; - s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); s->file = qemu_fopen_ops(s, &migration_file_ops); diff --git a/savevm.c b/savevm.c index 1414f08c1a..147e2d232e 100644 --- a/savevm.c +++ b/savevm.c @@ -119,6 +119,9 @@ struct QEMUFile { void *opaque; int is_write; + int64_t bytes_xfer; + int64_t xfer_limit; + int64_t pos; /* start of buffer when writing, end of buffer when reading */ int buf_index; @@ -479,7 +482,6 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) f->opaque = opaque; f->ops = ops; f->is_write = 0; - return f; } @@ -605,6 +607,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) memcpy(f->buf + f->buf_index, buf, l); f->is_write = 1; f->buf_index += l; + f->bytes_xfer += l; buf += l; size -= l; if (f->buf_index >= IO_BUF_SIZE) { @@ -725,28 +728,28 @@ int64_t qemu_ftell(QEMUFile *f) int qemu_file_rate_limit(QEMUFile *f) { - if (f->ops->rate_limit) - return f->ops->rate_limit(f->opaque); - + if (qemu_file_get_error(f)) { + return 1; + } + if (f->xfer_limit > 0 && f->bytes_xfer > f->xfer_limit) { + return 1; + } return 0; } int64_t qemu_file_get_rate_limit(QEMUFile *f) { - if (f->ops->get_rate_limit) - return f->ops->get_rate_limit(f->opaque); - - return 0; + return f->xfer_limit; } -int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate) +void qemu_file_set_rate_limit(QEMUFile *f, int64_t limit) { - /* any failed or completed migration keeps its state to allow probing of - * migration data, but has no associated file anymore */ - if (f && f->ops->set_rate_limit) - return f->ops->set_rate_limit(f->opaque, new_rate); + f->xfer_limit = limit; +} - return 0; +void qemu_file_reset_rate_limit(QEMUFile *f) +{ + f->bytes_xfer = 0; } void qemu_put_be16(QEMUFile *f, unsigned int v) From 404a7c05bcc20c51fe1a9bf2deaeb4d6b658d3a3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:46 +0100 Subject: [PATCH 1534/1634] migration: move contents of migration_close to migrate_fd_cleanup With this patch, the migration_file is not needed anymore. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/migration.c b/migration.c index 4b04d50d58..64d8e4644e 100644 --- a/migration.c +++ b/migration.c @@ -272,6 +272,12 @@ static void migrate_fd_cleanup(void *opaque) DPRINTF("closing file\n"); qemu_fclose(s->file); s->file = NULL; + + qemu_mutex_unlock_iothread(); + qemu_thread_join(&s->thread); + qemu_mutex_lock_iothread(); + + migrate_fd_close(s); } assert(s->migration_file == NULL); @@ -523,16 +529,7 @@ static int migration_put_buffer(void *opaque, const uint8_t *buf, static int migration_close(void *opaque) { - MigrationState *s = opaque; - - DPRINTF("closing\n"); - - qemu_mutex_unlock_iothread(); - qemu_thread_join(&s->thread); - qemu_mutex_lock_iothread(); - assert(s->state != MIG_STATE_ACTIVE); - - return migrate_fd_close(s); + return 0; } static int migration_get_fd(void *opaque) From b352365f5abec075dede0222f1bc37674d64117c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:47 +0100 Subject: [PATCH 1535/1634] migration: eliminate s->migration_file The indirection is useless now. Backends can open s->file directly. Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- include/migration/migration.h | 2 -- migration-exec.c | 4 +-- migration-fd.c | 2 +- migration-tcp.c | 4 +-- migration-unix.c | 4 +-- migration.c | 51 +++-------------------------------- 6 files changed, 11 insertions(+), 56 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index ae94706bdf..bb617fdacf 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -36,9 +36,7 @@ struct MigrationState size_t xfer_limit; QemuThread thread; QEMUBH *cleanup_bh; - QEMUFile *file; - QEMUFile *migration_file; int state; MigrationParams params; diff --git a/migration-exec.c b/migration-exec.c index 1c539de931..deab4e378e 100644 --- a/migration-exec.c +++ b/migration-exec.c @@ -35,8 +35,8 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp) { - s->migration_file = qemu_popen_cmd(command, "w"); - if (s->migration_file == NULL) { + s->file = qemu_popen_cmd(command, "w"); + if (s->file == NULL) { error_setg_errno(errp, errno, "failed to popen the migration target"); return; } diff --git a/migration-fd.c b/migration-fd.c index 07c758ab6b..3d4613cbaf 100644 --- a/migration-fd.c +++ b/migration-fd.c @@ -36,7 +36,7 @@ void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error ** if (fd == -1) { return; } - s->migration_file = qemu_fdopen(fd, "wb"); + s->file = qemu_fdopen(fd, "wb"); migrate_fd_connect(s); } diff --git a/migration-tcp.c b/migration-tcp.c index 5ea4f3d2b6..b20ee58f55 100644 --- a/migration-tcp.c +++ b/migration-tcp.c @@ -35,11 +35,11 @@ static void tcp_wait_for_connect(int fd, void *opaque) if (fd < 0) { DPRINTF("migrate connect error\n"); - s->migration_file = NULL; + s->file = NULL; migrate_fd_error(s); } else { DPRINTF("migrate connect success\n"); - s->migration_file = qemu_fopen_socket(fd, "wb"); + s->file = qemu_fopen_socket(fd, "wb"); migrate_fd_connect(s); } } diff --git a/migration-unix.c b/migration-unix.c index 64bfa31e35..94b7022fc8 100644 --- a/migration-unix.c +++ b/migration-unix.c @@ -35,11 +35,11 @@ static void unix_wait_for_connect(int fd, void *opaque) if (fd < 0) { DPRINTF("migrate connect error\n"); - s->migration_file = NULL; + s->file = NULL; migrate_fd_error(s); } else { DPRINTF("migrate connect success\n"); - s->migration_file = qemu_fopen_socket(fd, "wb"); + s->file = qemu_fopen_socket(fd, "wb"); migrate_fd_connect(s); } } diff --git a/migration.c b/migration.c index 64d8e4644e..5d048ef74c 100644 --- a/migration.c +++ b/migration.c @@ -270,9 +270,6 @@ static void migrate_fd_cleanup(void *opaque) if (s->file) { DPRINTF("closing file\n"); - qemu_fclose(s->file); - s->file = NULL; - qemu_mutex_unlock_iothread(); qemu_thread_join(&s->thread); qemu_mutex_lock_iothread(); @@ -280,7 +277,7 @@ static void migrate_fd_cleanup(void *opaque) migrate_fd_close(s); } - assert(s->migration_file == NULL); + assert(s->file == NULL); assert(s->state != MIG_STATE_ACTIVE); if (s->state != MIG_STATE_COMPLETED) { @@ -317,9 +314,9 @@ static void migrate_fd_cancel(MigrationState *s) int migrate_fd_close(MigrationState *s) { int rc = 0; - if (s->migration_file != NULL) { - rc = qemu_fclose(s->migration_file); - s->migration_file = NULL; + if (s->file != NULL) { + rc = qemu_fclose(s->file); + s->file = NULL; } return rc; } @@ -506,39 +503,6 @@ int64_t migrate_xbzrle_cache_size(void) /* migration thread support */ -static int migration_put_buffer(void *opaque, const uint8_t *buf, - int64_t pos, int size) -{ - MigrationState *s = opaque; - int ret; - - DPRINTF("putting %d bytes at %" PRId64 "\n", size, pos); - - if (size <= 0) { - return size; - } - - qemu_put_buffer(s->migration_file, buf, size); - ret = qemu_file_get_error(s->migration_file); - if (ret) { - return ret; - } - - return size; -} - -static int migration_close(void *opaque) -{ - return 0; -} - -static int migration_get_fd(void *opaque) -{ - MigrationState *s = opaque; - - return qemu_get_fd(s->migration_file); -} - static void *migration_thread(void *opaque) { MigrationState *s = opaque; @@ -628,12 +592,6 @@ static void *migration_thread(void *opaque) return NULL; } -static const QEMUFileOps migration_file_ops = { - .get_fd = migration_get_fd, - .put_buffer = migration_put_buffer, - .close = migration_close, -}; - void migrate_fd_connect(MigrationState *s) { s->state = MIG_STATE_ACTIVE; @@ -642,7 +600,6 @@ void migrate_fd_connect(MigrationState *s) /* This is a best 1st approximation. ns to ms */ s->expected_downtime = max_downtime/1000000; s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); - s->file = qemu_fopen_ops(s, &migration_file_ops); qemu_file_set_rate_limit(s->file, s->bandwidth_limit / XFER_LIMIT_RATIO); From 6f190a0641f5b06a462b62955c15c77b8fb3990c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Feb 2013 17:36:48 +0100 Subject: [PATCH 1536/1634] migration: inline migrate_fd_close Reviewed-by: Orit Wasserman Reviewed-by: Juan Quintela Signed-off-by: Paolo Bonzini Signed-off-by: Juan Quintela --- migration.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/migration.c b/migration.c index 5d048ef74c..185d11260d 100644 --- a/migration.c +++ b/migration.c @@ -274,10 +274,10 @@ static void migrate_fd_cleanup(void *opaque) qemu_thread_join(&s->thread); qemu_mutex_lock_iothread(); - migrate_fd_close(s); + qemu_fclose(s->file); + s->file = NULL; } - assert(s->file == NULL); assert(s->state != MIG_STATE_ACTIVE); if (s->state != MIG_STATE_COMPLETED) { @@ -311,16 +311,6 @@ static void migrate_fd_cancel(MigrationState *s) migrate_finish_set_state(s, MIG_STATE_CANCELLED); } -int migrate_fd_close(MigrationState *s) -{ - int rc = 0; - if (s->file != NULL) { - rc = qemu_fclose(s->file); - s->file = NULL; - } - return rc; -} - void add_migration_state_change_notifier(Notifier *notify) { notifier_list_add(&migration_state_notifiers, notify); From 0db65d624e0211a43c011579d6607a50d8f06082 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Mon, 25 Feb 2013 19:12:01 +0200 Subject: [PATCH 1537/1634] Fix page_cache leak in cache_resize Signed-off-by: Orit Wasserman Reviewed-by: Peter Maydell Signed-off-by: Juan Quintela --- page_cache.c | 1 + 1 file changed, 1 insertion(+) diff --git a/page_cache.c b/page_cache.c index ba5640bd73..748957bc42 100644 --- a/page_cache.c +++ b/page_cache.c @@ -208,6 +208,7 @@ int64_t cache_resize(PageCache *cache, int64_t new_num_pages) } } + g_free(cache->page_cache); cache->page_cache = new_cache->page_cache; cache->max_num_items = new_cache->max_num_items; cache->num_items = new_cache->num_items; From a0ee2031dbf5f0183412d4b20a30cbfd404616a8 Mon Sep 17 00:00:00 2001 From: Orit Wasserman Date: Mon, 25 Feb 2013 19:12:02 +0200 Subject: [PATCH 1538/1634] Fix cache_resize to keep old entry age Instead of using cache_insert do the update itself Signed-off-by: Orit Wasserman Reviewed-by: Peter Maydell Signed-off-by: Juan Quintela --- page_cache.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/page_cache.c b/page_cache.c index 748957bc42..e5717d53c9 100644 --- a/page_cache.c +++ b/page_cache.c @@ -192,18 +192,17 @@ int64_t cache_resize(PageCache *cache, int64_t new_num_pages) if (old_it->it_addr != -1) { /* check for collision, if there is, keep MRU page */ new_it = cache_get_by_addr(new_cache, old_it->it_addr); - if (new_it->it_data) { + if (new_it->it_data && new_it->it_age >= old_it->it_age) { /* keep the MRU page */ - if (new_it->it_age >= old_it->it_age) { - g_free(old_it->it_data); - } else { - g_free(new_it->it_data); - new_it->it_data = old_it->it_data; - new_it->it_age = old_it->it_age; - new_it->it_addr = old_it->it_addr; - } + g_free(old_it->it_data); } else { - cache_insert(new_cache, old_it->it_addr, old_it->it_data); + if (!new_it->it_data) { + new_cache->num_items++; + } + g_free(new_it->it_data); + new_it->it_data = old_it->it_data; + new_it->it_age = old_it->it_age; + new_it->it_addr = old_it->it_addr; } } } From 32a1c08b60a8ac0e63b54a5793a26b5e32b36618 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Mon, 25 Feb 2013 19:12:03 +0200 Subject: [PATCH 1539/1634] page_cache: fix memory leak XBZRLE encoded migration introduced a MRU page cache meachnism. Unfortunately, cached items where never freed in case of a collision in the page cache on cache_insert(). This lead to out of memory conditions during XBZRLE migration if the page cache was small and there where a lot of collisions in the cache. Signed-off-by: Peter Lieven Signed-off-by: Orit Wasserman Reviewed-by: Peter Maydell Signed-off-by: Juan Quintela --- page_cache.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/page_cache.c b/page_cache.c index e5717d53c9..809dadc7eb 100644 --- a/page_cache.c +++ b/page_cache.c @@ -152,6 +152,9 @@ void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata) /* actual update of entry */ it = cache_get_by_addr(cache, addr); + /* free old cached data if any */ + g_free(it->it_data); + if (!it->it_data) { cache->num_items++; } From ee0b44aa9d9450e873a761ca2030b2fa3ec52eb0 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Mon, 25 Feb 2013 19:12:04 +0200 Subject: [PATCH 1540/1634] page_cache: dup memory on insert The page cache frees all data on finish, on resize and if there is collision on insert. So it should be the caches responsibility to dup the data that is stored in the cache. Signed-off-by: Peter Lieven Signed-off-by: Orit Wasserman Reviewed-by: Peter Maydell Signed-off-by: Juan Quintela --- arch_init.c | 3 +-- include/migration/page_cache.h | 3 ++- page_cache.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch_init.c b/arch_init.c index 6089c53386..98e2bc6f55 100644 --- a/arch_init.c +++ b/arch_init.c @@ -293,8 +293,7 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data, if (!cache_is_cached(XBZRLE.cache, current_addr)) { if (!last_stage) { - cache_insert(XBZRLE.cache, current_addr, - g_memdup(current_data, TARGET_PAGE_SIZE)); + cache_insert(XBZRLE.cache, current_addr, current_data); } acct_info.xbzrle_cache_miss++; return -1; diff --git a/include/migration/page_cache.h b/include/migration/page_cache.h index 3839ac7726..87894fea9f 100644 --- a/include/migration/page_cache.h +++ b/include/migration/page_cache.h @@ -57,7 +57,8 @@ bool cache_is_cached(const PageCache *cache, uint64_t addr); uint8_t *get_cached_data(const PageCache *cache, uint64_t addr); /** - * cache_insert: insert the page into the cache. the previous value will be overwritten + * cache_insert: insert the page into the cache. the page cache + * will dup the data on insert. the previous value will be overwritten * * @cache pointer to the PageCache struct * @addr: page address diff --git a/page_cache.c b/page_cache.c index 809dadc7eb..938a79c9ea 100644 --- a/page_cache.c +++ b/page_cache.c @@ -159,7 +159,7 @@ void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata) cache->num_items++; } - it->it_data = pdata; + it->it_data = g_memdup(pdata, cache->page_size); it->it_age = ++cache->max_item_age; it->it_addr = addr; } From 63ec54d7b319824df8b60cfe25afdfb607ce3905 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 14 Feb 2013 08:46:43 +0000 Subject: [PATCH 1541/1634] linux-user: Fix layout of usage table to account for option text The linux-user usage message attempts to line up the columns in its table by calculating the maximum width of any item in them. However for the 'Argument' column it was only accounting for the length of the option switch (eg "-d"), not the additional example text (eg "item[,...]"). This currently has no adverse effects because the widest item in the column happens to be the argumentless "-singlestep" option, but improving the "-d" option help to read "-d item[,...]" exceeds that limit. Fix this by correctly calculating maxarglen as the width of the first column text including a possible option argument, and adjusting its uses to match. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/main.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index d8b0cd65fa..4e92a0b4c5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3406,27 +3406,35 @@ static void usage(void) "Options and associated environment variables:\n" "\n"); - maxarglen = maxenvlen = 0; + /* Calculate column widths. We must always have at least enough space + * for the column header. + */ + maxarglen = strlen("Argument"); + maxenvlen = strlen("Env-variable"); for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { + int arglen = strlen(arginfo->argv); + if (arginfo->has_arg) { + arglen += strlen(arginfo->example) + 1; + } if (strlen(arginfo->env) > maxenvlen) { maxenvlen = strlen(arginfo->env); } - if (strlen(arginfo->argv) > maxarglen) { - maxarglen = strlen(arginfo->argv); + if (arglen > maxarglen) { + maxarglen = arglen; } } - printf("%-*s%-*sDescription\n", maxarglen+3, "Argument", - maxenvlen+1, "Env-variable"); + printf("%-*s %-*s Description\n", maxarglen+1, "Argument", + maxenvlen, "Env-variable"); for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { if (arginfo->has_arg) { printf("-%s %-*s %-*s %s\n", arginfo->argv, - (int)(maxarglen-strlen(arginfo->argv)), arginfo->example, - maxenvlen, arginfo->env, arginfo->help); + (int)(maxarglen - strlen(arginfo->argv) - 1), + arginfo->example, maxenvlen, arginfo->env, arginfo->help); } else { - printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv, + printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv, maxenvlen, arginfo->env, arginfo->help); } From dfae8e00f8ddeedcda24bd28f71d4fd2a9f988b8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 8 Feb 2013 07:58:41 +0000 Subject: [PATCH 1542/1634] linux-user: make bogus negative iovec lengths fail EINVAL If the guest passes us a bogus negative length for an iovec, fail EINVAL rather than proceeding blindly forward. This fixes some of the error cases tests for readv and writev in the LTP. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1729446840..bab9ab58a0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1776,7 +1776,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, errno = 0; return NULL; } - if (count > IOV_MAX) { + if (count < 0 || count > IOV_MAX) { errno = EINVAL; return NULL; } From a8fd1aba8584cbe68583907ce766fd8ecfe81f4b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 8 Feb 2013 07:31:55 +0000 Subject: [PATCH 1543/1634] linux-user: Implement sendfile and sendfile64 Implement the sendfile and sendfile64 syscalls. This implementation passes all the LTP test cases for these syscalls. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- configure | 17 ++++++++++++++ linux-user/syscall.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/configure b/configure index 84317c6826..a416e23597 100755 --- a/configure +++ b/configure @@ -2760,6 +2760,20 @@ if compile_prog "" "" ; then epoll_pwait=yes fi +# check for sendfile support +sendfile=no +cat > $TMPC << EOF +#include + +int main(void) +{ + return sendfile(0, 0, 0, 0); +} +EOF +if compile_prog "" "" ; then + sendfile=yes +fi + # Check if tools are available to build documentation. if test "$docs" != "no" ; then if has makeinfo && has pod2man; then @@ -3628,6 +3642,9 @@ fi if test "$epoll_pwait" = "yes" ; then echo "CONFIG_EPOLL_PWAIT=y" >> $config_host_mak fi +if test "$sendfile" = "yes" ; then + echo "CONFIG_SENDFILE=y" >> $config_host_mak +fi if test "$inotify" = "yes" ; then echo "CONFIG_INOTIFY=y" >> $config_host_mak fi diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bab9ab58a0..77281f1b48 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -78,6 +78,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #ifdef CONFIG_ATTR #include "qemu/xattr.h" #endif +#ifdef CONFIG_SENDFILE +#include +#endif #define termios host_termios #define winsize host_winsize @@ -7531,8 +7534,58 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #else goto unimplemented; #endif + +#ifdef CONFIG_SENDFILE case TARGET_NR_sendfile: + { + off_t *offp = NULL; + off_t off; + if (arg3) { + ret = get_user_sal(off, arg3); + if (is_error(ret)) { + break; + } + offp = &off; + } + ret = get_errno(sendfile(arg1, arg2, offp, arg4)); + if (!is_error(ret) && arg3) { + abi_long ret2 = put_user_sal(off, arg3); + if (is_error(ret2)) { + ret = ret2; + } + } + break; + } +#ifdef TARGET_NR_sendfile64 + case TARGET_NR_sendfile64: + { + off_t *offp = NULL; + off_t off; + if (arg3) { + ret = get_user_s64(off, arg3); + if (is_error(ret)) { + break; + } + offp = &off; + } + ret = get_errno(sendfile(arg1, arg2, offp, arg4)); + if (!is_error(ret) && arg3) { + abi_long ret2 = put_user_s64(off, arg3); + if (is_error(ret2)) { + ret = ret2; + } + } + break; + } +#endif +#else + case TARGET_NR_sendfile: +#ifdef TARGET_NR_sendfile64: + case TARGET_NR_sendfile64: +#endif goto unimplemented; +#endif + #ifdef TARGET_NR_getpmsg case TARGET_NR_getpmsg: goto unimplemented; From a94b4987e243d9afebf56a098afeddae133276b5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 8 Feb 2013 04:35:04 +0000 Subject: [PATCH 1544/1634] linux-user: Implement accept4 Implement the accept4 syscall (which is identical to accept but has an additional flags argument). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/syscall.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 77281f1b48..6182a272ec 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2004,16 +2004,30 @@ out2: return ret; } -/* do_accept() Must return target values and target errnos. */ -static abi_long do_accept(int fd, abi_ulong target_addr, - abi_ulong target_addrlen_addr) +/* If we don't have a system accept4() then just call accept. + * The callsites to do_accept4() will ensure that they don't + * pass a non-zero flags argument in this config. + */ +#ifndef CONFIG_ACCEPT4 +static inline int accept4(int sockfd, struct sockaddr *addr, + socklen_t *addrlen, int flags) +{ + assert(flags == 0); + return accept(sockfd, addr, addrlen); +} +#endif + +/* do_accept4() Must return target values and target errnos. */ +static abi_long do_accept4(int fd, abi_ulong target_addr, + abi_ulong target_addrlen_addr, int flags) { socklen_t addrlen; void *addr; abi_long ret; - if (target_addr == 0) - return get_errno(accept(fd, NULL, NULL)); + if (target_addr == 0) { + return get_errno(accept4(fd, NULL, NULL, flags)); + } /* linux returns EINVAL if addrlen pointer is invalid */ if (get_user_u32(addrlen, target_addrlen_addr)) @@ -2028,7 +2042,7 @@ static abi_long do_accept(int fd, abi_ulong target_addr, addr = alloca(addrlen); - ret = get_errno(accept(fd, addr, &addrlen)); + ret = get_errno(accept4(fd, addr, &addrlen, flags)); if (!is_error(ret)) { host_to_target_sockaddr(target_addr, addr, addrlen); if (put_user_u32(addrlen, target_addrlen_addr)) @@ -2254,7 +2268,7 @@ static abi_long do_socketcall(int num, abi_ulong vptr) || get_user_ual(target_addrlen, vptr + 2 * n)) return -TARGET_EFAULT; - ret = do_accept(sockfd, target_addr, target_addrlen); + ret = do_accept4(sockfd, target_addr, target_addrlen, 0); } break; case SOCKOP_getsockname: @@ -6677,7 +6691,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_accept case TARGET_NR_accept: - ret = do_accept(arg1, arg2, arg3); + ret = do_accept4(arg1, arg2, arg3, 0); + break; +#endif +#ifdef TARGET_NR_accept4 + case TARGET_NR_accept4: +#ifdef CONFIG_ACCEPT4 + ret = do_accept4(arg1, arg2, arg3, arg4); +#else + goto unimplemented; +#endif break; #endif #ifdef TARGET_NR_bind From e9a970a8316f9f86a6c800a9a90175bd593f862c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 8 Feb 2013 04:34:54 +0000 Subject: [PATCH 1545/1634] linux-user/syscall.c: Don't warn about unimplemented get_robust_list The nature of the kernel ABI for the get_robust_list and set_robust_list syscalls means we cannot implement them in QEMU. Make get_robust_list silently return ENOSYS rather than using the default "print message and then fail ENOSYS" code path, in the same way we already do for set_robust_list, and add a comment documenting why we do this. This silences warnings which were being produced for emulating even trivial programs like 'ls' in x86-64-on-x86-64. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/syscall.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6182a272ec..ee82a2da4e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8631,7 +8631,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_set_robust_list case TARGET_NR_set_robust_list: - goto unimplemented_nowarn; + case TARGET_NR_get_robust_list: + /* The ABI for supporting robust futexes has userspace pass + * the kernel a pointer to a linked list which is updated by + * userspace after the syscall; the list is walked by the kernel + * when the thread exits. Since the linked list in QEMU guest + * memory isn't a valid linked list for the host and we have + * no way to reliably intercept the thread-death event, we can't + * support these. Silently return ENOSYS so that guest userspace + * falls back to a non-robust futex implementation (which should + * be OK except in the corner case of the guest crashing while + * holding a mutex that is shared with another process via + * shared memory). + */ + goto unimplemented_nowarn; #endif #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) From bba18e23f7266d63734fd31045fec7794cc34a38 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 11 Mar 2013 11:31:26 +0100 Subject: [PATCH 1546/1634] arm: fix compilation with CONFIG_FDT A conflict was resolved the wrong way when merging commit 320ba5f (build: always link device_tree.o into emulators if libfdt available, 2013-02-05). This causes a build failure for the arm-softmmu target due to multiply defined symbol. Signed-off-by: Paolo Bonzini Message-id: 1362997886-9470-1-git-send-email-pbonzini@redhat.com Signed-off-by: Anthony Liguori --- hw/arm/Makefile.objs | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2d9c69dfce..f5f7d0e539 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -23,7 +23,6 @@ obj-y += bitbang_i2c.o marvell_88w8618_audio.o obj-y += framebuffer.o obj-y += strongarm.o obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o -obj-$(CONFIG_FDT) += ../device_tree.o obj-$(CONFIG_KVM) += kvm/arm_gic.o obj-y := $(addprefix ../,$(obj-y)) From ed2cbf74446b008f9de526a50e4b06265635120c Mon Sep 17 00:00:00 2001 From: Lei Li Date: Mon, 28 Jan 2013 12:49:09 +0800 Subject: [PATCH 1547/1634] qga: cast to int for DWORD type This patch fixes a compiler warning when cross-build: qga/service-win32.c: In function 'printf_win_error': qga/service-win32.c:32:5: warning: format '%d' expects argument of type 'int', but argument 3 has type 'DWORD' [-Wformat] Signed-off-by: Lei Li Signed-off-by: Michael Roth --- qga/service-win32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/service-win32.c b/qga/service-win32.c index 09054565d3..843398a6c6 100644 --- a/qga/service-win32.c +++ b/qga/service-win32.c @@ -29,7 +29,7 @@ static int printf_win_error(const char *text) MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *)&message, 0, NULL); - n = printf("%s. (Error: %d) %s", text, err, message); + n = printf("%s. (Error: %d) %s", text, (int)err, message); LocalFree(message); return n; From 9e7c23db13b23febac4ba2d22419aa8f1884929e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 19 Feb 2013 15:12:34 +0100 Subject: [PATCH 1548/1634] qemu-ga: fix confusing GAChannelMethod comparison In commit 7868e26e5930f49ca942311885776b938dcf3b77 ("qemu-ga: add initial win32 support") support was added for qemu-ga on Windows using virtio-serial. Other channel methods (ISA serial and UNIX domain socket) are not supported on Windows. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael Roth --- qga/channel-win32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qga/channel-win32.c b/qga/channel-win32.c index 16bf44a376..7ed98d72fb 100644 --- a/qga/channel-win32.c +++ b/qga/channel-win32.c @@ -287,7 +287,7 @@ GIOStatus ga_channel_write_all(GAChannel *c, const char *buf, size_t size) static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method, const gchar *path) { - if (!method == GA_CHANNEL_VIRTIO_SERIAL) { + if (method != GA_CHANNEL_VIRTIO_SERIAL) { g_critical("unsupported communication method"); return false; } From c5dcb6ae23a3ed7a01bae1cd75ce02abea31db5e Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Fri, 1 Mar 2013 11:49:38 -0600 Subject: [PATCH 1549/1634] qemu-ga: make guest-sync-delimited available during fsfreeze We currently maintain a whitelist of commands that are safe during fsfreeze. During fsfreeze, we disable all commands that aren't part of that whitelist. guest-sync-delimited meets the criteria for being whitelisted, and is also required for qemu-ga clients that rely on guest-sync-delimited for re-syncing the channel after a timeout. Signed-off-by: Michael Roth Cc: qemu-stable@nongnu.org Reviewed-by: Eric Blake --- qga/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qga/main.c b/qga/main.c index db281a508b..ad751717fe 100644 --- a/qga/main.c +++ b/qga/main.c @@ -85,6 +85,7 @@ static const char *ga_freeze_whitelist[] = { "guest-ping", "guest-info", "guest-sync", + "guest-sync-delimited", "guest-fsfreeze-status", "guest-fsfreeze-thaw", NULL From 39097daf15c42243742667607d2cad2c9dc4f764 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Fri, 1 Mar 2013 11:40:27 -0600 Subject: [PATCH 1550/1634] qemu-ga: use key-value store to avoid recycling fd handles after restart Hosts hold on to handles provided by guest-file-open for periods that can span beyond the life of the qemu-ga process that issued them. Since these are issued starting from 0 on every restart, we run the risk of issuing duplicate handles after restarts/reboots. As a result, users with a stale copy of these handles may end up reading/writing corrupted data due to their existing handles effectively being re-assigned to an unexpected file or offset. We unfortunately do not issue handles as strings, but as integers, so a solution such as using UUIDs can't be implemented without introducing a new interface. As a workaround, we fix this by implementing a persistent key-value store that will be used to track the value of the last handle that was issued across restarts/reboots to avoid issuing duplicates. The store is automatically written to the same directory we currently set via --statedir to track fsfreeze state, and so should be applicable for stable releases where this flag is supported. A follow-up can use this same store for handling fsfreeze state, but that change is cosmetic and left out for now. Signed-off-by: Michael Roth Cc: qemu-stable@nongnu.org * fixed guest_file_handle_add() return value from uint64_t to int64_t --- qga/commands-posix.c | 25 ++++-- qga/guest-agent-core.h | 1 + qga/main.c | 184 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 6 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 7a0202eb2a..1c2aff356a 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -129,14 +129,22 @@ static struct { QTAILQ_HEAD(, GuestFileHandle) filehandles; } guest_file_state; -static void guest_file_handle_add(FILE *fh) +static int64_t guest_file_handle_add(FILE *fh, Error **errp) { GuestFileHandle *gfh; + int64_t handle; + + handle = ga_get_fd_handle(ga_state, errp); + if (error_is_set(errp)) { + return 0; + } gfh = g_malloc0(sizeof(GuestFileHandle)); - gfh->id = fileno(fh); + gfh->id = handle; gfh->fh = fh; QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next); + + return handle; } static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err) @@ -158,7 +166,7 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E { FILE *fh; int fd; - int64_t ret = -1; + int64_t ret = -1, handle; if (!has_mode) { mode = "r"; @@ -184,9 +192,14 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E return -1; } - guest_file_handle_add(fh); - slog("guest-file-open, handle: %d", fd); - return fd; + handle = guest_file_handle_add(fh, err); + if (error_is_set(err)) { + fclose(fh); + return -1; + } + + slog("guest-file-open, handle: %d", handle); + return handle; } void qmp_guest_file_close(int64_t handle, Error **err) diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h index 3354598362..624a559d94 100644 --- a/qga/guest-agent-core.h +++ b/qga/guest-agent-core.h @@ -35,6 +35,7 @@ bool ga_is_frozen(GAState *s); void ga_set_frozen(GAState *s); void ga_unset_frozen(GAState *s); const char *ga_fsfreeze_hook(GAState *s); +int64_t ga_get_fd_handle(GAState *s, Error **errp); #ifndef _WIN32 void reopen_fd_to_null(int fd); diff --git a/qga/main.c b/qga/main.c index ad751717fe..99346e15aa 100644 --- a/qga/main.c +++ b/qga/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifndef _WIN32 #include #include @@ -30,6 +31,7 @@ #include "qapi/qmp/qerror.h" #include "qapi/qmp/dispatch.h" #include "qga/channel.h" +#include "qemu/bswap.h" #ifdef _WIN32 #include "qga/service-win32.h" #include @@ -53,6 +55,11 @@ #endif #define QGA_SENTINEL_BYTE 0xFF +typedef struct GAPersistentState { +#define QGA_PSTATE_DEFAULT_FD_COUNTER 1000 + int64_t fd_counter; +} GAPersistentState; + struct GAState { JSONMessageParser parser; GMainLoop *main_loop; @@ -76,6 +83,8 @@ struct GAState { #ifdef CONFIG_FSFREEZE const char *fsfreeze_hook; #endif + const gchar *pstate_filepath; + GAPersistentState pstate; }; struct GAState *ga_state; @@ -725,6 +734,171 @@ VOID WINAPI service_main(DWORD argc, TCHAR *argv[]) } #endif +static void set_persistent_state_defaults(GAPersistentState *pstate) +{ + g_assert(pstate); + pstate->fd_counter = QGA_PSTATE_DEFAULT_FD_COUNTER; +} + +static void persistent_state_from_keyfile(GAPersistentState *pstate, + GKeyFile *keyfile) +{ + g_assert(pstate); + g_assert(keyfile); + /* if any fields are missing, either because the file was tampered with + * by agents of chaos, or because the field wasn't present at the time the + * file was created, the best we can ever do is start over with the default + * values. so load them now, and ignore any errors in accessing key-value + * pairs + */ + set_persistent_state_defaults(pstate); + + if (g_key_file_has_key(keyfile, "global", "fd_counter", NULL)) { + pstate->fd_counter = + g_key_file_get_int64(keyfile, "global", "fd_counter", NULL); + } +} + +static void persistent_state_to_keyfile(const GAPersistentState *pstate, + GKeyFile *keyfile) +{ + g_assert(pstate); + g_assert(keyfile); + + g_key_file_set_int64(keyfile, "global", "fd_counter", pstate->fd_counter); +} + +static gboolean write_persistent_state(const GAPersistentState *pstate, + const gchar *path) +{ + GKeyFile *keyfile = g_key_file_new(); + GError *gerr = NULL; + gboolean ret = true; + gchar *data = NULL; + gsize data_len; + + g_assert(pstate); + + persistent_state_to_keyfile(pstate, keyfile); + data = g_key_file_to_data(keyfile, &data_len, &gerr); + if (gerr) { + g_critical("failed to convert persistent state to string: %s", + gerr->message); + ret = false; + goto out; + } + + g_file_set_contents(path, data, data_len, &gerr); + if (gerr) { + g_critical("failed to write persistent state to %s: %s", + path, gerr->message); + ret = false; + goto out; + } + +out: + if (gerr) { + g_error_free(gerr); + } + if (keyfile) { + g_key_file_free(keyfile); + } + g_free(data); + return ret; +} + +static gboolean read_persistent_state(GAPersistentState *pstate, + const gchar *path, gboolean frozen) +{ + GKeyFile *keyfile = NULL; + GError *gerr = NULL; + struct stat st; + gboolean ret = true; + + g_assert(pstate); + + if (stat(path, &st) == -1) { + /* it's okay if state file doesn't exist, but any other error + * indicates a permissions issue or some other misconfiguration + * that we likely won't be able to recover from. + */ + if (errno != ENOENT) { + g_critical("unable to access state file at path %s: %s", + path, strerror(errno)); + ret = false; + goto out; + } + + /* file doesn't exist. initialize state to default values and + * attempt to save now. (we could wait till later when we have + * modified state we need to commit, but if there's a problem, + * such as a missing parent directory, we want to catch it now) + * + * there is a potential scenario where someone either managed to + * update the agent from a version that didn't use a key store + * while qemu-ga thought the filesystem was frozen, or + * deleted the key store prior to issuing a fsfreeze, prior + * to restarting the agent. in this case we go ahead and defer + * initial creation till we actually have modified state to + * write, otherwise fail to recover from freeze. + */ + set_persistent_state_defaults(pstate); + if (!frozen) { + ret = write_persistent_state(pstate, path); + if (!ret) { + g_critical("unable to create state file at path %s", path); + ret = false; + goto out; + } + } + ret = true; + goto out; + } + + keyfile = g_key_file_new(); + g_key_file_load_from_file(keyfile, path, 0, &gerr); + if (gerr) { + g_critical("error loading persistent state from path: %s, %s", + path, gerr->message); + ret = false; + goto out; + } + + persistent_state_from_keyfile(pstate, keyfile); + +out: + if (keyfile) { + g_key_file_free(keyfile); + } + if (gerr) { + g_error_free(gerr); + } + + return ret; +} + +int64_t ga_get_fd_handle(GAState *s, Error **errp) +{ + int64_t handle; + + g_assert(s->pstate_filepath); + /* we blacklist commands and avoid operations that potentially require + * writing to disk when we're in a frozen state. this includes opening + * new files, so we should never get here in that situation + */ + g_assert(!ga_is_frozen(s)); + + handle = s->pstate.fd_counter++; + if (s->pstate.fd_counter < 0) { + s->pstate.fd_counter = 0; + } + if (!write_persistent_state(&s->pstate, s->pstate_filepath)) { + error_setg(errp, "failed to commit persistent state to disk"); + } + + return handle; +} + int main(int argc, char **argv) { const char *sopt = "hVvdm:p:l:f:F::b:s:t:"; @@ -854,7 +1028,9 @@ int main(int argc, char **argv) ga_enable_logging(s); s->state_filepath_isfrozen = g_strdup_printf("%s/qga.state.isfrozen", state_dir); + s->pstate_filepath = g_strdup_printf("%s/qga.state", state_dir); s->frozen = false; + #ifndef _WIN32 /* check if a previous instance of qemu-ga exited with filesystems' state * marked as frozen. this could be a stale value (a non-qemu-ga process @@ -911,6 +1087,14 @@ int main(int argc, char **argv) } } + /* load persistent state from disk */ + if (!read_persistent_state(&s->pstate, + s->pstate_filepath, + ga_is_frozen(s))) { + g_critical("failed to load persistent state"); + goto out_bad; + } + if (blacklist) { s->blacklist = blacklist; do { From 6912e6a94cb0a1d650271103efbc3ac2299e4fd0 Mon Sep 17 00:00:00 2001 From: Lei Li Date: Tue, 5 Mar 2013 17:39:11 +0800 Subject: [PATCH 1551/1634] qga: add guest-get-time command Signed-off-by: Lei Li Reviewed-by: Eric Blake Reviewed-by: Michael Roth *added stub for w32 Signed-off-by: Michael Roth --- qga/commands-posix.c | 16 ++++++++++++++++ qga/commands-win32.c | 6 ++++++ qga/qapi-schema.json | 13 +++++++++++++ 3 files changed, 35 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 1c2aff356a..c83d26d0a5 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -119,6 +119,22 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err) /* succeded */ } +int64_t qmp_guest_get_time(Error **errp) +{ + int ret; + qemu_timeval tq; + int64_t time_ns; + + ret = qemu_gettimeofday(&tq); + if (ret < 0) { + error_setg_errno(errp, errno, "Failed to get time"); + return -1; + } + + time_ns = tq.tv_sec * 1000000000LL + tq.tv_usec * 1000; + return time_ns; +} + typedef struct GuestFileHandle { uint64_t id; FILE *fh; diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 7e8ecb3b40..3ebb856bea 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -278,6 +278,12 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **err) return NULL; } +int64_t qmp_guest_get_time(Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return -1; +} + /* register init/cleanup routines for stateful command groups */ void ga_command_state_init(GAState *s, GACommandState *cs) { diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index d91d903256..bb0f75ee5d 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -82,6 +82,19 @@ ## { 'command': 'guest-ping' } +## +# @guest-get-time: +# +# Get the information about guest time relative to the Epoch +# of 1970-01-01 in UTC. +# +# Returns: Time in nanoseconds. +# +# Since 1.5 +## +{ 'command': 'guest-get-time', + 'returns': 'int' } + ## # @GuestAgentCommandInfo: # From a1bca57f758a1ebe2ee808aa6c94f7687f9cfdd0 Mon Sep 17 00:00:00 2001 From: Lei Li Date: Tue, 5 Mar 2013 17:39:12 +0800 Subject: [PATCH 1552/1634] qga: add guest-set-time command Signed-off-by: Lei Li Reviewed-by: Eric Blake Reviewed-by: Michael Roth *added stub for w32 Signed-off-by: Michael Roth --- qga/commands-posix.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ qga/commands-win32.c | 5 ++++ qga/qapi-schema.json | 26 +++++++++++++++++++++ 3 files changed, 86 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index c83d26d0a5..c253f97fa7 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -135,6 +135,61 @@ int64_t qmp_guest_get_time(Error **errp) return time_ns; } +void qmp_guest_set_time(int64_t time_ns, Error **errp) +{ + int ret; + int status; + pid_t pid; + Error *local_err = NULL; + struct timeval tv; + + /* year-2038 will overflow in case time_t is 32bit */ + if (time_ns / 1000000000 != (time_t)(time_ns / 1000000000)) { + error_setg(errp, "Time %" PRId64 " is too large", time_ns); + return; + } + + tv.tv_sec = time_ns / 1000000000; + tv.tv_usec = (time_ns % 1000000000) / 1000; + + ret = settimeofday(&tv, NULL); + if (ret < 0) { + error_setg_errno(errp, errno, "Failed to set time to guest"); + return; + } + + /* Set the Hardware Clock to the current System Time. */ + pid = fork(); + if (pid == 0) { + setsid(); + reopen_fd_to_null(0); + reopen_fd_to_null(1); + reopen_fd_to_null(2); + + execle("/sbin/hwclock", "hwclock", "-w", NULL, environ); + _exit(EXIT_FAILURE); + } else if (pid < 0) { + error_setg_errno(errp, errno, "failed to create child process"); + return; + } + + ga_wait_child(pid, &status, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + return; + } + + if (!WIFEXITED(status)) { + error_setg(errp, "child process has terminated abnormally"); + return; + } + + if (WEXITSTATUS(status)) { + error_setg(errp, "hwclock failed to set hardware clock to system time"); + return; + } +} + typedef struct GuestFileHandle { uint64_t id; FILE *fh; diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 3ebb856bea..622c74dd88 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -284,6 +284,11 @@ int64_t qmp_guest_get_time(Error **errp) return -1; } +void qmp_guest_set_time(int64_t time_ns, Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); +} + /* register init/cleanup routines for stateful command groups */ void ga_command_state_init(GAState *s, GACommandState *cs) { diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index bb0f75ee5d..437d750e34 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -95,6 +95,32 @@ { 'command': 'guest-get-time', 'returns': 'int' } +## +# @guest-set-time: +# +# Set guest time. +# +# When a guest is paused or migrated to a file then loaded +# from that file, the guest OS has no idea that there +# was a big gap in the time. Depending on how long the +# gap was, NTP might not be able to resynchronize the +# guest. +# +# This command tries to set guest time to the given value, +# then sets the Hardware Clock to the current System Time. +# This will make it easier for a guest to resynchronize +# without waiting for NTP. +# +# @time: time of nanoseconds, relative to the Epoch of +# 1970-01-01 in UTC. +# +# Returns: Nothing on success. +# +# Since: 1.5 +## +{ 'command': 'guest-set-time', + 'data': { 'time': 'int' } } + ## # @GuestAgentCommandInfo: # From 70e133a7080116340b1a8898893c6d455bd47299 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 6 Mar 2013 22:59:29 +0100 Subject: [PATCH 1553/1634] qga: introduce guest-get-vcpus / guest-set-vcpus with stubs Signed-off-by: Laszlo Ersek Reviewed-by: Eric Blake Signed-off-by: Michael Roth --- qga/commands-posix.c | 12 ++++++++ qga/commands-win32.c | 12 ++++++++ qga/qapi-schema.json | 72 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index c253f97fa7..03a41a23cf 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -1167,6 +1167,18 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) } #endif +GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return NULL; +} + +int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return -1; +} + /* register init/cleanup routines for stateful command groups */ void ga_command_state_init(GAState *s, GACommandState *cs) { diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 622c74dd88..b19be9db48 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -289,6 +289,18 @@ void qmp_guest_set_time(int64_t time_ns, Error **errp) error_set(errp, QERR_UNSUPPORTED); } +GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return NULL; +} + +int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return -1; +} + /* register init/cleanup routines for stateful command groups */ void ga_command_state_init(GAState *s, GACommandState *cs) { diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 437d750e34..dac4e6f95f 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -554,3 +554,75 @@ ## { 'command': 'guest-network-get-interfaces', 'returns': ['GuestNetworkInterface'] } + +## +# @GuestLogicalProcessor: +# +# @logical-id: Arbitrary guest-specific unique identifier of the VCPU. +# +# @online: Whether the VCPU is enabled. +# +# @can-offline: Whether offlining the VCPU is possible. This member is always +# filled in by the guest agent when the structure is returned, +# and always ignored on input (hence it can be omitted then). +# +# Since: 1.5 +## +{ 'type': 'GuestLogicalProcessor', + 'data': {'logical-id': 'int', + 'online': 'bool', + '*can-offline': 'bool'} } + +## +# @guest-get-vcpus: +# +# Retrieve the list of the guest's logical processors. +# +# This is a read-only operation. +# +# Returns: The list of all VCPUs the guest knows about. Each VCPU is put on the +# list exactly once, but their order is unspecified. +# +# Since: 1.5 +## +{ 'command': 'guest-get-vcpus', + 'returns': ['GuestLogicalProcessor'] } + +## +# @guest-set-vcpus: +# +# Attempt to reconfigure (currently: enable/disable) logical processors inside +# the guest. +# +# The input list is processed node by node in order. In each node @logical-id +# is used to look up the guest VCPU, for which @online specifies the requested +# state. The set of distinct @logical-id's is only required to be a subset of +# the guest-supported identifiers. There's no restriction on list length or on +# repeating the same @logical-id (with possibly different @online field). +# Preferably the input list should describe a modified subset of +# @guest-get-vcpus' return value. +# +# Returns: The length of the initial sublist that has been successfully +# processed. The guest agent maximizes this value. Possible cases: +# +# 0: if the @vcpus list was empty on input. Guest state +# has not been changed. Otherwise, +# +# Error: processing the first node of @vcpus failed for the +# reason returned. Guest state has not been changed. +# Otherwise, +# +# < length(@vcpus): more than zero initial nodes have been processed, +# but not the entire @vcpus list. Guest state has +# changed accordingly. To retrieve the error +# (assuming it persists), repeat the call with the +# successfully processed initial sublist removed. +# Otherwise, +# +# length(@vcpus): call successful. +# +# Since: 1.5 +## +{ 'command': 'guest-set-vcpus', + 'data': {'vcpus': ['GuestLogicalProcessor'] }, + 'returns': 'int' } From d2baff62538d6c638c1c0d2b3fc900060a90dd78 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 6 Mar 2013 22:59:30 +0100 Subject: [PATCH 1554/1634] qga: implement qmp_guest_get_vcpus() for Linux with sysfs Signed-off-by: Laszlo Ersek Reviewed-by: Eric Blake Signed-off-by: Michael Roth --- qga/commands-posix.c | 146 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 6 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 03a41a23cf..17cedab645 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -15,6 +15,10 @@ #include #include #include +#include +#include +#include +#include #include "qga/guest-agent-core.h" #include "qga-qmp-commands.h" #include "qapi/qmp/qerror.h" @@ -1111,6 +1115,136 @@ error: return NULL; } +#define SYSCONF_EXACT(name, err) sysconf_exact((name), #name, (err)) + +static long sysconf_exact(int name, const char *name_str, Error **err) +{ + long ret; + + errno = 0; + ret = sysconf(name); + if (ret == -1) { + if (errno == 0) { + error_setg(err, "sysconf(%s): value indefinite", name_str); + } else { + error_setg_errno(err, errno, "sysconf(%s)", name_str); + } + } + return ret; +} + +/* Transfer online/offline status between @vcpu and the guest system. + * + * On input either @errp or *@errp must be NULL. + * + * In system-to-@vcpu direction, the following @vcpu fields are accessed: + * - R: vcpu->logical_id + * - W: vcpu->online + * - W: vcpu->can_offline + * + * In @vcpu-to-system direction, the following @vcpu fields are accessed: + * - R: vcpu->logical_id + * - R: vcpu->online + * + * Written members remain unmodified on error. + */ +static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu, + Error **errp) +{ + char *dirpath; + int dirfd; + + dirpath = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/", + vcpu->logical_id); + dirfd = open(dirpath, O_RDONLY | O_DIRECTORY); + if (dirfd == -1) { + error_setg_errno(errp, errno, "open(\"%s\")", dirpath); + } else { + static const char fn[] = "online"; + int fd; + int res; + + fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR); + if (fd == -1) { + if (errno != ENOENT) { + error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn); + } else if (sys2vcpu) { + vcpu->online = true; + vcpu->can_offline = false; + } else if (!vcpu->online) { + error_setg(errp, "logical processor #%" PRId64 " can't be " + "offlined", vcpu->logical_id); + } /* otherwise pretend successful re-onlining */ + } else { + unsigned char status; + + res = pread(fd, &status, 1, 0); + if (res == -1) { + error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn); + } else if (res == 0) { + error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath, + fn); + } else if (sys2vcpu) { + vcpu->online = (status != '0'); + vcpu->can_offline = true; + } else if (vcpu->online != (status != '0')) { + status = '0' + vcpu->online; + if (pwrite(fd, &status, 1, 0) == -1) { + error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath, + fn); + } + } /* otherwise pretend successful re-(on|off)-lining */ + + res = close(fd); + g_assert(res == 0); + } + + res = close(dirfd); + g_assert(res == 0); + } + + g_free(dirpath); +} + +GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) +{ + int64_t current; + GuestLogicalProcessorList *head, **link; + long sc_max; + Error *local_err = NULL; + + current = 0; + head = NULL; + link = &head; + sc_max = SYSCONF_EXACT(_SC_NPROCESSORS_CONF, &local_err); + + while (local_err == NULL && current < sc_max) { + GuestLogicalProcessor *vcpu; + GuestLogicalProcessorList *entry; + + vcpu = g_malloc0(sizeof *vcpu); + vcpu->logical_id = current++; + vcpu->has_can_offline = true; /* lolspeak ftw */ + transfer_vcpu(vcpu, true, &local_err); + + entry = g_malloc0(sizeof *entry); + entry->value = vcpu; + + *link = entry; + link = &entry->next; + } + + if (local_err == NULL) { + /* there's no guest with zero VCPUs */ + g_assert(head != NULL); + return head; + } + + qapi_free_GuestLogicalProcessorList(head); + error_propagate(errp, local_err); + return NULL; +} + #else /* defined(__linux__) */ void qmp_guest_suspend_disk(Error **err) @@ -1134,6 +1268,12 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) return NULL; } +GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return NULL; +} + #endif #if !defined(CONFIG_FSFREEZE) @@ -1167,12 +1307,6 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) } #endif -GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) -{ - error_set(errp, QERR_UNSUPPORTED); - return NULL; -} - int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) { error_set(errp, QERR_UNSUPPORTED); From cbb65fc27fd97a3b020df7fce9db4ce09e3956ad Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 6 Mar 2013 22:59:31 +0100 Subject: [PATCH 1555/1634] qga: implement qmp_guest_set_vcpus() for Linux with sysfs Signed-off-by: Laszlo Ersek Reviewed-by: Eric Blake Signed-off-by: Michael Roth --- qga/commands-posix.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 17cedab645..d7da850615 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -1245,6 +1245,32 @@ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) return NULL; } +int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) +{ + int64_t processed; + Error *local_err = NULL; + + processed = 0; + while (vcpus != NULL) { + transfer_vcpu(vcpus->value, false, &local_err); + if (local_err != NULL) { + break; + } + ++processed; + vcpus = vcpus->next; + } + + if (local_err != NULL) { + if (processed == 0) { + error_propagate(errp, local_err); + } else { + error_free(local_err); + } + } + + return processed; +} + #else /* defined(__linux__) */ void qmp_guest_suspend_disk(Error **err) @@ -1274,6 +1300,12 @@ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) return NULL; } +int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) +{ + error_set(errp, QERR_UNSUPPORTED); + return -1; +} + #endif #if !defined(CONFIG_FSFREEZE) @@ -1307,12 +1339,6 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err) } #endif -int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp) -{ - error_set(errp, QERR_UNSUPPORTED); - return -1; -} - /* register init/cleanup routines for stateful command groups */ void ga_command_state_init(GAState *s, GACommandState *cs) { From d76fddaeeec674cab4802b585db6c9fb3a0066dc Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Thu, 7 Mar 2013 19:12:43 +0100 Subject: [PATCH 1556/1634] cpu: Fix qemu_get_cpu() to return NULL if CPU not found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 55e5c2850 breaks CPU not found return value, and returns CPU corresponding to the last non NULL env. Fix it by returning CPU only if env is not NULL, otherwise CPU is not found and function should return NULL. Signed-off-by: Igor Mammedov Signed-off-by: Andreas Färber --- exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 46a283071a..0a96ddbc93 100644 --- a/exec.c +++ b/exec.c @@ -260,7 +260,7 @@ CPUState *qemu_get_cpu(int index) env = env->next_cpu; } - return cpu; + return env ? cpu : NULL; } void cpu_exec_init(CPUArchState *env) From 1c8bb3cc7b98ad07a028567b86fc6baa5c5a0b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 15 Feb 2013 17:01:09 +0100 Subject: [PATCH 1557/1634] monitor: Use qemu_get_cpu() in monitor_set_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change, just a reduction of CPU loops. The mon_cpu field is left untouched for now since changing that requires a number of larger prerequisites, including cpu_synchronize_state() and mon_get_cpu(). Reviewed-by: Luiz Capitulino Reviewed-by: Markus Armbruster Signed-off-by: Andreas Färber --- monitor.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/monitor.c b/monitor.c index c48530bd55..ab05c49abb 100644 --- a/monitor.c +++ b/monitor.c @@ -855,17 +855,14 @@ EventInfoList *qmp_query_events(Error **errp) /* set the current CPU defined by the user */ int monitor_set_cpu(int cpu_index) { - CPUArchState *env; CPUState *cpu; - for (env = first_cpu; env != NULL; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); - if (cpu->cpu_index == cpu_index) { - cur_mon->mon_cpu = env; - return 0; - } + cpu = qemu_get_cpu(cpu_index); + if (cpu == NULL) { + return -1; } - return -1; + cur_mon->mon_cpu = cpu->env_ptr; + return 0; } static CPUArchState *mon_get_cpu(void) From 151d1322a3a0c865089c09aeb50f18215121921a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 15 Feb 2013 15:41:49 +0100 Subject: [PATCH 1558/1634] cpus: Replace open-coded CPU loop in qmp_memsave() with qemu_get_cpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change, just less usages of first_cpu and next_cpu fields. env is passed to cpu_memory_rw_debug(), which in turn passes it to target-specific cpu_get_phys_page_debug(). Changing both would be a larger refactoring, so defer that by using env_ptr for now. Reviewed-by: Luiz Capitulino Signed-off-by: Andreas Färber --- cpus.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/cpus.c b/cpus.c index c4b021dd2e..46355c1321 100644 --- a/cpus.c +++ b/cpus.c @@ -1241,18 +1241,13 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename, cpu_index = 0; } - for (env = first_cpu; env; env = env->next_cpu) { - cpu = ENV_GET_CPU(env); - if (cpu_index == cpu->cpu_index) { - break; - } - } - - if (env == NULL) { + cpu = qemu_get_cpu(cpu_index); + if (cpu == NULL) { error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number"); return; } + env = cpu->env_ptr; f = fopen(filename, "wb"); if (!f) { From c1b382e77d8693955d8838c19b33aeb214724f9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 19 Nov 2012 02:42:18 +0100 Subject: [PATCH 1559/1634] target-sh4: Introduce SuperHCPU subclasses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store legacy name in SuperHCPUClass for -cpu ? and for case-insensitive class lookup. List CPUs by iterating over TYPE_SUPERH_CPU subclasses. Signed-off-by: Andreas Färber --- target-sh4/cpu-qom.h | 7 ++ target-sh4/cpu.c | 180 ++++++++++++++++++++++++++++++++++++++++- target-sh4/translate.c | 84 ------------------- 3 files changed, 186 insertions(+), 85 deletions(-) diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h index f4e8976478..19d8b084ff 100644 --- a/target-sh4/cpu-qom.h +++ b/target-sh4/cpu-qom.h @@ -24,6 +24,10 @@ #define TYPE_SUPERH_CPU "superh-cpu" +#define TYPE_SH7750R_CPU "sh7750r-" TYPE_SUPERH_CPU +#define TYPE_SH7751R_CPU "sh7751r-" TYPE_SUPERH_CPU +#define TYPE_SH7785_CPU "sh7785-" TYPE_SUPERH_CPU + #define SUPERH_CPU_CLASS(klass) \ OBJECT_CLASS_CHECK(SuperHCPUClass, (klass), TYPE_SUPERH_CPU) #define SUPERH_CPU(obj) \ @@ -35,6 +39,7 @@ * SuperHCPUClass: * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. + * @name: The name. * * A SuperH CPU model. */ @@ -45,6 +50,8 @@ typedef struct SuperHCPUClass { DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); + + const char *name; } SuperHCPUClass; /** diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index ef0e62195d..fba1534f86 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -54,6 +54,180 @@ static void superh_cpu_reset(CPUState *s) set_default_nan_mode(1, &env->fp_status); } +typedef struct SuperHCPUListState { + fprintf_function cpu_fprintf; + FILE *file; +} SuperHCPUListState; + +/* Sort alphabetically by type name. */ +static gint superh_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *class_a = (ObjectClass *)a; + ObjectClass *class_b = (ObjectClass *)b; + const char *name_a, *name_b; + + name_a = object_class_get_name(class_a); + name_b = object_class_get_name(class_b); + return strcmp(name_a, name_b); +} + +static void superh_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); + SuperHCPUListState *s = user_data; + + (*s->cpu_fprintf)(s->file, "%s\n", + scc->name); +} + +void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + SuperHCPUListState s = { + .cpu_fprintf = cpu_fprintf, + .file = f, + }; + GSList *list; + + list = object_class_get_list(TYPE_SUPERH_CPU, false); + list = g_slist_sort(list, superh_cpu_list_compare); + g_slist_foreach(list, superh_cpu_list_entry, &s); + g_slist_free(list); +} + +static gint superh_cpu_name_compare(gconstpointer a, gconstpointer b) +{ + const SuperHCPUClass *scc = SUPERH_CPU_CLASS(a); + const char *name = b; + + return strcasecmp(scc->name, name); +} + +static ObjectClass *superh_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + GSList *list, *item; + + if (cpu_model == NULL) { + return NULL; + } + if (strcasecmp(cpu_model, "any") == 0) { + return object_class_by_name(TYPE_SH7750R_CPU); + } + + oc = object_class_by_name(cpu_model); + if (oc != NULL && object_class_dynamic_cast(oc, TYPE_SUPERH_CPU) != NULL + && !object_class_is_abstract(oc)) { + return oc; + } + + oc = NULL; + list = object_class_get_list(TYPE_SUPERH_CPU, false); + item = g_slist_find_custom(list, cpu_model, superh_cpu_name_compare); + if (item != NULL) { + oc = item->data; + } + g_slist_free(list); + return oc; +} + +SuperHCPU *cpu_sh4_init(const char *cpu_model) +{ + SuperHCPU *cpu; + CPUSH4State *env; + ObjectClass *oc; + + oc = superh_cpu_class_by_name(cpu_model); + if (oc == NULL) { + return NULL; + } + cpu = SUPERH_CPU(object_new(object_class_get_name(oc))); + env = &cpu->env; + env->cpu_model_str = cpu_model; + + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + + return cpu; +} + +static void sh7750r_cpu_initfn(Object *obj) +{ + SuperHCPU *cpu = SUPERH_CPU(obj); + CPUSH4State *env = &cpu->env; + + env->id = SH_CPU_SH7750R; + env->pvr = 0x00050000; + env->prr = 0x00000100; + env->cvr = 0x00110000; + env->features = SH_FEATURE_BCR3_AND_BCR4; +} + +static void sh7750r_class_init(ObjectClass *oc, void *data) +{ + SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); + + scc->name = "SH7750R"; +} + +static const TypeInfo sh7750r_type_info = { + .name = TYPE_SH7750R_CPU, + .parent = TYPE_SUPERH_CPU, + .class_init = sh7750r_class_init, + .instance_init = sh7750r_cpu_initfn, +}; + +static void sh7751r_cpu_initfn(Object *obj) +{ + SuperHCPU *cpu = SUPERH_CPU(obj); + CPUSH4State *env = &cpu->env; + + env->id = SH_CPU_SH7751R; + env->pvr = 0x04050005; + env->prr = 0x00000113; + env->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */ + env->features = SH_FEATURE_BCR3_AND_BCR4; +} + +static void sh7751r_class_init(ObjectClass *oc, void *data) +{ + SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); + + scc->name = "SH7751R"; +} + +static const TypeInfo sh7751r_type_info = { + .name = TYPE_SH7751R_CPU, + .parent = TYPE_SUPERH_CPU, + .class_init = sh7751r_class_init, + .instance_init = sh7751r_cpu_initfn, +}; + +static void sh7785_cpu_initfn(Object *obj) +{ + SuperHCPU *cpu = SUPERH_CPU(obj); + CPUSH4State *env = &cpu->env; + + env->id = SH_CPU_SH7785; + env->pvr = 0x10300700; + env->prr = 0x00000200; + env->cvr = 0x71440211; + env->features = SH_FEATURE_SH4A; +} + +static void sh7785_class_init(ObjectClass *oc, void *data) +{ + SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); + + scc->name = "SH7785"; +} + +static const TypeInfo sh7785_type_info = { + .name = TYPE_SH7785_CPU, + .parent = TYPE_SUPERH_CPU, + .class_init = sh7785_class_init, + .instance_init = sh7785_cpu_initfn, +}; + static void superh_cpu_realizefn(DeviceState *dev, Error **errp) { SuperHCPU *cpu = SUPERH_CPU(dev); @@ -98,6 +272,7 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) scc->parent_reset = cc->reset; cc->reset = superh_cpu_reset; + cc->class_by_name = superh_cpu_class_by_name; dc->vmsd = &vmstate_sh_cpu; } @@ -106,7 +281,7 @@ static const TypeInfo superh_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(SuperHCPU), .instance_init = superh_cpu_initfn, - .abstract = false, + .abstract = true, .class_size = sizeof(SuperHCPUClass), .class_init = superh_cpu_class_init, }; @@ -114,6 +289,9 @@ static const TypeInfo superh_cpu_type_info = { static void superh_cpu_register_types(void) { type_register_static(&superh_cpu_type_info); + type_register_static(&sh7750r_type_info); + type_register_static(&sh7751r_type_info); + type_register_static(&sh7785_type_info); } type_init(superh_cpu_register_types) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 7f300e3444..14fdb8fc2d 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -175,90 +175,6 @@ void cpu_dump_state(CPUSH4State * env, FILE * f, } } -typedef struct { - const char *name; - int id; - uint32_t pvr; - uint32_t prr; - uint32_t cvr; - uint32_t features; -} sh4_def_t; - -static sh4_def_t sh4_defs[] = { - { - .name = "SH7750R", - .id = SH_CPU_SH7750R, - .pvr = 0x00050000, - .prr = 0x00000100, - .cvr = 0x00110000, - .features = SH_FEATURE_BCR3_AND_BCR4, - }, { - .name = "SH7751R", - .id = SH_CPU_SH7751R, - .pvr = 0x04050005, - .prr = 0x00000113, - .cvr = 0x00110000, /* Neutered caches, should be 0x20480000 */ - .features = SH_FEATURE_BCR3_AND_BCR4, - }, { - .name = "SH7785", - .id = SH_CPU_SH7785, - .pvr = 0x10300700, - .prr = 0x00000200, - .cvr = 0x71440211, - .features = SH_FEATURE_SH4A, - }, -}; - -static const sh4_def_t *cpu_sh4_find_by_name(const char *name) -{ - int i; - - if (strcasecmp(name, "any") == 0) - return &sh4_defs[0]; - - for (i = 0; i < ARRAY_SIZE(sh4_defs); i++) - if (strcasecmp(name, sh4_defs[i].name) == 0) - return &sh4_defs[i]; - - return NULL; -} - -void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sh4_defs); i++) - (*cpu_fprintf)(f, "%s\n", sh4_defs[i].name); -} - -static void cpu_register(CPUSH4State *env, const sh4_def_t *def) -{ - env->pvr = def->pvr; - env->prr = def->prr; - env->cvr = def->cvr; - env->id = def->id; -} - -SuperHCPU *cpu_sh4_init(const char *cpu_model) -{ - SuperHCPU *cpu; - CPUSH4State *env; - const sh4_def_t *def; - - def = cpu_sh4_find_by_name(cpu_model); - if (!def) - return NULL; - cpu = SUPERH_CPU(object_new(TYPE_SUPERH_CPU)); - env = &cpu->env; - env->features = def->features; - env->cpu_model_str = cpu_model; - cpu_register(env, def); - - object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - - return cpu; -} - static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) { TranslationBlock *tb; From b350ab758342c764a6ead6ef064b15a72c830808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 20 Nov 2012 16:15:47 +0100 Subject: [PATCH 1560/1634] target-sh4: Move PVR/PRR/CVR into SuperHCPUClass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They are never changed once initialized, and moving them to the class will allow to inspect them before instantiating. Signed-off-by: Andreas Färber --- hw/sh4/sh7750.c | 10 +++++++--- target-sh4/cpu-qom.h | 6 ++++++ target-sh4/cpu.c | 18 +++++++++--------- target-sh4/cpu.h | 3 --- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index 6778c94f8e..e4d37ad6ac 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -255,6 +255,7 @@ static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr) static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) { SH7750State *s = opaque; + SuperHCPUClass *scc; switch (addr) { case SH7750_BCR1_A7: @@ -288,11 +289,14 @@ static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr) case SH7750_CCR_A7: return s->ccr; case 0x1f000030: /* Processor version */ - return s->cpu->pvr; + scc = SUPERH_CPU_GET_CLASS(s->cpu); + return scc->pvr; case 0x1f000040: /* Cache version */ - return s->cpu->cvr; + scc = SUPERH_CPU_GET_CLASS(s->cpu); + return scc->cvr; case 0x1f000044: /* Processor revision */ - return s->cpu->prr; + scc = SUPERH_CPU_GET_CLASS(s->cpu); + return scc->prr; default: error_access("long read", addr); abort(); diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h index 19d8b084ff..29628c8077 100644 --- a/target-sh4/cpu-qom.h +++ b/target-sh4/cpu-qom.h @@ -40,6 +40,9 @@ * @parent_realize: The parent class' realize handler. * @parent_reset: The parent class' reset handler. * @name: The name. + * @pvr: Processor Version Register + * @prr: Processor Revision Register + * @cvr: Cache Version Register * * A SuperH CPU model. */ @@ -52,6 +55,9 @@ typedef struct SuperHCPUClass { void (*parent_reset)(CPUState *cpu); const char *name; + uint32_t pvr; + uint32_t prr; + uint32_t cvr; } SuperHCPUClass; /** diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index fba1534f86..5251aa08a5 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -156,9 +156,6 @@ static void sh7750r_cpu_initfn(Object *obj) CPUSH4State *env = &cpu->env; env->id = SH_CPU_SH7750R; - env->pvr = 0x00050000; - env->prr = 0x00000100; - env->cvr = 0x00110000; env->features = SH_FEATURE_BCR3_AND_BCR4; } @@ -167,6 +164,9 @@ static void sh7750r_class_init(ObjectClass *oc, void *data) SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); scc->name = "SH7750R"; + scc->pvr = 0x00050000; + scc->prr = 0x00000100; + scc->cvr = 0x00110000; } static const TypeInfo sh7750r_type_info = { @@ -182,9 +182,6 @@ static void sh7751r_cpu_initfn(Object *obj) CPUSH4State *env = &cpu->env; env->id = SH_CPU_SH7751R; - env->pvr = 0x04050005; - env->prr = 0x00000113; - env->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */ env->features = SH_FEATURE_BCR3_AND_BCR4; } @@ -193,6 +190,9 @@ static void sh7751r_class_init(ObjectClass *oc, void *data) SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); scc->name = "SH7751R"; + scc->pvr = 0x04050005; + scc->prr = 0x00000113; + scc->cvr = 0x00110000; /* Neutered caches, should be 0x20480000 */ } static const TypeInfo sh7751r_type_info = { @@ -208,9 +208,6 @@ static void sh7785_cpu_initfn(Object *obj) CPUSH4State *env = &cpu->env; env->id = SH_CPU_SH7785; - env->pvr = 0x10300700; - env->prr = 0x00000200; - env->cvr = 0x71440211; env->features = SH_FEATURE_SH4A; } @@ -219,6 +216,9 @@ static void sh7785_class_init(ObjectClass *oc, void *data) SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); scc->name = "SH7785"; + scc->pvr = 0x10300700; + scc->prr = 0x00000200; + scc->cvr = 0x71440211; } static const TypeInfo sh7785_type_info = { diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 49dcd9e7f3..f805778075 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -179,9 +179,6 @@ typedef struct CPUSH4State { CPU_COMMON int id; /* CPU model */ - uint32_t pvr; /* Processor Version Register */ - uint32_t prr; /* Processor Revision Register */ - uint32_t cvr; /* Cache Version Register */ void *intc_handle; int in_sleep; /* SR_BL ignored during sleep */ From d7650eab429a033c23947f20d1ae14c4d1e719a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 18 Feb 2013 21:41:59 +0100 Subject: [PATCH 1561/1634] vmstate: Make vmstate_register() static inline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids adding a duplicate stub for CONFIG_USER_ONLY. Suggested-by: Eduardo Habkost Reviewed-by: Eduardo Habkost Reviewed-by: Juan Quintela Signed-off-by: Andreas Färber --- include/migration/vmstate.h | 12 ++++++++++-- savevm.c | 7 ------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index a64db941bc..20db76fdf7 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -638,12 +638,20 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, int version_id); void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque); -int vmstate_register(DeviceState *dev, int instance_id, - const VMStateDescription *vmsd, void *base); + int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, const VMStateDescription *vmsd, void *base, int alias_id, int required_for_version); + +static inline int vmstate_register(DeviceState *dev, int instance_id, + const VMStateDescription *vmsd, + void *opaque) +{ + return vmstate_register_with_alias_id(dev, instance_id, vmsd, + opaque, -1, 0); +} + void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd, void *opaque); diff --git a/savevm.c b/savevm.c index 147e2d232e..35c8d1e445 100644 --- a/savevm.c +++ b/savevm.c @@ -1423,13 +1423,6 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, return 0; } -int vmstate_register(DeviceState *dev, int instance_id, - const VMStateDescription *vmsd, void *opaque) -{ - return vmstate_register_with_alias_id(dev, instance_id, vmsd, - opaque, -1, 0); -} - void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd, void *opaque) { From c71c3e99b8897323af8c2fe0b9851610cd148538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Mon, 18 Feb 2013 17:56:20 +0100 Subject: [PATCH 1562/1634] stubs: Add a vmstate_dummy struct for CONFIG_USER_ONLY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Juan Quintela Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/migration/vmstate.h | 4 ++++ stubs/vmstate.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 20db76fdf7..6666d27b25 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -134,6 +134,10 @@ struct VMStateDescription { const VMStateSubsection *subsections; }; +#ifdef CONFIG_USER_ONLY +extern const VMStateDescription vmstate_dummy; +#endif + extern const VMStateInfo vmstate_info_bool; extern const VMStateInfo vmstate_info_int8; diff --git a/stubs/vmstate.c b/stubs/vmstate.c index 3682af599e..778bc3fc69 100644 --- a/stubs/vmstate.c +++ b/stubs/vmstate.c @@ -1,6 +1,8 @@ #include "qemu-common.h" #include "migration/vmstate.h" +const VMStateDescription vmstate_dummy = {}; + int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, const VMStateDescription *vmsd, From b170fce3dd06372f7bfec9a780ebcb1fce6d57e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 20 Jan 2013 20:23:22 +0100 Subject: [PATCH 1563/1634] cpu: Register VMStateDescription through CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In comparison to DeviceClass::vmsd, CPU VMState is split in two, "cpu_common" and "cpu", and uses cpu_index as instance_id instead of -1. Therefore add a CPU-specific CPUClass::vmsd field. Unlike the legacy CPUArchState registration, rather register CPUState. Signed-off-by: Juan Quintela Signed-off-by: Andreas Färber Reviewed-by: Eduardo Habkost --- exec.c | 11 +++++++++-- include/qom/cpu.h | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index 0a96ddbc93..254ae620ce 100644 --- a/exec.c +++ b/exec.c @@ -219,7 +219,7 @@ void cpu_exec_init_all(void) #endif } -#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) static int cpu_common_post_load(void *opaque, int version_id) { @@ -245,6 +245,8 @@ static const VMStateDescription vmstate_cpu_common = { VMSTATE_END_OF_LIST() } }; +#else +#define vmstate_cpu_common vmstate_dummy #endif CPUState *qemu_get_cpu(int index) @@ -266,6 +268,7 @@ CPUState *qemu_get_cpu(int index) void cpu_exec_init(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); + CPUClass *cc = CPU_GET_CLASS(cpu); CPUArchState **penv; int cpu_index; @@ -290,11 +293,15 @@ void cpu_exec_init(CPUArchState *env) #if defined(CONFIG_USER_ONLY) cpu_list_unlock(); #endif -#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) vmstate_register(NULL, cpu_index, &vmstate_cpu_common, env); +#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION, cpu_save, cpu_load, env); + assert(cc->vmsd == NULL); #endif + if (cc->vmsd != NULL) { + vmstate_register(NULL, cpu_index, cc->vmsd, cpu); + } } #if defined(TARGET_HAS_ICE) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index ab2657c558..5b1b0d7ac4 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -44,6 +44,7 @@ typedef struct CPUState CPUState; * @class_by_name: Callback to map -cpu command line model name to an * instantiatable CPU type. * @reset: Callback to reset the #CPUState to its initial state. + * @vmsd: State description for migration. * * Represents a CPU family or model. */ @@ -55,6 +56,8 @@ typedef struct CPUClass { ObjectClass *(*class_by_name)(const char *cpu_model); void (*reset)(CPUState *cpu); + + const struct VMStateDescription *vmsd; } CPUClass; struct KVMState; From ca91b15f2d2e43eba8f9a3ec5090f0a11b861ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 22 Feb 2013 21:50:10 +0100 Subject: [PATCH 1564/1634] cpu: Introduce cpu_class_set_vmsd() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This setter avoids redefining each VMStateDescription value to vmstate_dummy by not referencing the value for CONFIG_USER_ONLY. Suggested-by: Juan Quintela Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/qom/cpu.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 5b1b0d7ac4..90c5f4579f 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -137,6 +137,27 @@ void cpu_reset(CPUState *cpu); */ ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model); +/** + * cpu_class_set_vmsd: + * @cc: CPU class + * @value: Value to set. Unused for %CONFIG_USER_ONLY. + * + * Sets #VMStateDescription for @cc. + * + * The @value argument is intentionally discarded for the non-softmmu targets + * to avoid linker errors or excessive preprocessor usage. If this behavior + * is undesired, you should assign #CPUState.vmsd directly instead. + */ +#ifndef CONFIG_USER_ONLY +static inline void cpu_class_set_vmsd(CPUClass *cc, + const struct VMStateDescription *value) +{ + cc->vmsd = value; +} +#else +#define cpu_class_set_vmsd(cc, value) ((cc)->vmsd = NULL) +#endif + /** * qemu_cpu_has_work: * @cpu: The vCPU to check. From f56e3a147683f0ed69d8339e497b7a36e3260c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 2 Feb 2013 13:38:08 +0100 Subject: [PATCH 1565/1634] target-i386: Update VMStateDescription to X86CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose vmstate_cpu as vmstate_x86_cpu and hook it up to CPUClass::vmsd. Adapt opaques and VMState fields to X86CPU. Drop cpu_{save,load}(). Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu-qom.h | 4 + target-i386/cpu.c | 2 + target-i386/cpu.h | 2 - target-i386/machine.c | 207 +++++++++++++++++++++--------------------- 4 files changed, 109 insertions(+), 106 deletions(-) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index b7bdcb6892..83c5318d3a 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -76,4 +76,8 @@ static inline X86CPU *x86_env_get_cpu(CPUX86State *env) #define ENV_OFFSET offsetof(X86CPU, env) +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_x86_cpu; +#endif + #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8fb736a5b4..8ff2fff9f7 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2250,6 +2250,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) xcc->parent_reset = cc->reset; cc->reset = x86_cpu_reset; + + cpu_class_set_vmsd(cc, &vmstate_x86_cpu); } static const TypeInfo x86_cpu_type_info = { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 493dda8bb6..0c1c5c54ab 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1092,8 +1092,6 @@ static inline CPUX86State *cpu_init(const char *cpu_model) #define cpu_list x86_cpu_list #define cpudef_setup x86_cpudef_setup -#define CPU_SAVE_VERSION 12 - /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _kernel #define MMU_MODE1_SUFFIX _user diff --git a/target-i386/machine.c b/target-i386/machine.c index 8df6a6b645..c9984b87a1 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -171,14 +171,16 @@ static const VMStateInfo vmstate_fpreg_1_no_mmx = { static bool fpregs_is_0(void *opaque, int version_id) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; return (env->fpregs_format_vmstate == 0); } static bool fpregs_is_1_mmx(void *opaque, int version_id) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; int guess_mmx; guess_mmx = ((env->fptag_vmstate == 0xff) && @@ -188,7 +190,8 @@ static bool fpregs_is_1_mmx(void *opaque, int version_id) static bool fpregs_is_1_no_mmx(void *opaque, int version_id) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; int guess_mmx; guess_mmx = ((env->fptag_vmstate == 0xff) && @@ -237,7 +240,8 @@ static const VMStateInfo vmstate_hack_uint64_as_uint32 = { static void cpu_pre_save(void *opaque) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; int i; /* FPU */ @@ -252,7 +256,8 @@ static void cpu_pre_save(void *opaque) static int cpu_post_load(void *opaque, int version_id) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; int i; /* XXX: restore FPU round state */ @@ -275,16 +280,16 @@ static int cpu_post_load(void *opaque, int version_id) static bool async_pf_msr_needed(void *opaque) { - CPUX86State *cpu = opaque; + X86CPU *cpu = opaque; - return cpu->async_pf_en_msr != 0; + return cpu->env.async_pf_en_msr != 0; } static bool pv_eoi_msr_needed(void *opaque) { - CPUX86State *cpu = opaque; + X86CPU *cpu = opaque; - return cpu->pv_eoi_en_msr != 0; + return cpu->env.pv_eoi_en_msr != 0; } static const VMStateDescription vmstate_async_pf_msr = { @@ -293,7 +298,7 @@ static const VMStateDescription vmstate_async_pf_msr = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT64(async_pf_en_msr, CPUX86State), + VMSTATE_UINT64(env.async_pf_en_msr, X86CPU), VMSTATE_END_OF_LIST() } }; @@ -304,14 +309,15 @@ static const VMStateDescription vmstate_pv_eoi_msr = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT64(pv_eoi_en_msr, CPUX86State), + VMSTATE_UINT64(env.pv_eoi_en_msr, X86CPU), VMSTATE_END_OF_LIST() } }; static bool fpop_ip_dp_needed(void *opaque) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; return env->fpop != 0 || env->fpip != 0 || env->fpdp != 0; } @@ -322,16 +328,17 @@ static const VMStateDescription vmstate_fpop_ip_dp = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT16(fpop, CPUX86State), - VMSTATE_UINT64(fpip, CPUX86State), - VMSTATE_UINT64(fpdp, CPUX86State), + VMSTATE_UINT16(env.fpop, X86CPU), + VMSTATE_UINT64(env.fpip, X86CPU), + VMSTATE_UINT64(env.fpdp, X86CPU), VMSTATE_END_OF_LIST() } }; static bool tsc_adjust_needed(void *opaque) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; return env->tsc_adjust != 0; } @@ -342,14 +349,15 @@ static const VMStateDescription vmstate_msr_tsc_adjust = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_UINT64(tsc_adjust, CPUX86State), + VMSTATE_UINT64(env.tsc_adjust, X86CPU), VMSTATE_END_OF_LIST() } }; static bool tscdeadline_needed(void *opaque) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; return env->tsc_deadline != 0; } @@ -360,14 +368,15 @@ static const VMStateDescription vmstate_msr_tscdeadline = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT64(tsc_deadline, CPUX86State), + VMSTATE_UINT64(env.tsc_deadline, X86CPU), VMSTATE_END_OF_LIST() } }; static bool misc_enable_needed(void *opaque) { - CPUX86State *env = opaque; + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; return env->msr_ia32_misc_enable != MSR_IA32_MISC_ENABLE_DEFAULT; } @@ -378,111 +387,111 @@ static const VMStateDescription vmstate_msr_ia32_misc_enable = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT64(msr_ia32_misc_enable, CPUX86State), + VMSTATE_UINT64(env.msr_ia32_misc_enable, X86CPU), VMSTATE_END_OF_LIST() } }; -static const VMStateDescription vmstate_cpu = { +const VMStateDescription vmstate_x86_cpu = { .name = "cpu", - .version_id = CPU_SAVE_VERSION, + .version_id = 12, .minimum_version_id = 3, .minimum_version_id_old = 3, .pre_save = cpu_pre_save, .post_load = cpu_post_load, .fields = (VMStateField []) { - VMSTATE_UINTTL_ARRAY(regs, CPUX86State, CPU_NB_REGS), - VMSTATE_UINTTL(eip, CPUX86State), - VMSTATE_UINTTL(eflags, CPUX86State), - VMSTATE_UINT32(hflags, CPUX86State), + VMSTATE_UINTTL_ARRAY(env.regs, X86CPU, CPU_NB_REGS), + VMSTATE_UINTTL(env.eip, X86CPU), + VMSTATE_UINTTL(env.eflags, X86CPU), + VMSTATE_UINT32(env.hflags, X86CPU), /* FPU */ - VMSTATE_UINT16(fpuc, CPUX86State), - VMSTATE_UINT16(fpus_vmstate, CPUX86State), - VMSTATE_UINT16(fptag_vmstate, CPUX86State), - VMSTATE_UINT16(fpregs_format_vmstate, CPUX86State), - VMSTATE_FP_REGS(fpregs, CPUX86State, 8), + VMSTATE_UINT16(env.fpuc, X86CPU), + VMSTATE_UINT16(env.fpus_vmstate, X86CPU), + VMSTATE_UINT16(env.fptag_vmstate, X86CPU), + VMSTATE_UINT16(env.fpregs_format_vmstate, X86CPU), + VMSTATE_FP_REGS(env.fpregs, X86CPU, 8), - VMSTATE_SEGMENT_ARRAY(segs, CPUX86State, 6), - VMSTATE_SEGMENT(ldt, CPUX86State), - VMSTATE_SEGMENT(tr, CPUX86State), - VMSTATE_SEGMENT(gdt, CPUX86State), - VMSTATE_SEGMENT(idt, CPUX86State), + VMSTATE_SEGMENT_ARRAY(env.segs, X86CPU, 6), + VMSTATE_SEGMENT(env.ldt, X86CPU), + VMSTATE_SEGMENT(env.tr, X86CPU), + VMSTATE_SEGMENT(env.gdt, X86CPU), + VMSTATE_SEGMENT(env.idt, X86CPU), - VMSTATE_UINT32(sysenter_cs, CPUX86State), + VMSTATE_UINT32(env.sysenter_cs, X86CPU), #ifdef TARGET_X86_64 /* Hack: In v7 size changed from 32 to 64 bits on x86_64 */ - VMSTATE_HACK_UINT32(sysenter_esp, CPUX86State, less_than_7), - VMSTATE_HACK_UINT32(sysenter_eip, CPUX86State, less_than_7), - VMSTATE_UINTTL_V(sysenter_esp, CPUX86State, 7), - VMSTATE_UINTTL_V(sysenter_eip, CPUX86State, 7), + VMSTATE_HACK_UINT32(env.sysenter_esp, X86CPU, less_than_7), + VMSTATE_HACK_UINT32(env.sysenter_eip, X86CPU, less_than_7), + VMSTATE_UINTTL_V(env.sysenter_esp, X86CPU, 7), + VMSTATE_UINTTL_V(env.sysenter_eip, X86CPU, 7), #else - VMSTATE_UINTTL(sysenter_esp, CPUX86State), - VMSTATE_UINTTL(sysenter_eip, CPUX86State), + VMSTATE_UINTTL(env.sysenter_esp, X86CPU), + VMSTATE_UINTTL(env.sysenter_eip, X86CPU), #endif - VMSTATE_UINTTL(cr[0], CPUX86State), - VMSTATE_UINTTL(cr[2], CPUX86State), - VMSTATE_UINTTL(cr[3], CPUX86State), - VMSTATE_UINTTL(cr[4], CPUX86State), - VMSTATE_UINTTL_ARRAY(dr, CPUX86State, 8), + VMSTATE_UINTTL(env.cr[0], X86CPU), + VMSTATE_UINTTL(env.cr[2], X86CPU), + VMSTATE_UINTTL(env.cr[3], X86CPU), + VMSTATE_UINTTL(env.cr[4], X86CPU), + VMSTATE_UINTTL_ARRAY(env.dr, X86CPU, 8), /* MMU */ - VMSTATE_INT32(a20_mask, CPUX86State), + VMSTATE_INT32(env.a20_mask, X86CPU), /* XMM */ - VMSTATE_UINT32(mxcsr, CPUX86State), - VMSTATE_XMM_REGS(xmm_regs, CPUX86State, CPU_NB_REGS), + VMSTATE_UINT32(env.mxcsr, X86CPU), + VMSTATE_XMM_REGS(env.xmm_regs, X86CPU, CPU_NB_REGS), #ifdef TARGET_X86_64 - VMSTATE_UINT64(efer, CPUX86State), - VMSTATE_UINT64(star, CPUX86State), - VMSTATE_UINT64(lstar, CPUX86State), - VMSTATE_UINT64(cstar, CPUX86State), - VMSTATE_UINT64(fmask, CPUX86State), - VMSTATE_UINT64(kernelgsbase, CPUX86State), + VMSTATE_UINT64(env.efer, X86CPU), + VMSTATE_UINT64(env.star, X86CPU), + VMSTATE_UINT64(env.lstar, X86CPU), + VMSTATE_UINT64(env.cstar, X86CPU), + VMSTATE_UINT64(env.fmask, X86CPU), + VMSTATE_UINT64(env.kernelgsbase, X86CPU), #endif - VMSTATE_UINT32_V(smbase, CPUX86State, 4), + VMSTATE_UINT32_V(env.smbase, X86CPU, 4), - VMSTATE_UINT64_V(pat, CPUX86State, 5), - VMSTATE_UINT32_V(hflags2, CPUX86State, 5), + VMSTATE_UINT64_V(env.pat, X86CPU, 5), + VMSTATE_UINT32_V(env.hflags2, X86CPU, 5), - VMSTATE_UINT32_TEST(halted, CPUX86State, version_is_5), - VMSTATE_UINT64_V(vm_hsave, CPUX86State, 5), - VMSTATE_UINT64_V(vm_vmcb, CPUX86State, 5), - VMSTATE_UINT64_V(tsc_offset, CPUX86State, 5), - VMSTATE_UINT64_V(intercept, CPUX86State, 5), - VMSTATE_UINT16_V(intercept_cr_read, CPUX86State, 5), - VMSTATE_UINT16_V(intercept_cr_write, CPUX86State, 5), - VMSTATE_UINT16_V(intercept_dr_read, CPUX86State, 5), - VMSTATE_UINT16_V(intercept_dr_write, CPUX86State, 5), - VMSTATE_UINT32_V(intercept_exceptions, CPUX86State, 5), - VMSTATE_UINT8_V(v_tpr, CPUX86State, 5), + VMSTATE_UINT32_TEST(env.halted, X86CPU, version_is_5), + VMSTATE_UINT64_V(env.vm_hsave, X86CPU, 5), + VMSTATE_UINT64_V(env.vm_vmcb, X86CPU, 5), + VMSTATE_UINT64_V(env.tsc_offset, X86CPU, 5), + VMSTATE_UINT64_V(env.intercept, X86CPU, 5), + VMSTATE_UINT16_V(env.intercept_cr_read, X86CPU, 5), + VMSTATE_UINT16_V(env.intercept_cr_write, X86CPU, 5), + VMSTATE_UINT16_V(env.intercept_dr_read, X86CPU, 5), + VMSTATE_UINT16_V(env.intercept_dr_write, X86CPU, 5), + VMSTATE_UINT32_V(env.intercept_exceptions, X86CPU, 5), + VMSTATE_UINT8_V(env.v_tpr, X86CPU, 5), /* MTRRs */ - VMSTATE_UINT64_ARRAY_V(mtrr_fixed, CPUX86State, 11, 8), - VMSTATE_UINT64_V(mtrr_deftype, CPUX86State, 8), - VMSTATE_MTRR_VARS(mtrr_var, CPUX86State, 8, 8), + VMSTATE_UINT64_ARRAY_V(env.mtrr_fixed, X86CPU, 11, 8), + VMSTATE_UINT64_V(env.mtrr_deftype, X86CPU, 8), + VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, 8, 8), /* KVM-related states */ - VMSTATE_INT32_V(interrupt_injected, CPUX86State, 9), - VMSTATE_UINT32_V(mp_state, CPUX86State, 9), - VMSTATE_UINT64_V(tsc, CPUX86State, 9), - VMSTATE_INT32_V(exception_injected, CPUX86State, 11), - VMSTATE_UINT8_V(soft_interrupt, CPUX86State, 11), - VMSTATE_UINT8_V(nmi_injected, CPUX86State, 11), - VMSTATE_UINT8_V(nmi_pending, CPUX86State, 11), - VMSTATE_UINT8_V(has_error_code, CPUX86State, 11), - VMSTATE_UINT32_V(sipi_vector, CPUX86State, 11), + VMSTATE_INT32_V(env.interrupt_injected, X86CPU, 9), + VMSTATE_UINT32_V(env.mp_state, X86CPU, 9), + VMSTATE_UINT64_V(env.tsc, X86CPU, 9), + VMSTATE_INT32_V(env.exception_injected, X86CPU, 11), + VMSTATE_UINT8_V(env.soft_interrupt, X86CPU, 11), + VMSTATE_UINT8_V(env.nmi_injected, X86CPU, 11), + VMSTATE_UINT8_V(env.nmi_pending, X86CPU, 11), + VMSTATE_UINT8_V(env.has_error_code, X86CPU, 11), + VMSTATE_UINT32_V(env.sipi_vector, X86CPU, 11), /* MCE */ - VMSTATE_UINT64_V(mcg_cap, CPUX86State, 10), - VMSTATE_UINT64_V(mcg_status, CPUX86State, 10), - VMSTATE_UINT64_V(mcg_ctl, CPUX86State, 10), - VMSTATE_UINT64_ARRAY_V(mce_banks, CPUX86State, MCE_BANKS_DEF *4, 10), + VMSTATE_UINT64_V(env.mcg_cap, X86CPU, 10), + VMSTATE_UINT64_V(env.mcg_status, X86CPU, 10), + VMSTATE_UINT64_V(env.mcg_ctl, X86CPU, 10), + VMSTATE_UINT64_ARRAY_V(env.mce_banks, X86CPU, MCE_BANKS_DEF * 4, 10), /* rdtscp */ - VMSTATE_UINT64_V(tsc_aux, CPUX86State, 11), + VMSTATE_UINT64_V(env.tsc_aux, X86CPU, 11), /* KVM pvclock msr */ - VMSTATE_UINT64_V(system_time_msr, CPUX86State, 11), - VMSTATE_UINT64_V(wall_clock_msr, CPUX86State, 11), + VMSTATE_UINT64_V(env.system_time_msr, X86CPU, 11), + VMSTATE_UINT64_V(env.wall_clock_msr, X86CPU, 11), /* XSAVE related fields */ - VMSTATE_UINT64_V(xcr0, CPUX86State, 12), - VMSTATE_UINT64_V(xstate_bv, CPUX86State, 12), - VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUX86State, CPU_NB_REGS, 12), + VMSTATE_UINT64_V(env.xcr0, X86CPU, 12), + VMSTATE_UINT64_V(env.xstate_bv, X86CPU, 12), + VMSTATE_YMMH_REGS_VARS(env.ymmh_regs, X86CPU, CPU_NB_REGS, 12), VMSTATE_END_OF_LIST() /* The above list is not sorted /wrt version numbers, watch out! */ }, @@ -510,13 +519,3 @@ static const VMStateDescription vmstate_cpu = { } } }; - -void cpu_save(QEMUFile *f, void *opaque) -{ - vmstate_save_state(f, &vmstate_cpu, opaque); -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - return vmstate_load_state(f, &vmstate_cpu, opaque, version_id); -} From 21317bc222ef4cdca594b1856eea62f3dfbbfb6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 25 Jan 2013 17:37:28 +0100 Subject: [PATCH 1566/1634] target-cris/helper.c: Update Coding Style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reindent, add missing braces and drop/adjust whitespace. Prepares for CPUArchState-to-CPUState field movements in cpu_cris_handle_mmu_fault(), do_interruptv10() and do_interrupt(). The remaining functions were so minor that they can be fixed in one go. Acked-by: Edgar E. Iglesias Signed-off-by: Andreas Färber --- target-cris/helper.c | 345 +++++++++++++++++++++---------------------- 1 file changed, 172 insertions(+), 173 deletions(-) diff --git a/target-cris/helper.c b/target-cris/helper.c index 6e75e9819e..de04143da8 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -36,19 +36,19 @@ #if defined(CONFIG_USER_ONLY) -void do_interrupt (CPUCRISState *env) +void do_interrupt(CPUCRISState *env) { - env->exception_index = -1; - env->pregs[PR_ERP] = env->pc; + env->exception_index = -1; + env->pregs[PR_ERP] = env->pc; } int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw, int mmu_idx) { - env->exception_index = 0xaa; - env->pregs[PR_EDA] = address; - cpu_dump_state(env, stderr, fprintf, 0); - return 1; + env->exception_index = 0xaa; + env->pregs[PR_EDA] = address; + cpu_dump_state(env, stderr, fprintf, 0); + return 1; } #else /* !CONFIG_USER_ONLY */ @@ -56,211 +56,210 @@ int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw, static void cris_shift_ccs(CPUCRISState *env) { - uint32_t ccs; - /* Apply the ccs shift. */ - ccs = env->pregs[PR_CCS]; - ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; - env->pregs[PR_CCS] = ccs; + uint32_t ccs; + /* Apply the ccs shift. */ + ccs = env->pregs[PR_CCS]; + ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; + env->pregs[PR_CCS] = ccs; } -int cpu_cris_handle_mmu_fault (CPUCRISState *env, target_ulong address, int rw, - int mmu_idx) +int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw, + int mmu_idx) { - struct cris_mmu_result res; - int prot, miss; - int r = -1; - target_ulong phy; + struct cris_mmu_result res; + int prot, miss; + int r = -1; + target_ulong phy; - D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw)); - miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, - rw, mmu_idx, 0); - if (miss) - { - if (env->exception_index == EXCP_BUSFAULT) - cpu_abort(env, - "CRIS: Illegal recursive bus fault." - "addr=%x rw=%d\n", - address, rw); + D(printf("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw)); + miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, + rw, mmu_idx, 0); + if (miss) { + if (env->exception_index == EXCP_BUSFAULT) { + cpu_abort(env, + "CRIS: Illegal recursive bus fault." + "addr=%x rw=%d\n", + address, rw); + } - env->pregs[PR_EDA] = address; - env->exception_index = EXCP_BUSFAULT; - env->fault_vector = res.bf_vec; - r = 1; - } - else - { - /* - * Mask off the cache selection bit. The ETRAX busses do not - * see the top bit. - */ - phy = res.phy & ~0x80000000; - prot = res.prot; - tlb_set_page(env, address & TARGET_PAGE_MASK, phy, - prot, mmu_idx, TARGET_PAGE_SIZE); - r = 0; - } - if (r > 0) - D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n", - __func__, r, env->interrupt_request, address, res.phy, - res.bf_vec, env->pc); - return r; + env->pregs[PR_EDA] = address; + env->exception_index = EXCP_BUSFAULT; + env->fault_vector = res.bf_vec; + r = 1; + } else { + /* + * Mask off the cache selection bit. The ETRAX busses do not + * see the top bit. + */ + phy = res.phy & ~0x80000000; + prot = res.prot; + tlb_set_page(env, address & TARGET_PAGE_MASK, phy, + prot, mmu_idx, TARGET_PAGE_SIZE); + r = 0; + } + if (r > 0) { + D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n", + __func__, r, env->interrupt_request, address, res.phy, + res.bf_vec, env->pc); + } + return r; } static void do_interruptv10(CPUCRISState *env) { - int ex_vec = -1; + int ex_vec = -1; - D_LOG( "exception index=%d interrupt_req=%d\n", - env->exception_index, - env->interrupt_request); + D_LOG("exception index=%d interrupt_req=%d\n", + env->exception_index, + env->interrupt_request); - assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); - switch (env->exception_index) - { - case EXCP_BREAK: - /* These exceptions are genereated by the core itself. - ERP should point to the insn following the brk. */ - ex_vec = env->trap_vector; - env->pregs[PRV10_BRP] = env->pc; - break; + assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); + switch (env->exception_index) { + case EXCP_BREAK: + /* These exceptions are genereated by the core itself. + ERP should point to the insn following the brk. */ + ex_vec = env->trap_vector; + env->pregs[PRV10_BRP] = env->pc; + break; - case EXCP_NMI: - /* NMI is hardwired to vector zero. */ - ex_vec = 0; - env->pregs[PR_CCS] &= ~M_FLAG_V10; - env->pregs[PRV10_BRP] = env->pc; - break; + case EXCP_NMI: + /* NMI is hardwired to vector zero. */ + ex_vec = 0; + env->pregs[PR_CCS] &= ~M_FLAG_V10; + env->pregs[PRV10_BRP] = env->pc; + break; - case EXCP_BUSFAULT: - cpu_abort(env, "Unhandled busfault"); - break; + case EXCP_BUSFAULT: + cpu_abort(env, "Unhandled busfault"); + break; - default: - /* The interrupt controller gives us the vector. */ - ex_vec = env->interrupt_vector; - /* Normal interrupts are taken between - TB's. env->pc is valid here. */ - env->pregs[PR_ERP] = env->pc; - break; - } + default: + /* The interrupt controller gives us the vector. */ + ex_vec = env->interrupt_vector; + /* Normal interrupts are taken between + TB's. env->pc is valid here. */ + env->pregs[PR_ERP] = env->pc; + break; + } - if (env->pregs[PR_CCS] & U_FLAG) { - /* Swap stack pointers. */ - env->pregs[PR_USP] = env->regs[R_SP]; - env->regs[R_SP] = env->ksp; - } + if (env->pregs[PR_CCS] & U_FLAG) { + /* Swap stack pointers. */ + env->pregs[PR_USP] = env->regs[R_SP]; + env->regs[R_SP] = env->ksp; + } - /* Now that we are in kernel mode, load the handlers address. */ - env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); - env->locked_irq = 1; - env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ + /* Now that we are in kernel mode, load the handlers address. */ + env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); + env->locked_irq = 1; + env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ - qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", - __func__, env->pc, ex_vec, - env->pregs[PR_CCS], - env->pregs[PR_PID], - env->pregs[PR_ERP]); + qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", + __func__, env->pc, ex_vec, + env->pregs[PR_CCS], + env->pregs[PR_PID], + env->pregs[PR_ERP]); } void do_interrupt(CPUCRISState *env) { - int ex_vec = -1; + int ex_vec = -1; - if (env->pregs[PR_VR] < 32) - return do_interruptv10(env); + if (env->pregs[PR_VR] < 32) { + return do_interruptv10(env); + } - D_LOG( "exception index=%d interrupt_req=%d\n", - env->exception_index, - env->interrupt_request); + D_LOG("exception index=%d interrupt_req=%d\n", + env->exception_index, + env->interrupt_request); - switch (env->exception_index) - { - case EXCP_BREAK: - /* These exceptions are genereated by the core itself. - ERP should point to the insn following the brk. */ - ex_vec = env->trap_vector; - env->pregs[PR_ERP] = env->pc; - break; + switch (env->exception_index) { + case EXCP_BREAK: + /* These exceptions are genereated by the core itself. + ERP should point to the insn following the brk. */ + ex_vec = env->trap_vector; + env->pregs[PR_ERP] = env->pc; + break; - case EXCP_NMI: - /* NMI is hardwired to vector zero. */ - ex_vec = 0; - env->pregs[PR_CCS] &= ~M_FLAG_V32; - env->pregs[PR_NRP] = env->pc; - break; + case EXCP_NMI: + /* NMI is hardwired to vector zero. */ + ex_vec = 0; + env->pregs[PR_CCS] &= ~M_FLAG_V32; + env->pregs[PR_NRP] = env->pc; + break; - case EXCP_BUSFAULT: - ex_vec = env->fault_vector; - env->pregs[PR_ERP] = env->pc; - break; + case EXCP_BUSFAULT: + ex_vec = env->fault_vector; + env->pregs[PR_ERP] = env->pc; + break; - default: - /* The interrupt controller gives us the vector. */ - ex_vec = env->interrupt_vector; - /* Normal interrupts are taken between - TB's. env->pc is valid here. */ - env->pregs[PR_ERP] = env->pc; - break; - } + default: + /* The interrupt controller gives us the vector. */ + ex_vec = env->interrupt_vector; + /* Normal interrupts are taken between + TB's. env->pc is valid here. */ + env->pregs[PR_ERP] = env->pc; + break; + } - /* Fill in the IDX field. */ - env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; + /* Fill in the IDX field. */ + env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; - if (env->dslot) { - D_LOG("excp isr=%x PC=%x ds=%d SP=%x" - " ERP=%x pid=%x ccs=%x cc=%d %x\n", - ex_vec, env->pc, env->dslot, - env->regs[R_SP], - env->pregs[PR_ERP], env->pregs[PR_PID], - env->pregs[PR_CCS], - env->cc_op, env->cc_mask); - /* We loose the btarget, btaken state here so rexec the - branch. */ - env->pregs[PR_ERP] -= env->dslot; - /* Exception starts with dslot cleared. */ - env->dslot = 0; - } + if (env->dslot) { + D_LOG("excp isr=%x PC=%x ds=%d SP=%x" + " ERP=%x pid=%x ccs=%x cc=%d %x\n", + ex_vec, env->pc, env->dslot, + env->regs[R_SP], + env->pregs[PR_ERP], env->pregs[PR_PID], + env->pregs[PR_CCS], + env->cc_op, env->cc_mask); + /* We loose the btarget, btaken state here so rexec the + branch. */ + env->pregs[PR_ERP] -= env->dslot; + /* Exception starts with dslot cleared. */ + env->dslot = 0; + } - if (env->pregs[PR_CCS] & U_FLAG) { - /* Swap stack pointers. */ - env->pregs[PR_USP] = env->regs[R_SP]; - env->regs[R_SP] = env->ksp; - } + if (env->pregs[PR_CCS] & U_FLAG) { + /* Swap stack pointers. */ + env->pregs[PR_USP] = env->regs[R_SP]; + env->regs[R_SP] = env->ksp; + } - /* Apply the CRIS CCS shift. Clears U if set. */ - cris_shift_ccs(env); + /* Apply the CRIS CCS shift. Clears U if set. */ + cris_shift_ccs(env); - /* Now that we are in kernel mode, load the handlers address. - This load may not fault, real hw leaves that behaviour as - undefined. */ - env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); + /* Now that we are in kernel mode, load the handlers address. + This load may not fault, real hw leaves that behaviour as + undefined. */ + env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); - /* Clear the excption_index to avoid spurios hw_aborts for recursive - bus faults. */ - env->exception_index = -1; + /* Clear the excption_index to avoid spurios hw_aborts for recursive + bus faults. */ + env->exception_index = -1; - D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", - __func__, env->pc, ex_vec, - env->pregs[PR_CCS], - env->pregs[PR_PID], - env->pregs[PR_ERP]); + D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", + __func__, env->pc, ex_vec, + env->pregs[PR_CCS], + env->pregs[PR_PID], + env->pregs[PR_ERP]); } hwaddr cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr) { - uint32_t phy = addr; - struct cris_mmu_result res; - int miss; + uint32_t phy = addr; + struct cris_mmu_result res; + int miss; - miss = cris_mmu_translate(&res, env, addr, 0, 0, 1); - /* If D TLB misses, try I TLB. */ - if (miss) { - miss = cris_mmu_translate(&res, env, addr, 2, 0, 1); - } + miss = cris_mmu_translate(&res, env, addr, 0, 0, 1); + /* If D TLB misses, try I TLB. */ + if (miss) { + miss = cris_mmu_translate(&res, env, addr, 2, 0, 1); + } - if (!miss) - phy = res.phy; - D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); - return phy; + if (!miss) { + phy = res.phy; + } + D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); + return phy; } #endif From 259186a7d2f7184efc96ae99bc5658e6159f53ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Jan 2013 18:51:17 +0100 Subject: [PATCH 1567/1634] cpu: Move halted and interrupt_request fields to CPUState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both fields are used in VMState, thus need to be moved together. Explicitly zero them on reset since they were located before breakpoints. Pass PowerPCCPU to kvmppc_handle_halt(). Signed-off-by: Andreas Färber --- cpu-exec.c | 34 ++++++++++---------- cpus.c | 4 +-- exec.c | 16 +++++----- gdbstub.c | 2 +- hw/arm/omap1.c | 7 +++-- hw/arm/pxa2xx_gpio.c | 3 +- hw/arm/pxa2xx_pic.c | 3 +- hw/i386/xen_machine_pv.c | 6 ++-- hw/openrisc/cputimer.c | 4 ++- hw/ppc/e500.c | 10 +++--- hw/ppc/ppc.c | 22 ++++++++----- hw/ppc/ppce500_spin.c | 2 +- hw/ppc/spapr.c | 10 ++++-- hw/ppc/spapr_hcall.c | 2 +- hw/ppc/spapr_rtas.c | 6 ++-- hw/s390x/s390-virtio.c | 14 ++++++--- hw/sparc/leon3.c | 5 +-- hw/sparc/sun4m.c | 21 +++++++------ hw/sparc64/sun4u.c | 15 ++++++--- hw/xtensa/pic_cpu.c | 8 +++-- include/exec/cpu-defs.h | 2 -- include/qom/cpu.h | 4 +++ kvm-all.c | 2 +- qom/cpu.c | 2 ++ target-alpha/cpu.h | 4 +-- target-alpha/translate.c | 3 +- target-arm/cpu.h | 4 +-- target-arm/helper.c | 4 ++- target-arm/op_helper.c | 4 ++- target-cris/cpu.h | 4 +-- target-cris/helper.c | 9 ++++-- target-cris/translate.c | 3 +- target-i386/cpu.c | 2 +- target-i386/cpu.h | 20 ++++++------ target-i386/helper.c | 12 ++++--- target-i386/kvm.c | 50 ++++++++++++++++-------------- target-i386/machine.c | 2 +- target-i386/misc_helper.c | 21 ++++++++----- target-i386/svm_helper.c | 9 ++++-- target-lm32/cpu.h | 4 +-- target-lm32/op_helper.c | 4 ++- target-m68k/cpu.h | 4 +-- target-m68k/op_helper.c | 4 ++- target-m68k/qregs.def | 1 - target-m68k/translate.c | 8 ++++- target-microblaze/cpu.h | 4 +-- target-mips/cpu.h | 4 +-- target-mips/op_helper.c | 10 ++++-- target-mips/translate.c | 4 +-- target-openrisc/cpu.h | 4 +-- target-openrisc/interrupt_helper.c | 3 +- target-openrisc/sys_helper.c | 3 +- target-ppc/cpu.h | 5 +-- target-ppc/excp_helper.c | 22 ++++++++----- target-ppc/helper_regs.h | 11 ++++--- target-ppc/kvm.c | 16 +++++----- target-ppc/translate.c | 3 +- target-s390x/cpu.c | 8 ++--- target-s390x/cpu.h | 5 +-- target-s390x/helper.c | 7 +++-- target-sh4/cpu.h | 4 +-- target-sh4/helper.c | 5 +-- target-sh4/op_helper.c | 4 ++- target-sparc/cpu.h | 5 +-- target-sparc/helper.c | 4 ++- target-unicore32/cpu.h | 4 +-- target-unicore32/softmmu.c | 3 +- target-xtensa/op_helper.c | 5 ++- translate-all.c | 10 +++--- xen-all.c | 10 +++--- 70 files changed, 319 insertions(+), 224 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 9092145d0b..c9e1a8208b 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -203,12 +203,12 @@ int cpu_exec(CPUArchState *env) uint8_t *tc_ptr; tcg_target_ulong next_tb; - if (env->halted) { + if (cpu->halted) { if (!cpu_has_work(cpu)) { return EXCP_HALTED; } - env->halted = 0; + cpu->halted = 0; } cpu_single_env = env; @@ -278,14 +278,14 @@ int cpu_exec(CPUArchState *env) next_tb = 0; /* force lookup of first TB */ for(;;) { - interrupt_request = env->interrupt_request; + interrupt_request = cpu->interrupt_request; if (unlikely(interrupt_request)) { if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) { /* Mask out external interrupts for this step. */ interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK; } if (interrupt_request & CPU_INTERRUPT_DEBUG) { - env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; + cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG; env->exception_index = EXCP_DEBUG; cpu_loop_exit(env); } @@ -293,8 +293,8 @@ int cpu_exec(CPUArchState *env) defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32) if (interrupt_request & CPU_INTERRUPT_HALT) { - env->interrupt_request &= ~CPU_INTERRUPT_HALT; - env->halted = 1; + cpu->interrupt_request &= ~CPU_INTERRUPT_HALT; + cpu->halted = 1; env->exception_index = EXCP_HLT; cpu_loop_exit(env); } @@ -302,7 +302,7 @@ int cpu_exec(CPUArchState *env) #if defined(TARGET_I386) #if !defined(CONFIG_USER_ONLY) if (interrupt_request & CPU_INTERRUPT_POLL) { - env->interrupt_request &= ~CPU_INTERRUPT_POLL; + cpu->interrupt_request &= ~CPU_INTERRUPT_POLL; apic_poll_irq(env->apic_state); } #endif @@ -319,17 +319,17 @@ int cpu_exec(CPUArchState *env) !(env->hflags & HF_SMM_MASK)) { cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0); - env->interrupt_request &= ~CPU_INTERRUPT_SMI; + cpu->interrupt_request &= ~CPU_INTERRUPT_SMI; do_smm_enter(env); next_tb = 0; } else if ((interrupt_request & CPU_INTERRUPT_NMI) && !(env->hflags2 & HF2_NMI_MASK)) { - env->interrupt_request &= ~CPU_INTERRUPT_NMI; + cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; env->hflags2 |= HF2_NMI_MASK; do_interrupt_x86_hardirq(env, EXCP02_NMI, 1); next_tb = 0; } else if (interrupt_request & CPU_INTERRUPT_MCE) { - env->interrupt_request &= ~CPU_INTERRUPT_MCE; + cpu->interrupt_request &= ~CPU_INTERRUPT_MCE; do_interrupt_x86_hardirq(env, EXCP12_MCHK, 0); next_tb = 0; } else if ((interrupt_request & CPU_INTERRUPT_HARD) && @@ -341,7 +341,8 @@ int cpu_exec(CPUArchState *env) int intno; cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0); - env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ); + cpu->interrupt_request &= ~(CPU_INTERRUPT_HARD | + CPU_INTERRUPT_VIRQ); intno = cpu_get_pic_interrupt(env); qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno); do_interrupt_x86_hardirq(env, intno, 1); @@ -359,7 +360,7 @@ int cpu_exec(CPUArchState *env) intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector)); qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno); do_interrupt_x86_hardirq(env, intno, 1); - env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + cpu->interrupt_request &= ~CPU_INTERRUPT_VIRQ; next_tb = 0; #endif } @@ -370,8 +371,9 @@ int cpu_exec(CPUArchState *env) } if (interrupt_request & CPU_INTERRUPT_HARD) { ppc_hw_interrupt(env); - if (env->pending_interrupts == 0) - env->interrupt_request &= ~CPU_INTERRUPT_HARD; + if (env->pending_interrupts == 0) { + cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; + } next_tb = 0; } #elif defined(TARGET_LM32) @@ -548,8 +550,8 @@ int cpu_exec(CPUArchState *env) #endif /* Don't use the cached interrupt_request value, do_interrupt may have updated the EXITTB flag. */ - if (env->interrupt_request & CPU_INTERRUPT_EXITTB) { - env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; + if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) { + cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB; /* ensure that no TB jump will be modified as the program flow was changed */ next_tb = 0; diff --git a/cpus.c b/cpus.c index 46355c1321..8d47bfd85b 100644 --- a/cpus.c +++ b/cpus.c @@ -72,7 +72,7 @@ static bool cpu_thread_is_idle(CPUArchState *env) if (cpu->stopped || !runstate_is_running()) { return true; } - if (!env->halted || qemu_cpu_has_work(cpu) || + if (!cpu->halted || qemu_cpu_has_work(cpu) || kvm_async_interrupts_enabled()) { return false; } @@ -1198,7 +1198,7 @@ CpuInfoList *qmp_query_cpus(Error **errp) info->value = g_malloc0(sizeof(*info->value)); info->value->CPU = cpu->cpu_index; info->value->current = (env == first_cpu); - info->value->halted = env->halted; + info->value->halted = cpu->halted; info->value->thread_id = cpu->thread_id; #if defined(TARGET_I386) info->value->has_pc = true; diff --git a/exec.c b/exec.c index 254ae620ce..4462edf076 100644 --- a/exec.c +++ b/exec.c @@ -223,12 +223,12 @@ void cpu_exec_init_all(void) static int cpu_common_post_load(void *opaque, int version_id) { - CPUArchState *env = opaque; + CPUState *cpu = opaque; /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the version_id is increased. */ - env->interrupt_request &= ~0x01; - tlb_flush(env, 1); + cpu->interrupt_request &= ~0x01; + tlb_flush(cpu->env_ptr, 1); return 0; } @@ -240,8 +240,8 @@ static const VMStateDescription vmstate_cpu_common = { .minimum_version_id_old = 1, .post_load = cpu_common_post_load, .fields = (VMStateField []) { - VMSTATE_UINT32(halted, CPUArchState), - VMSTATE_UINT32(interrupt_request, CPUArchState), + VMSTATE_UINT32(halted, CPUState), + VMSTATE_UINT32(interrupt_request, CPUState), VMSTATE_END_OF_LIST() } }; @@ -293,7 +293,7 @@ void cpu_exec_init(CPUArchState *env) #if defined(CONFIG_USER_ONLY) cpu_list_unlock(); #endif - vmstate_register(NULL, cpu_index, &vmstate_cpu_common, env); + vmstate_register(NULL, cpu_index, &vmstate_cpu_common, cpu); #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) register_savevm(NULL, "cpu", cpu_index, CPU_SAVE_VERSION, cpu_save, cpu_load, env); @@ -494,7 +494,9 @@ void cpu_single_step(CPUArchState *env, int enabled) void cpu_reset_interrupt(CPUArchState *env, int mask) { - env->interrupt_request &= ~mask; + CPUState *cpu = ENV_GET_CPU(env); + + cpu->interrupt_request &= ~mask; } void cpu_exit(CPUArchState *env) diff --git a/gdbstub.c b/gdbstub.c index e414ad9157..43b7d4d00f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2408,7 +2408,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) cpu_synchronize_state(env); len = snprintf((char *)mem_buf, sizeof(mem_buf), "CPU#%d [%s]", cpu->cpu_index, - env->halted ? "halted " : "running"); + cpu->halted ? "halted " : "running"); memtohex(buf, mem_buf, len); put_packet(s, buf); } diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 6f0a8ca074..7afd590ec7 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -1721,6 +1721,7 @@ static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, unsigned size) { struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; + CPUState *cpu = CPU(s->cpu); if (size != 2) { return omap_badwidth_read16(opaque, addr); @@ -1737,8 +1738,9 @@ static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, return s->clkm.dsp_rstct2; case 0x18: /* DSP_SYSST */ + cpu = CPU(s->cpu); return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | - (s->cpu->env.halted << 6); /* Quite useless... */ + (cpu->halted << 6); /* Quite useless... */ } OMAP_BAD_REG(addr); @@ -3754,8 +3756,9 @@ static void omap_setup_dsp_mapping(MemoryRegion *system_memory, void omap_mpu_wakeup(void *opaque, int irq, int req) { struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque; + CPUState *cpu = CPU(mpu->cpu); - if (mpu->cpu->env.halted) { + if (cpu->halted) { cpu_interrupt(&mpu->cpu->env, CPU_INTERRUPT_EXITTB); } } diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index eef8411e86..d2da928ac0 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -93,6 +93,7 @@ static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = { static void pxa2xx_gpio_set(void *opaque, int line, int level) { PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque; + CPUState *cpu = CPU(s->cpu); int bank; uint32_t mask; @@ -118,7 +119,7 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level) pxa2xx_gpio_irq_update(s); /* Wake-up GPIOs */ - if (s->cpu->env.halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { + if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); } } diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index 145fc78c2f..b55ce479f4 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -46,8 +46,9 @@ static void pxa2xx_pic_update(void *opaque) { uint32_t mask[2]; PXA2xxPICState *s = (PXA2xxPICState *) opaque; + CPUState *cpu = CPU(s->cpu); - if (s->cpu->env.halted) { + if (cpu->halted) { mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); if (mask[0] || mask[1]) { diff --git a/hw/i386/xen_machine_pv.c b/hw/i386/xen_machine_pv.c index a8177b6340..37ba34e5a9 100644 --- a/hw/i386/xen_machine_pv.c +++ b/hw/i386/xen_machine_pv.c @@ -36,7 +36,7 @@ static void xen_init_pv(QEMUMachineInitArgs *args) const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; X86CPU *cpu; - CPUX86State *env; + CPUState *cs; DriveInfo *dinfo; int i; @@ -49,8 +49,8 @@ static void xen_init_pv(QEMUMachineInitArgs *args) #endif } cpu = cpu_x86_init(cpu_model); - env = &cpu->env; - env->halted = 1; + cs = CPU(cpu); + cs->halted = 1; /* Initialize backend core & drivers */ if (xen_be_init() != 0) { diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index f6c877f425..4144b34be7 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -73,8 +73,10 @@ static void openrisc_timer_cb(void *opaque) if ((cpu->env.ttmr & TTMR_IE) && qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) { + CPUState *cs = CPU(cpu); + cpu->env.ttmr |= TTMR_IP; - cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER; + cs->interrupt_request |= CPU_INTERRUPT_TIMER; } switch (cpu->env.ttmr & TTMR_M) { diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 451682cb83..fef9c5d842 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -420,26 +420,28 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env) static void ppce500_cpu_reset_sec(void *opaque) { PowerPCCPU *cpu = opaque; + CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - cpu_reset(CPU(cpu)); + cpu_reset(cs); /* Secondary CPU starts in halted state for now. Needs to change when implementing non-kernel boot. */ - env->halted = 1; + cs->halted = 1; env->exception_index = EXCP_HLT; } static void ppce500_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; + CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; struct boot_info *bi = env->load_info; - cpu_reset(CPU(cpu)); + cpu_reset(cs); /* Set initial guest state. */ - env->halted = 0; + cs->halted = 0; env->gpr[1] = (16<<20) - 8; env->gpr[3] = bi->dt_base; env->nip = bi->entry; diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index c9437fc6a7..b2d7fe8df7 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -72,7 +72,7 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) LOG_IRQ("%s: %p n_IRQ %d level %d => pending %08" PRIx32 "req %08x\n", __func__, env, n_IRQ, level, - env->pending_interrupts, env->interrupt_request); + env->pending_interrupts, CPU(cpu)->interrupt_request); } /* PowerPC 6xx / 7xx internal IRQ controller */ @@ -87,6 +87,8 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + CPUState *cs = CPU(cpu); + switch (pin) { case PPC6xx_INPUT_TBEN: /* Level sensitive - active high */ @@ -126,7 +128,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) /* XXX: Note that the only way to restart the CPU is to reset it */ if (level) { LOG_IRQ("%s: stop the CPU\n", __func__); - env->halted = 1; + cs->halted = 1; } break; case PPC6xx_INPUT_HRESET: @@ -174,6 +176,8 @@ static void ppc970_set_irq(void *opaque, int pin, int level) cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + CPUState *cs = CPU(cpu); + switch (pin) { case PPC970_INPUT_INT: /* Level sensitive - active high */ @@ -203,11 +207,11 @@ static void ppc970_set_irq(void *opaque, int pin, int level) /* XXX: TODO: relay the signal to CKSTP_OUT pin */ if (level) { LOG_IRQ("%s: stop the CPU\n", __func__); - env->halted = 1; + cs->halted = 1; } else { LOG_IRQ("%s: restart the CPU\n", __func__); - env->halted = 0; - qemu_cpu_kick(CPU(cpu)); + cs->halted = 0; + qemu_cpu_kick(cs); } break; case PPC970_INPUT_HRESET: @@ -295,6 +299,8 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { + CPUState *cs = CPU(cpu); + switch (pin) { case PPC40x_INPUT_RESET_SYS: if (level) { @@ -332,11 +338,11 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) /* Level sensitive - active low */ if (level) { LOG_IRQ("%s: stop the CPU\n", __func__); - env->halted = 1; + cs->halted = 1; } else { LOG_IRQ("%s: restart the CPU\n", __func__); - env->halted = 0; - qemu_cpu_kick(CPU(cpu)); + cs->halted = 0; + qemu_cpu_kick(cs); } break; case PPC40x_INPUT_DEBUG: diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c index d904fbe176..1290d37bb9 100644 --- a/hw/ppc/ppce500_spin.c +++ b/hw/ppc/ppce500_spin.c @@ -112,7 +112,7 @@ static void spin_kick(void *data) map_start = ldq_p(&curspin->addr) & ~(map_size - 1); mmubooke_create_initial_mapping(env, 0, map_start, map_size); - env->halted = 0; + cpu->halted = 0; env->exception_index = -1; cpu->stopped = false; qemu_cpu_kick(cpu); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index fd2411310c..f355a9bb84 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -617,6 +617,8 @@ static void spapr_reset_htab(sPAPREnvironment *spapr) static void ppc_spapr_reset(void) { + CPUState *first_cpu_cpu; + /* Reset the hash table & recalc the RMA */ spapr_reset_htab(spapr); @@ -627,9 +629,10 @@ static void ppc_spapr_reset(void) spapr->rtas_size); /* Set up the entry state */ + first_cpu_cpu = CPU(first_cpu); first_cpu->gpr[3] = spapr->fdt_addr; first_cpu->gpr[5] = 0; - first_cpu->halted = 0; + first_cpu_cpu->halted = 0; first_cpu->nip = spapr->entry_point; } @@ -637,14 +640,15 @@ static void ppc_spapr_reset(void) static void spapr_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; + CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - cpu_reset(CPU(cpu)); + cpu_reset(cs); /* All CPUs start halted. CPU0 is unhalted from the machine level * reset code and the rest are explicitly started up by the guest * using an RTAS call */ - env->halted = 1; + cs->halted = 1; env->spr[SPR_HIOR] = 0; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 77c052fcb1..dd72743b52 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -543,7 +543,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr, env->msr |= (1ULL << MSR_EE); hreg_compute_hflags(env); if (!cpu_has_work(cs)) { - env->halted = 1; + cs->halted = 1; env->exception_index = EXCP_HLT; cs->exit_request = 1; } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 5ec787f29d..a24e853d4d 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -145,7 +145,7 @@ static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, continue; } - if (env->halted) { + if (cpu->halted) { rtas_st(rets, 1, 0); } else { rtas_st(rets, 1, 2); @@ -184,7 +184,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, continue; } - if (!env->halted) { + if (!cpu->halted) { rtas_st(rets, 0, -1); return; } @@ -197,7 +197,7 @@ static void rtas_start_cpu(sPAPREnvironment *spapr, env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); env->nip = start; env->gpr[3] = r3; - env->halted = 0; + cpu->halted = 0; qemu_cpu_kick(cpu); diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index e25c330320..ca275bd9d7 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -132,23 +132,25 @@ static unsigned s390_running_cpus; void s390_add_running_cpu(S390CPU *cpu) { + CPUState *cs = CPU(cpu); CPUS390XState *env = &cpu->env; - if (env->halted) { + if (cs->halted) { s390_running_cpus++; - env->halted = 0; + cs->halted = 0; env->exception_index = -1; } } unsigned s390_del_running_cpu(S390CPU *cpu) { + CPUState *cs = CPU(cpu); CPUS390XState *env = &cpu->env; - if (env->halted == 0) { + if (cs->halted == 0) { assert(s390_running_cpus >= 1); s390_running_cpus--; - env->halted = 1; + cs->halted = 1; env->exception_index = EXCP_HLT; } return s390_running_cpus; @@ -183,11 +185,13 @@ void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys) for (i = 0; i < smp_cpus; i++) { S390CPU *cpu; + CPUState *cs; cpu = cpu_s390x_init(cpu_model); + cs = CPU(cpu); ipi_states[i] = cpu; - cpu->env.halted = 1; + cs->halted = 1; cpu->env.exception_index = EXCP_HLT; cpu->env.storage_keys = storage_keys; } diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index f58061f8ed..a9167e6f93 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -49,11 +49,12 @@ typedef struct ResetData { static void main_cpu_reset(void *opaque) { ResetData *s = (ResetData *)opaque; + CPUState *cpu = CPU(s->cpu); CPUSPARCState *env = &s->cpu->env; - cpu_reset(CPU(s->cpu)); + cpu_reset(cpu); - env->halted = 0; + cpu->halted = 0; env->pc = s->entry; env->npc = s->entry + 4; } diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 37bd04108d..a7e6966435 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -256,10 +256,11 @@ void cpu_check_irqs(CPUSPARCState *env) static void cpu_kick_irq(SPARCCPU *cpu) { CPUSPARCState *env = &cpu->env; + CPUState *cs = CPU(cpu); - env->halted = 0; + cs->halted = 0; cpu_check_irqs(env); - qemu_cpu_kick(CPU(cpu)); + qemu_cpu_kick(cs); } static void cpu_set_irq(void *opaque, int irq, int level) @@ -285,19 +286,19 @@ static void dummy_cpu_set_irq(void *opaque, int irq, int level) static void main_cpu_reset(void *opaque) { SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; + CPUState *cs = CPU(cpu); - cpu_reset(CPU(cpu)); - env->halted = 0; + cpu_reset(cs); + cs->halted = 0; } static void secondary_cpu_reset(void *opaque) { SPARCCPU *cpu = opaque; - CPUSPARCState *env = &cpu->env; + CPUState *cs = CPU(cpu); - cpu_reset(CPU(cpu)); - env->halted = 1; + cpu_reset(cs); + cs->halted = 1; } static void cpu_halt_signal(void *opaque, int irq, int level) @@ -826,6 +827,7 @@ static const TypeInfo ram_info = { static void cpu_devinit(const char *cpu_model, unsigned int id, uint64_t prom_addr, qemu_irq **cpu_irqs) { + CPUState *cs; SPARCCPU *cpu; CPUSPARCState *env; @@ -841,7 +843,8 @@ static void cpu_devinit(const char *cpu_model, unsigned int id, qemu_register_reset(main_cpu_reset, cpu); } else { qemu_register_reset(secondary_cpu_reset, cpu); - env->halted = 1; + cs = CPU(cpu); + cs->halted = 1; } *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS); env->prom_addr = prom_addr; diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 51ffa1c09b..ae3c95b5cf 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -254,6 +254,7 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename, void cpu_check_irqs(CPUSPARCState *env) { + CPUState *cs; uint32_t pil = env->pil_in | (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER)); @@ -261,6 +262,7 @@ void cpu_check_irqs(CPUSPARCState *env) if (env->ivec_status & 0x20) { return; } + cs = CPU(sparc_env_get_cpu(env)); /* check if TM or SM in SOFTINT are set setting these also causes interrupt 14 */ if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) { @@ -270,7 +272,7 @@ void cpu_check_irqs(CPUSPARCState *env) /* The bit corresponding to psrpil is (1<< psrpil), the next bit is (2 << psrpil). */ if (pil < (2 << env->psrpil)){ - if (env->interrupt_request & CPU_INTERRUPT_HARD) { + if (cs->interrupt_request & CPU_INTERRUPT_HARD) { CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n", env->interrupt_index); env->interrupt_index = 0; @@ -302,7 +304,7 @@ void cpu_check_irqs(CPUSPARCState *env) break; } } - } else if (env->interrupt_request & CPU_INTERRUPT_HARD) { + } else if (cs->interrupt_request & CPU_INTERRUPT_HARD) { CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x " "current interrupt %x\n", pil, env->pil_in, env->softint, env->interrupt_index); @@ -313,22 +315,25 @@ void cpu_check_irqs(CPUSPARCState *env) static void cpu_kick_irq(SPARCCPU *cpu) { + CPUState *cs = CPU(cpu); CPUSPARCState *env = &cpu->env; - env->halted = 0; + cs->halted = 0; cpu_check_irqs(env); - qemu_cpu_kick(CPU(cpu)); + qemu_cpu_kick(cs); } static void cpu_set_ivec_irq(void *opaque, int irq, int level) { SPARCCPU *cpu = opaque; CPUSPARCState *env = &cpu->env; + CPUState *cs; if (level) { if (!(env->ivec_status & 0x20)) { CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq); - env->halted = 0; + cs = CPU(cpu); + cs->halted = 0; env->interrupt_index = TT_IVEC; env->ivec_status |= 0x20; env->ivec_data[0] = (0x1f << 6) | irq; diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index f485a1465c..12f66b6f55 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -47,6 +47,7 @@ void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d) void check_interrupts(CPUXtensaState *env) { + CPUState *cs = CPU(xtensa_env_get_cpu(env)); int minlevel = xtensa_get_cintlevel(env); uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE]; int level; @@ -54,7 +55,7 @@ void check_interrupts(CPUXtensaState *env) /* If the CPU is halted advance CCOUNT according to the vm_clock time * elapsed since the moment when it was advanced last time. */ - if (env->halted) { + if (cs->halted) { int64_t now = qemu_get_clock_ns(vm_clock); xtensa_advance_ccount(env, @@ -127,11 +128,12 @@ static void xtensa_ccompare_cb(void *opaque) { XtensaCPU *cpu = opaque; CPUXtensaState *env = &cpu->env; + CPUState *cs = CPU(cpu); - if (env->halted) { + if (cs->halted) { env->halt_clock = qemu_get_clock_ns(vm_clock); xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); - if (!cpu_has_work(CPU(cpu))) { + if (!cpu_has_work(cs)) { env->sregs[CCOUNT] = env->wake_ccount + 1; xtensa_rearm_ccompare_timer(env); } diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 3dc96568ac..0ae967ae20 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -156,8 +156,6 @@ typedef struct CPUWatchpoint { accessed */ \ target_ulong mem_io_vaddr; /* target virtual addr at which the \ memory was accessed */ \ - uint32_t halted; /* Nonzero if the CPU is in suspend state */ \ - uint32_t interrupt_request; \ CPU_COMMON_TLB \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ /* buffer for temporaries in the code generator */ \ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 90c5f4579f..23c80b9251 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -72,6 +72,8 @@ struct kvm_run; * @host_tid: Host thread ID. * @running: #true if CPU is currently running (usermode). * @created: Indicates whether the CPU thread has been successfully created. + * @interrupt_request: Indicates a pending interrupt request. + * @halted: Nonzero if the CPU is in suspended state. * @stop: Indicates a pending stop request. * @stopped: Indicates the CPU has been artificially stopped. * @tcg_exit_req: Set to force TCG to stop executing linked TBs for this @@ -106,6 +108,7 @@ struct CPUState { bool stopped; volatile sig_atomic_t exit_request; volatile sig_atomic_t tcg_exit_req; + uint32_t interrupt_request; void *env_ptr; /* CPUArchState */ struct TranslationBlock *current_tb; @@ -117,6 +120,7 @@ struct CPUState { /* TODO Move common fields from CPUArchState here. */ int cpu_index; /* used by alpha TCG */ + uint32_t halted; /* used by alpha, cris, ppc TCG */ }; diff --git a/kvm-all.c b/kvm-all.c index 4decfdccd3..2b761e0a0d 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -830,7 +830,7 @@ static void kvm_handle_interrupt(CPUArchState *env, int mask) { CPUState *cpu = ENV_GET_CPU(env); - env->interrupt_request |= mask; + cpu->interrupt_request |= mask; if (!qemu_cpu_is_self(cpu)) { qemu_cpu_kick(cpu); diff --git a/qom/cpu.c b/qom/cpu.c index 0a2194d413..0aa9be793d 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -33,7 +33,9 @@ void cpu_reset(CPUState *cpu) static void cpu_common_reset(CPUState *cpu) { cpu->exit_request = 0; + cpu->interrupt_request = 0; cpu->current_tb = NULL; + cpu->halted = 0; } ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index f1db6518ce..90f78acc30 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -517,8 +517,6 @@ static inline void cpu_set_tls(CPUAlphaState *env, target_ulong newtls) static inline bool cpu_has_work(CPUState *cpu) { - CPUAlphaState *env = &ALPHA_CPU(cpu)->env; - /* Here we are checking to see if the CPU should wake up from HALT. We will have gotten into this state only for WTINT from PALmode. */ /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU @@ -526,7 +524,7 @@ static inline bool cpu_has_work(CPUState *cpu) assume that if a CPU really wants to stay asleep, it will mask interrupts at the chipset level, which will prevent these bits from being set in the first place. */ - return env->interrupt_request & (CPU_INTERRUPT_HARD + return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER | CPU_INTERRUPT_SMP | CPU_INTERRUPT_MCHK); diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 657f5e1e5f..4db16db462 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1686,7 +1686,8 @@ static ExitStatus gen_mtpr(DisasContext *ctx, int rb, int regno) case 253: /* WAIT */ tmp = tcg_const_i64(1); - tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUAlphaState, halted)); + tcg_gen_st32_i64(tmp, cpu_env, -offsetof(AlphaCPU, env) + + offsetof(CPUState, halted)); return gen_excp(ctx, EXCP_HLT, 0); case 252: diff --git a/target-arm/cpu.h b/target-arm/cpu.h index c28a0d94c3..957866c0e2 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -722,9 +722,7 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, static inline bool cpu_has_work(CPUState *cpu) { - CPUARMState *env = &ARM_CPU(cpu)->env; - - return env->interrupt_request & + return cpu->interrupt_request & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); } diff --git a/target-arm/helper.c b/target-arm/helper.c index 6cad936d3e..d7e22dda13 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1801,6 +1801,7 @@ static void do_interrupt_v7m(CPUARMState *env) /* Handle a CPU exception. */ void do_interrupt(CPUARMState *env) { + CPUState *cs; uint32_t addr; uint32_t mask; int new_mode; @@ -1907,7 +1908,8 @@ void do_interrupt(CPUARMState *env) } env->regs[14] = env->regs[15] + offset; env->regs[15] = addr; - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + cs = CPU(arm_env_get_cpu(env)); + cs->interrupt_request |= CPU_INTERRUPT_EXITTB; } /* Check section/page access permissions. diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index a52231346c..a918e5b27a 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -218,8 +218,10 @@ uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift) void HELPER(wfi)(CPUARMState *env) { + CPUState *cs = CPU(arm_env_get_cpu(env)); + env->exception_index = EXCP_HLT; - env->halted = 1; + cs->halted = 1; cpu_loop_exit(env); } diff --git a/target-cris/cpu.h b/target-cris/cpu.h index ebf2d4027f..2fc7c5c772 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -289,9 +289,7 @@ void cris_cpu_list(FILE *f, fprintf_function cpu_fprintf); static inline bool cpu_has_work(CPUState *cpu) { - CPUCRISState *env = &CRIS_CPU(cpu)->env; - - return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); + return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); } #include "exec/exec-all.h" diff --git a/target-cris/helper.c b/target-cris/helper.c index de04143da8..885f67fa33 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -66,6 +66,7 @@ static void cris_shift_ccs(CPUCRISState *env) int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw, int mmu_idx) { + D(CPUState *cpu = CPU(cris_env_get_cpu(env))); struct cris_mmu_result res; int prot, miss; int r = -1; @@ -99,7 +100,7 @@ int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw, } if (r > 0) { D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n", - __func__, r, env->interrupt_request, address, res.phy, + __func__, r, cpu->interrupt_request, address, res.phy, res.bf_vec, env->pc); } return r; @@ -107,11 +108,12 @@ int cpu_cris_handle_mmu_fault(CPUCRISState *env, target_ulong address, int rw, static void do_interruptv10(CPUCRISState *env) { + D(CPUState *cs = CPU(cris_env_get_cpu(env))); int ex_vec = -1; D_LOG("exception index=%d interrupt_req=%d\n", env->exception_index, - env->interrupt_request); + cs->interrupt_request); assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); switch (env->exception_index) { @@ -162,6 +164,7 @@ static void do_interruptv10(CPUCRISState *env) void do_interrupt(CPUCRISState *env) { + D(CPUState *cs = CPU(cris_env_get_cpu(env))); int ex_vec = -1; if (env->pregs[PR_VR] < 32) { @@ -170,7 +173,7 @@ void do_interrupt(CPUCRISState *env) D_LOG("exception index=%d interrupt_req=%d\n", env->exception_index, - env->interrupt_request); + cs->interrupt_request); switch (env->exception_index) { case EXCP_BREAK: diff --git a/target-cris/translate.c b/target-cris/translate.c index ec71ef4721..dbcb811b7b 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -2888,7 +2888,8 @@ static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc) cris_cc_mask(dc, 0); if (dc->op2 == 15) { - t_gen_mov_env_TN(halted, tcg_const_tl(1)); + tcg_gen_st_i32(tcg_const_i32(1), cpu_env, + -offsetof(CRISCPU, env) + offsetof(CPUState, halted)); tcg_gen_movi_tl(env_pc, dc->pc + 2); t_gen_raise_exception(EXCP_HLT); return 2; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8ff2fff9f7..2bdbf1b453 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2014,7 +2014,7 @@ static void x86_cpu_reset(CPUState *s) apic_designate_bsp(env->apic_state); } - env->halted = !cpu_is_bsp(cpu); + s->halted = !cpu_is_bsp(cpu); #endif } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 0c1c5c54ab..bf6e21073d 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -967,6 +967,7 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env, static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu, int sipi_vector) { + CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; env->eip = 0; @@ -974,7 +975,7 @@ static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu, sipi_vector << 12, env->segs[R_CS].limit, env->segs[R_CS].flags); - env->halted = 0; + cs->halted = 0; } int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, @@ -1166,17 +1167,18 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp) #include "hw/apic.h" #endif -static inline bool cpu_has_work(CPUState *cpu) +static inline bool cpu_has_work(CPUState *cs) { - CPUX86State *env = &X86_CPU(cpu)->env; + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; - return ((env->interrupt_request & (CPU_INTERRUPT_HARD | - CPU_INTERRUPT_POLL)) && + return ((cs->interrupt_request & (CPU_INTERRUPT_HARD | + CPU_INTERRUPT_POLL)) && (env->eflags & IF_MASK)) || - (env->interrupt_request & (CPU_INTERRUPT_NMI | - CPU_INTERRUPT_INIT | - CPU_INTERRUPT_SIPI | - CPU_INTERRUPT_MCE)); + (cs->interrupt_request & (CPU_INTERRUPT_NMI | + CPU_INTERRUPT_INIT | + CPU_INTERRUPT_SIPI | + CPU_INTERRUPT_MCE)); } #include "exec/exec-all.h" diff --git a/target-i386/helper.c b/target-i386/helper.c index 82a731c77d..b49a0fc5f3 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -182,6 +182,7 @@ done: void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, int flags) { + CPUState *cs = CPU(x86_env_get_cpu(env)); int eflags, i, nb; char cc_op_name[32]; static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; @@ -225,7 +226,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, (env->a20_mask >> 20) & 1, (env->hflags >> HF_SMM_SHIFT) & 1, - env->halted); + cs->halted); } else #endif { @@ -252,7 +253,7 @@ void cpu_dump_state(CPUX86State *env, FILE *f, fprintf_function cpu_fprintf, (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, (env->a20_mask >> 20) & 1, (env->hflags >> HF_SMM_SHIFT) & 1, - env->halted); + cs->halted); } for(i = 0; i < 6; i++) { @@ -1281,12 +1282,13 @@ int cpu_x86_get_descr_debug(CPUX86State *env, unsigned int selector, #if !defined(CONFIG_USER_ONLY) void do_cpu_init(X86CPU *cpu) { + CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; - int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI; + int sipi = cs->interrupt_request & CPU_INTERRUPT_SIPI; uint64_t pat = env->pat; - cpu_reset(CPU(cpu)); - env->interrupt_request = sipi; + cpu_reset(cs); + cs->interrupt_request = sipi; env->pat = pat; apic_init_reset(env->apic_state); } diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 0cf413dbfd..df30fa6ed6 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -1460,17 +1460,18 @@ static int kvm_put_mp_state(X86CPU *cpu) static int kvm_get_mp_state(X86CPU *cpu) { + CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; struct kvm_mp_state mp_state; int ret; - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state); + ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state); if (ret < 0) { return ret; } env->mp_state = mp_state.mp_state; if (kvm_irqchip_in_kernel()) { - env->halted = (mp_state.mp_state == KVM_MP_STATE_HALTED); + cs->halted = (mp_state.mp_state == KVM_MP_STATE_HALTED); } return 0; } @@ -1762,8 +1763,8 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) int ret; /* Inject NMI */ - if (env->interrupt_request & CPU_INTERRUPT_NMI) { - env->interrupt_request &= ~CPU_INTERRUPT_NMI; + if (cpu->interrupt_request & CPU_INTERRUPT_NMI) { + cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; DPRINTF("injected NMI\n"); ret = kvm_vcpu_ioctl(cpu, KVM_NMI); if (ret < 0) { @@ -1775,18 +1776,18 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) if (!kvm_irqchip_in_kernel()) { /* Force the VCPU out of its inner loop to process any INIT requests * or pending TPR access reports. */ - if (env->interrupt_request & + if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { cpu->exit_request = 1; } /* Try to inject an interrupt if the guest can accept it */ if (run->ready_for_interrupt_injection && - (env->interrupt_request & CPU_INTERRUPT_HARD) && + (cpu->interrupt_request & CPU_INTERRUPT_HARD) && (env->eflags & IF_MASK)) { int irq; - env->interrupt_request &= ~CPU_INTERRUPT_HARD; + cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; irq = cpu_get_pic_interrupt(env); if (irq >= 0) { struct kvm_interrupt intr; @@ -1806,7 +1807,7 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) * interrupt, request an interrupt window exit. This will * cause a return to userspace as soon as the guest is ready to * receive interrupts. */ - if ((env->interrupt_request & CPU_INTERRUPT_HARD)) { + if ((cpu->interrupt_request & CPU_INTERRUPT_HARD)) { run->request_interrupt_window = 1; } else { run->request_interrupt_window = 0; @@ -1836,11 +1837,11 @@ int kvm_arch_process_async_events(CPUState *cs) X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; - if (env->interrupt_request & CPU_INTERRUPT_MCE) { + if (cs->interrupt_request & CPU_INTERRUPT_MCE) { /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */ assert(env->mcg_cap); - env->interrupt_request &= ~CPU_INTERRUPT_MCE; + cs->interrupt_request &= ~CPU_INTERRUPT_MCE; kvm_cpu_synchronize_state(env); @@ -1853,7 +1854,7 @@ int kvm_arch_process_async_events(CPUState *cs) env->exception_injected = EXCP12_MCHK; env->has_error_code = 0; - env->halted = 0; + cs->halted = 0; if (kvm_irqchip_in_kernel() && env->mp_state == KVM_MP_STATE_HALTED) { env->mp_state = KVM_MP_STATE_RUNNABLE; } @@ -1863,41 +1864,42 @@ int kvm_arch_process_async_events(CPUState *cs) return 0; } - if (env->interrupt_request & CPU_INTERRUPT_POLL) { - env->interrupt_request &= ~CPU_INTERRUPT_POLL; + if (cs->interrupt_request & CPU_INTERRUPT_POLL) { + cs->interrupt_request &= ~CPU_INTERRUPT_POLL; apic_poll_irq(env->apic_state); } - if (((env->interrupt_request & CPU_INTERRUPT_HARD) && + if (((cs->interrupt_request & CPU_INTERRUPT_HARD) && (env->eflags & IF_MASK)) || - (env->interrupt_request & CPU_INTERRUPT_NMI)) { - env->halted = 0; + (cs->interrupt_request & CPU_INTERRUPT_NMI)) { + cs->halted = 0; } - if (env->interrupt_request & CPU_INTERRUPT_INIT) { + if (cs->interrupt_request & CPU_INTERRUPT_INIT) { kvm_cpu_synchronize_state(env); do_cpu_init(cpu); } - if (env->interrupt_request & CPU_INTERRUPT_SIPI) { + if (cs->interrupt_request & CPU_INTERRUPT_SIPI) { kvm_cpu_synchronize_state(env); do_cpu_sipi(cpu); } - if (env->interrupt_request & CPU_INTERRUPT_TPR) { - env->interrupt_request &= ~CPU_INTERRUPT_TPR; + if (cs->interrupt_request & CPU_INTERRUPT_TPR) { + cs->interrupt_request &= ~CPU_INTERRUPT_TPR; kvm_cpu_synchronize_state(env); apic_handle_tpr_access_report(env->apic_state, env->eip, env->tpr_access_type); } - return env->halted; + return cs->halted; } static int kvm_handle_halt(X86CPU *cpu) { + CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; - if (!((env->interrupt_request & CPU_INTERRUPT_HARD) && + if (!((cs->interrupt_request & CPU_INTERRUPT_HARD) && (env->eflags & IF_MASK)) && - !(env->interrupt_request & CPU_INTERRUPT_NMI)) { - env->halted = 1; + !(cs->interrupt_request & CPU_INTERRUPT_NMI)) { + cs->halted = 1; return EXCP_HLT; } diff --git a/target-i386/machine.c b/target-i386/machine.c index c9984b87a1..b80a5f4470 100644 --- a/target-i386/machine.c +++ b/target-i386/machine.c @@ -453,7 +453,7 @@ const VMStateDescription vmstate_x86_cpu = { VMSTATE_UINT64_V(env.pat, X86CPU, 5), VMSTATE_UINT32_V(env.hflags2, X86CPU, 5), - VMSTATE_UINT32_TEST(env.halted, X86CPU, version_is_5), + VMSTATE_UINT32_TEST(parent_obj.halted, X86CPU, version_is_5), VMSTATE_UINT64_V(env.vm_hsave, X86CPU, 5), VMSTATE_UINT64_V(env.vm_vmcb, X86CPU, 5), VMSTATE_UINT64_V(env.tsc_offset, X86CPU, 5), diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index b6d574019a..dfbc07b7f8 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -553,20 +553,25 @@ void helper_rdmsr(CPUX86State *env) } #endif -static void do_hlt(CPUX86State *env) +static void do_hlt(X86CPU *cpu) { + CPUState *cs = CPU(cpu); + CPUX86State *env = &cpu->env; + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ - env->halted = 1; + cs->halted = 1; env->exception_index = EXCP_HLT; cpu_loop_exit(env); } void helper_hlt(CPUX86State *env, int next_eip_addend) { + X86CPU *cpu = x86_env_get_cpu(env); + cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0); EIP += next_eip_addend; - do_hlt(env); + do_hlt(cpu); } void helper_monitor(CPUX86State *env, target_ulong ptr) @@ -580,7 +585,8 @@ void helper_monitor(CPUX86State *env, target_ulong ptr) void helper_mwait(CPUX86State *env, int next_eip_addend) { - CPUState *cpu; + CPUState *cs; + X86CPU *cpu; if ((uint32_t)ECX != 0) { raise_exception(env, EXCP0D_GPF); @@ -588,13 +594,14 @@ void helper_mwait(CPUX86State *env, int next_eip_addend) cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0); EIP += next_eip_addend; - cpu = CPU(x86_env_get_cpu(env)); + cpu = x86_env_get_cpu(env); + cs = CPU(cpu); /* XXX: not complete but not completely erroneous */ - if (cpu->cpu_index != 0 || env->next_cpu != NULL) { + if (cs->cpu_index != 0 || env->next_cpu != NULL) { /* more than one CPU: do not sleep because another CPU may wake this one */ } else { - do_hlt(env); + do_hlt(cpu); } } diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c index 3f246e9073..c46a213c9c 100644 --- a/target-i386/svm_helper.c +++ b/target-i386/svm_helper.c @@ -271,7 +271,9 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) env->hflags2 |= HF2_GIF_MASK; if (int_ctl & V_IRQ_MASK) { - env->interrupt_request |= CPU_INTERRUPT_VIRQ; + CPUState *cs = CPU(x86_env_get_cpu(env)); + + cs->interrupt_request |= CPU_INTERRUPT_VIRQ; } /* maybe we need to inject an event */ @@ -548,6 +550,7 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, /* Note: currently only 32 bits of exit_code are used */ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) { + CPUState *cs = CPU(x86_env_get_cpu(env)); uint32_t int_ctl; qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" @@ -594,7 +597,7 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK); int_ctl |= env->v_tpr & V_TPR_MASK; - if (env->interrupt_request & CPU_INTERRUPT_VIRQ) { + if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) { int_ctl |= V_IRQ_MASK; } stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl); @@ -615,7 +618,7 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1) env->hflags &= ~HF_SVMI_MASK; env->intercept = 0; env->intercept_exceptions = 0; - env->interrupt_request &= ~CPU_INTERRUPT_VIRQ; + cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ; env->tsc_offset = 0; env->gdt.base = ldq_phys(env->vm_hsave + offsetof(struct vmcb, diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 6948d0e248..d81f103e66 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -254,9 +254,7 @@ static inline void cpu_get_tb_cpu_state(CPULM32State *env, target_ulong *pc, static inline bool cpu_has_work(CPUState *cpu) { - CPULM32State *env = &LM32_CPU(cpu)->env; - - return env->interrupt_request & CPU_INTERRUPT_HARD; + return cpu->interrupt_request & CPU_INTERRUPT_HARD; } #include "exec/exec-all.h" diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c index 53410b176e..ebc94a0681 100644 --- a/target-lm32/op_helper.c +++ b/target-lm32/op_helper.c @@ -25,7 +25,9 @@ void helper_raise_exception(CPULM32State *env, uint32_t index) void helper_hlt(CPULM32State *env) { - env->halted = 1; + CPUState *cs = CPU(lm32_env_get_cpu(env)); + + cs->halted = 1; env->exception_index = EXCP_HLT; cpu_loop_exit(env); } diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 2672eae7c8..bb2fbd6d4d 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -265,9 +265,7 @@ static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc, static inline bool cpu_has_work(CPUState *cpu) { - CPUM68KState *env = &M68K_CPU(cpu)->env; - - return env->interrupt_request & CPU_INTERRUPT_HARD; + return cpu->interrupt_request & CPU_INTERRUPT_HARD; } #include "exec/exec-all.h" diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 16df24c0ca..e11f34b0f9 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -84,6 +84,7 @@ static void do_rte(CPUM68KState *env) static void do_interrupt_all(CPUM68KState *env, int is_hw) { + CPUState *cs; uint32_t sp; uint32_t fmt; uint32_t retaddr; @@ -108,7 +109,8 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw) do_m68k_semihosting(env, env->dregs[0]); return; } - env->halted = 1; + cs = CPU(m68k_env_get_cpu(env)); + cs->halted = 1; env->exception_index = EXCP_HLT; cpu_loop_exit(env); return; diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def index 49400c4475..4235b02764 100644 --- a/target-m68k/qregs.def +++ b/target-m68k/qregs.def @@ -8,6 +8,5 @@ DEFO32(CC_X, cc_x) DEFO32(DIV1, div1) DEFO32(DIV2, div2) DEFO32(EXCEPTION, exception_index) -DEFO32(HALTED, halted) DEFO32(MACSR, macsr) DEFO32(MAC_MASK, mac_mask) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 20a86d8efe..32b8132da6 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -42,6 +42,8 @@ #undef DEFO64 #undef DEFF64 +static TCGv_i32 cpu_halted; + static TCGv_ptr cpu_env; static char cpu_reg_names[3*8*3 + 5*4]; @@ -76,6 +78,10 @@ void m68k_tcg_init(void) #undef DEFO64 #undef DEFF64 + cpu_halted = tcg_global_mem_new_i32(TCG_AREG0, + -offsetof(M68kCPU, env) + + offsetof(CPUState, halted), "HALTED"); + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); p = cpu_reg_names; @@ -2024,7 +2030,7 @@ DISAS_INSN(stop) s->pc += 2; gen_set_sr_im(s, ext, 0); - tcg_gen_movi_i32(QREG_HALTED, 1); + tcg_gen_movi_i32(cpu_halted, 1); gen_exception(s, s->pc, EXCP_HLT); } diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index c3dd7f6219..7548aa903d 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -374,9 +374,7 @@ void cpu_unassigned_access(CPUMBState *env1, hwaddr addr, static inline bool cpu_has_work(CPUState *cpu) { - CPUMBState *env = &MICROBLAZE_CPU(cpu)->env; - - return env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); + return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); } #include "exec/exec-all.h" diff --git a/target-mips/cpu.h b/target-mips/cpu.h index ca63148b18..22b0497757 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -722,7 +722,7 @@ static inline bool cpu_has_work(CPUState *cpu) /* It is implementation dependent if non-enabled interrupts wake-up the CPU, however most of the implementations only check for interrupts that can be taken. */ - if ((env->interrupt_request & CPU_INTERRUPT_HARD) && + if ((cpu->interrupt_request & CPU_INTERRUPT_HARD) && cpu_mips_hw_interrupts_pending(env)) { has_work = true; } @@ -731,7 +731,7 @@ static inline bool cpu_has_work(CPUState *cpu) if (env->CP0_Config3 & (1 << CP0C3_MT)) { /* The QEMU model will issue an _WAKE request whenever the CPUs should be woken up. */ - if (env->interrupt_request & CPU_INTERRUPT_WAKE) { + if (cpu->interrupt_request & CPU_INTERRUPT_WAKE) { has_work = true; } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 45cbb2f1c2..3ab4356587 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -515,11 +515,12 @@ void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, /* SMP helpers. */ static bool mips_vpe_is_wfi(MIPSCPU *c) { + CPUState *cpu = CPU(c); CPUMIPSState *env = &c->env; /* If the VPE is halted but otherwise active, it means it's waiting for an interrupt. */ - return env->halted && mips_vpe_active(env); + return cpu->halted && mips_vpe_active(env); } static inline void mips_vpe_wake(CPUMIPSState *c) @@ -532,11 +533,12 @@ static inline void mips_vpe_wake(CPUMIPSState *c) static inline void mips_vpe_sleep(MIPSCPU *cpu) { + CPUState *cs = CPU(cpu); CPUMIPSState *c = &cpu->env; /* The VPE was shut off, really go to bed. Reset any old _WAKE requests. */ - c->halted = 1; + cs->halted = 1; cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE); } @@ -2099,7 +2101,9 @@ void helper_pmon(CPUMIPSState *env, int function) void helper_wait(CPUMIPSState *env) { - env->halted = 1; + CPUState *cs = CPU(mips_env_get_cpu(env)); + + cs->halted = 1; cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE); helper_raise_exception(env, EXCP_HLT); } diff --git a/target-mips/translate.c b/target-mips/translate.c index 694f07c49f..b7f8203e57 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -16004,7 +16004,7 @@ void cpu_state_reset(CPUMIPSState *env) env->tcs[i].CP0_TCHalt = 1; } env->active_tc.CP0_TCHalt = 1; - env->halted = 1; + cs->halted = 1; if (cs->cpu_index == 0) { /* VPE0 starts up enabled. */ @@ -16012,7 +16012,7 @@ void cpu_state_reset(CPUMIPSState *env) env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA); /* TC0 starts up unhalted. */ - env->halted = 0; + cs->halted = 0; env->active_tc.CP0_TCHalt = 0; env->tcs[0].CP0_TCHalt = 0; /* With thread 0 active. */ diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index 4cfd1c74fb..64370a3772 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -423,9 +423,7 @@ static inline int cpu_mmu_index(CPUOpenRISCState *env) #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 static inline bool cpu_has_work(CPUState *cpu) { - CPUOpenRISCState *env = &OPENRISC_CPU(cpu)->env; - - return env->interrupt_request & (CPU_INTERRUPT_HARD | + return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER); } diff --git a/target-openrisc/interrupt_helper.c b/target-openrisc/interrupt_helper.c index a176441b01..844648f780 100644 --- a/target-openrisc/interrupt_helper.c +++ b/target-openrisc/interrupt_helper.c @@ -24,6 +24,7 @@ void HELPER(rfe)(CPUOpenRISCState *env) { OpenRISCCPU *cpu = openrisc_env_get_cpu(env); + CPUState *cs = CPU(cpu); #ifndef CONFIG_USER_ONLY int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^ (cpu->env.esr & (SR_SM | SR_IME | SR_DME)); @@ -53,5 +54,5 @@ void HELPER(rfe)(CPUOpenRISCState *env) tlb_flush(&cpu->env, 1); } #endif - cpu->env.interrupt_request |= CPU_INTERRUPT_EXITTB; + cs->interrupt_request |= CPU_INTERRUPT_EXITTB; } diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c index 3c5f45ab75..cccbc0e939 100644 --- a/target-openrisc/sys_helper.c +++ b/target-openrisc/sys_helper.c @@ -31,6 +31,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, int idx; OpenRISCCPU *cpu = openrisc_env_get_cpu(env); + CPUState *cs = CPU(cpu); switch (spr) { case TO_SPR(0, 0): /* VR */ @@ -132,7 +133,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, env->ttmr = (rb & ~TTMR_IP) + ip; } else { /* Clear IP bit. */ env->ttmr = rb & ~TTMR_IP; - env->interrupt_request &= ~CPU_INTERRUPT_TIMER; + cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } cpu_openrisc_count_update(cpu); diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 417abb0dd1..1b31b1d9c9 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -2217,9 +2217,10 @@ extern void (*cpu_ppc_hypercall)(PowerPCCPU *); static inline bool cpu_has_work(CPUState *cpu) { - CPUPPCState *env = &POWERPC_CPU(cpu)->env; + PowerPCCPU *ppc_cpu = POWERPC_CPU(cpu); + CPUPPCState *env = &ppc_cpu->env; - return msr_ee && (env->interrupt_request & CPU_INTERRUPT_HARD); + return msr_ee && (cpu->interrupt_request & CPU_INTERRUPT_HARD); } #include "exec/exec-all.h" diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 0a1ac86a42..79ce7bf7c4 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -66,6 +66,7 @@ static inline void dump_syscall(CPUPPCState *env) static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) { CPUPPCState *env = &cpu->env; + CPUState *cs; target_ulong msr, new_msr, vector; int srr0, srr1, asrr0, asrr1; int lpes0, lpes1, lev; @@ -131,8 +132,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) fprintf(stderr, "Machine check while not allowed. " "Entering checkstop state\n"); } - env->halted = 1; - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + cs = CPU(cpu); + cs->halted = 1; + cs->interrupt_request |= CPU_INTERRUPT_EXITTB; } if (0) { /* XXX: find a suitable condition to enable the hypervisor mode */ @@ -663,11 +665,12 @@ void ppc_hw_interrupt(CPUPPCState *env) { PowerPCCPU *cpu = ppc_env_get_cpu(env); int hdice; - #if 0 + CPUState *cs = CPU(cpu); + qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n", - __func__, env, env->pending_interrupts, - env->interrupt_request, (int)msr_me, (int)msr_ee); + __func__, env, env->pending_interrupts, + cs->interrupt_request, (int)msr_me, (int)msr_ee); #endif /* External reset */ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { @@ -807,9 +810,12 @@ void helper_raise_exception(CPUPPCState *env, uint32_t exception) #if !defined(CONFIG_USER_ONLY) void helper_store_msr(CPUPPCState *env, target_ulong val) { + CPUState *cs; + val = hreg_store_msr(env, val, 0); if (val != 0) { - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + cs = CPU(ppc_env_get_cpu(env)); + cs->interrupt_request |= CPU_INTERRUPT_EXITTB; helper_raise_exception(env, val); } } @@ -817,6 +823,8 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, target_ulong msrm, int keep_msrh) { + CPUState *cs = CPU(ppc_env_get_cpu(env)); + #if defined(TARGET_PPC64) if (msr_is_64bit(env, msr)) { nip = (uint64_t)nip; @@ -841,7 +849,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, /* No need to raise an exception here, * as rfi is always the last insn of a TB */ - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + cs->interrupt_request |= CPU_INTERRUPT_EXITTB; } void helper_rfi(CPUPPCState *env) diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h index 3c988502ed..a6d5e2fe2f 100644 --- a/target-ppc/helper_regs.h +++ b/target-ppc/helper_regs.h @@ -68,10 +68,13 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) { int excp; +#if !defined(CONFIG_USER_ONLY) + CPUState *cs = CPU(ppc_env_get_cpu(env)); +#endif excp = 0; value &= env->msr_mask; -#if !defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) if (!alter_hv) { /* mtmsr cannot alter the hypervisor state */ value &= ~MSR_HVB; @@ -82,7 +85,7 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, /* Flush all tlb when changing translation mode */ tlb_flush(env, 1); excp = POWERPC_EXCP_NONE; - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + cs->interrupt_request |= CPU_INTERRUPT_EXITTB; } if (unlikely((env->flags & POWERPC_FLAG_TGPR) && ((value ^ env->msr) & (1 << MSR_TGPR)))) { @@ -96,10 +99,10 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, #endif env->msr = value; hreg_compute_hflags(env); -#if !defined (CONFIG_USER_ONLY) +#if !defined(CONFIG_USER_ONLY) if (unlikely(msr_pow == 1)) { if ((*env->check_pow)(env)) { - env->halted = 1; + cs->halted = 1; excp = EXCP_HALTED; } } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 9dff7607f1..e663ff0acb 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -993,7 +993,7 @@ void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) * interrupt, reset, etc) in PPC-specific env->irq_input_state. */ if (!cap_interrupt_level && run->ready_for_interrupt_injection && - (env->interrupt_request & CPU_INTERRUPT_HARD) && + (cs->interrupt_request & CPU_INTERRUPT_HARD) && (env->irq_input_state & (1<env.halted; + return cs->halted; } -static int kvmppc_handle_halt(CPUPPCState *env) +static int kvmppc_handle_halt(PowerPCCPU *cpu) { - if (!(env->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) { - env->halted = 1; + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) { + cs->halted = 1; env->exception_index = EXCP_HLT; } @@ -1073,7 +1075,7 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) break; case KVM_EXIT_HLT: dprintf("handle halt\n"); - ret = kvmppc_handle_halt(env); + ret = kvmppc_handle_halt(cpu); break; #ifdef CONFIG_PSERIES case KVM_EXIT_PAPR_HCALL: diff --git a/target-ppc/translate.c b/target-ppc/translate.c index fa9e9e3857..380a884131 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -3103,7 +3103,8 @@ static void gen_sync(DisasContext *ctx) static void gen_wait(DisasContext *ctx) { TCGv_i32 t0 = tcg_temp_new_i32(); - tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, halted)); + tcg_gen_st_i32(t0, cpu_env, + -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted)); tcg_temp_free_i32(t0); /* Stop translation, as the CPU is supposed to sleep from now */ gen_exception_err(ctx, EXCP_HLT, 1); diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index b74654724d..738a0ad1ee 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -80,10 +80,10 @@ static void s390_cpu_reset(CPUState *s) env->cregs[0] = CR0_RESET; env->cregs[14] = CR14_RESET; /* set halted to 1 to make sure we can add the cpu in - * s390_ipl_cpu code, where env->halted is set back to 0 + * s390_ipl_cpu code, where CPUState::halted is set back to 0 * after incrementing the cpu counter */ #if !defined(CONFIG_USER_ONLY) - env->halted = 1; + s->halted = 1; #endif tlb_flush(env, 1); } @@ -129,10 +129,10 @@ static void s390_cpu_initfn(Object *obj) env->tod_basetime = 0; env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu); env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu); - /* set env->halted state to 1 to avoid decrementing the running + /* set CPUState::halted state to 1 to avoid decrementing the running * cpu counter in s390_cpu_reset to a negative number at * initial ipl */ - env->halted = 1; + cs->halted = 1; #endif env->cpu_num = cpu_num++; env->ext_index = -1; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 9cb739da1e..db263bf4e3 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1039,9 +1039,10 @@ static inline void cpu_inject_crw_mchk(S390CPU *cpu) static inline bool cpu_has_work(CPUState *cpu) { - CPUS390XState *env = &S390_CPU(cpu)->env; + S390CPU *s390_cpu = S390_CPU(cpu); + CPUS390XState *env = &s390_cpu->env; - return (env->interrupt_request & CPU_INTERRUPT_HARD) && + return (cpu->interrupt_request & CPU_INTERRUPT_HARD) && (env->psw.mask & PSW_MASK_EXT); } diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 1183b45ca1..c88a58743e 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -437,6 +437,7 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) { if (mask & PSW_MASK_WAIT) { S390CPU *cpu = s390_env_get_cpu(env); + CPUState *cs = CPU(cpu); if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) { if (s390_del_running_cpu(cpu) == 0) { #ifndef CONFIG_USER_ONLY @@ -444,7 +445,7 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) #endif } } - env->halted = 1; + cs->halted = 1; env->exception_index = EXCP_HLT; } @@ -739,6 +740,7 @@ static void do_mchk_interrupt(CPUS390XState *env) void do_interrupt(CPUS390XState *env) { S390CPU *cpu = s390_env_get_cpu(env); + CPUState *cs; qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, env->psw.addr); @@ -797,7 +799,8 @@ void do_interrupt(CPUS390XState *env) env->exception_index = -1; if (!env->pending_int) { - env->interrupt_request &= ~CPU_INTERRUPT_HARD; + cs = CPU(s390_env_get_cpu(env)); + cs->interrupt_request &= ~CPU_INTERRUPT_HARD; } } diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index f805778075..49663556ef 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -369,9 +369,7 @@ static inline void cpu_get_tb_cpu_state(CPUSH4State *env, target_ulong *pc, static inline bool cpu_has_work(CPUState *cpu) { - CPUSH4State *env = &SUPERH_CPU(cpu)->env; - - return env->interrupt_request & CPU_INTERRUPT_HARD; + return cpu->interrupt_request & CPU_INTERRUPT_HARD; } #include "exec/exec-all.h" diff --git a/target-sh4/helper.c b/target-sh4/helper.c index ddebc78964..fd4efee4a6 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -78,9 +78,10 @@ int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) #define MMU_DADDR_ERROR_READ (-12) #define MMU_DADDR_ERROR_WRITE (-13) -void do_interrupt(CPUSH4State * env) +void do_interrupt(CPUSH4State *env) { - int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD; + CPUState *cs = CPU(sh_env_get_cpu(env)); + int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD; int do_exp, irq_vector = env->exception_index; /* prioritize exceptions over interrupts */ diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c index 09e3d23aff..e955e810b5 100644 --- a/target-sh4/op_helper.c +++ b/target-sh4/op_helper.c @@ -102,7 +102,9 @@ void helper_debug(CPUSH4State *env) void helper_sleep(CPUSH4State *env) { - env->halted = 1; + CPUState *cs = CPU(sh_env_get_cpu(env)); + + cs->halted = 1; env->in_sleep = 1; raise_exception(env, EXCP_HLT, 0); } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index a2f2cc8989..8a2f8df992 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -762,9 +762,10 @@ static inline bool tb_am_enabled(int tb_flags) static inline bool cpu_has_work(CPUState *cpu) { - CPUSPARCState *env1 = &SPARC_CPU(cpu)->env; + SPARCCPU *sparc_cpu = SPARC_CPU(cpu); + CPUSPARCState *env1 = &sparc_cpu->env; - return (env1->interrupt_request & CPU_INTERRUPT_HARD) && + return (cpu->interrupt_request & CPU_INTERRUPT_HARD) && cpu_interrupts_enabled(env1); } diff --git a/target-sparc/helper.c b/target-sparc/helper.c index 58e7efe567..57c20af478 100644 --- a/target-sparc/helper.c +++ b/target-sparc/helper.c @@ -229,7 +229,9 @@ target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1, #ifndef TARGET_SPARC64 void helper_power_down(CPUSPARCState *env) { - env->halted = 1; + CPUState *cs = CPU(sparc_env_get_cpu(env)); + + cs->halted = 1; env->exception_index = EXCP_HLT; env->pc = env->npc; env->npc = env->pc + 4; diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h index ae9a9d623d..58f1f20ca5 100644 --- a/target-unicore32/cpu.h +++ b/target-unicore32/cpu.h @@ -181,9 +181,7 @@ void switch_mode(CPUUniCore32State *, int); static inline bool cpu_has_work(CPUState *cpu) { - CPUUniCore32State *env = &UNICORE32_CPU(cpu)->env; - - return env->interrupt_request & + return cpu->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); } diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c index fc27100f27..1c4c7f5245 100644 --- a/target-unicore32/softmmu.c +++ b/target-unicore32/softmmu.c @@ -74,6 +74,7 @@ void switch_mode(CPUUniCore32State *env, int mode) /* Handle a CPU exception. */ void do_interrupt(CPUUniCore32State *env) { + CPUState *cs = CPU(uc32_env_get_cpu(env)); uint32_t addr; int new_mode; @@ -112,7 +113,7 @@ void do_interrupt(CPUUniCore32State *env) /* The PC already points to the proper instruction. */ env->regs[30] = env->regs[31]; env->regs[31] = addr; - env->interrupt_request |= CPU_INTERRUPT_EXITTB; + cs->interrupt_request |= CPU_INTERRUPT_EXITTB; } static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address, diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index 3813a72626..1037101f2e 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -373,6 +373,8 @@ void HELPER(dump_state)(CPUXtensaState *env) void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel) { + CPUState *cpu; + env->pc = pc; env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | (intlevel << PS_INTLEVEL_SHIFT); @@ -382,8 +384,9 @@ void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel) return; } + cpu = CPU(xtensa_env_get_cpu(env)); env->halt_clock = qemu_get_clock_ns(vm_clock); - env->halted = 1; + cpu->halted = 1; if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { xtensa_rearm_ccompare_timer(env); } diff --git a/translate-all.c b/translate-all.c index 90ea002935..f0c7d1e4c9 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1077,8 +1077,8 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, tb_phys_invalidate(tb, -1); if (cpu != NULL) { cpu->current_tb = saved_tb; - if (env && env->interrupt_request && cpu->current_tb) { - cpu_interrupt(env, env->interrupt_request); + if (env && cpu->interrupt_request && cpu->current_tb) { + cpu_interrupt(env, cpu->interrupt_request); } } } @@ -1387,8 +1387,8 @@ static void tcg_handle_interrupt(CPUArchState *env, int mask) CPUState *cpu = ENV_GET_CPU(env); int old_mask; - old_mask = env->interrupt_request; - env->interrupt_request |= mask; + old_mask = cpu->interrupt_request; + cpu->interrupt_request |= mask; /* * If called from iothread context, wake the target cpu in @@ -1556,7 +1556,7 @@ void cpu_interrupt(CPUArchState *env, int mask) { CPUState *cpu = ENV_GET_CPU(env); - env->interrupt_request |= mask; + cpu->interrupt_request |= mask; cpu->tcg_exit_req = 1; } diff --git a/xen-all.c b/xen-all.c index 110f958a53..8c05843faf 100644 --- a/xen-all.c +++ b/xen-all.c @@ -578,16 +578,18 @@ void qmp_xen_set_global_dirty_log(bool enable, Error **errp) static void xen_reset_vcpu(void *opaque) { - CPUArchState *env = opaque; + CPUState *cpu = opaque; - env->halted = 1; + cpu->halted = 1; } void xen_vcpu_init(void) { if (first_cpu != NULL) { - qemu_register_reset(xen_reset_vcpu, first_cpu); - xen_reset_vcpu(first_cpu); + CPUState *cpu = ENV_GET_CPU(first_cpu); + + qemu_register_reset(xen_reset_vcpu, cpu); + xen_reset_vcpu(cpu); } /* if rtc_clock is left to default (host_clock), disable it */ if (rtc_clock == host_clock) { From d8ed887bdcd29ce2e967f8b15a6a2b6dcaa11cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Thu, 17 Jan 2013 22:30:20 +0100 Subject: [PATCH 1568/1634] exec: Pass CPUState to cpu_reset_interrupt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move it to qom/cpu.c to avoid build failures depending on include order of cpu-qom.h and exec/cpu-all.h. Change opaques of various ..._irq_handler() functions to the appropriate CPU type to facilitate using cpu_reset_interrupt(). Fix Coding Style issues while at it (missing braces, indentation). Signed-off-by: Andreas Färber --- exec.c | 7 ------- hw/alpha_typhoon.c | 8 +++++--- hw/apic.c | 4 ++-- hw/arm/pic_cpu.c | 15 +++++++++------ hw/arm/pxa2xx_pic.c | 4 ++-- hw/cris/pic_cpu.c | 13 ++++++++----- hw/i386/pc.c | 8 +++++--- hw/lm32/lm32_boards.c | 8 +++++--- hw/lm32/milkymist.c | 8 +++++--- hw/microblaze/pic_cpu.c | 14 +++++++++----- hw/mips/mips_int.c | 8 +++++--- hw/openrisc/pic_cpu.c | 3 ++- hw/ppc/ppc.c | 6 ++++-- hw/sh_intc.c | 9 +++++---- hw/sparc/leon3.c | 4 +++- hw/sparc/sun4m.c | 5 ++++- hw/sparc64/sun4u.c | 7 ++++--- hw/unicore32/puv3.c | 9 ++++++--- hw/xtensa/pic_cpu.c | 2 +- include/exec/cpu-all.h | 2 -- include/qom/cpu.h | 9 +++++++++ qom/cpu.c | 5 +++++ target-m68k/helper.c | 8 +++++--- target-mips/op_helper.c | 5 ++--- 24 files changed, 105 insertions(+), 66 deletions(-) diff --git a/exec.c b/exec.c index 4462edf076..ae5a4b4430 100644 --- a/exec.c +++ b/exec.c @@ -492,13 +492,6 @@ void cpu_single_step(CPUArchState *env, int enabled) #endif } -void cpu_reset_interrupt(CPUArchState *env, int mask) -{ - CPUState *cpu = ENV_GET_CPU(env); - - cpu->interrupt_request &= ~mask; -} - void cpu_exit(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 95571ffc5d..7bfde5771c 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -63,10 +63,11 @@ static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) /* If there are any non-masked interrupts, tell the cpu. */ if (cpu != NULL) { CPUAlphaState *env = &cpu->env; + CPUState *cs = CPU(cpu); if (req) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } } @@ -359,16 +360,17 @@ static void cchip_write(void *opaque, hwaddr addr, AlphaCPU *cpu = s->cchip.cpu[i]; if (cpu != NULL) { CPUAlphaState *env = &cpu->env; + CPUState *cs = CPU(cpu); /* IPI can be either cleared or set by the write. */ if (newval & (1 << (i + 8))) { cpu_interrupt(env, CPU_INTERRUPT_SMP); } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_SMP); + cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP); } /* ITI can only be cleared by the write. */ if ((newval & (1 << (i + 4))) == 0) { - cpu_reset_interrupt(env, CPU_INTERRUPT_TIMER); + cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER); } } } diff --git a/hw/apic.c b/hw/apic.c index 8eddba06e5..cc9236a41c 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -187,7 +187,7 @@ void apic_deliver_pic_intr(DeviceState *d, int level) reset_bit(s->irr, lvt & 0xff); /* fall through */ case APIC_DM_EXTINT: - cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD); break; } } @@ -485,7 +485,7 @@ void apic_sipi(DeviceState *d) { APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); - cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI); + cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); if (!s->wait_for_sipi) return; diff --git a/hw/arm/pic_cpu.c b/hw/arm/pic_cpu.c index 82236006d2..95f5bf1777 100644 --- a/hw/arm/pic_cpu.c +++ b/hw/arm/pic_cpu.c @@ -16,19 +16,22 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level) { ARMCPU *cpu = opaque; CPUARMState *env = &cpu->env; + CPUState *cs = CPU(cpu); switch (irq) { case ARM_PIC_CPU_IRQ: - if (level) + if (level) { cpu_interrupt(env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } break; case ARM_PIC_CPU_FIQ: - if (level) + if (level) { cpu_interrupt(env, CPU_INTERRUPT_FIQ); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ); + } break; default: hw_error("arm_pic_cpu_handler: Bad interrupt line %d\n", irq); diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index b55ce479f4..b45b371435 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -62,13 +62,13 @@ static void pxa2xx_pic_update(void *opaque) if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) { cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); } else { - cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ); } if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) { cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD); } } diff --git a/hw/cris/pic_cpu.c b/hw/cris/pic_cpu.c index 7f50471e53..afd0df8041 100644 --- a/hw/cris/pic_cpu.c +++ b/hw/cris/pic_cpu.c @@ -30,16 +30,19 @@ static void cris_pic_cpu_handler(void *opaque, int irq, int level) { - CPUCRISState *env = (CPUCRISState *)opaque; + CRISCPU *cpu = opaque; + CPUCRISState *env = &cpu->env; + CPUState *cs = CPU(cpu); int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; - if (level) + if (level) { cpu_interrupt(env, type); - else - cpu_reset_interrupt(env, type); + } else { + cpu_reset_interrupt(cs, type); + } } qemu_irq *cris_pic_init_cpu(CPUCRISState *env) { - return qemu_allocate_irqs(cris_pic_cpu_handler, env, 2); + return qemu_allocate_irqs(cris_pic_cpu_handler, cris_env_get_cpu(env), 2); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 309bb83cab..c731bdc024 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -190,10 +190,12 @@ static void pic_irq_request(void *opaque, int irq, int level) env = env->next_cpu; } } else { - if (level) + CPUState *cs = CPU(x86_env_get_cpu(env)); + if (level) { cpu_interrupt(env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } } } diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index 1ce466a1b1..538c20397f 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -41,12 +41,14 @@ typedef struct { static void cpu_irq_handler(void *opaque, int irq, int level) { - CPULM32State *env = opaque; + LM32CPU *cpu = opaque; + CPULM32State *env = &cpu->env; + CPUState *cs = CPU(cpu); if (level) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -117,7 +119,7 @@ static void lm32_evr_init(QEMUMachineInitArgs *args) 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); /* create irq lines */ - cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); + cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1); env->pic_state = lm32_pic_init(*cpu_irq); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(env->pic_state, i); diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index fd36de57b5..9ff6d28854 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -46,12 +46,14 @@ typedef struct { static void cpu_irq_handler(void *opaque, int irq, int level) { - CPULM32State *env = opaque; + LM32CPU *cpu = opaque; + CPULM32State *env = &cpu->env; + CPUState *cs = CPU(cpu); if (level) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -123,7 +125,7 @@ milkymist_init(QEMUMachineInitArgs *args) 0x00, 0x89, 0x00, 0x1d, 1); /* create irq lines */ - cpu_irq = qemu_allocate_irqs(cpu_irq_handler, env, 1); + cpu_irq = qemu_allocate_irqs(cpu_irq_handler, cpu, 1); env->pic_state = lm32_pic_init(*cpu_irq); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(env->pic_state, i); diff --git a/hw/microblaze/pic_cpu.c b/hw/microblaze/pic_cpu.c index d4743ab390..47568505c7 100644 --- a/hw/microblaze/pic_cpu.c +++ b/hw/microblaze/pic_cpu.c @@ -29,16 +29,20 @@ static void microblaze_pic_cpu_handler(void *opaque, int irq, int level) { - CPUMBState *env = (CPUMBState *)opaque; + MicroBlazeCPU *cpu = opaque; + CPUMBState *env = &cpu->env; + CPUState *cs = CPU(cpu); int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; - if (level) + if (level) { cpu_interrupt(env, type); - else - cpu_reset_interrupt(env, type); + } else { + cpu_reset_interrupt(cs, type); + } } qemu_irq *microblaze_pic_init_cpu(CPUMBState *env) { - return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2); + return qemu_allocate_irqs(microblaze_pic_cpu_handler, mb_env_get_cpu(env), + 2); } diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index ddd3b1bb01..3a78999e02 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -26,7 +26,9 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) { - CPUMIPSState *env = (CPUMIPSState *)opaque; + MIPSCPU *cpu = opaque; + CPUMIPSState *env = &cpu->env; + CPUState *cs = CPU(cpu); if (irq < 0 || irq > 7) return; @@ -40,7 +42,7 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) if (env->CP0_Cause & CP0Ca_IP_mask) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -49,7 +51,7 @@ void cpu_mips_irq_init_cpu(CPUMIPSState *env) qemu_irq *qi; int i; - qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8); + qi = qemu_allocate_irqs(cpu_mips_irq_request, mips_env_get_cpu(env), 8); for (i = 0; i < 8; i++) { env->irq[i] = qi[i]; } diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c index 931511ec0f..7e4f9e015e 100644 --- a/hw/openrisc/pic_cpu.c +++ b/hw/openrisc/pic_cpu.c @@ -25,6 +25,7 @@ static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) { OpenRISCCPU *cpu = (OpenRISCCPU *)opaque; + CPUState *cs = CPU(cpu); int i; uint32_t irq_bit = 1 << irq; @@ -42,7 +43,7 @@ static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) { cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(&cpu->env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); cpu->env.picsr &= ~(1 << i); } } diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index b2d7fe8df7..ae2ed70181 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -52,6 +52,7 @@ static void cpu_ppc_tb_start (CPUPPCState *env); void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) { + CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; unsigned int old_pending = env->pending_interrupts; @@ -60,8 +61,9 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { env->pending_interrupts &= ~(1 << n_IRQ); - if (env->pending_interrupts == 0) - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + if (env->pending_interrupts == 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } } if (old_pending != env->pending_interrupts) { diff --git a/hw/sh_intc.c b/hw/sh_intc.c index 9e64e4d353..97903140ab 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -42,15 +42,16 @@ void sh_intc_toggle_source(struct intc_source *source, pending_changed = 1; if (pending_changed) { + CPUState *cpu = CPU(sh_env_get_cpu(first_cpu)); if (source->pending) { source->parent->pending++; if (source->parent->pending == 1) cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); - } - else { + } else { source->parent->pending--; - if (source->parent->pending == 0) - cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); + if (source->parent->pending == 0) { + cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD); + } } } diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index a9167e6f93..b1fbde0ff7 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -67,6 +67,7 @@ void leon3_irq_ack(void *irq_manager, int intno) static void leon3_set_pil_in(void *opaque, uint32_t pil_in) { CPUSPARCState *env = (CPUSPARCState *)opaque; + CPUState *cs; assert(env != NULL); @@ -89,9 +90,10 @@ static void leon3_set_pil_in(void *opaque, uint32_t pil_in) } } } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + cs = CPU(sparc_env_get_cpu(env)); trace_leon3_reset_irq(env->interrupt_index & 15); env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index a7e6966435..a1822f16f3 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -230,6 +230,8 @@ void sun4m_irq_info(Monitor *mon, const QDict *qdict) void cpu_check_irqs(CPUSPARCState *env) { + CPUState *cs; + if (env->pil_in && (env->interrupt_index == 0 || (env->interrupt_index & ~15) == TT_EXTINT)) { unsigned int i; @@ -247,9 +249,10 @@ void cpu_check_irqs(CPUSPARCState *env) } } } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + cs = CPU(sparc_env_get_cpu(env)); trace_sun4m_cpu_reset_interrupt(env->interrupt_index & 15); env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index ae3c95b5cf..817c23cde3 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -276,7 +276,7 @@ void cpu_check_irqs(CPUSPARCState *env) CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n", env->interrupt_index); env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } return; } @@ -309,7 +309,7 @@ void cpu_check_irqs(CPUSPARCState *env) "current interrupt %x\n", pil, env->pil_in, env->softint, env->interrupt_index); env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -344,8 +344,9 @@ static void cpu_set_ivec_irq(void *opaque, int irq, int level) } else { if (env->ivec_status & 0x20) { CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq); + cs = CPU(cpu); env->ivec_status &= ~0x20; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } } diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index f9d0c2bab1..6e87c41f28 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -26,13 +26,15 @@ static void puv3_intc_cpu_handler(void *opaque, int irq, int level) { - CPUUniCore32State *env = opaque; + UniCore32CPU *cpu = opaque; + CPUUniCore32State *env = &cpu->env; + CPUState *cs = CPU(cpu); assert(irq == 0); if (level) { cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -44,7 +46,8 @@ static void puv3_soc_init(CPUUniCore32State *env) int i; /* Initialize interrupt controller */ - cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1); + cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, + uc32_env_get_cpu(env), 1); dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc); for (i = 0; i < PUV3_IRQS_NR; i++) { irqs[i] = qdev_get_gpio_in(dev, i); diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 12f66b6f55..fd590c64ce 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -80,7 +80,7 @@ void check_interrupts(CPUXtensaState *env) } } env->pending_irq_level = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } static void xtensa_set_irq(void *opaque, int irq, int active) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 249e0464f2..5218a53576 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -434,8 +434,6 @@ static inline void cpu_interrupt(CPUArchState *s, int mask) void cpu_interrupt(CPUArchState *env, int mask); #endif /* USER_ONLY */ -void cpu_reset_interrupt(CPUArchState *env, int mask); - void cpu_exit(CPUArchState *s); /* Breakpoint/watchpoint flags */ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 23c80b9251..b83ba6f150 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -221,5 +221,14 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); */ CPUState *qemu_get_cpu(int index); +/** + * cpu_reset_interrupt: + * @cpu: The CPU to clear the interrupt on. + * @mask: The interrupt mask to clear. + * + * Resets interrupts on the vCPU @cpu. + */ +void cpu_reset_interrupt(CPUState *cpu, int mask); + #endif diff --git a/qom/cpu.c b/qom/cpu.c index 0aa9be793d..e242dcbeb4 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -21,6 +21,11 @@ #include "qom/cpu.h" #include "qemu-common.h" +void cpu_reset_interrupt(CPUState *cpu, int mask) +{ + cpu->interrupt_request &= ~mask; +} + void cpu_reset(CPUState *cpu) { CPUClass *klass = CPU_GET_CLASS(cpu); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 1bae3ab326..d9c8374be4 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -312,14 +312,16 @@ int cpu_m68k_handle_mmu_fault (CPUM68KState *env, target_ulong address, int rw, simplicitly we calculate it when the interrupt is signalled. */ void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) { + CPUState *cs = CPU(cpu); CPUM68KState *env = &cpu->env; env->pending_level = level; env->pending_vector = vector; - if (level) + if (level) { cpu_interrupt(env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } } #endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 3ab4356587..d568188703 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -534,12 +534,11 @@ static inline void mips_vpe_wake(CPUMIPSState *c) static inline void mips_vpe_sleep(MIPSCPU *cpu) { CPUState *cs = CPU(cpu); - CPUMIPSState *c = &cpu->env; /* The VPE was shut off, really go to bed. Reset any old _WAKE requests. */ cs->halted = 1; - cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE); + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); } static inline void mips_tc_wake(MIPSCPU *cpu, int tc) @@ -2104,7 +2103,7 @@ void helper_wait(CPUMIPSState *env) CPUState *cs = CPU(mips_env_get_cpu(env)); cs->halted = 1; - cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE); + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); helper_raise_exception(env, EXCP_HLT); } From c3affe5670e5d0df8a7e06f1d6e80853633146df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 18 Jan 2013 15:03:43 +0100 Subject: [PATCH 1569/1634] cpu: Pass CPUState to cpu_interrupt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move it to qom/cpu.h to avoid issues with include order. Change pc_acpi_smi_interrupt() opaque to X86CPU. Signed-off-by: Andreas Färber --- cpus.c | 2 +- exec.c | 2 +- hw/alpha_typhoon.c | 10 ++++------ hw/apic.c | 21 +++++++++++---------- hw/arm/omap1.c | 4 ++-- hw/arm/pic_cpu.c | 5 ++--- hw/arm/pxa2xx.c | 7 ++++--- hw/arm/pxa2xx_gpio.c | 2 +- hw/arm/pxa2xx_pic.c | 6 +++--- hw/cris/pic_cpu.c | 3 +-- hw/i386/pc.c | 6 +++--- hw/i386/pc_piix.c | 3 ++- hw/lm32/lm32_boards.c | 3 +-- hw/lm32/milkymist.c | 3 +-- hw/lpc_ich9.c | 2 +- hw/microblaze/pic_cpu.c | 3 +-- hw/mips/mips_int.c | 2 +- hw/openrisc/pic_cpu.c | 2 +- hw/ppc/ppc.c | 6 +++--- hw/ppc/ppc405_uc.c | 4 ++-- hw/sh_intc.c | 5 +++-- hw/sparc/leon3.c | 3 ++- hw/sparc/sun4m.c | 9 ++++++--- hw/sparc64/sun4u.c | 4 ++-- hw/unicore32/puv3.c | 3 +-- hw/xtensa/pic_cpu.c | 2 +- include/exec/cpu-all.h | 13 ------------- include/qom/cpu.h | 24 ++++++++++++++++++++++++ kvm-all.c | 4 +--- target-arm/helper.c | 2 +- target-i386/helper.c | 6 +++--- target-m68k/helper.c | 2 +- target-mips/op_helper.c | 8 ++++---- target-ppc/excp_helper.c | 2 +- target-s390x/cpu.h | 6 +++--- target-s390x/helper.c | 4 ++-- translate-all.c | 12 +++++------- 37 files changed, 106 insertions(+), 99 deletions(-) diff --git a/cpus.c b/cpus.c index 8d47bfd85b..e919dd7fb6 100644 --- a/cpus.c +++ b/cpus.c @@ -1309,7 +1309,7 @@ void qmp_inject_nmi(Error **errp) for (env = first_cpu; env != NULL; env = env->next_cpu) { if (!env->apic_state) { - cpu_interrupt(env, CPU_INTERRUPT_NMI); + cpu_interrupt(CPU(x86_env_get_cpu(env)), CPU_INTERRUPT_NMI); } else { apic_deliver_nmi(env->apic_state); } diff --git a/exec.c b/exec.c index ae5a4b4430..c5e65a9380 100644 --- a/exec.c +++ b/exec.c @@ -1467,7 +1467,7 @@ static void check_watchpoint(int offset, int len_mask, int flags) /* We re-entered the check after replacing the TB. Now raise * the debug interrupt so that is will trigger after the * current instruction. */ - cpu_interrupt(env, CPU_INTERRUPT_DEBUG); + cpu_interrupt(ENV_GET_CPU(env), CPU_INTERRUPT_DEBUG); return; } vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset; diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 7bfde5771c..770dc8cf0d 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -62,10 +62,9 @@ static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) { /* If there are any non-masked interrupts, tell the cpu. */ if (cpu != NULL) { - CPUAlphaState *env = &cpu->env; CPUState *cs = CPU(cpu); if (req) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } @@ -359,11 +358,10 @@ static void cchip_write(void *opaque, hwaddr addr, for (i = 0; i < 4; ++i) { AlphaCPU *cpu = s->cchip.cpu[i]; if (cpu != NULL) { - CPUAlphaState *env = &cpu->env; CPUState *cs = CPU(cpu); /* IPI can be either cleared or set by the write. */ if (newval & (1 << (i + 8))) { - cpu_interrupt(env, CPU_INTERRUPT_SMP); + cpu_interrupt(cs, CPU_INTERRUPT_SMP); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP); } @@ -687,7 +685,7 @@ static void typhoon_set_timer_irq(void *opaque, int irq, int level) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (i + 4); /* And signal the interrupt. */ - cpu_interrupt(&cpu->env, CPU_INTERRUPT_TIMER); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER); } } } @@ -700,7 +698,7 @@ static void typhoon_alarm_timer(void *opaque) /* Set the ITI bit for this cpu. */ s->cchip.misc |= 1 << (cpu + 4); - cpu_interrupt(&s->cchip.cpu[cpu]->env, CPU_INTERRUPT_TIMER); + cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER); } PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, diff --git a/hw/apic.c b/hw/apic.c index cc9236a41c..d2395f04dd 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -151,15 +151,15 @@ static void apic_local_deliver(APICCommonState *s, int vector) switch ((lvt >> 8) & 7) { case APIC_DM_SMI: - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SMI); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI); break; case APIC_DM_NMI: - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_NMI); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI); break; case APIC_DM_EXTINT: - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD); break; case APIC_DM_FIXED: @@ -248,20 +248,20 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, case APIC_DM_SMI: foreach_apic(apic_iter, deliver_bitmask, - cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_SMI) + cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI) ); return; case APIC_DM_NMI: foreach_apic(apic_iter, deliver_bitmask, - cpu_interrupt(&apic_iter->cpu->env, CPU_INTERRUPT_NMI) + cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI) ); return; case APIC_DM_INIT: /* normal INIT IPI sent to processors */ foreach_apic(apic_iter, deliver_bitmask, - cpu_interrupt(&apic_iter->cpu->env, + cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_INIT) ); return; @@ -363,15 +363,16 @@ static int apic_irq_pending(APICCommonState *s) /* signal the CPU if an irq is pending */ static void apic_update_irq(APICCommonState *s) { - CPUState *cpu = CPU(s->cpu); + CPUState *cpu; if (!(s->spurious_vec & APIC_SV_ENABLE)) { return; } + cpu = CPU(s->cpu); if (!qemu_cpu_is_self(cpu)) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_POLL); + cpu_interrupt(cpu, CPU_INTERRUPT_POLL); } else if (apic_irq_pending(s) > 0) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + cpu_interrupt(cpu, CPU_INTERRUPT_HARD); } } @@ -478,7 +479,7 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, static void apic_startup(APICCommonState *s, int vector_num) { s->sipi_vector = vector_num; - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_SIPI); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); } void apic_sipi(DeviceState *d) diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 7afd590ec7..3245c62e68 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -1523,7 +1523,7 @@ static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, omap_clk clk; if (value & (1 << 11)) { /* SETARM_IDLE */ - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT); } if (!(value & (1 << 10))) /* WKUP_MODE */ qemu_system_shutdown_request(); /* XXX: disable wakeup from IRQ */ @@ -3759,7 +3759,7 @@ void omap_mpu_wakeup(void *opaque, int irq, int req) CPUState *cpu = CPU(mpu->cpu); if (cpu->halted) { - cpu_interrupt(&mpu->cpu->env, CPU_INTERRUPT_EXITTB); + cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB); } } diff --git a/hw/arm/pic_cpu.c b/hw/arm/pic_cpu.c index 95f5bf1777..3a3f06566b 100644 --- a/hw/arm/pic_cpu.c +++ b/hw/arm/pic_cpu.c @@ -15,20 +15,19 @@ static void arm_pic_cpu_handler(void *opaque, int irq, int level) { ARMCPU *cpu = opaque; - CPUARMState *env = &cpu->env; CPUState *cs = CPU(cpu); switch (irq) { case ARM_PIC_CPU_IRQ: if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } break; case ARM_PIC_CPU_FIQ: if (level) { - cpu_interrupt(env, CPU_INTERRUPT_FIQ); + cpu_interrupt(cs, CPU_INTERRUPT_FIQ); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ); } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index c0f50c90fe..7467cca4f7 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -263,14 +263,14 @@ static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, case 1: /* Idle */ if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT); break; } /* Fall through. */ case 2: /* Deep-Idle */ - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); + cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT); s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ goto message; @@ -301,7 +301,8 @@ static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, #endif /* Suspend */ - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); + cpu_interrupt(CPU(arm_env_get_cpu(cpu_single_env)), + CPU_INTERRUPT_HALT); goto message; diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index d2da928ac0..55ebcd724a 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -120,7 +120,7 @@ static void pxa2xx_gpio_set(void *opaque, int line, int level) /* Wake-up GPIOs */ if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB); } } diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index b45b371435..25e90895e1 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -52,7 +52,7 @@ static void pxa2xx_pic_update(void *opaque) mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); if (mask[0] || mask[1]) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_EXITTB); + cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB); } } @@ -60,13 +60,13 @@ static void pxa2xx_pic_update(void *opaque) mask[1] = s->int_pending[1] & s->int_enabled[1]; if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_FIQ); + cpu_interrupt(cpu, CPU_INTERRUPT_FIQ); } else { cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ); } if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) { - cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HARD); + cpu_interrupt(cpu, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD); } diff --git a/hw/cris/pic_cpu.c b/hw/cris/pic_cpu.c index afd0df8041..85c68c0497 100644 --- a/hw/cris/pic_cpu.c +++ b/hw/cris/pic_cpu.c @@ -31,12 +31,11 @@ static void cris_pic_cpu_handler(void *opaque, int irq, int level) { CRISCPU *cpu = opaque; - CPUCRISState *env = &cpu->env; CPUState *cs = CPU(cpu); int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; if (level) { - cpu_interrupt(env, type); + cpu_interrupt(cs, type); } else { cpu_reset_interrupt(cs, type); } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c731bdc024..ed7d9badb5 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -192,7 +192,7 @@ static void pic_irq_request(void *opaque, int irq, int level) } else { CPUState *cs = CPU(x86_env_get_cpu(env)); if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } @@ -856,10 +856,10 @@ DeviceState *cpu_get_current_apic(void) void pc_acpi_smi_interrupt(void *opaque, int irq, int level) { - CPUX86State *s = opaque; + X86CPU *cpu = opaque; if (level) { - cpu_interrupt(s, CPU_INTERRUPT_SMI); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_SMI); } } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 0ee3b3b806..0abc9f11e3 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -205,7 +205,8 @@ static void pc_init1(MemoryRegion *system_memory, if (pci_enabled && acpi_enabled) { i2c_bus *smbus; - smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1); + smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, + x86_env_get_cpu(first_cpu), 1); /* TODO: Populate SPD eeprom data. */ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, gsi[9], *smi_irq, diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index 538c20397f..db92948092 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -42,11 +42,10 @@ typedef struct { static void cpu_irq_handler(void *opaque, int irq, int level) { LM32CPU *cpu = opaque; - CPULM32State *env = &cpu->env; CPUState *cs = CPU(cpu); if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index 9ff6d28854..b347cf964c 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -47,11 +47,10 @@ typedef struct { static void cpu_irq_handler(void *opaque, int irq, int level) { LM32CPU *cpu = opaque; - CPULM32State *env = &cpu->env; CPUState *cs = CPU(cpu); if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index 0ca0a59ef7..ff0a3092d5 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -381,7 +381,7 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg) /* SMI_EN = PMBASE + 30. SMI control and enable register */ if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) { - cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); + cpu_interrupt(CPU(x86_env_get_cpu(first_cpu)), CPU_INTERRUPT_SMI); } } diff --git a/hw/microblaze/pic_cpu.c b/hw/microblaze/pic_cpu.c index 47568505c7..6248de92bb 100644 --- a/hw/microblaze/pic_cpu.c +++ b/hw/microblaze/pic_cpu.c @@ -30,12 +30,11 @@ static void microblaze_pic_cpu_handler(void *opaque, int irq, int level) { MicroBlazeCPU *cpu = opaque; - CPUMBState *env = &cpu->env; CPUState *cs = CPU(cpu); int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; if (level) { - cpu_interrupt(env, type); + cpu_interrupt(cs, type); } else { cpu_reset_interrupt(cs, type); } diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 3a78999e02..0e5e86699c 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -40,7 +40,7 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) } if (env->CP0_Cause & CP0Ca_IP_mask) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } diff --git a/hw/openrisc/pic_cpu.c b/hw/openrisc/pic_cpu.c index 7e4f9e015e..ca0b7c11bd 100644 --- a/hw/openrisc/pic_cpu.c +++ b/hw/openrisc/pic_cpu.c @@ -41,7 +41,7 @@ static void openrisc_pic_cpu_handler(void *opaque, int irq, int level) for (i = 0; i < 32; i++) { if ((cpu->env.picsr && (1 << i)) && (cpu->env.picmr && (1 << i))) { - cpu_interrupt(&cpu->env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); cpu->env.picsr &= ~(1 << i); diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index ae2ed70181..85bc821d94 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -58,7 +58,7 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level) if (level) { env->pending_interrupts |= 1 << n_IRQ; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { env->pending_interrupts &= ~(1 << n_IRQ); if (env->pending_interrupts == 0) { @@ -137,7 +137,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) /* Level sensitive - active low */ if (level) { LOG_IRQ("%s: reset the CPU\n", __func__); - cpu_interrupt(env, CPU_INTERRUPT_RESET); + cpu_interrupt(cs, CPU_INTERRUPT_RESET); } break; case PPC6xx_INPUT_SRESET: @@ -219,7 +219,7 @@ static void ppc970_set_irq(void *opaque, int pin, int level) case PPC970_INPUT_HRESET: /* Level sensitive - active low */ if (level) { - cpu_interrupt(env, CPU_INTERRUPT_RESET); + cpu_interrupt(cs, CPU_INTERRUPT_RESET); } break; case PPC970_INPUT_SRESET: diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index 8465f6dcd4..56bae8f6e0 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -1776,7 +1776,7 @@ void ppc40x_core_reset(PowerPCCPU *cpu) target_ulong dbsr; printf("Reset PowerPC core\n"); - cpu_interrupt(env, CPU_INTERRUPT_RESET); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); dbsr = env->spr[SPR_40x_DBSR]; dbsr &= ~0x00000300; dbsr |= 0x00000100; @@ -1789,7 +1789,7 @@ void ppc40x_chip_reset(PowerPCCPU *cpu) target_ulong dbsr; printf("Reset PowerPC chip\n"); - cpu_interrupt(env, CPU_INTERRUPT_RESET); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_RESET); /* XXX: TODO reset all internal peripherals */ dbsr = env->spr[SPR_40x_DBSR]; dbsr &= ~0x00000300; diff --git a/hw/sh_intc.c b/hw/sh_intc.c index 97903140ab..29e3d8f127 100644 --- a/hw/sh_intc.c +++ b/hw/sh_intc.c @@ -45,8 +45,9 @@ void sh_intc_toggle_source(struct intc_source *source, CPUState *cpu = CPU(sh_env_get_cpu(first_cpu)); if (source->pending) { source->parent->pending++; - if (source->parent->pending == 1) - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); + if (source->parent->pending == 1) { + cpu_interrupt(cpu, CPU_INTERRUPT_HARD); + } } else { source->parent->pending--; if (source->parent->pending == 0) { diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index b1fbde0ff7..bf06bf4b51 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -83,8 +83,9 @@ static void leon3_set_pil_in(void *opaque, uint32_t pil_in) env->interrupt_index = TT_EXTINT | i; if (old_interrupt != env->interrupt_index) { + cs = CPU(sparc_env_get_cpu(env)); trace_leon3_set_irq(i); - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } break; } diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index a1822f16f3..2f214da557 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -242,8 +242,9 @@ void cpu_check_irqs(CPUSPARCState *env) env->interrupt_index = TT_EXTINT | i; if (old_interrupt != env->interrupt_index) { + cs = CPU(sparc_env_get_cpu(env)); trace_sun4m_cpu_interrupt(i); - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } break; } @@ -306,8 +307,10 @@ static void secondary_cpu_reset(void *opaque) static void cpu_halt_signal(void *opaque, int irq, int level) { - if (level && cpu_single_env) - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); + if (level && cpu_single_env) { + cpu_interrupt(CPU(sparc_env_get_cpu(cpu_single_env)), + CPU_INTERRUPT_HALT); + } } static uint64_t translate_kernel_address(void *opaque, uint64_t addr) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 817c23cde3..4c39cf6607 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -299,7 +299,7 @@ void cpu_check_irqs(CPUSPARCState *env) env->interrupt_index = new_interrupt; CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i, old_interrupt, new_interrupt); - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } break; } @@ -339,7 +339,7 @@ static void cpu_set_ivec_irq(void *opaque, int irq, int level) env->ivec_data[0] = (0x1f << 6) | irq; env->ivec_data[1] = 0; env->ivec_data[2] = 0; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } } else { if (env->ivec_status & 0x20) { diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index 6e87c41f28..78ab13f9ed 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -27,12 +27,11 @@ static void puv3_intc_cpu_handler(void *opaque, int irq, int level) { UniCore32CPU *cpu = opaque; - CPUUniCore32State *env = &cpu->env; CPUState *cs = CPU(cpu); assert(irq == 0); if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index fd590c64ce..7f015ff5ab 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -66,7 +66,7 @@ void check_interrupts(CPUXtensaState *env) for (level = env->config->nlevel; level > minlevel; --level) { if (env->config->level_mask[level] & int_set_enabled) { env->pending_irq_level = level; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); qemu_log_mask(CPU_LOG_INT, "%s level = %d, cintlevel = %d, " "pc = %08x, a0 = %08x, ps = %08x, " diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 5218a53576..e9c3717863 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -421,19 +421,6 @@ DECLARE_TLS(CPUArchState *,cpu_single_env); | CPU_INTERRUPT_TGT_EXT_3 \ | CPU_INTERRUPT_TGT_EXT_4) -#ifndef CONFIG_USER_ONLY -typedef void (*CPUInterruptHandler)(CPUArchState *, int); - -extern CPUInterruptHandler cpu_interrupt_handler; - -static inline void cpu_interrupt(CPUArchState *s, int mask) -{ - cpu_interrupt_handler(s, mask); -} -#else /* USER_ONLY */ -void cpu_interrupt(CPUArchState *env, int mask); -#endif /* USER_ONLY */ - void cpu_exit(CPUArchState *s); /* Breakpoint/watchpoint flags */ diff --git a/include/qom/cpu.h b/include/qom/cpu.h index b83ba6f150..2e08135acd 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -221,6 +221,30 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data); */ CPUState *qemu_get_cpu(int index); +#ifndef CONFIG_USER_ONLY + +typedef void (*CPUInterruptHandler)(CPUState *, int); + +extern CPUInterruptHandler cpu_interrupt_handler; + +/** + * cpu_interrupt: + * @cpu: The CPU to set an interrupt on. + * @mask: The interupts to set. + * + * Invokes the interrupt handler. + */ +static inline void cpu_interrupt(CPUState *cpu, int mask) +{ + cpu_interrupt_handler(cpu, mask); +} + +#else /* USER_ONLY */ + +void cpu_interrupt(CPUState *cpu, int mask); + +#endif /* USER_ONLY */ + /** * cpu_reset_interrupt: * @cpu: The CPU to clear the interrupt on. diff --git a/kvm-all.c b/kvm-all.c index 2b761e0a0d..9b433d3163 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -826,10 +826,8 @@ static MemoryListener kvm_io_listener = { .priority = 10, }; -static void kvm_handle_interrupt(CPUArchState *env, int mask) +static void kvm_handle_interrupt(CPUState *cpu, int mask) { - CPUState *cpu = ENV_GET_CPU(env); - cpu->interrupt_request |= mask; if (!qemu_cpu_is_self(cpu)) { diff --git a/target-arm/helper.c b/target-arm/helper.c index d7e22dda13..f839726f52 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -764,7 +764,7 @@ static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { /* Wait-for-interrupt (deprecated) */ - cpu_interrupt(env, CPU_INTERRUPT_HALT); + cpu_interrupt(CPU(arm_env_get_cpu(env)), CPU_INTERRUPT_HALT); return 0; } diff --git a/target-i386/helper.c b/target-i386/helper.c index b49a0fc5f3..9449a0c49d 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -389,7 +389,7 @@ void x86_cpu_set_a20(X86CPU *cpu, int a20_state) #endif /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ - cpu_interrupt(env, CPU_INTERRUPT_EXITTB); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_EXITTB); /* when a20 is changed, all the MMU mappings are invalid, so we must flush everything */ @@ -1169,7 +1169,7 @@ static void do_inject_x86_mce(void *data) banks[3] = params->misc; cenv->mcg_status = params->mcg_status; banks[1] = params->status; - cpu_interrupt(cenv, CPU_INTERRUPT_MCE); + cpu_interrupt(cpu, CPU_INTERRUPT_MCE); } else if (!(banks[1] & MCI_STATUS_VAL) || !(banks[1] & MCI_STATUS_UC)) { if (banks[1] & MCI_STATUS_VAL) { @@ -1241,7 +1241,7 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access) if (kvm_enabled()) { env->tpr_access_type = access; - cpu_interrupt(env, CPU_INTERRUPT_TPR); + cpu_interrupt(CPU(x86_env_get_cpu(env)), CPU_INTERRUPT_TPR); } else { cpu_restore_state(env, env->mem_io_pc); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index d9c8374be4..54fa419ace 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -318,7 +318,7 @@ void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector) env->pending_level = level; env->pending_vector = vector; if (level) { - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index d568188703..3fa0d00cf9 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -523,12 +523,12 @@ static bool mips_vpe_is_wfi(MIPSCPU *c) return cpu->halted && mips_vpe_active(env); } -static inline void mips_vpe_wake(CPUMIPSState *c) +static inline void mips_vpe_wake(MIPSCPU *c) { /* Dont set ->halted = 0 directly, let it be done via cpu_has_work because there might be other conditions that state that c should be sleeping. */ - cpu_interrupt(c, CPU_INTERRUPT_WAKE); + cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE); } static inline void mips_vpe_sleep(MIPSCPU *cpu) @@ -547,7 +547,7 @@ static inline void mips_tc_wake(MIPSCPU *cpu, int tc) /* FIXME: TC reschedule. */ if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) { - mips_vpe_wake(c); + mips_vpe_wake(cpu); } } @@ -1725,7 +1725,7 @@ target_ulong helper_evpe(CPUMIPSState *env) && !mips_vpe_is_wfi(other_cpu)) { /* Enable the VPE. */ other_cpu_env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP); - mips_vpe_wake(other_cpu_env); /* And wake it up. */ + mips_vpe_wake(other_cpu); /* And wake it up. */ } other_cpu_env = other_cpu_env->next_cpu; } while (other_cpu_env); diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index 79ce7bf7c4..d1767340ef 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -991,7 +991,7 @@ void helper_msgsnd(target_ulong rb) for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { cenv->pending_interrupts |= 1 << irq; - cpu_interrupt(cenv, CPU_INTERRUPT_HARD); + cpu_interrupt(CPU(ppc_env_get_cpu(cenv)), CPU_INTERRUPT_HARD); } } } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index db263bf4e3..642e661e7d 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -992,7 +992,7 @@ static inline void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, env->ext_queue[env->ext_index].param64 = param64; env->pending_int |= INTERRUPT_EXT; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } static inline void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, @@ -1016,7 +1016,7 @@ static inline void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, env->io_queue[env->io_index[isc]][isc].word = io_int_word; env->pending_int |= INTERRUPT_IO; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } static inline void cpu_inject_crw_mchk(S390CPU *cpu) @@ -1034,7 +1034,7 @@ static inline void cpu_inject_crw_mchk(S390CPU *cpu) env->mchk_queue[env->mchk_index].type = 1; env->pending_int |= INTERRUPT_MCHK; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } static inline bool cpu_has_work(CPUState *cpu) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index c88a58743e..2cb8dc86e3 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -57,7 +57,7 @@ void s390x_tod_timer(void *opaque) CPUS390XState *env = &cpu->env; env->pending_int |= INTERRUPT_TOD; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } void s390x_cpu_timer(void *opaque) @@ -66,7 +66,7 @@ void s390x_cpu_timer(void *opaque) CPUS390XState *env = &cpu->env; env->pending_int |= INTERRUPT_CPUTIMER; - cpu_interrupt(env, CPU_INTERRUPT_HARD); + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); } #endif diff --git a/translate-all.c b/translate-all.c index f0c7d1e4c9..1f3237e60e 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1077,8 +1077,8 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, tb_phys_invalidate(tb, -1); if (cpu != NULL) { cpu->current_tb = saved_tb; - if (env && cpu->interrupt_request && cpu->current_tb) { - cpu_interrupt(env, cpu->interrupt_request); + if (cpu->interrupt_request && cpu->current_tb) { + cpu_interrupt(cpu, cpu->interrupt_request); } } } @@ -1382,9 +1382,9 @@ void tb_check_watchpoint(CPUArchState *env) #ifndef CONFIG_USER_ONLY /* mask must never be zero, except for A20 change call */ -static void tcg_handle_interrupt(CPUArchState *env, int mask) +static void tcg_handle_interrupt(CPUState *cpu, int mask) { - CPUState *cpu = ENV_GET_CPU(env); + CPUArchState *env = cpu->env_ptr; int old_mask; old_mask = cpu->interrupt_request; @@ -1552,10 +1552,8 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) #else /* CONFIG_USER_ONLY */ -void cpu_interrupt(CPUArchState *env, int mask) +void cpu_interrupt(CPUState *cpu, int mask) { - CPUState *cpu = ENV_GET_CPU(env); - cpu->interrupt_request |= mask; cpu->tcg_exit_req = 1; } From 97a8ea5a3ae7938cb54fd4dc19d3a413024bc6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 2 Feb 2013 10:57:51 +0100 Subject: [PATCH 1570/1634] cpu: Replace do_interrupt() by CPUClass::do_interrupt method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes a global per-target function and thus takes us one step closer to compiling multiple targets into one executable. It will also allow to override the interrupt handling for certain CPU families. Signed-off-by: Andreas Färber --- cpu-exec.c | 36 ++++++++++++++++++++---------------- include/qom/cpu.h | 2 ++ target-alpha/cpu-qom.h | 2 ++ target-alpha/cpu.c | 1 + target-alpha/cpu.h | 1 - target-alpha/helper.c | 4 +++- target-arm/cpu-qom.h | 2 ++ target-arm/cpu.c | 1 + target-arm/cpu.h | 1 - target-arm/helper.c | 11 +++++++---- target-cris/cpu-qom.h | 2 ++ target-cris/cpu.c | 1 + target-cris/cpu.h | 1 - target-cris/helper.c | 10 +++++++--- target-i386/cpu-qom.h | 6 ++++++ target-i386/cpu.c | 1 + target-i386/cpu.h | 3 +-- target-i386/seg_helper.c | 5 ++++- target-lm32/cpu-qom.h | 2 ++ target-lm32/cpu.c | 2 ++ target-lm32/cpu.h | 1 - target-lm32/helper.c | 5 ++++- target-m68k/cpu-qom.h | 2 ++ target-m68k/cpu.c | 1 + target-m68k/cpu.h | 1 - target-m68k/op_helper.c | 10 ++++++++-- target-microblaze/cpu-qom.h | 2 ++ target-microblaze/cpu.c | 1 + target-microblaze/cpu.h | 1 - target-microblaze/helper.c | 9 +++++++-- target-mips/cpu-qom.h | 2 ++ target-mips/cpu.c | 2 ++ target-mips/cpu.h | 1 - target-mips/helper.c | 5 +++-- target-openrisc/cpu.c | 1 + target-openrisc/cpu.h | 2 +- target-openrisc/interrupt.c | 4 +++- target-ppc/cpu-qom.h | 2 ++ target-ppc/cpu.h | 1 - target-ppc/excp_helper.c | 10 +++++++--- target-ppc/translate_init.c | 1 + target-s390x/cpu-qom.h | 2 ++ target-s390x/cpu.c | 1 + target-s390x/cpu.h | 1 - target-s390x/helper.c | 12 +++++++----- target-sh4/cpu-qom.h | 2 ++ target-sh4/cpu.c | 1 + target-sh4/cpu.h | 1 - target-sh4/helper.c | 12 ++++++++---- target-sparc/cpu-qom.h | 2 ++ target-sparc/cpu.c | 2 ++ target-sparc/cpu.h | 1 - target-sparc/int32_helper.c | 4 +++- target-sparc/int64_helper.c | 4 +++- target-unicore32/cpu-qom.h | 2 ++ target-unicore32/cpu.c | 1 + target-unicore32/cpu.h | 1 - target-unicore32/helper.c | 5 ++++- target-unicore32/softmmu.c | 5 +++-- target-xtensa/cpu-qom.h | 2 ++ target-xtensa/cpu.c | 1 + target-xtensa/cpu.h | 1 - target-xtensa/helper.c | 5 ++++- 63 files changed, 159 insertions(+), 67 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index c9e1a8208b..94fedc5805 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -198,6 +198,10 @@ volatile sig_atomic_t exit_request; int cpu_exec(CPUArchState *env) { CPUState *cpu = ENV_GET_CPU(env); +#if !(defined(CONFIG_USER_ONLY) && \ + (defined(TARGET_M68K) || defined(TARGET_PPC) || defined(TARGET_S390X))) + CPUClass *cc = CPU_GET_CLASS(cpu); +#endif int ret, interrupt_request; TranslationBlock *tb; uint8_t *tc_ptr; @@ -265,12 +269,12 @@ int cpu_exec(CPUArchState *env) which will be handled outside the cpu execution loop */ #if defined(TARGET_I386) - do_interrupt(env); + cc->do_interrupt(cpu); #endif ret = env->exception_index; break; #else - do_interrupt(env); + cc->do_interrupt(cpu); env->exception_index = -1; #endif } @@ -380,7 +384,7 @@ int cpu_exec(CPUArchState *env) if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->ie & IE_IE)) { env->exception_index = EXCP_IRQ; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #elif defined(TARGET_MICROBLAZE) @@ -389,7 +393,7 @@ int cpu_exec(CPUArchState *env) && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) && !(env->iflags & (D_FLAG | IMM_FLAG))) { env->exception_index = EXCP_IRQ; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #elif defined(TARGET_MIPS) @@ -398,7 +402,7 @@ int cpu_exec(CPUArchState *env) /* Raise it */ env->exception_index = EXCP_EXT_INTERRUPT; env->error_code = 0; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #elif defined(TARGET_OPENRISC) @@ -414,7 +418,7 @@ int cpu_exec(CPUArchState *env) } if (idx >= 0) { env->exception_index = idx; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } } @@ -429,7 +433,7 @@ int cpu_exec(CPUArchState *env) cpu_pil_allowed(env, pil)) || type != TT_EXTINT) { env->exception_index = env->interrupt_index; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } } @@ -438,7 +442,7 @@ int cpu_exec(CPUArchState *env) if (interrupt_request & CPU_INTERRUPT_FIQ && !(env->uncached_cpsr & CPSR_F)) { env->exception_index = EXCP_FIQ; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } /* ARMv7-M interrupt return works by loading a magic value @@ -454,19 +458,19 @@ int cpu_exec(CPUArchState *env) && ((IS_M(env) && env->regs[15] < 0xfffffff0) || !(env->uncached_cpsr & CPSR_I))) { env->exception_index = EXCP_IRQ; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #elif defined(TARGET_UNICORE32) if (interrupt_request & CPU_INTERRUPT_HARD && !(env->uncached_asr & ASR_I)) { env->exception_index = UC32_EXCP_INTR; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #elif defined(TARGET_SH4) if (interrupt_request & CPU_INTERRUPT_HARD) { - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #elif defined(TARGET_ALPHA) @@ -497,7 +501,7 @@ int cpu_exec(CPUArchState *env) if (idx >= 0) { env->exception_index = idx; env->error_code = 0; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } } @@ -506,7 +510,7 @@ int cpu_exec(CPUArchState *env) && (env->pregs[PR_CCS] & I_FLAG) && !env->locked_irq) { env->exception_index = EXCP_IRQ; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } if (interrupt_request & CPU_INTERRUPT_NMI) { @@ -518,7 +522,7 @@ int cpu_exec(CPUArchState *env) } if ((env->pregs[PR_CCS] & m_flag_archval)) { env->exception_index = EXCP_NMI; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } } @@ -538,13 +542,13 @@ int cpu_exec(CPUArchState *env) #elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY) if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->psw.mask & PSW_MASK_EXT)) { - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #elif defined(TARGET_XTENSA) if (interrupt_request & CPU_INTERRUPT_HARD) { env->exception_index = EXC_IRQ; - do_interrupt(env); + cc->do_interrupt(cpu); next_tb = 0; } #endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 2e08135acd..3664a1b631 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -44,6 +44,7 @@ typedef struct CPUState CPUState; * @class_by_name: Callback to map -cpu command line model name to an * instantiatable CPU type. * @reset: Callback to reset the #CPUState to its initial state. + * @do_interrupt: Callback for interrupt handling. * @vmsd: State description for migration. * * Represents a CPU family or model. @@ -56,6 +57,7 @@ typedef struct CPUClass { ObjectClass *(*class_by_name)(const char *cpu_model); void (*reset)(CPUState *cpu); + void (*do_interrupt)(CPUState *cpu); const struct VMStateDescription *vmsd; } CPUClass; diff --git a/target-alpha/cpu-qom.h b/target-alpha/cpu-qom.h index 252bd14821..32ee286db3 100644 --- a/target-alpha/cpu-qom.h +++ b/target-alpha/cpu-qom.h @@ -74,4 +74,6 @@ static inline AlphaCPU *alpha_env_get_cpu(CPUAlphaState *env) #define ENV_OFFSET offsetof(AlphaCPU, env) +void alpha_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index cec9989925..cad1716601 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -263,6 +263,7 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data) dc->realize = alpha_cpu_realizefn; cc->class_by_name = alpha_cpu_class_by_name; + cc->do_interrupt = alpha_cpu_do_interrupt; } static const TypeInfo alpha_cpu_type_info = { diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index 90f78acc30..2156a1e5fd 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -449,7 +449,6 @@ int cpu_alpha_signal_handler(int host_signum, void *pinfo, int cpu_alpha_handle_mmu_fault (CPUAlphaState *env, uint64_t address, int rw, int mmu_idx); #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault -void do_interrupt (CPUAlphaState *env); void do_restore_state(CPUAlphaState *, uintptr_t retaddr); void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int); void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t); diff --git a/target-alpha/helper.c b/target-alpha/helper.c index 22c9c6ec8c..5741ec25ea 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -345,8 +345,10 @@ int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong addr, int rw, } #endif /* USER_ONLY */ -void do_interrupt (CPUAlphaState *env) +void alpha_cpu_do_interrupt(CPUState *cs) { + AlphaCPU *cpu = ALPHA_CPU(cs); + CPUAlphaState *env = &cpu->env; int i = env->exception_index; if (qemu_loglevel_mask(CPU_LOG_INT)) { diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 7539727768..eeecc9265d 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -113,4 +113,6 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) void register_cp_regs_for_features(ARMCPU *cpu); +void arm_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 5dfcb740d9..aeaa3b7834 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -802,6 +802,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->reset = arm_cpu_reset; cc->class_by_name = arm_cpu_class_by_name; + cc->do_interrupt = arm_cpu_do_interrupt; } static void cpu_register(const ARMCPUInfo *info) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 957866c0e2..2b97221209 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -236,7 +236,6 @@ ARMCPU *cpu_arm_init(const char *cpu_model); void arm_translate_init(void); void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu); int cpu_arm_exec(CPUARMState *s); -void do_interrupt(CPUARMState *); int bank_number(int mode); void switch_mode(CPUARMState *, int); uint32_t do_arm_semihosting(CPUARMState *env); diff --git a/target-arm/helper.c b/target-arm/helper.c index f839726f52..b4cbb8718a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1567,8 +1567,11 @@ uint32_t HELPER(rbit)(uint32_t x) #if defined(CONFIG_USER_ONLY) -void do_interrupt (CPUARMState *env) +void arm_cpu_do_interrupt(CPUState *cs) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + env->exception_index = -1; } @@ -1799,9 +1802,10 @@ static void do_interrupt_v7m(CPUARMState *env) } /* Handle a CPU exception. */ -void do_interrupt(CPUARMState *env) +void arm_cpu_do_interrupt(CPUState *cs) { - CPUState *cs; + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; uint32_t addr; uint32_t mask; int new_mode; @@ -1908,7 +1912,6 @@ void do_interrupt(CPUARMState *env) } env->regs[14] = env->regs[15] + offset; env->regs[15] = addr; - cs = CPU(arm_env_get_cpu(env)); cs->interrupt_request |= CPU_INTERRUPT_EXITTB; } diff --git a/target-cris/cpu-qom.h b/target-cris/cpu-qom.h index 11e528661d..deea1d804b 100644 --- a/target-cris/cpu-qom.h +++ b/target-cris/cpu-qom.h @@ -73,4 +73,6 @@ static inline CRISCPU *cris_env_get_cpu(CPUCRISState *env) #define ENV_OFFSET offsetof(CRISCPU, env) +void cris_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-cris/cpu.c b/target-cris/cpu.c index 7974be33f2..95cbf399d9 100644 --- a/target-cris/cpu.c +++ b/target-cris/cpu.c @@ -243,6 +243,7 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) cc->reset = cris_cpu_reset; cc->class_by_name = cris_cpu_class_by_name; + cc->do_interrupt = cris_cpu_do_interrupt; } static const TypeInfo cris_cpu_type_info = { diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 2fc7c5c772..dbd7d36870 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -175,7 +175,6 @@ typedef struct CPUCRISState { CRISCPU *cpu_cris_init(const char *cpu_model); int cpu_cris_exec(CPUCRISState *s); -void do_interrupt(CPUCRISState *env); /* 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-cris/helper.c b/target-cris/helper.c index 885f67fa33..e1ef7bcc0b 100644 --- a/target-cris/helper.c +++ b/target-cris/helper.c @@ -36,8 +36,11 @@ #if defined(CONFIG_USER_ONLY) -void do_interrupt(CPUCRISState *env) +void cris_cpu_do_interrupt(CPUState *cs) { + CRISCPU *cpu = CRIS_CPU(cs); + CPUCRISState *env = &cpu->env; + env->exception_index = -1; env->pregs[PR_ERP] = env->pc; } @@ -162,9 +165,10 @@ static void do_interruptv10(CPUCRISState *env) env->pregs[PR_ERP]); } -void do_interrupt(CPUCRISState *env) +void cris_cpu_do_interrupt(CPUState *cs) { - D(CPUState *cs = CPU(cris_env_get_cpu(env))); + CRISCPU *cpu = CRIS_CPU(cs); + CPUCRISState *env = &cpu->env; int ex_vec = -1; if (env->pregs[PR_VR] < 32) { diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 83c5318d3a..08f9eb67b2 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -80,4 +80,10 @@ static inline X86CPU *x86_env_get_cpu(CPUX86State *env) extern const struct VMStateDescription vmstate_x86_cpu; #endif +/** + * x86_cpu_do_interrupt: + * @cpu: vCPU the interrupt is to be handled by. + */ +void x86_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 2bdbf1b453..a0640db9e3 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2251,6 +2251,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) xcc->parent_reset = cc->reset; cc->reset = x86_cpu_reset; + cc->do_interrupt = x86_cpu_do_interrupt; cpu_class_set_vmsd(cc, &vmstate_x86_cpu); } diff --git a/target-i386/cpu.h b/target-i386/cpu.h index bf6e21073d..48f41ca3e3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1252,8 +1252,7 @@ void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type, uint64_t param); void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1); -/* op_helper.c */ -void do_interrupt(CPUX86State *env); +/* seg_helper.c */ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); void do_smm_enter(CPUX86State *env1); diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 3247deeb60..906e4f3d20 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -1231,8 +1231,11 @@ static void do_interrupt_all(CPUX86State *env, int intno, int is_int, #endif } -void do_interrupt(CPUX86State *env) +void x86_cpu_do_interrupt(CPUState *cs) { + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + #if defined(CONFIG_USER_ONLY) /* if user mode only, we simulate a fake exception which will be handled outside the cpu execution diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h index c0b6ce5897..3ba86b7c88 100644 --- a/target-lm32/cpu-qom.h +++ b/target-lm32/cpu-qom.h @@ -71,4 +71,6 @@ static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env) #define ENV_OFFSET offsetof(LM32CPU, env) +void lm32_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index a2badb5701..a4692b7d5f 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -83,6 +83,8 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data) lcc->parent_reset = cc->reset; cc->reset = lm32_cpu_reset; + + cc->do_interrupt = lm32_cpu_do_interrupt; } static const TypeInfo lm32_cpu_type_info = { diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index d81f103e66..1be9778400 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -189,7 +189,6 @@ struct CPULM32State { LM32CPU *cpu_lm32_init(const char *cpu_model); void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf); int cpu_lm32_exec(CPULM32State *s); -void do_interrupt(CPULM32State *env); /* 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-lm32/helper.c b/target-lm32/helper.c index 47ae7e775a..a0a8399906 100644 --- a/target-lm32/helper.c +++ b/target-lm32/helper.c @@ -42,8 +42,11 @@ hwaddr cpu_get_phys_page_debug(CPULM32State *env, target_ulong addr) return addr & TARGET_PAGE_MASK; } -void do_interrupt(CPULM32State *env) +void lm32_cpu_do_interrupt(CPUState *cs) { + LM32CPU *cpu = LM32_CPU(cs); + CPULM32State *env = &cpu->env; + qemu_log_mask(CPU_LOG_INT, "exception at pc=%x type=%x\n", env->pc, env->exception_index); diff --git a/target-m68k/cpu-qom.h b/target-m68k/cpu-qom.h index f4c33b2eb3..846aa7453e 100644 --- a/target-m68k/cpu-qom.h +++ b/target-m68k/cpu-qom.h @@ -70,4 +70,6 @@ static inline M68kCPU *m68k_env_get_cpu(CPUM68KState *env) #define ENV_OFFSET offsetof(M68kCPU, env) +void m68k_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index f5a109854b..3c65b4e44f 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -186,6 +186,7 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) cc->reset = m68k_cpu_reset; cc->class_by_name = m68k_cpu_class_by_name; + cc->do_interrupt = m68k_cpu_do_interrupt; dc->vmsd = &vmstate_m68k_cpu; } diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index bb2fbd6d4d..c90c40c370 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -119,7 +119,6 @@ void m68k_tcg_init(void); void m68k_cpu_init_gdb(M68kCPU *cpu); M68kCPU *cpu_m68k_init(const char *cpu_model); int cpu_m68k_exec(CPUM68KState *s); -void do_interrupt(CPUM68KState *env1); void do_interrupt_m68k_hardirq(CPUM68KState *env1); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index e11f34b0f9..30f7d8b1ab 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -21,8 +21,11 @@ #if defined(CONFIG_USER_ONLY) -void do_interrupt(CPUM68KState *env) +void m68k_cpu_do_interrupt(CPUState *cs) { + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; + env->exception_index = -1; } @@ -149,8 +152,11 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw) env->pc = cpu_ldl_kernel(env, env->vbr + vector); } -void do_interrupt(CPUM68KState *env) +void m68k_cpu_do_interrupt(CPUState *cs) { + M68kCPU *cpu = M68K_CPU(cs); + CPUM68KState *env = &cpu->env; + do_interrupt_all(env, 0); } diff --git a/target-microblaze/cpu-qom.h b/target-microblaze/cpu-qom.h index a0248a5a22..aa51cf6406 100644 --- a/target-microblaze/cpu-qom.h +++ b/target-microblaze/cpu-qom.h @@ -70,4 +70,6 @@ static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env) #define ENV_OFFSET offsetof(MicroBlazeCPU, env) +void mb_cpu_do_interrupt(CPUState *cs); + #endif diff --git a/target-microblaze/cpu.c b/target-microblaze/cpu.c index 81359db168..0f4293dbd5 100644 --- a/target-microblaze/cpu.c +++ b/target-microblaze/cpu.c @@ -131,6 +131,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) mcc->parent_reset = cc->reset; cc->reset = mb_cpu_reset; + cc->do_interrupt = mb_cpu_do_interrupt; dc->vmsd = &vmstate_mb_cpu; } diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h index 7548aa903d..1813939fc9 100644 --- a/target-microblaze/cpu.h +++ b/target-microblaze/cpu.h @@ -275,7 +275,6 @@ struct CPUMBState { void mb_tcg_init(void); MicroBlazeCPU *cpu_mb_init(const char *cpu_model); int cpu_mb_exec(CPUMBState *s); -void do_interrupt(CPUMBState *env); /* 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-microblaze/helper.c b/target-microblaze/helper.c index 97aedc52bb..a0416d0b72 100644 --- a/target-microblaze/helper.c +++ b/target-microblaze/helper.c @@ -26,8 +26,11 @@ #if defined(CONFIG_USER_ONLY) -void do_interrupt (CPUMBState *env) +void mb_cpu_do_interrupt(CPUState *cs) { + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + CPUMBState *env = &cpu->env; + env->exception_index = -1; env->res_addr = RES_ADDR_NONE; env->regs[14] = env->sregs[SR_PC]; @@ -109,8 +112,10 @@ int cpu_mb_handle_mmu_fault (CPUMBState *env, target_ulong address, int rw, return r; } -void do_interrupt(CPUMBState *env) +void mb_cpu_do_interrupt(CPUState *cs) { + MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); + CPUMBState *env = &cpu->env; uint32_t t; /* IMM flag cannot propagate across a branch and into the dslot. */ diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h index c6bcddfb9a..32e3cad7bf 100644 --- a/target-mips/cpu-qom.h +++ b/target-mips/cpu-qom.h @@ -74,4 +74,6 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env) #define ENV_OFFSET offsetof(MIPSCPU, env) +void mips_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-mips/cpu.c b/target-mips/cpu.c index 4d62031c36..5315f7bda0 100644 --- a/target-mips/cpu.c +++ b/target-mips/cpu.c @@ -78,6 +78,8 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) mcc->parent_reset = cc->reset; cc->reset = mips_cpu_reset; + + cc->do_interrupt = mips_cpu_do_interrupt; } static const TypeInfo mips_cpu_type_info = { diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 22b0497757..cedf03df43 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -663,7 +663,6 @@ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level); int cpu_mips_handle_mmu_fault (CPUMIPSState *env, target_ulong address, int rw, int mmu_idx); #define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault -void do_interrupt (CPUMIPSState *env); #if !defined(CONFIG_USER_ONLY) void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra); hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address, diff --git a/target-mips/helper.c b/target-mips/helper.c index e877b8db78..3a54acf706 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -396,10 +396,11 @@ static void set_hflags_for_handler (CPUMIPSState *env) } #endif -void do_interrupt (CPUMIPSState *env) +void mips_cpu_do_interrupt(CPUState *cs) { + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; #if !defined(CONFIG_USER_ONLY) - MIPSCPU *cpu = mips_env_get_cpu(env); target_ulong offset; int cause = -1; const char *name; diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 72d5e8d2a5..ffe14f3c8d 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -148,6 +148,7 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) cc->reset = openrisc_cpu_reset; cc->class_by_name = openrisc_cpu_class_by_name; + cc->do_interrupt = openrisc_cpu_do_interrupt; } static void cpu_register(const OpenRISCCPUInfo *info) diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h index 64370a3772..b9c55ba83b 100644 --- a/target-openrisc/cpu.h +++ b/target-openrisc/cpu.h @@ -346,7 +346,7 @@ OpenRISCCPU *cpu_openrisc_init(const char *cpu_model); void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf); int cpu_openrisc_exec(CPUOpenRISCState *s); -void do_interrupt(CPUOpenRISCState *env); +void openrisc_cpu_do_interrupt(CPUState *cpu); void openrisc_translate_init(void); int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, target_ulong address, diff --git a/target-openrisc/interrupt.c b/target-openrisc/interrupt.c index 7f2c025da2..16ef4b3e79 100644 --- a/target-openrisc/interrupt.c +++ b/target-openrisc/interrupt.c @@ -25,8 +25,10 @@ #include "hw/loader.h" #endif -void do_interrupt(CPUOpenRISCState *env) +void openrisc_cpu_do_interrupt(CPUState *cs) { + OpenRISCCPU *cpu = OPENRISC_CPU(cs); + CPUOpenRISCState *env = &cpu->env; #ifndef CONFIG_USER_ONLY if (env->flags & D_FLAG) { /* Delay Slot insn */ env->flags &= ~D_FLAG; diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 2bf0ab62d4..09bfae3d54 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -95,4 +95,6 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env) PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr); +void ppc_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 1b31b1d9c9..6886666d6e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1133,7 +1133,6 @@ int cpu_ppc_signal_handler (int host_signum, void *pinfo, int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw, int mmu_idx); #define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault -void do_interrupt (CPUPPCState *env); void ppc_hw_interrupt (CPUPPCState *env); #if !defined(CONFIG_USER_ONLY) diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c index d1767340ef..4a0fc6dd57 100644 --- a/target-ppc/excp_helper.c +++ b/target-ppc/excp_helper.c @@ -38,8 +38,11 @@ void (*cpu_ppc_hypercall)(PowerPCCPU *); /*****************************************************************************/ /* Exception processing */ #if defined(CONFIG_USER_ONLY) -void do_interrupt(CPUPPCState *env) +void ppc_cpu_do_interrupt(CPUState *cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + env->exception_index = POWERPC_EXCP_NONE; env->error_code = 0; } @@ -654,9 +657,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } } -void do_interrupt(CPUPPCState *env) +void ppc_cpu_do_interrupt(CPUState *cs) { - PowerPCCPU *cpu = ppc_env_get_cpu(env); + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; powerpc_excp(cpu, env->excp_model, env->exception_index); } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 09ad4ba639..15eebe9177 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8427,6 +8427,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->reset = ppc_cpu_reset; cc->class_by_name = ppc_cpu_class_by_name; + cc->do_interrupt = ppc_cpu_do_interrupt; } static const TypeInfo ppc_cpu_type_info = { diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h index f6e514570c..34d45c262b 100644 --- a/target-s390x/cpu-qom.h +++ b/target-s390x/cpu-qom.h @@ -71,4 +71,6 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env) #define ENV_OFFSET offsetof(S390CPU, env) +void s390_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index 738a0ad1ee..23fe51f0f4 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -169,6 +169,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) scc->parent_reset = cc->reset; cc->reset = s390_cpu_reset; + cc->do_interrupt = s390_cpu_do_interrupt; dc->vmsd = &vmstate_s390_cpu; } diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 642e661e7d..e351005901 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -315,7 +315,6 @@ static inline int get_ilen(uint8_t opc) S390CPU *cpu_s390x_init(const char *cpu_model); void s390x_translate_init(void); int cpu_s390x_exec(CPUS390XState *s); -void do_interrupt (CPUS390XState *env); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 2cb8dc86e3..b425054be8 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -86,8 +86,11 @@ S390CPU *cpu_s390x_init(const char *cpu_model) #if defined(CONFIG_USER_ONLY) -void do_interrupt(CPUS390XState *env) +void s390_cpu_do_interrupt(CPUState *cs) { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; + env->exception_index = -1; } @@ -737,10 +740,10 @@ static void do_mchk_interrupt(CPUS390XState *env) load_psw(env, mask, addr); } -void do_interrupt(CPUS390XState *env) +void s390_cpu_do_interrupt(CPUState *cs) { - S390CPU *cpu = s390_env_get_cpu(env); - CPUState *cs; + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, env->psw.addr); @@ -799,7 +802,6 @@ void do_interrupt(CPUS390XState *env) env->exception_index = -1; if (!env->pending_int) { - cs = CPU(s390_env_get_cpu(env)); cs->interrupt_request &= ~CPU_INTERRUPT_HARD; } } diff --git a/target-sh4/cpu-qom.h b/target-sh4/cpu-qom.h index 29628c8077..f8c80d30b4 100644 --- a/target-sh4/cpu-qom.h +++ b/target-sh4/cpu-qom.h @@ -83,4 +83,6 @@ static inline SuperHCPU *sh_env_get_cpu(CPUSH4State *env) #define ENV_OFFSET offsetof(SuperHCPU, env) +void superh_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-sh4/cpu.c b/target-sh4/cpu.c index 5251aa08a5..898aecde4f 100644 --- a/target-sh4/cpu.c +++ b/target-sh4/cpu.c @@ -273,6 +273,7 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) cc->reset = superh_cpu_reset; cc->class_by_name = superh_cpu_class_by_name; + cc->do_interrupt = superh_cpu_do_interrupt; dc->vmsd = &vmstate_sh_cpu; } diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 49663556ef..fd7da92548 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -196,7 +196,6 @@ int cpu_sh4_signal_handler(int host_signum, void *pinfo, int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw, int mmu_idx); #define cpu_handle_mmu_fault cpu_sh4_handle_mmu_fault -void do_interrupt(CPUSH4State * env); void sh4_cpu_list(FILE *f, fprintf_function cpu_fprintf); #if !defined(CONFIG_USER_ONLY) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index fd4efee4a6..0a9cb3ac98 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -31,9 +31,12 @@ #if defined(CONFIG_USER_ONLY) -void do_interrupt (CPUSH4State *env) +void superh_cpu_do_interrupt(CPUState *cs) { - env->exception_index = -1; + SuperHCPU *cpu = SUPERH_CPU(cs); + CPUSH4State *env = &cpu->env; + + env->exception_index = -1; } int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw, @@ -78,9 +81,10 @@ int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr) #define MMU_DADDR_ERROR_READ (-12) #define MMU_DADDR_ERROR_WRITE (-13) -void do_interrupt(CPUSH4State *env) +void superh_cpu_do_interrupt(CPUState *cs) { - CPUState *cs = CPU(sh_env_get_cpu(env)); + SuperHCPU *cpu = SUPERH_CPU(cs); + CPUSH4State *env = &cpu->env; int do_irq = cs->interrupt_request & CPU_INTERRUPT_HARD; int do_exp, irq_vector = env->exception_index; diff --git a/target-sparc/cpu-qom.h b/target-sparc/cpu-qom.h index efeeca0d97..d4fe89ebfd 100644 --- a/target-sparc/cpu-qom.h +++ b/target-sparc/cpu-qom.h @@ -75,4 +75,6 @@ static inline SPARCCPU *sparc_env_get_cpu(CPUSPARCState *env) #define ENV_OFFSET offsetof(SPARCCPU, env) +void sparc_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c index 50def61848..ab1adfd7ea 100644 --- a/target-sparc/cpu.c +++ b/target-sparc/cpu.c @@ -891,6 +891,8 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) scc->parent_reset = cc->reset; cc->reset = sparc_cpu_reset; + + cc->do_interrupt = sparc_cpu_do_interrupt; } static const TypeInfo sparc_cpu_type_info = { diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 8a2f8df992..6fa77789cd 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -553,7 +553,6 @@ int cpu_cwp_dec(CPUSPARCState *env1, int cwp); void cpu_set_cwp(CPUSPARCState *env1, int new_cwp); /* int_helper.c */ -void do_interrupt(CPUSPARCState *env); void leon3_irq_manager(CPUSPARCState *env, void *irq_manager, int intno); /* sun4m.c, sun4u.c */ diff --git a/target-sparc/int32_helper.c b/target-sparc/int32_helper.c index c35f522e0f..722146065a 100644 --- a/target-sparc/int32_helper.c +++ b/target-sparc/int32_helper.c @@ -58,8 +58,10 @@ static const char * const excp_names[0x80] = { }; #endif -void do_interrupt(CPUSPARCState *env) +void sparc_cpu_do_interrupt(CPUState *cs) { + SPARCCPU *cpu = SPARC_CPU(cs); + CPUSPARCState *env = &cpu->env; int cwp, intno = env->exception_index; /* Compute PSR before exposing state. */ diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c index df37aa1d14..f411884c6e 100644 --- a/target-sparc/int64_helper.c +++ b/target-sparc/int64_helper.c @@ -59,8 +59,10 @@ static const char * const excp_names[0x80] = { }; #endif -void do_interrupt(CPUSPARCState *env) +void sparc_cpu_do_interrupt(CPUState *cs) { + SPARCCPU *cpu = SPARC_CPU(cs); + CPUSPARCState *env = &cpu->env; int intno = env->exception_index; trap_state *tsptr; diff --git a/target-unicore32/cpu-qom.h b/target-unicore32/cpu-qom.h index c6590bdf01..ba4dee4b9f 100644 --- a/target-unicore32/cpu-qom.h +++ b/target-unicore32/cpu-qom.h @@ -60,4 +60,6 @@ static inline UniCore32CPU *uc32_env_get_cpu(CPUUniCore32State *env) #define ENV_OFFSET offsetof(UniCore32CPU, env) +void uc32_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index b7024c85bb..66a1a74646 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -132,6 +132,7 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data) dc->realize = uc32_cpu_realizefn; cc->class_by_name = uc32_cpu_class_by_name; + cc->do_interrupt = uc32_cpu_do_interrupt; dc->vmsd = &vmstate_uc32_cpu; } diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h index 58f1f20ca5..5b2b9d1cc7 100644 --- a/target-unicore32/cpu.h +++ b/target-unicore32/cpu.h @@ -176,7 +176,6 @@ static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc } void uc32_translate_init(void); -void do_interrupt(CPUUniCore32State *); void switch_mode(CPUUniCore32State *, int); static inline bool cpu_has_work(CPUState *cpu) diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index 7eeb9bc633..61eb2c374a 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -242,8 +242,11 @@ void switch_mode(CPUUniCore32State *env, int mode) } } -void do_interrupt(CPUUniCore32State *env) +void uc32_cpu_do_interrupt(CPUState *cs) { + UniCore32CPU *cpu = UNICORE32_CPU(cs); + CPUUniCore32State *env = &cpu->env; + cpu_abort(env, "NO interrupt in user mode\n"); } diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c index 1c4c7f5245..eadaeb11ab 100644 --- a/target-unicore32/softmmu.c +++ b/target-unicore32/softmmu.c @@ -72,9 +72,10 @@ void switch_mode(CPUUniCore32State *env, int mode) } /* Handle a CPU exception. */ -void do_interrupt(CPUUniCore32State *env) +void uc32_cpu_do_interrupt(CPUState *cs) { - CPUState *cs = CPU(uc32_env_get_cpu(env)); + UniCore32CPU *cpu = UNICORE32_CPU(cs); + CPUUniCore32State *env = &cpu->env; uint32_t addr; int new_mode; diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h index c78136bf72..af0ce2823c 100644 --- a/target-xtensa/cpu-qom.h +++ b/target-xtensa/cpu-qom.h @@ -80,4 +80,6 @@ static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env) #define ENV_OFFSET offsetof(XtensaCPU, env) +void xtensa_cpu_do_interrupt(CPUState *cpu); + #endif diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 785e56d367..6e93dd8d24 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -101,6 +101,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) xcc->parent_reset = cc->reset; cc->reset = xtensa_cpu_reset; + cc->do_interrupt = xtensa_cpu_do_interrupt; dc->vmsd = &vmstate_xtensa_cpu; } diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index dece224478..6c9fc35dcc 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -388,7 +388,6 @@ void xtensa_translate_init(void); void xtensa_breakpoint_handler(CPUXtensaState *env); int cpu_xtensa_exec(CPUXtensaState *s); void xtensa_register_core(XtensaConfigList *node); -void do_interrupt(CPUXtensaState *s); void check_interrupts(CPUXtensaState *s); void xtensa_irq_init(CPUXtensaState *env); void *xtensa_get_extint(CPUXtensaState *env, unsigned extint); diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index a8a64932da..6f613c66a6 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -178,8 +178,11 @@ static void handle_interrupt(CPUXtensaState *env) } } -void do_interrupt(CPUXtensaState *env) +void xtensa_cpu_do_interrupt(CPUState *cs) { + XtensaCPU *cpu = XTENSA_CPU(cs); + CPUXtensaState *env = &cpu->env; + if (env->exception_index == EXC_IRQ) { qemu_log_mask(CPU_LOG_INT, "%s(EXC_IRQ) level = %d, cintlevel = %d, " From e6f010cc27177c97596455b2e2b589bd19b2a486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 2 Feb 2013 12:33:14 +0100 Subject: [PATCH 1571/1634] target-arm: Override do_interrupt for ARMv7-M profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable ARMCPUInfo to specify a custom class_init functions. Introduce arm_v7m_class_init() and use it for "cortex-m3" model. Instead of forwarding from arm_cpu_do_interrupt() to do_interrupt_v7m(), override CPUClass::do_interrupt with arm_v7m_cpu_do_interrupt() in arm_v7m_class_init(). Acked-by: Peter Maydell Signed-off-by: Andreas Färber --- target-arm/cpu-qom.h | 1 + target-arm/cpu.c | 14 +++++++++++++- target-arm/helper.c | 10 +++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index eeecc9265d..25895509be 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -114,5 +114,6 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env) void register_cp_regs_for_features(ARMCPU *cpu); void arm_cpu_do_interrupt(CPUState *cpu); +void arm_v7m_cpu_do_interrupt(CPUState *cpu); #endif diff --git a/target-arm/cpu.c b/target-arm/cpu.c index aeaa3b7834..a1e90939d6 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -412,6 +412,15 @@ static void cortex_m3_initfn(Object *obj) cpu->midr = 0x410fc231; } +static void arm_v7m_class_init(ObjectClass *oc, void *data) +{ +#ifndef CONFIG_USER_ONLY + CPUClass *cc = CPU_CLASS(oc); + + cc->do_interrupt = arm_v7m_cpu_do_interrupt; +#endif +} + static const ARMCPRegInfo cortexa8_cp_reginfo[] = { { .name = "L2LOCKDOWN", .cp = 15, .crn = 9, .crm = 0, .opc1 = 1, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, @@ -752,6 +761,7 @@ static void arm_any_initfn(Object *obj) typedef struct ARMCPUInfo { const char *name; void (*initfn)(Object *obj); + void (*class_init)(ObjectClass *oc, void *data); } ARMCPUInfo; static const ARMCPUInfo arm_cpus[] = { @@ -766,7 +776,8 @@ static const ARMCPUInfo arm_cpus[] = { { .name = "arm1136", .initfn = arm1136_initfn }, { .name = "arm1176", .initfn = arm1176_initfn }, { .name = "arm11mpcore", .initfn = arm11mpcore_initfn }, - { .name = "cortex-m3", .initfn = cortex_m3_initfn }, + { .name = "cortex-m3", .initfn = cortex_m3_initfn, + .class_init = arm_v7m_class_init }, { .name = "cortex-a8", .initfn = cortex_a8_initfn }, { .name = "cortex-a9", .initfn = cortex_a9_initfn }, { .name = "cortex-a15", .initfn = cortex_a15_initfn }, @@ -812,6 +823,7 @@ static void cpu_register(const ARMCPUInfo *info) .instance_size = sizeof(ARMCPU), .instance_init = info->initfn, .class_size = sizeof(ARMCPUClass), + .class_init = info->class_init, }; type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); diff --git a/target-arm/helper.c b/target-arm/helper.c index b4cbb8718a..fd055e89f2 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1725,8 +1725,10 @@ static void do_v7m_exception_exit(CPUARMState *env) pointer. */ } -static void do_interrupt_v7m(CPUARMState *env) +void arm_v7m_cpu_do_interrupt(CPUState *cs) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; uint32_t xpsr = xpsr_read(env); uint32_t lr; uint32_t addr; @@ -1811,10 +1813,8 @@ void arm_cpu_do_interrupt(CPUState *cs) int new_mode; uint32_t offset; - if (IS_M(env)) { - do_interrupt_v7m(env); - return; - } + assert(!IS_M(env)); + /* TODO: Vectored interrupt controller. */ switch (env->exception_index) { case EXCP_UDEF: From 0ad6773f1151c9e172b0b714aada78655dda4cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sat, 2 Feb 2013 13:45:29 +0100 Subject: [PATCH 1572/1634] target-lm32: Update VMStateDescription to LM32CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a vmstate_lm32_cpu referencing the previous VMStateDescription as a sub-struct and hook it up to CPUClass::vmsd. Drop cpu_{save,load}(). Acked-by: Michael Walle Signed-off-by: Andreas Färber --- target-lm32/cpu-qom.h | 4 ++++ target-lm32/cpu.c | 1 + target-lm32/cpu.h | 2 -- target-lm32/machine.c | 25 +++++++++++++------------ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/target-lm32/cpu-qom.h b/target-lm32/cpu-qom.h index 3ba86b7c88..957186075b 100644 --- a/target-lm32/cpu-qom.h +++ b/target-lm32/cpu-qom.h @@ -71,6 +71,10 @@ static inline LM32CPU *lm32_env_get_cpu(CPULM32State *env) #define ENV_OFFSET offsetof(LM32CPU, env) +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_lm32_cpu; +#endif + void lm32_cpu_do_interrupt(CPUState *cpu); #endif diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c index a4692b7d5f..bbb7fbf768 100644 --- a/target-lm32/cpu.c +++ b/target-lm32/cpu.c @@ -85,6 +85,7 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data) cc->reset = lm32_cpu_reset; cc->do_interrupt = lm32_cpu_do_interrupt; + cpu_class_set_vmsd(cc, &vmstate_lm32_cpu); } static const TypeInfo lm32_cpu_type_info = { diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h index 1be9778400..fd50b534fc 100644 --- a/target-lm32/cpu.h +++ b/target-lm32/cpu.h @@ -211,8 +211,6 @@ static inline CPULM32State *cpu_init(const char *cpu_model) #define cpu_gen_code cpu_lm32_gen_code #define cpu_signal_handler cpu_lm32_signal_handler -#define CPU_SAVE_VERSION 1 - int cpu_lm32_handle_mmu_fault(CPULM32State *env, target_ulong address, int rw, int mmu_idx); #define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault diff --git a/target-lm32/machine.c b/target-lm32/machine.c index 6802e818f8..9e0919c254 100644 --- a/target-lm32/machine.c +++ b/target-lm32/machine.c @@ -1,9 +1,9 @@ #include "hw/hw.h" #include "hw/boards.h" -static const VMStateDescription vmstate_cpu = { - .name = "cpu", - .version_id = CPU_SAVE_VERSION, +static const VMStateDescription vmstate_env = { + .name = "env", + .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { @@ -22,12 +22,13 @@ static const VMStateDescription vmstate_cpu = { } }; -void cpu_save(QEMUFile *f, void *opaque) -{ - vmstate_save_state(f, &vmstate_cpu, opaque); -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - return vmstate_load_state(f, &vmstate_cpu, opaque, version_id); -} +const VMStateDescription vmstate_lm32_cpu = { + .name = "cpu", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(env, LM32CPU, 1, vmstate_env, CPULM32State), + VMSTATE_END_OF_LIST() + } +}; From b8a205f2ed222a5d24bf7e8346919abee861d026 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 20 Feb 2013 13:02:07 +0100 Subject: [PATCH 1573/1634] virtio-ccw: remove qdev_unparent in unplug routing This patch fixes unplugging a virtio-ccw device. We no longer need to do that in virtio-ccw since common code does now proper handling. Signed-off-by: Christian Borntraeger Signed-off-by: Jens Freimann Signed-off-by: Cornelia Huck --- hw/s390x/virtio-ccw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index a9cf703d53..06b964124c 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -865,7 +865,6 @@ static int virtio_ccw_busdev_unplug(DeviceState *dev) css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); - object_unparent(OBJECT(dev)); qdev_free(dev); return 0; } From 2362ecc5c6f4073f7f4c9c3f45c335aa8a2261bb Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 4 Mar 2013 13:06:56 +0100 Subject: [PATCH 1574/1634] virtio-ccw: Wire up virtio-rng. Make virtio-rng devices available for s390-ccw-virtio machines. Signed-off-by: Cornelia Huck --- hw/s390x/virtio-ccw.c | 60 +++++++++++++++++++++++++++++++++++++++++++ hw/s390x/virtio-ccw.h | 2 ++ 2 files changed, 62 insertions(+) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 06b964124c..d4361f6e3e 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -642,6 +642,30 @@ static int virtio_ccw_scsi_exit(VirtioCcwDevice *dev) return virtio_ccw_exit(dev); } +static int virtio_ccw_rng_init(VirtioCcwDevice *dev) +{ + VirtIODevice *vdev; + + if (dev->rng.rng == NULL) { + dev->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM)); + object_property_add_child(OBJECT(dev), "default-backend", + OBJECT(dev->rng.default_backend), NULL); + object_property_set_link(OBJECT(dev), OBJECT(dev->rng.default_backend), + "rng", NULL); + } + vdev = virtio_rng_init((DeviceState *)dev, &dev->rng); + if (!vdev) { + return -1; + } + return virtio_ccw_device_init(dev, vdev); +} + +static int virtio_ccw_rng_exit(VirtioCcwDevice *dev) +{ + virtio_rng_exit(dev->vdev); + return virtio_ccw_exit(dev); +} + /* DeviceState to VirtioCcwDevice. Note: used on datapath, * be careful and test performance if you change this. */ @@ -831,6 +855,41 @@ static const TypeInfo virtio_ccw_scsi = { .class_init = virtio_ccw_scsi_class_init, }; +static void virtio_ccw_rng_initfn(Object *obj) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(obj); + + object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, + (Object **)&dev->rng.rng, NULL); +} + +static Property virtio_ccw_rng_properties[] = { + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), + DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]), + DEFINE_PROP_UINT64("max-bytes", VirtioCcwDevice, rng.max_bytes, INT64_MAX), + DEFINE_PROP_UINT32("period", VirtioCcwDevice, rng.period_ms, 1 << 16), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->init = virtio_ccw_rng_init; + k->exit = virtio_ccw_rng_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_rng_properties; +} + +static const TypeInfo virtio_ccw_rng = { + .name = "virtio-rng-ccw", + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtioCcwDevice), + .instance_init = virtio_ccw_rng_initfn, + .class_init = virtio_ccw_rng_class_init, +}; + static int virtio_ccw_busdev_init(DeviceState *dev) { VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; @@ -953,6 +1012,7 @@ static void virtio_ccw_register(void) type_register_static(&virtio_ccw_net); type_register_static(&virtio_ccw_balloon); type_register_static(&virtio_ccw_scsi); + type_register_static(&virtio_ccw_rng); type_register_static(&virtual_css_bridge_info); } diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 48474b31ab..88c46c081b 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #define VIRTUAL_CSSID 0xfe @@ -77,6 +78,7 @@ struct VirtioCcwDevice { virtio_serial_conf serial; virtio_net_conf net; VirtIOSCSIConf scsi; + VirtIORNGConf rng; VirtioBusState bus; /* Guest provided values: */ hwaddr indicators; From d1a0cf738dab24fbfd8e9225b7f3df43dcfafc06 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 27 Feb 2013 12:47:49 -0500 Subject: [PATCH 1575/1634] Support for TPM command line options This patch adds support for TPM command line options. The command line options supported here are ./qemu-... -tpmdev passthrough,path=,id= -device tpm-tis,tpmdev=,id= and ./qemu-... -tpmdev help where the latter works similar to -soundhw help and shows a list of available TPM backends (for example 'passthrough'). Using the type parameter, the backend is chosen, i.e., 'passthrough' for the passthrough driver. The interpretation of the other parameters along with determining whether enough parameters were provided is pushed into the backend driver, which needs to implement the interface function 'create' and return a TPMDriverOpts structure if the VM can be started or 'NULL' if not enough or bad parameters were provided. Monitor support for 'info tpm' has been added. It for example prints the following: (qemu) info tpm TPM devices: tpm0: model=tpm-tis \ tpm0: type=passthrough,path=/dev/tpm0,cancel-path=/sys/devices/pnp0/00:09/cancel Signed-off-by: Stefan Berger Reviewed-by: Corey Bryant Reviewed-by: Joel Schopp Message-id: 1361987275-26289-2-git-send-email-stefanb@linux.vnet.ibm.com Signed-off-by: Anthony Liguori --- Makefile.objs | 1 + hmp-commands.hx | 2 + hmp.c | 44 ++++++ hmp.h | 1 + include/tpm/tpm.h | 21 +++ monitor.c | 8 ++ qapi-schema.json | 104 ++++++++++++++ qemu-options.hx | 33 +++++ qmp-commands.hx | 18 +++ tpm/Makefile.objs | 1 + tpm/tpm.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++ tpm/tpm_int.h | 83 +++++++++++ tpm/tpm_tis.h | 80 +++++++++++ vl.c | 37 +++++ 14 files changed, 776 insertions(+) create mode 100644 include/tpm/tpm.h create mode 100644 tpm/Makefile.objs create mode 100644 tpm/tpm.c create mode 100644 tpm/tpm_int.h create mode 100644 tpm/tpm_tis.h diff --git a/Makefile.objs b/Makefile.objs index 8c90b92d01..f99841ce54 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -74,6 +74,7 @@ common-obj-y += bt-host.o bt-vhci.o common-obj-y += dma-helpers.o common-obj-y += vl.o +common-obj-y += tpm/ common-obj-$(CONFIG_SLIRP) += slirp/ diff --git a/hmp-commands.hx b/hmp-commands.hx index 69c707d332..4bda3fea0e 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1642,6 +1642,8 @@ show device tree show qdev device model list @item info roms show roms +@item info tpm +show the TPM device @end table ETEXI diff --git a/hmp.c b/hmp.c index 2f47a8a9dd..b0a861cfbb 100644 --- a/hmp.c +++ b/hmp.c @@ -607,6 +607,50 @@ void hmp_info_block_jobs(Monitor *mon, const QDict *qdict) } } +void hmp_info_tpm(Monitor *mon, const QDict *qdict) +{ + TPMInfoList *info_list, *info; + Error *err = NULL; + unsigned int c = 0; + TPMPassthroughOptions *tpo; + + info_list = qmp_query_tpm(&err); + if (err) { + monitor_printf(mon, "TPM device not supported\n"); + error_free(err); + return; + } + + if (info_list) { + monitor_printf(mon, "TPM device:\n"); + } + + for (info = info_list; info; info = info->next) { + TPMInfo *ti = info->value; + monitor_printf(mon, " tpm%d: model=%s\n", + c, TpmModel_lookup[ti->model]); + + monitor_printf(mon, " \\ %s: type=%s", + ti->id, TpmType_lookup[ti->type]); + + switch (ti->tpm_options->kind) { + case TPM_TYPE_OPTIONS_KIND_TPM_PASSTHROUGH_OPTIONS: + tpo = ti->tpm_options->tpm_passthrough_options; + monitor_printf(mon, "%s%s%s%s", + tpo->has_path ? ",path=" : "", + tpo->has_path ? tpo->path : "", + tpo->has_cancel_path ? ",cancel-path=" : "", + tpo->has_cancel_path ? tpo->cancel_path : ""); + break; + case TPM_TYPE_OPTIONS_KIND_MAX: + break; + } + monitor_printf(mon, "\n"); + c++; + } + qapi_free_TPMInfoList(info_list); +} + void hmp_quit(Monitor *mon, const QDict *qdict) { monitor_suspend(mon); diff --git a/hmp.h b/hmp.h index 30b3c20ca4..95fe76e218 100644 --- a/hmp.h +++ b/hmp.h @@ -36,6 +36,7 @@ void hmp_info_spice(Monitor *mon, const QDict *qdict); void hmp_info_balloon(Monitor *mon, const QDict *qdict); void hmp_info_pci(Monitor *mon, const QDict *qdict); void hmp_info_block_jobs(Monitor *mon, const QDict *qdict); +void hmp_info_tpm(Monitor *mon, const QDict *qdict); void hmp_quit(Monitor *mon, const QDict *qdict); void hmp_stop(Monitor *mon, const QDict *qdict); void hmp_system_reset(Monitor *mon, const QDict *qdict); diff --git a/include/tpm/tpm.h b/include/tpm/tpm.h new file mode 100644 index 0000000000..cc8f20e69e --- /dev/null +++ b/include/tpm/tpm.h @@ -0,0 +1,21 @@ +/* + * Public TPM functions + * + * Copyright (C) 2011-2013 IBM Corporation + * + * Authors: + * Stefan Berger + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_TPM_H +#define QEMU_TPM_H + +#include "qemu/option.h" + +int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); +int tpm_init(void); +void tpm_cleanup(void); + +#endif /* QEMU_TPM_H */ diff --git a/monitor.c b/monitor.c index c48530bd55..1b5acf876d 100644 --- a/monitor.c +++ b/monitor.c @@ -47,6 +47,7 @@ #include "migration/migration.h" #include "sysemu/kvm.h" #include "qemu/acl.h" +#include "tpm/tpm.h" #include "qapi/qmp/qint.h" #include "qapi/qmp/qfloat.h" #include "qapi/qmp/qlist.h" @@ -2721,6 +2722,13 @@ static mon_cmd_t info_cmds[] = { .help = "show available trace-events & their state", .mhandler.cmd = do_trace_print_events, }, + { + .name = "tpm", + .args_type = "", + .params = "", + .help = "show the TPM device", + .mhandler.cmd = hmp_info_tpm, + }, { .name = NULL, }, diff --git a/qapi-schema.json b/qapi-schema.json index 28b070f16b..4494e53693 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3240,3 +3240,107 @@ # Since: 1.4 ## { 'command': 'chardev-remove', 'data': {'id': 'str'} } + +## +# @TpmModel: +# +# An enumeration of TPM models +# +# @tpm-tis: TPM TIS model +# +# Since: 1.5 +## +{ 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] } + +## +# @query-tpm-models: +# +# Return a list of supported TPM models +# +# Returns: a list of TpmModel +# +# Since: 1.5 +## +{ 'command': 'query-tpm-models', 'returns': ['TpmModel'] } + +## +# @TpmType: +# +# An enumeration of TPM types +# +# @passthrough: TPM passthrough type +# +# Since: 1.5 +## +{ 'enum': 'TpmType', 'data': [ 'passthrough' ] } + +## +# @query-tpm-types: +# +# Return a list of supported TPM types +# +# Returns: a list of TpmType +# +# Since: 1.5 +## +{ 'command': 'query-tpm-types', 'returns': ['TpmType'] } + +## +# @TPMPassthroughOptions: +# +# Information about the TPM passthrough type +# +# @path: #optional string describing the path used for accessing the TPM device +# +# @cancel-path: #optional string showing the TPM's sysfs cancel file +# for cancellation of TPM commands while they are executing +# +# Since: 1.5 +## +{ 'type': 'TPMPassthroughOptions', 'data': { '*path' : 'str', + '*cancel-path' : 'str'} } + +## +# @TpmTypeOptions: +# +# A union referencing different TPM backend types' configuration options +# +# @tpm-passthough-options: TPMPassthroughOptions describing the TPM +# passthrough configuration options +# +# Since: 1.5 +## +{ 'union': 'TpmTypeOptions', + 'data': { 'tpm-passthrough-options' : 'TPMPassthroughOptions' } } + +## +# @TpmInfo: +# +# Information about the TPM +# +# @id: The Id of the TPM +# +# @model: The TPM frontend model +# +# @type: The TPM (backend) type being used +# +# @tpm-options: The TPM (backend) type configuration options +# +# Since: 1.5 +## +{ 'type': 'TPMInfo', + 'data': {'id': 'str', + 'model': 'TpmModel', + 'type': 'TpmType', + 'tpm-options': 'TpmTypeOptions' } } + +## +# @query-tpm: +# +# Return information about the TPM device +# +# Returns: @TPMInfo on success +# +# Since: 1.5 +## +{ 'command': 'query-tpm', 'returns': ['TPMInfo'] } diff --git a/qemu-options.hx b/qemu-options.hx index cd76f2a00c..291932faae 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2217,6 +2217,39 @@ STEXI ETEXI DEFHEADING() +#ifdef CONFIG_TPM +DEFHEADING(TPM device options:) + +DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \ + "-tpmdev [],id=str[,option][,option][,...]\n", + QEMU_ARCH_ALL) +STEXI + +The general form of a TPM device option is: +@table @option + +@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}] +@findex -tpmdev +Backend type must be: + +The specific backend type will determine the applicable options. +The @code{-tpmdev} option requires a @code{-device} option. + +Options to each backend are described below. + +Use 'help' to print all available TPM backend types. +@example +qemu -tpmdev help +@end example + +@end table + +ETEXI + +DEFHEADING() + +#endif + DEFHEADING(Linux/Multiboot boot specific:) STEXI diff --git a/qmp-commands.hx b/qmp-commands.hx index 95022e259f..b370060848 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2715,6 +2715,24 @@ EQMP .mhandler.cmd_new = qmp_marshal_input_query_target, }, + { + .name = "query-tpm", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_tpm, + }, + + { + .name = "query-tpm-models", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_tpm_models, + }, + + { + .name = "query-tpm-types", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_tpm_types, + }, + { .name = "chardev-add", .args_type = "id:s,backend:q", diff --git a/tpm/Makefile.objs b/tpm/Makefile.objs new file mode 100644 index 0000000000..dffb567aa3 --- /dev/null +++ b/tpm/Makefile.objs @@ -0,0 +1 @@ +common-obj-y = tpm.o diff --git a/tpm/tpm.c b/tpm/tpm.c new file mode 100644 index 0000000000..02735493c5 --- /dev/null +++ b/tpm/tpm.c @@ -0,0 +1,343 @@ +/* + * TPM configuration + * + * Copyright (C) 2011-2013 IBM Corporation + * + * Authors: + * Stefan Berger + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Based on net.c + */ +#include "config-host.h" + +#include "monitor/monitor.h" +#include "qapi/qmp/qerror.h" +#include "tpm_int.h" +#include "tpm/tpm.h" +#include "qemu/config-file.h" +#include "qmp-commands.h" + +static QLIST_HEAD(, TPMBackend) tpm_backends = + QLIST_HEAD_INITIALIZER(tpm_backends); + + +#define TPM_MAX_MODELS 1 +#define TPM_MAX_DRIVERS 1 + +static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = { + NULL, +}; + +static enum TpmModel tpm_models[TPM_MAX_MODELS] = { + -1, +}; + +int tpm_register_model(enum TpmModel model) +{ + int i; + + for (i = 0; i < TPM_MAX_MODELS; i++) { + if (tpm_models[i] == -1) { + tpm_models[i] = model; + return 0; + } + } + error_report("Could not register TPM model"); + return 1; +} + +static bool tpm_model_is_registered(enum TpmModel model) +{ + int i; + + for (i = 0; i < TPM_MAX_MODELS; i++) { + if (tpm_models[i] == model) { + return true; + } + } + return false; +} + +const TPMDriverOps *tpm_get_backend_driver(const char *type) +{ + int i; + + for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { + if (!strcmp(TpmType_lookup[be_drivers[i]->type], type)) { + return be_drivers[i]; + } + } + + return NULL; +} + +#ifdef CONFIG_TPM + +int tpm_register_driver(const TPMDriverOps *tdo) +{ + int i; + + for (i = 0; i < TPM_MAX_DRIVERS; i++) { + if (!be_drivers[i]) { + be_drivers[i] = tdo; + return 0; + } + } + error_report("Could not register TPM driver"); + return 1; +} + +/* + * Walk the list of available TPM backend drivers and display them on the + * screen. + */ +void tpm_display_backend_drivers(void) +{ + int i; + + fprintf(stderr, "Supported TPM types (choose only one):\n"); + + for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { + fprintf(stderr, "%12s %s\n", + TpmType_lookup[be_drivers[i]->type], be_drivers[i]->desc()); + } + fprintf(stderr, "\n"); +} + +/* + * Find the TPM with the given Id + */ +TPMBackend *qemu_find_tpm(const char *id) +{ + TPMBackend *drv; + + if (id) { + QLIST_FOREACH(drv, &tpm_backends, list) { + if (!strcmp(drv->id, id)) { + return drv; + } + } + } + + return NULL; +} + +static int configure_tpm(QemuOpts *opts) +{ + const char *value; + const char *id; + const TPMDriverOps *be; + TPMBackend *drv; + + if (!QLIST_EMPTY(&tpm_backends)) { + error_report("Only one TPM is allowed.\n"); + return 1; + } + + id = qemu_opts_id(opts); + if (id == NULL) { + qerror_report(QERR_MISSING_PARAMETER, "id"); + return 1; + } + + value = qemu_opt_get(opts, "type"); + if (!value) { + qerror_report(QERR_MISSING_PARAMETER, "type"); + tpm_display_backend_drivers(); + return 1; + } + + be = tpm_get_backend_driver(value); + if (be == NULL) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "type", + "a TPM backend type"); + tpm_display_backend_drivers(); + return 1; + } + + drv = be->create(opts, id); + if (!drv) { + return 1; + } + + QLIST_INSERT_HEAD(&tpm_backends, drv, list); + + return 0; +} + +static int tpm_init_tpmdev(QemuOpts *opts, void *dummy) +{ + return configure_tpm(opts); +} + +/* + * Walk the list of TPM backend drivers that are in use and call their + * destroy function to have them cleaned up. + */ +void tpm_cleanup(void) +{ + TPMBackend *drv, *next; + + QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) { + QLIST_REMOVE(drv, list); + drv->ops->destroy(drv); + } +} + +/* + * Initialize the TPM. Process the tpmdev command line options describing the + * TPM backend. + */ +int tpm_init(void) +{ + if (qemu_opts_foreach(qemu_find_opts("tpmdev"), + tpm_init_tpmdev, NULL, 1) != 0) { + return -1; + } + + atexit(tpm_cleanup); + + return 0; +} + +/* + * Parse the TPM configuration options. + * To display all available TPM backends the user may use '-tpmdev help' + */ +int tpm_config_parse(QemuOptsList *opts_list, const char *optarg) +{ + QemuOpts *opts; + + if (!strcmp(optarg, "help")) { + tpm_display_backend_drivers(); + return -1; + } + opts = qemu_opts_parse(opts_list, optarg, 1); + if (!opts) { + return -1; + } + return 0; +} + +#endif /* CONFIG_TPM */ + +static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type) +{ + int i; + + for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { + if (be_drivers[i]->type == type) { + return be_drivers[i]; + } + } + return NULL; +} + +static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv) +{ + TPMInfo *res = g_new0(TPMInfo, 1); + TPMPassthroughOptions *tpo; + + res->id = g_strdup(drv->id); + res->model = drv->fe_model; + res->type = drv->ops->type; + res->tpm_options = g_new0(TpmTypeOptions, 1); + + switch (res->type) { + case TPM_TYPE_PASSTHROUGH: + res->tpm_options->kind = TPM_TYPE_OPTIONS_KIND_TPM_PASSTHROUGH_OPTIONS; + tpo = g_new0(TPMPassthroughOptions, 1); + res->tpm_options->tpm_passthrough_options = tpo; + if (drv->path) { + tpo->path = g_strdup(drv->path); + tpo->has_path = true; + } + if (drv->cancel_path) { + tpo->cancel_path = g_strdup(drv->cancel_path); + tpo->has_cancel_path = true; + } + break; + case TPM_TYPE_MAX: + break; + } + + return res; +} + +/* + * Walk the list of active TPM backends and collect information about them + * following the schema description in qapi-schema.json. + */ +TPMInfoList *qmp_query_tpm(Error **errp) +{ + TPMBackend *drv; + TPMInfoList *info, *head = NULL, *cur_item = NULL; + + QLIST_FOREACH(drv, &tpm_backends, list) { + if (!tpm_model_is_registered(drv->fe_model)) { + continue; + } + info = g_new0(TPMInfoList, 1); + info->value = qmp_query_tpm_inst(drv); + + if (!cur_item) { + head = cur_item = info; + } else { + cur_item->next = info; + cur_item = info; + } + } + + return head; +} + +TpmTypeList *qmp_query_tpm_types(Error **errp) +{ + unsigned int i = 0; + TpmTypeList *head = NULL, *prev = NULL, *cur_item; + + for (i = 0; i < TPM_TYPE_MAX; i++) { + if (!tpm_driver_find_by_type(i)) { + continue; + } + cur_item = g_new0(TpmTypeList, 1); + cur_item->value = i; + + if (prev) { + prev->next = cur_item; + } + if (!head) { + head = cur_item; + } + prev = cur_item; + } + + return head; +} + +TpmModelList *qmp_query_tpm_models(Error **errp) +{ + unsigned int i = 0; + TpmModelList *head = NULL, *prev = NULL, *cur_item; + + for (i = 0; i < TPM_MODEL_MAX; i++) { + if (!tpm_model_is_registered(i)) { + continue; + } + cur_item = g_new0(TpmModelList, 1); + cur_item->value = i; + + if (prev) { + prev->next = cur_item; + } + if (!head) { + head = cur_item; + } + prev = cur_item; + } + + return head; +} diff --git a/tpm/tpm_int.h b/tpm/tpm_int.h new file mode 100644 index 0000000000..d5358adf83 --- /dev/null +++ b/tpm/tpm_int.h @@ -0,0 +1,83 @@ +/* + * TPM configuration + * + * Copyright (C) 2011-2013 IBM Corporation + * + * Authors: + * Stefan Berger + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef TPM_TPM_INT_H +#define TPM_TPM_INT_H + +#include "exec/memory.h" +#include "tpm/tpm_tis.h" + +struct TPMDriverOps; +typedef struct TPMDriverOps TPMDriverOps; + +typedef struct TPMBackend { + char *id; + enum TpmModel fe_model; + char *path; + char *cancel_path; + const TPMDriverOps *ops; + + QLIST_ENTRY(TPMBackend) list; +} TPMBackend; + +/* overall state of the TPM interface */ +typedef struct TPMState { + ISADevice busdev; + MemoryRegion mmio; + + union { + TPMTISEmuState tis; + } s; + + uint8_t locty_number; + TPMLocality *locty_data; + + char *backend; + TPMBackend *be_driver; +} TPMState; + +#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) + +typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty); + +struct TPMDriverOps { + enum TpmType type; + /* get a descriptive text of the backend to display to the user */ + const char *(*desc)(void); + + TPMBackend *(*create)(QemuOpts *opts, const char *id); + void (*destroy)(TPMBackend *t); + + /* initialize the backend */ + int (*init)(TPMBackend *t, TPMState *s, TPMRecvDataCB *datacb); + /* start up the TPM on the backend */ + int (*startup_tpm)(TPMBackend *t); + /* returns true if nothing will ever answer TPM requests */ + bool (*had_startup_error)(TPMBackend *t); + + size_t (*realloc_buffer)(TPMSizedBuffer *sb); + + void (*deliver_request)(TPMBackend *t); + + void (*reset)(TPMBackend *t); + + void (*cancel_cmd)(TPMBackend *t); + + bool (*get_tpm_established_flag)(TPMBackend *t); +}; + +TPMBackend *qemu_find_tpm(const char *id); +int tpm_register_model(enum TpmModel model); +int tpm_register_driver(const TPMDriverOps *tdo); +void tpm_display_backend_drivers(void); +const TPMDriverOps *tpm_get_backend_driver(const char *type); + +#endif /* TPM_TPM_INT_H */ diff --git a/tpm/tpm_tis.h b/tpm/tpm_tis.h new file mode 100644 index 0000000000..0c8df80cce --- /dev/null +++ b/tpm/tpm_tis.h @@ -0,0 +1,80 @@ +/* + * tpm_tis.h - QEMU's TPM TIS interface emulator + * + * Copyright (C) 2006, 2010-2013 IBM Corporation + * + * Authors: + * Stefan Berger + * David Safford + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Implementation of the TIS interface according to specs found at + * http://www.trustedcomputinggroup.org + * + */ +#ifndef TPM_TPM_TIS_H +#define TPM_TPM_TIS_H + +#include "hw/isa.h" +#include "qemu-common.h" + +#define TPM_TIS_ADDR_BASE 0xFED40000 + +#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ +#define TPM_TIS_LOCALITY_SHIFT 12 +#define TPM_TIS_NO_LOCALITY 0xff + +#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES) + +#define TPM_TIS_IRQ 5 + +#define TPM_TIS_BUFFER_MAX 4096 + +#define TYPE_TPM_TIS "tpm-tis" + + +typedef struct TPMSizedBuffer { + uint32_t size; + uint8_t *buffer; +} TPMSizedBuffer; + +typedef enum { + TPM_TIS_STATE_IDLE = 0, + TPM_TIS_STATE_READY, + TPM_TIS_STATE_COMPLETION, + TPM_TIS_STATE_EXECUTION, + TPM_TIS_STATE_RECEPTION, +} TPMTISState; + +/* locality data -- all fields are persisted */ +typedef struct TPMLocality { + TPMTISState state; + uint8_t access; + uint8_t sts; + uint32_t inte; + uint32_t ints; + + uint16_t w_offset; + uint16_t r_offset; + TPMSizedBuffer w_buffer; + TPMSizedBuffer r_buffer; +} TPMLocality; + +typedef struct TPMTISEmuState { + QEMUBH *bh; + uint32_t offset; + uint8_t buf[TPM_TIS_BUFFER_MAX]; + + uint8_t active_locty; + uint8_t aborting_locty; + uint8_t next_locty; + + TPMLocality loc[TPM_TIS_NUM_LOCALITIES]; + + qemu_irq irq; + uint32_t irq_num; +} TPMTISEmuState; + +#endif /* TPM_TPM_TIS_H */ diff --git a/vl.c b/vl.c index 154f7bae6a..0c6c2bfa6a 100644 --- a/vl.c +++ b/vl.c @@ -139,6 +139,7 @@ int main(int argc, char **argv) #include "sysemu/blockdev.h" #include "hw/block-common.h" #include "migration/block.h" +#include "tpm/tpm.h" #include "sysemu/dma.h" #include "audio/audio.h" #include "migration/migration.h" @@ -491,6 +492,25 @@ static QemuOptsList qemu_object_opts = { }, }; +static QemuOptsList qemu_tpmdev_opts = { + .name = "tpmdev", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_tpmdev_opts.head), + .desc = { + { + .name = "type", + .type = QEMU_OPT_STRING, + .help = "Type of TPM backend", + }, + { + .name = "path", + .type = QEMU_OPT_STRING, + .help = "Path to TPM device on the host", + }, + { /* end of list */ } + }, +}; + const char *qemu_get_vm_name(void) { return qemu_name; @@ -2868,6 +2888,7 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_sandbox_opts); qemu_add_opts(&qemu_add_fd_opts); qemu_add_opts(&qemu_object_opts); + qemu_add_opts(&qemu_tpmdev_opts); runstate_init(); @@ -3231,6 +3252,13 @@ int main(int argc, char **argv, char **envp) } break; } +#ifdef CONFIG_TPM + case QEMU_OPTION_tpmdev: + if (tpm_config_parse(qemu_find_opts("tpmdev"), optarg) < 0) { + exit(1); + } + break; +#endif case QEMU_OPTION_mempath: mem_path = optarg; break; @@ -4108,6 +4136,12 @@ int main(int argc, char **argv, char **envp) exit(1); } +#ifdef CONFIG_TPM + if (tpm_init() < 0) { + exit(1); + } +#endif + /* init the bluetooth world */ if (foreach_device_config(DEV_BT, bt_parse)) exit(1); @@ -4353,6 +4387,9 @@ int main(int argc, char **argv, char **envp) bdrv_close_all(); pause_all_vcpus(); res_free(); +#ifdef CONFIG_TPM + tpm_cleanup(); +#endif return 0; } From edff867807fefd9b8cc2bfd0e88a957987225f55 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 27 Feb 2013 12:47:50 -0500 Subject: [PATCH 1576/1634] Add TPM (frontend) hardware interface (TPM TIS) to QEMU This patch adds the main code of the TPM frontend driver, the TPM TIS interface, to QEMU. The code is largely based on the previous implementation for Xen but has been significantly extended to meet the standard's requirements, such as the support for changing of localities and all the functionality of the available flags. Communication with the backend (i.e., for Xen or the libtpms-based one) is cleanly separated through an interface which the backend driver needs to implement. Whenever the frontend has collected a complete packet, it will submit a task to the backend, which then starts processing the command. Once the result has been returned, the backend invokes a callback function (tpm_tis_receive_cb()). Testing the proper functioning of the different flags and localities cannot be done from user space when running in Linux for example, since access to the address space of the TPM TIS interface is not possible. Also the Linux driver itself does not exercise all functionality. So, for testing there is a fairly extensive test suite as part of the SeaBIOS patches since from within the BIOS one can have full access to all the TPM's registers. Signed-off-by: Stefan Berger Reviewed-by: Corey Bryant Reviewed-by: Joel Schopp Message-id: 1361987275-26289-3-git-send-email-stefanb@linux.vnet.ibm.com Signed-off-by: Anthony Liguori --- tpm/tpm_tis.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 859 insertions(+) create mode 100644 tpm/tpm_tis.c diff --git a/tpm/tpm_tis.c b/tpm/tpm_tis.c new file mode 100644 index 0000000000..5386e1833e --- /dev/null +++ b/tpm/tpm_tis.c @@ -0,0 +1,859 @@ +/* + * tpm_tis.c - QEMU's TPM TIS interface emulator + * + * Copyright (C) 2006,2010-2013 IBM Corporation + * + * Authors: + * Stefan Berger + * David Safford + * + * Xen 4 support: Andrease Niederl + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Implementation of the TIS interface according to specs found at + * http://www.trustedcomputinggroup.org. This implementation currently + * supports version 1.21, revision 1.0. + * In the developers menu choose the PC Client section then find the TIS + * specification. + */ + +#include "tpm_int.h" +#include "block/block.h" +#include "exec/address-spaces.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "hw/pci/pci_ids.h" +#include "tpm/tpm_tis.h" +#include "qemu-common.h" + +/*#define DEBUG_TIS */ + +#ifdef DEBUG_TIS +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +/* whether the STS interrupt is supported */ +#define RAISE_STS_IRQ + +/* tis registers */ +#define TPM_TIS_REG_ACCESS 0x00 +#define TPM_TIS_REG_INT_ENABLE 0x08 +#define TPM_TIS_REG_INT_VECTOR 0x0c +#define TPM_TIS_REG_INT_STATUS 0x10 +#define TPM_TIS_REG_INTF_CAPABILITY 0x14 +#define TPM_TIS_REG_STS 0x18 +#define TPM_TIS_REG_DATA_FIFO 0x24 +#define TPM_TIS_REG_DID_VID 0xf00 +#define TPM_TIS_REG_RID 0xf04 + +#define TPM_TIS_STS_VALID (1 << 7) +#define TPM_TIS_STS_COMMAND_READY (1 << 6) +#define TPM_TIS_STS_TPM_GO (1 << 5) +#define TPM_TIS_STS_DATA_AVAILABLE (1 << 4) +#define TPM_TIS_STS_EXPECT (1 << 3) +#define TPM_TIS_STS_RESPONSE_RETRY (1 << 1) + +#define TPM_TIS_BURST_COUNT_SHIFT 8 +#define TPM_TIS_BURST_COUNT(X) \ + ((X) << TPM_TIS_BURST_COUNT_SHIFT) + +#define TPM_TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) +#define TPM_TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) +#define TPM_TIS_ACCESS_BEEN_SEIZED (1 << 4) +#define TPM_TIS_ACCESS_SEIZE (1 << 3) +#define TPM_TIS_ACCESS_PENDING_REQUEST (1 << 2) +#define TPM_TIS_ACCESS_REQUEST_USE (1 << 1) +#define TPM_TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) + +#define TPM_TIS_INT_ENABLED (1 << 31) +#define TPM_TIS_INT_DATA_AVAILABLE (1 << 0) +#define TPM_TIS_INT_STS_VALID (1 << 1) +#define TPM_TIS_INT_LOCALITY_CHANGED (1 << 2) +#define TPM_TIS_INT_COMMAND_READY (1 << 7) + +#define TPM_TIS_INT_POLARITY_MASK (3 << 3) +#define TPM_TIS_INT_POLARITY_LOW_LEVEL (1 << 3) + +#ifndef RAISE_STS_IRQ + +#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \ + TPM_TIS_INT_DATA_AVAILABLE | \ + TPM_TIS_INT_COMMAND_READY) + +#else + +#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \ + TPM_TIS_INT_DATA_AVAILABLE | \ + TPM_TIS_INT_STS_VALID | \ + TPM_TIS_INT_COMMAND_READY) + +#endif + +#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */ +#define TPM_TIS_CAPABILITIES_SUPPORTED (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \ + TPM_TIS_INTERRUPTS_SUPPORTED) + +#define TPM_TIS_TPM_DID 0x0001 +#define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM +#define TPM_TIS_TPM_RID 0x0001 + +#define TPM_TIS_NO_DATA_BYTE 0xff + +/* utility functions */ + +static uint8_t tpm_tis_locality_from_addr(hwaddr addr) +{ + return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); +} + +static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb) +{ + return be32_to_cpu(*(uint32_t *)&sb->buffer[2]); +} + +static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string) +{ +#ifdef DEBUG_TIS + uint32_t len, i; + + len = tpm_tis_get_size_from_buffer(sb); + DPRINTF("tpm_tis: %s length = %d\n", string, len); + for (i = 0; i < len; i++) { + if (i && !(i % 16)) { + DPRINTF("\n"); + } + DPRINTF("%.2X ", sb->buffer[i]); + } + DPRINTF("\n"); +#endif +} + +/* + * Send a request to the TPM. + */ +static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) +{ + TPMTISEmuState *tis = &s->s.tis; + + tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM"); + + s->locty_number = locty; + s->locty_data = &tis->loc[locty]; + + /* + * w_offset serves as length indicator for length of data; + * it's reset when the response comes back + */ + tis->loc[locty].state = TPM_TIS_STATE_EXECUTION; + + s->be_driver->ops->deliver_request(s->be_driver); +} + +/* raise an interrupt if allowed */ +static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask) +{ + TPMTISEmuState *tis = &s->s.tis; + + if (!TPM_TIS_IS_VALID_LOCTY(locty)) { + return; + } + + if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) && + (tis->loc[locty].inte & irqmask)) { + DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask); + qemu_irq_raise(s->s.tis.irq); + tis->loc[locty].ints |= irqmask; + } +} + +static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty) +{ + uint8_t l; + + for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { + if (l == locty) { + continue; + } + if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) { + return 1; + } + } + + return 0; +} + +static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) +{ + TPMTISEmuState *tis = &s->s.tis; + bool change = (s->s.tis.active_locty != new_active_locty); + bool is_seize; + uint8_t mask; + + if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) { + is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) && + tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE; + + if (is_seize) { + mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY); + } else { + mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY| + TPM_TIS_ACCESS_REQUEST_USE); + } + /* reset flags on the old active locality */ + tis->loc[s->s.tis.active_locty].access &= mask; + + if (is_seize) { + tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED; + } + } + + tis->active_locty = new_active_locty; + + DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty); + + if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) { + /* set flags on the new active locality */ + tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY; + tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE | + TPM_TIS_ACCESS_SEIZE); + } + + if (change) { + tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED); + } +} + +/* abort -- this function switches the locality */ +static void tpm_tis_abort(TPMState *s, uint8_t locty) +{ + TPMTISEmuState *tis = &s->s.tis; + + tis->loc[locty].r_offset = 0; + tis->loc[locty].w_offset = 0; + + DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty); + + /* + * Need to react differently depending on who's aborting now and + * which locality will become active afterwards. + */ + if (tis->aborting_locty == tis->next_locty) { + tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY; + tis->loc[tis->aborting_locty].sts = TPM_TIS_STS_COMMAND_READY; + tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY); + } + + /* locality after abort is another one than the current one */ + tpm_tis_new_active_locality(s, tis->next_locty); + + tis->next_locty = TPM_TIS_NO_LOCALITY; + /* nobody's aborting a command anymore */ + tis->aborting_locty = TPM_TIS_NO_LOCALITY; +} + +/* prepare aborting current command */ +static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) +{ + TPMTISEmuState *tis = &s->s.tis; + uint8_t busy_locty; + + tis->aborting_locty = locty; + tis->next_locty = newlocty; /* locality after successful abort */ + + /* + * only abort a command using an interrupt if currently executing + * a command AND if there's a valid connection to the vTPM. + */ + for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) { + if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) { + /* + * request the backend to cancel. Some backends may not + * support it + */ + s->be_driver->ops->cancel_cmd(s->be_driver); + return; + } + } + + tpm_tis_abort(s, locty); +} + +static void tpm_tis_receive_bh(void *opaque) +{ + TPMState *s = opaque; + TPMTISEmuState *tis = &s->s.tis; + uint8_t locty = s->locty_number; + + tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE; + tis->loc[locty].state = TPM_TIS_STATE_COMPLETION; + tis->loc[locty].r_offset = 0; + tis->loc[locty].w_offset = 0; + + if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) { + tpm_tis_abort(s, locty); + } + +#ifndef RAISE_STS_IRQ + tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE); +#else + tpm_tis_raise_irq(s, locty, + TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); +#endif +} + +/* + * Callback from the TPM to indicate that the response was received. + */ +static void tpm_tis_receive_cb(TPMState *s, uint8_t locty) +{ + TPMTISEmuState *tis = &s->s.tis; + + assert(s->locty_number == locty); + + qemu_bh_schedule(tis->bh); +} + +/* + * Read a byte of response data + */ +static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) +{ + TPMTISEmuState *tis = &s->s.tis; + uint32_t ret = TPM_TIS_NO_DATA_BYTE; + uint16_t len; + + if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { + len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer); + + ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++]; + if (tis->loc[locty].r_offset >= len) { + /* got last byte */ + tis->loc[locty].sts = TPM_TIS_STS_VALID; +#ifdef RAISE_STS_IRQ + tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); +#endif + } + DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n", + ret, tis->loc[locty].r_offset-1); + } + + return ret; +} + +/* + * Read a register of the TIS interface + * See specs pages 33-63 for description of the registers + */ +static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + TPMState *s = opaque; + TPMTISEmuState *tis = &s->s.tis; + uint16_t offset = addr & 0xffc; + uint8_t shift = (addr & 0x3) * 8; + uint32_t val = 0xffffffff; + uint8_t locty = tpm_tis_locality_from_addr(addr); + uint32_t avail; + + if (s->be_driver->ops->had_startup_error(s->be_driver)) { + return val; + } + + switch (offset) { + case TPM_TIS_REG_ACCESS: + /* never show the SEIZE flag even though we use it internally */ + val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE; + /* the pending flag is always calculated */ + if (tpm_tis_check_request_use_except(s, locty)) { + val |= TPM_TIS_ACCESS_PENDING_REQUEST; + } + val |= !s->be_driver->ops->get_tpm_established_flag(s->be_driver); + break; + case TPM_TIS_REG_INT_ENABLE: + val = tis->loc[locty].inte; + break; + case TPM_TIS_REG_INT_VECTOR: + val = tis->irq_num; + break; + case TPM_TIS_REG_INT_STATUS: + val = tis->loc[locty].ints; + break; + case TPM_TIS_REG_INTF_CAPABILITY: + val = TPM_TIS_CAPABILITIES_SUPPORTED; + break; + case TPM_TIS_REG_STS: + if (tis->active_locty == locty) { + if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { + val = TPM_TIS_BURST_COUNT( + tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer) + - tis->loc[locty].r_offset) | tis->loc[locty].sts; + } else { + avail = tis->loc[locty].w_buffer.size + - tis->loc[locty].w_offset; + /* + * byte-sized reads should not return 0x00 for 0x100 + * available bytes. + */ + if (size == 1 && avail > 0xff) { + avail = 0xff; + } + val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts; + } + } + break; + case TPM_TIS_REG_DATA_FIFO: + if (tis->active_locty == locty) { + switch (tis->loc[locty].state) { + case TPM_TIS_STATE_COMPLETION: + val = tpm_tis_data_read(s, locty); + break; + default: + val = TPM_TIS_NO_DATA_BYTE; + break; + } + } + break; + case TPM_TIS_REG_DID_VID: + val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; + break; + case TPM_TIS_REG_RID: + val = TPM_TIS_TPM_RID; + break; + } + + if (shift) { + val >>= shift; + } + + DPRINTF("tpm_tis: read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val); + + return val; +} + +/* + * Write a value to a register of the TIS interface + * See specs pages 33-63 for description of the registers + */ +static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr, + uint64_t val, unsigned size, + bool hw_access) +{ + TPMState *s = opaque; + TPMTISEmuState *tis = &s->s.tis; + uint16_t off = addr & 0xfff; + uint8_t locty = tpm_tis_locality_from_addr(addr); + uint8_t active_locty, l; + int c, set_new_locty = 1; + uint16_t len; + + DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val); + + if (locty == 4 && !hw_access) { + DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n"); + return; + } + + if (s->be_driver->ops->had_startup_error(s->be_driver)) { + return; + } + + switch (off) { + case TPM_TIS_REG_ACCESS: + + if ((val & TPM_TIS_ACCESS_SEIZE)) { + val &= ~(TPM_TIS_ACCESS_REQUEST_USE | + TPM_TIS_ACCESS_ACTIVE_LOCALITY); + } + + active_locty = tis->active_locty; + + if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) { + /* give up locality if currently owned */ + if (tis->active_locty == locty) { + DPRINTF("tpm_tis: Releasing locality %d\n", locty); + + uint8_t newlocty = TPM_TIS_NO_LOCALITY; + /* anybody wants the locality ? */ + for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) { + if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) { + DPRINTF("tpm_tis: Locality %d requests use.\n", c); + newlocty = c; + break; + } + } + DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: " + "Next active locality: %d\n", + newlocty); + + if (TPM_TIS_IS_VALID_LOCTY(newlocty)) { + set_new_locty = 0; + tpm_tis_prep_abort(s, locty, newlocty); + } else { + active_locty = TPM_TIS_NO_LOCALITY; + } + } else { + /* not currently the owner; clear a pending request */ + tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE; + } + } + + if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) { + tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED; + } + + if ((val & TPM_TIS_ACCESS_SEIZE)) { + /* + * allow seize if a locality is active and the requesting + * locality is higher than the one that's active + * OR + * allow seize for requesting locality if no locality is + * active + */ + while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) && + locty > tis->active_locty) || + !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) { + bool higher_seize = FALSE; + + /* already a pending SEIZE ? */ + if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { + break; + } + + /* check for ongoing seize by a higher locality */ + for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { + if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { + higher_seize = TRUE; + break; + } + } + + if (higher_seize) { + break; + } + + /* cancel any seize by a lower locality */ + for (l = 0; l < locty - 1; l++) { + tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE; + } + + tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE; + DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: " + "Locality %d seized from locality %d\n", + locty, tis->active_locty); + DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n"); + set_new_locty = 0; + tpm_tis_prep_abort(s, tis->active_locty, locty); + break; + } + } + + if ((val & TPM_TIS_ACCESS_REQUEST_USE)) { + if (tis->active_locty != locty) { + if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) { + tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE; + } else { + /* no locality active -> make this one active now */ + active_locty = locty; + } + } + } + + if (set_new_locty) { + tpm_tis_new_active_locality(s, active_locty); + } + + break; + case TPM_TIS_REG_INT_ENABLE: + if (tis->active_locty != locty) { + break; + } + + tis->loc[locty].inte = (val & (TPM_TIS_INT_ENABLED | + TPM_TIS_INT_POLARITY_MASK | + TPM_TIS_INTERRUPTS_SUPPORTED)); + break; + case TPM_TIS_REG_INT_VECTOR: + /* hard wired -- ignore */ + break; + case TPM_TIS_REG_INT_STATUS: + if (tis->active_locty != locty) { + break; + } + + /* clearing of interrupt flags */ + if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) && + (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) { + tis->loc[locty].ints &= ~val; + if (tis->loc[locty].ints == 0) { + qemu_irq_lower(tis->irq); + DPRINTF("tpm_tis: Lowering IRQ\n"); + } + } + tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED); + break; + case TPM_TIS_REG_STS: + if (tis->active_locty != locty) { + break; + } + + val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO | + TPM_TIS_STS_RESPONSE_RETRY); + + if (val == TPM_TIS_STS_COMMAND_READY) { + switch (tis->loc[locty].state) { + + case TPM_TIS_STATE_READY: + tis->loc[locty].w_offset = 0; + tis->loc[locty].r_offset = 0; + break; + + case TPM_TIS_STATE_IDLE: + tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY; + tis->loc[locty].state = TPM_TIS_STATE_READY; + tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); + break; + + case TPM_TIS_STATE_EXECUTION: + case TPM_TIS_STATE_RECEPTION: + /* abort currently running command */ + DPRINTF("tpm_tis: %s: Initiating abort.\n", + __func__); + tpm_tis_prep_abort(s, locty, locty); + break; + + case TPM_TIS_STATE_COMPLETION: + tis->loc[locty].w_offset = 0; + tis->loc[locty].r_offset = 0; + /* shortcut to ready state with C/R set */ + tis->loc[locty].state = TPM_TIS_STATE_READY; + if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { + tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY; + tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); + } + tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE); + break; + + } + } else if (val == TPM_TIS_STS_TPM_GO) { + switch (tis->loc[locty].state) { + case TPM_TIS_STATE_RECEPTION: + if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) { + tpm_tis_tpm_send(s, locty); + } + break; + default: + /* ignore */ + break; + } + } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { + switch (tis->loc[locty].state) { + case TPM_TIS_STATE_COMPLETION: + tis->loc[locty].r_offset = 0; + tis->loc[locty].sts = TPM_TIS_STS_VALID | + TPM_TIS_STS_DATA_AVAILABLE; + break; + default: + /* ignore */ + break; + } + } + break; + case TPM_TIS_REG_DATA_FIFO: + /* data fifo */ + if (tis->active_locty != locty) { + break; + } + + if (tis->loc[locty].state == TPM_TIS_STATE_IDLE || + tis->loc[locty].state == TPM_TIS_STATE_EXECUTION || + tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) { + /* drop the byte */ + } else { + DPRINTF("tpm_tis: Byte to send to TPM: %02x\n", (uint8_t)val); + if (tis->loc[locty].state == TPM_TIS_STATE_READY) { + tis->loc[locty].state = TPM_TIS_STATE_RECEPTION; + tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID; + } + + if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) { + if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) { + tis->loc[locty].w_buffer. + buffer[tis->loc[locty].w_offset++] = (uint8_t)val; + } else { + tis->loc[locty].sts = TPM_TIS_STS_VALID; + } + } + + /* check for complete packet */ + if (tis->loc[locty].w_offset > 5 && + (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) { + /* we have a packet length - see if we have all of it */ +#ifdef RAISE_STS_IRQ + bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID); +#endif + len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer); + if (len > tis->loc[locty].w_offset) { + tis->loc[locty].sts = TPM_TIS_STS_EXPECT | + TPM_TIS_STS_VALID; + } else { + /* packet complete */ + tis->loc[locty].sts = TPM_TIS_STS_VALID; + } +#ifdef RAISE_STS_IRQ + if (needIrq) { + tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); + } +#endif + } + } + break; + } +} + +static void tpm_tis_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + return tpm_tis_mmio_write_intern(opaque, addr, val, size, false); +} + +static const MemoryRegionOps tpm_tis_memory_ops = { + .read = tpm_tis_mmio_read, + .write = tpm_tis_mmio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +static int tpm_tis_do_startup_tpm(TPMState *s) +{ + return s->be_driver->ops->startup_tpm(s->be_driver); +} + +/* + * This function is called when the machine starts, resets or due to + * S3 resume. + */ +static void tpm_tis_reset(DeviceState *dev) +{ + TPMState *s = TPM(dev); + TPMTISEmuState *tis = &s->s.tis; + int c; + + s->be_driver->ops->reset(s->be_driver); + + tis->active_locty = TPM_TIS_NO_LOCALITY; + tis->next_locty = TPM_TIS_NO_LOCALITY; + tis->aborting_locty = TPM_TIS_NO_LOCALITY; + + for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) { + tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; + tis->loc[c].sts = 0; + tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL; + tis->loc[c].ints = 0; + tis->loc[c].state = TPM_TIS_STATE_IDLE; + + tis->loc[c].w_offset = 0; + s->be_driver->ops->realloc_buffer(&tis->loc[c].w_buffer); + tis->loc[c].r_offset = 0; + s->be_driver->ops->realloc_buffer(&tis->loc[c].r_buffer); + } + + tpm_tis_do_startup_tpm(s); +} + +static const VMStateDescription vmstate_tpm_tis = { + .name = "tpm", + .unmigratable = 1, +}; + +static Property tpm_tis_properties[] = { + DEFINE_PROP_UINT32("irq", TPMState, + s.tis.irq_num, TPM_TIS_IRQ), + DEFINE_PROP_STRING("tpmdev", TPMState, backend), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tpm_tis_realizefn(DeviceState *dev, Error **errp) +{ + TPMState *s = TPM(dev); + TPMTISEmuState *tis = &s->s.tis; + + s->be_driver = qemu_find_tpm(s->backend); + if (!s->be_driver) { + error_setg(errp, "tpm_tis: backend driver with id %s could not be " + "found", s->backend); + return; + } + + s->be_driver->fe_model = TPM_MODEL_TPM_TIS; + + if (s->be_driver->ops->init(s->be_driver, s, tpm_tis_receive_cb)) { + error_setg(errp, "tpm_tis: backend driver with id %s could not be " + "initialized", s->backend); + return; + } + + if (tis->irq_num > 15) { + error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range " + "of 0 to 15.\n", tis->irq_num); + return; + } + + tis->bh = qemu_bh_new(tpm_tis_receive_bh, s); + + isa_init_irq(&s->busdev, &tis->irq, tis->irq_num); +} + +static void tpm_tis_initfn(Object *obj) +{ + ISADevice *dev = ISA_DEVICE(obj); + TPMState *s = TPM(obj); + + memory_region_init_io(&s->mmio, &tpm_tis_memory_ops, s, "tpm-tis-mmio", + TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); + memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE, + &s->mmio); +} + +static void tpm_tis_uninitfn(Object *obj) +{ + TPMState *s = TPM(obj); + + memory_region_del_subregion(get_system_memory(), &s->mmio); + memory_region_destroy(&s->mmio); +} + +static void tpm_tis_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = tpm_tis_realizefn; + dc->props = tpm_tis_properties; + dc->reset = tpm_tis_reset; + dc->vmsd = &vmstate_tpm_tis; +} + +static const TypeInfo tpm_tis_info = { + .name = TYPE_TPM_TIS, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(TPMState), + .instance_init = tpm_tis_initfn, + .instance_finalize = tpm_tis_uninitfn, + .class_init = tpm_tis_class_init, +}; + +static void tpm_tis_register(void) +{ + type_register_static(&tpm_tis_info); + tpm_register_model(TPM_MODEL_TPM_TIS); +} + +type_init(tpm_tis_register) From 8db7c4152188a13b4de6fbab158d61e5dd50e7ec Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 27 Feb 2013 12:47:51 -0500 Subject: [PATCH 1577/1634] Add a debug register This patch uses the possibility to add a vendor-specific register and adds a debug register useful for dumping the TIS's internal state. This register is only active in a debug build (#define DEBUG_TIS). Signed-off-by: Stefan Berger Reviewed-by: Corey Bryant Reviewed-by: Joel Schopp Message-id: 1361987275-26289-4-git-send-email-stefanb@linux.vnet.ibm.com Signed-off-by: Anthony Liguori --- tpm/tpm_tis.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tpm/tpm_tis.c b/tpm/tpm_tis.c index 5386e1833e..e93825eec1 100644 --- a/tpm/tpm_tis.c +++ b/tpm/tpm_tis.c @@ -52,6 +52,9 @@ #define TPM_TIS_REG_DID_VID 0xf00 #define TPM_TIS_REG_RID 0xf04 +/* vendor-specific registers */ +#define TPM_TIS_REG_DEBUG 0xf90 + #define TPM_TIS_STS_VALID (1 << 7) #define TPM_TIS_STS_COMMAND_READY (1 << 6) #define TPM_TIS_STS_TPM_GO (1 << 5) @@ -105,6 +108,11 @@ #define TPM_TIS_NO_DATA_BYTE 0xff +/* local prototypes */ + +static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, + unsigned size); + /* utility functions */ static uint8_t tpm_tis_locality_from_addr(hwaddr addr) @@ -346,6 +354,63 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) return ret; } +#ifdef DEBUG_TIS +static void tpm_tis_dump_state(void *opaque, hwaddr addr) +{ + static const unsigned regs[] = { + TPM_TIS_REG_ACCESS, + TPM_TIS_REG_INT_ENABLE, + TPM_TIS_REG_INT_VECTOR, + TPM_TIS_REG_INT_STATUS, + TPM_TIS_REG_INTF_CAPABILITY, + TPM_TIS_REG_STS, + TPM_TIS_REG_DID_VID, + TPM_TIS_REG_RID, + 0xfff}; + int idx; + uint8_t locty = tpm_tis_locality_from_addr(addr); + hwaddr base = addr & ~0xfff; + TPMState *s = opaque; + TPMTISEmuState *tis = &s->s.tis; + + DPRINTF("tpm_tis: active locality : %d\n" + "tpm_tis: state of locality %d : %d\n" + "tpm_tis: register dump:\n", + tis->active_locty, + locty, tis->loc[locty].state); + + for (idx = 0; regs[idx] != 0xfff; idx++) { + DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], + (uint32_t)tpm_tis_mmio_read(opaque, base + regs[idx], 4)); + } + + DPRINTF("tpm_tis: read offset : %d\n" + "tpm_tis: result buffer : ", + tis->loc[locty].r_offset); + for (idx = 0; + idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer); + idx++) { + DPRINTF("%c%02x%s", + tis->loc[locty].r_offset == idx ? '>' : ' ', + tis->loc[locty].r_buffer.buffer[idx], + ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); + } + DPRINTF("\n" + "tpm_tis: write offset : %d\n" + "tpm_tis: request buffer: ", + tis->loc[locty].w_offset); + for (idx = 0; + idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer); + idx++) { + DPRINTF("%c%02x%s", + tis->loc[locty].w_offset == idx ? '>' : ' ', + tis->loc[locty].w_buffer.buffer[idx], + ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); + } + DPRINTF("\n"); +} +#endif + /* * Read a register of the TIS interface * See specs pages 33-63 for description of the registers @@ -425,6 +490,11 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, case TPM_TIS_REG_RID: val = TPM_TIS_TPM_RID; break; +#ifdef DEBUG_TIS + case TPM_TIS_REG_DEBUG: + tpm_tis_dump_state(opaque, addr); + break; +#endif } if (shift) { From ab214c2960e3a6d2a86b1ff53e9ba2505d173f93 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 27 Feb 2013 12:47:52 -0500 Subject: [PATCH 1578/1634] Build the TPM frontend code Build the TPM frontend code that has been added so far. Signed-off-by: Stefan Berger Reviewed-by: Corey Bryant Reviewed-by: Joel Schopp Message-id: 1361987275-26289-5-git-send-email-stefanb@linux.vnet.ibm.com Signed-off-by: Anthony Liguori --- configure | 11 +++++++++++ default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + tpm/Makefile.objs | 3 +++ 4 files changed, 16 insertions(+) diff --git a/configure b/configure index 84317c6826..a382ff2562 100755 --- a/configure +++ b/configure @@ -228,6 +228,7 @@ glusterfs="" virtio_blk_data_plane="" gtk="" gtkabi="2.0" +tpm="no" # parse CC options first for opt do @@ -905,6 +906,8 @@ for opt do ;; --with-gtkabi=*) gtkabi="$optarg" ;; + --enable-tpm) tpm="yes" + ;; *) echo "ERROR: unknown option $opt"; show_help="yes" ;; esac @@ -1160,6 +1163,7 @@ echo " --enable-glusterfs enable GlusterFS backend" echo " --disable-glusterfs disable GlusterFS backend" echo " --enable-gcov enable test coverage analysis with gcov" echo " --gcov=GCOV use specified gcov [$gcov_tool]" +echo " --enable-tpm enable TPM support" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -3420,6 +3424,7 @@ echo "GlusterFS support $glusterfs" echo "virtio-blk-data-plane $virtio_blk_data_plane" echo "gcov $gcov_tool" echo "gcov enabled $gcov" +echo "TPM support $tpm" if test "$sdl_too_old" = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -4329,6 +4334,12 @@ if test "$gprof" = "yes" ; then fi fi +if test "$tpm" = "yes"; then + if test "$target_softmmu" = "yes" ; then + echo "CONFIG_TPM=y" >> $config_host_mak + fi +fi + if test "$ARCH" = "tci"; then linker_script="" else diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 1b23025a98..f70594d3d4 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -26,3 +26,4 @@ CONFIG_HPET=y CONFIG_APPLESMC=y CONFIG_I8259=y CONFIG_PFLASH_CFI01=y +CONFIG_TPM_TIS=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 3392f5abd6..66c4855418 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -26,3 +26,4 @@ CONFIG_HPET=y CONFIG_APPLESMC=y CONFIG_I8259=y CONFIG_PFLASH_CFI01=y +CONFIG_TPM_TIS=y diff --git a/tpm/Makefile.objs b/tpm/Makefile.objs index dffb567aa3..94ad2e700b 100644 --- a/tpm/Makefile.objs +++ b/tpm/Makefile.objs @@ -1 +1,4 @@ common-obj-y = tpm.o +ifeq ($(CONFIG_TPM),y) +common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o +endif From 4549a8b7ee3c47155c09582f31086f7d0ba61fc4 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 27 Feb 2013 12:47:53 -0500 Subject: [PATCH 1579/1634] Add a TPM Passthrough backend driver implementation This patch is based of off version 9 of Stefan Berger's patch series "QEMU Trusted Platform Module (TPM) integration" and adds a new backend driver for it. This patch adds a passthrough backend driver for passing commands sent to the emulated TPM device directly to a TPM device opened on the host machine. Thus it is possible to use a hardware TPM device in a system running on QEMU, providing the ability to access a TPM in a special state (e.g. after a Trusted Boot). This functionality is being used in the acTvSM Trusted Virtualization Platform which is available on [1]. Usage example: qemu-system-x86_64 -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ -device tpm-tis,tpmdev=tpm0 \ -cdrom test.iso -boot d Some notes about the host TPM: The TPM needs to be enabled and activated. If that's not the case one has to go through the BIOS/UEFI and enable and activate that TPM for TPM commands to work as expected. It may be necessary to boot the kernel using tpm_tis.force=1 in the boot command line or 'modprobe tpm_tis force=1' in case of using it as a module. Regards, Andreas Niederl, Stefan Berger [1] http://trustedjava.sourceforge.net/ Signed-off-by: Andreas Niederl Signed-off-by: Stefan Berger Reviewed-by: Corey Bryant Reviewed-by: Joel Schopp Message-id: 1361987275-26289-6-git-send-email-stefanb@linux.vnet.ibm.com Signed-off-by: Anthony Liguori --- include/qemu/sockets.h | 1 + qemu-char.c | 24 +++ qemu-options.hx | 36 +++- tpm/Makefile.objs | 2 + tpm/tpm.c | 14 ++ tpm/tpm_backend.c | 58 ++++++ tpm/tpm_backend.h | 45 +++++ tpm/tpm_int.h | 33 ++++ tpm/tpm_passthrough.c | 387 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 599 insertions(+), 1 deletion(-) create mode 100644 tpm/tpm_backend.c create mode 100644 tpm/tpm_backend.h create mode 100644 tpm/tpm_passthrough.c diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 6125bf7bdf..c5cee4bf2f 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -38,6 +38,7 @@ int socket_set_nodelay(int fd); void socket_set_block(int fd); void socket_set_nonblock(int fd); int send_all(int fd, const void *buf, int len1); +int recv_all(int fd, void *buf, int len1, bool single_read); /* callback function for nonblocking connect * valid fd on success, negative error code on failure diff --git a/qemu-char.c b/qemu-char.c index 04aa589c7e..83787c74c4 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -533,6 +533,30 @@ int send_all(int fd, const void *_buf, int len1) } return len1 - len; } + +int recv_all(int fd, void *_buf, int len1, bool single_read) +{ + int ret, len; + uint8_t *buf = _buf; + + len = len1; + while ((len > 0) && (ret = read(fd, buf, len)) != 0) { + if (ret < 0) { + if (errno != EINTR && errno != EAGAIN) { + return -1; + } + continue; + } else { + if (single_read) { + return ret; + } + buf += ret; + len -= ret; + } + } + return len1 - len; +} + #endif /* !_WIN32 */ typedef struct IOWatchPoll diff --git a/qemu-options.hx b/qemu-options.hx index 291932faae..0be16b4d76 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2221,7 +2221,8 @@ DEFHEADING() DEFHEADING(TPM device options:) DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \ - "-tpmdev [],id=str[,option][,option][,...]\n", + "-tpmdev passthrough,id=id[,path=path]\n" + " use path to provide path to a character device; default is /dev/tpm0\n", QEMU_ARCH_ALL) STEXI @@ -2231,6 +2232,7 @@ The general form of a TPM device option is: @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}] @findex -tpmdev Backend type must be: +@option{passthrough}. The specific backend type will determine the applicable options. The @code{-tpmdev} option requires a @code{-device} option. @@ -2242,6 +2244,38 @@ Use 'help' to print all available TPM backend types. qemu -tpmdev help @end example +@item -tpmdev passthrough, id=@var{id}, path=@var{path} + +(Linux-host only) Enable access to the host's TPM using the passthrough +driver. + +@option{path} specifies the path to the host's TPM device, i.e., on +a Linux host this would be @code{/dev/tpm0}. +@option{path} is optional and by default @code{/dev/tpm0} is used. + +Some notes about using the host's TPM with the passthrough driver: + +The TPM device accessed by the passthrough driver must not be +used by any other application on the host. + +Since the host's firmware (BIOS/UEFI) has already initialized the TPM, +the VM's firmware (BIOS/UEFI) will not be able to initialize the +TPM again and may therefore not show a TPM-specific menu that would +otherwise allow the user to configure the TPM, e.g., allow the user to +enable/disable or activate/deactivate the TPM. +Further, if TPM ownership is released from within a VM then the host's TPM +will get disabled and deactivated. To enable and activate the +TPM again afterwards, the host has to be rebooted and the user is +required to enter the firmware's menu to enable and activate the TPM. +If the TPM is left disabled and/or deactivated most TPM commands will fail. + +To create a passthrough TPM use the following two options: +@example +-tpmdev passthrough,id=tpm0 -device tpm-tis,tpmdev=tpm0 +@end example +Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by +@code{tpmdev=tpm0} in the device option. + @end table ETEXI diff --git a/tpm/Makefile.objs b/tpm/Makefile.objs index 94ad2e700b..86768244e4 100644 --- a/tpm/Makefile.objs +++ b/tpm/Makefile.objs @@ -1,4 +1,6 @@ common-obj-y = tpm.o ifeq ($(CONFIG_TPM),y) +common-obj-y += tpm_backend.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o +common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o endif diff --git a/tpm/tpm.c b/tpm/tpm.c index 02735493c5..ffd24956d7 100644 --- a/tpm/tpm.c +++ b/tpm/tpm.c @@ -61,6 +61,20 @@ static bool tpm_model_is_registered(enum TpmModel model) return false; } +/* + * Write an error message in the given output buffer. + */ +void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len) +{ + if (out_len >= sizeof(struct tpm_resp_hdr)) { + struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out; + + resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND); + resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr)); + resp->errcode = cpu_to_be32(TPM_FAIL); + } +} + const TPMDriverOps *tpm_get_backend_driver(const char *type) { int i; diff --git a/tpm/tpm_backend.c b/tpm/tpm_backend.c new file mode 100644 index 0000000000..4144ef7d76 --- /dev/null +++ b/tpm/tpm_backend.c @@ -0,0 +1,58 @@ +/* + * common TPM backend driver functions + * + * Copyright (c) 2012-2013 IBM Corporation + * Authors: + * Stefan Berger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "tpm/tpm.h" +#include "qemu/thread.h" +#include "tpm_backend.h" + +void tpm_backend_thread_deliver_request(TPMBackendThread *tbt) +{ + g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD, NULL); +} + +void tpm_backend_thread_create(TPMBackendThread *tbt, + GFunc func, gpointer user_data) +{ + if (!tbt->pool) { + tbt->pool = g_thread_pool_new(func, user_data, 1, TRUE, NULL); + g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_INIT, NULL); + } +} + +void tpm_backend_thread_end(TPMBackendThread *tbt) +{ + if (tbt->pool) { + g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_END, NULL); + g_thread_pool_free(tbt->pool, FALSE, TRUE); + tbt->pool = NULL; + } +} + +void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt, + GFunc func, gpointer user_data) +{ + if (!tbt->pool) { + tpm_backend_thread_create(tbt, func, user_data); + } else { + g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_TPM_RESET, + NULL); + } +} diff --git a/tpm/tpm_backend.h b/tpm/tpm_backend.h new file mode 100644 index 0000000000..05d94d0f5b --- /dev/null +++ b/tpm/tpm_backend.h @@ -0,0 +1,45 @@ +/* + * common TPM backend driver functions + * + * Copyright (c) 2012-2013 IBM Corporation + * Authors: + * Stefan Berger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#ifndef TPM_TPM_BACKEND_H +#define TPM_TPM_BACKEND_H + +#include + +typedef struct TPMBackendThread { + GThreadPool *pool; +} TPMBackendThread; + +void tpm_backend_thread_deliver_request(TPMBackendThread *tbt); +void tpm_backend_thread_create(TPMBackendThread *tbt, + GFunc func, gpointer user_data); +void tpm_backend_thread_end(TPMBackendThread *tbt); +void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt, + GFunc func, gpointer user_data); + +typedef enum TPMBackendCmd { + TPM_BACKEND_CMD_INIT = 1, + TPM_BACKEND_CMD_PROCESS_CMD, + TPM_BACKEND_CMD_END, + TPM_BACKEND_CMD_TPM_RESET, +} TPMBackendCmd; + +#endif /* TPM_TPM_BACKEND_H */ diff --git a/tpm/tpm_int.h b/tpm/tpm_int.h index d5358adf83..f7056436cc 100644 --- a/tpm/tpm_int.h +++ b/tpm/tpm_int.h @@ -18,6 +18,8 @@ struct TPMDriverOps; typedef struct TPMDriverOps TPMDriverOps; +typedef struct TPMPassthruState TPMPassthruState; + typedef struct TPMBackend { char *id; enum TpmModel fe_model; @@ -25,6 +27,10 @@ typedef struct TPMBackend { char *cancel_path; const TPMDriverOps *ops; + union { + TPMPassthruState *tpm_pt; + } s; + QLIST_ENTRY(TPMBackend) list; } TPMBackend; @@ -74,10 +80,37 @@ struct TPMDriverOps { bool (*get_tpm_established_flag)(TPMBackend *t); }; +struct tpm_req_hdr { + uint16_t tag; + uint32_t len; + uint32_t ordinal; +} QEMU_PACKED; + +struct tpm_resp_hdr { + uint16_t tag; + uint32_t len; + uint32_t errcode; +} QEMU_PACKED; + +#define TPM_TAG_RQU_COMMAND 0xc1 +#define TPM_TAG_RQU_AUTH1_COMMAND 0xc2 +#define TPM_TAG_RQU_AUTH2_COMMAND 0xc3 + +#define TPM_TAG_RSP_COMMAND 0xc4 +#define TPM_TAG_RSP_AUTH1_COMMAND 0xc5 +#define TPM_TAG_RSP_AUTH2_COMMAND 0xc6 + +#define TPM_FAIL 9 + +#define TPM_ORD_GetTicks 0xf1 + TPMBackend *qemu_find_tpm(const char *id); int tpm_register_model(enum TpmModel model); int tpm_register_driver(const TPMDriverOps *tdo); void tpm_display_backend_drivers(void); const TPMDriverOps *tpm_get_backend_driver(const char *type); +void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len); + +extern const TPMDriverOps tpm_passthrough_driver; #endif /* TPM_TPM_INT_H */ diff --git a/tpm/tpm_passthrough.c b/tpm/tpm_passthrough.c new file mode 100644 index 0000000000..760e18f034 --- /dev/null +++ b/tpm/tpm_passthrough.c @@ -0,0 +1,387 @@ +/* + * passthrough TPM driver + * + * Copyright (c) 2010 - 2013 IBM Corporation + * Authors: + * Stefan Berger + * + * Copyright (C) 2011 IAIK, Graz University of Technology + * Author: Andreas Niederl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + */ + +#include "qemu-common.h" +#include "qapi/error.h" +#include "qemu/sockets.h" +#include "tpm_int.h" +#include "hw/hw.h" +#include "hw/pc.h" +#include "tpm_tis.h" +#include "tpm_backend.h" + +/* #define DEBUG_TPM */ + +#ifdef DEBUG_TPM +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +/* data structures */ + +typedef struct TPMPassthruThreadParams { + TPMState *tpm_state; + + TPMRecvDataCB *recv_data_callback; + TPMBackend *tb; +} TPMPassthruThreadParams; + +struct TPMPassthruState { + TPMBackendThread tbt; + + TPMPassthruThreadParams tpm_thread_params; + + char *tpm_dev; + int tpm_fd; + bool had_startup_error; +}; + +#define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0" + +static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len) +{ + return send_all(fd, buf, len); +} + +static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len) +{ + return recv_all(fd, buf, len, true); +} + +static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf) +{ + struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf; + + return be32_to_cpu(resp->len); +} + +static int tpm_passthrough_unix_tx_bufs(int tpm_fd, + const uint8_t *in, uint32_t in_len, + uint8_t *out, uint32_t out_len) +{ + int ret; + + ret = tpm_passthrough_unix_write(tpm_fd, in, in_len); + if (ret != in_len) { + error_report("tpm_passthrough: error while transmitting data " + "to TPM: %s (%i)\n", + strerror(errno), errno); + goto err_exit; + } + + ret = tpm_passthrough_unix_read(tpm_fd, out, out_len); + if (ret < 0) { + error_report("tpm_passthrough: error while reading data from " + "TPM: %s (%i)\n", + strerror(errno), errno); + } else if (ret < sizeof(struct tpm_resp_hdr) || + tpm_passthrough_get_size_from_buffer(out) != ret) { + ret = -1; + error_report("tpm_passthrough: received invalid response " + "packet from TPM\n"); + } + +err_exit: + if (ret < 0) { + tpm_write_fatal_error_response(out, out_len); + } + + return ret; +} + +static int tpm_passthrough_unix_transfer(int tpm_fd, + const TPMLocality *locty_data) +{ + return tpm_passthrough_unix_tx_bufs(tpm_fd, + locty_data->w_buffer.buffer, + locty_data->w_offset, + locty_data->r_buffer.buffer, + locty_data->r_buffer.size); +} + +static void tpm_passthrough_worker_thread(gpointer data, + gpointer user_data) +{ + TPMPassthruThreadParams *thr_parms = user_data; + TPMPassthruState *tpm_pt = thr_parms->tb->s.tpm_pt; + TPMBackendCmd cmd = (TPMBackendCmd)data; + + DPRINTF("tpm_passthrough: processing command type %d\n", cmd); + + switch (cmd) { + case TPM_BACKEND_CMD_PROCESS_CMD: + tpm_passthrough_unix_transfer(tpm_pt->tpm_fd, + thr_parms->tpm_state->locty_data); + + thr_parms->recv_data_callback(thr_parms->tpm_state, + thr_parms->tpm_state->locty_number); + break; + case TPM_BACKEND_CMD_INIT: + case TPM_BACKEND_CMD_END: + case TPM_BACKEND_CMD_TPM_RESET: + /* nothing to do */ + break; + } +} + +/* + * Start the TPM (thread). If it had been started before, then terminate + * and start it again. + */ +static int tpm_passthrough_startup_tpm(TPMBackend *tb) +{ + TPMPassthruState *tpm_pt = tb->s.tpm_pt; + + /* terminate a running TPM */ + tpm_backend_thread_end(&tpm_pt->tbt); + + tpm_backend_thread_create(&tpm_pt->tbt, + tpm_passthrough_worker_thread, + &tb->s.tpm_pt->tpm_thread_params); + + return 0; +} + +static void tpm_passthrough_reset(TPMBackend *tb) +{ + TPMPassthruState *tpm_pt = tb->s.tpm_pt; + + DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n"); + + tpm_backend_thread_end(&tpm_pt->tbt); + + tpm_pt->had_startup_error = false; +} + +static int tpm_passthrough_init(TPMBackend *tb, TPMState *s, + TPMRecvDataCB *recv_data_cb) +{ + TPMPassthruState *tpm_pt = tb->s.tpm_pt; + + tpm_pt->tpm_thread_params.tpm_state = s; + tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb; + tpm_pt->tpm_thread_params.tb = tb; + + return 0; +} + +static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) +{ + return false; +} + +static bool tpm_passthrough_get_startup_error(TPMBackend *tb) +{ + TPMPassthruState *tpm_pt = tb->s.tpm_pt; + + return tpm_pt->had_startup_error; +} + +static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb) +{ + size_t wanted_size = 4096; /* Linux tpm.c buffer size */ + + if (sb->size != wanted_size) { + sb->buffer = g_realloc(sb->buffer, wanted_size); + sb->size = wanted_size; + } + return sb->size; +} + +static void tpm_passthrough_deliver_request(TPMBackend *tb) +{ + TPMPassthruState *tpm_pt = tb->s.tpm_pt; + + tpm_backend_thread_deliver_request(&tpm_pt->tbt); +} + +static void tpm_passthrough_cancel_cmd(TPMBackend *tb) +{ + /* cancelling an ongoing command is known not to work with some TPMs */ +} + +static const char *tpm_passthrough_create_desc(void) +{ + return "Passthrough TPM backend driver"; +} + +/* + * A basic test of a TPM device. We expect a well formatted response header + * (error response is fine) within one second. + */ +static int tpm_passthrough_test_tpmdev(int fd) +{ + struct tpm_req_hdr req = { + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .len = cpu_to_be32(sizeof(req)), + .ordinal = cpu_to_be32(TPM_ORD_GetTicks), + }; + struct tpm_resp_hdr *resp; + fd_set readfds; + int n; + struct timeval tv = { + .tv_sec = 1, + .tv_usec = 0, + }; + unsigned char buf[1024]; + + n = write(fd, &req, sizeof(req)); + if (n < 0) { + return errno; + } + if (n != sizeof(req)) { + return EFAULT; + } + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + /* wait for a second */ + n = select(fd + 1, &readfds, NULL, NULL, &tv); + if (n != 1) { + return errno; + } + + n = read(fd, &buf, sizeof(buf)); + if (n < sizeof(struct tpm_resp_hdr)) { + return EFAULT; + } + + resp = (struct tpm_resp_hdr *)buf; + /* check the header */ + if (be16_to_cpu(resp->tag) != TPM_TAG_RSP_COMMAND || + be32_to_cpu(resp->len) != n) { + return EBADMSG; + } + + return 0; +} + +static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) +{ + const char *value; + + value = qemu_opt_get(opts, "path"); + if (!value) { + value = TPM_PASSTHROUGH_DEFAULT_DEVICE; + } + + tb->s.tpm_pt->tpm_dev = g_strdup(value); + + tb->path = g_strdup(tb->s.tpm_pt->tpm_dev); + + tb->s.tpm_pt->tpm_fd = qemu_open(tb->s.tpm_pt->tpm_dev, O_RDWR); + if (tb->s.tpm_pt->tpm_fd < 0) { + error_report("Cannot access TPM device using '%s': %s\n", + tb->s.tpm_pt->tpm_dev, strerror(errno)); + goto err_free_parameters; + } + + if (tpm_passthrough_test_tpmdev(tb->s.tpm_pt->tpm_fd)) { + error_report("'%s' is not a TPM device.\n", + tb->s.tpm_pt->tpm_dev); + goto err_close_tpmdev; + } + + return 0; + + err_close_tpmdev: + qemu_close(tb->s.tpm_pt->tpm_fd); + tb->s.tpm_pt->tpm_fd = -1; + + err_free_parameters: + g_free(tb->path); + tb->path = NULL; + + g_free(tb->s.tpm_pt->tpm_dev); + tb->s.tpm_pt->tpm_dev = NULL; + + return 1; +} + +static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) +{ + TPMBackend *tb; + + tb = g_new0(TPMBackend, 1); + tb->s.tpm_pt = g_new0(TPMPassthruState, 1); + tb->id = g_strdup(id); + /* let frontend set the fe_model to proper value */ + tb->fe_model = -1; + + tb->ops = &tpm_passthrough_driver; + + if (tpm_passthrough_handle_device_opts(opts, tb)) { + goto err_exit; + } + + return tb; + +err_exit: + g_free(tb->id); + g_free(tb->s.tpm_pt); + g_free(tb); + + return NULL; +} + +static void tpm_passthrough_destroy(TPMBackend *tb) +{ + TPMPassthruState *tpm_pt = tb->s.tpm_pt; + + tpm_backend_thread_end(&tpm_pt->tbt); + + qemu_close(tpm_pt->tpm_fd); + + g_free(tb->id); + g_free(tb->path); + g_free(tb->s.tpm_pt->tpm_dev); + g_free(tb->s.tpm_pt); + g_free(tb); +} + +const TPMDriverOps tpm_passthrough_driver = { + .type = TPM_TYPE_PASSTHROUGH, + .desc = tpm_passthrough_create_desc, + .create = tpm_passthrough_create, + .destroy = tpm_passthrough_destroy, + .init = tpm_passthrough_init, + .startup_tpm = tpm_passthrough_startup_tpm, + .realloc_buffer = tpm_passthrough_realloc_buffer, + .reset = tpm_passthrough_reset, + .had_startup_error = tpm_passthrough_get_startup_error, + .deliver_request = tpm_passthrough_deliver_request, + .cancel_cmd = tpm_passthrough_cancel_cmd, + .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, +}; + +static void tpm_passthrough_register(void) +{ + tpm_register_driver(&tpm_passthrough_driver); +} + +type_init(tpm_passthrough_register) From 92dcc234ec1f266fb5d59bed77d66320c2c75965 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 27 Feb 2013 12:47:54 -0500 Subject: [PATCH 1580/1634] Add support for cancelling of a TPM command This patch adds support for cancelling an executing TPM command. In Linux for example a user can cancel a command through the TPM's sysfs 'cancel' entry using echo "1" > /sysfs/class/misc/tpm0/device/cancel This patch propagates the cancellation of a command inside a VM to the host TPM's sysfs entry. It also uses the possibility to cancel the command before QEMU VM shutdown or reboot, which helps in preventing QEMU from hanging while waiting for the completion of the command. To relieve higher layers or users from having to determine the TPM's cancel sysfs entry, the driver searches for the entry in well known locations. Signed-off-by: Stefan Berger Reviewed-by: Corey Bryant Reviewed-by: Joel Schopp Message-id: 1361987275-26289-7-git-send-email-stefanb@linux.vnet.ibm.com Signed-off-by: Anthony Liguori --- qemu-options.hx | 13 +++- tpm/tpm_passthrough.c | 169 ++++++++++++++++++++++++++++++++++++++---- vl.c | 5 ++ 3 files changed, 171 insertions(+), 16 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 0be16b4d76..30fb85d619 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2221,8 +2221,10 @@ DEFHEADING() DEFHEADING(TPM device options:) DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \ - "-tpmdev passthrough,id=id[,path=path]\n" - " use path to provide path to a character device; default is /dev/tpm0\n", + "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n" + " use path to provide path to a character device; default is /dev/tpm0\n" + " use cancel-path to provide path to TPM's cancel sysfs entry; if\n" + " not provided it will be searched for in /sys/class/misc/tpm?/device\n", QEMU_ARCH_ALL) STEXI @@ -2244,7 +2246,7 @@ Use 'help' to print all available TPM backend types. qemu -tpmdev help @end example -@item -tpmdev passthrough, id=@var{id}, path=@var{path} +@item -tpmdev passthrough, id=@var{id}, path=@var{path}, cancel-path=@var{cancel-path} (Linux-host only) Enable access to the host's TPM using the passthrough driver. @@ -2253,6 +2255,11 @@ driver. a Linux host this would be @code{/dev/tpm0}. @option{path} is optional and by default @code{/dev/tpm0} is used. +@option{cancel-path} specifies the path to the host TPM device's sysfs +entry allowing for cancellation of an ongoing TPM command. +@option{cancel-path} is optional and by default QEMU will search for the +sysfs entry to use. + Some notes about using the host's TPM with the passthrough driver: The TPM device accessed by the passthrough driver must not be diff --git a/tpm/tpm_passthrough.c b/tpm/tpm_passthrough.c index 760e18f034..24aff4d69c 100644 --- a/tpm/tpm_passthrough.c +++ b/tpm/tpm_passthrough.c @@ -22,6 +22,8 @@ * License along with this library; if not, see */ +#include + #include "qemu-common.h" #include "qapi/error.h" #include "qemu/sockets.h" @@ -57,11 +59,18 @@ struct TPMPassthruState { char *tpm_dev; int tpm_fd; + bool tpm_executing; + bool tpm_op_canceled; + int cancel_fd; bool had_startup_error; }; #define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0" +/* functions */ + +static void tpm_passthrough_cancel_cmd(TPMBackend *tb); + static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len) { return send_all(fd, buf, len); @@ -79,25 +88,36 @@ static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf) return be32_to_cpu(resp->len); } -static int tpm_passthrough_unix_tx_bufs(int tpm_fd, +static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, const uint8_t *in, uint32_t in_len, uint8_t *out, uint32_t out_len) { int ret; - ret = tpm_passthrough_unix_write(tpm_fd, in, in_len); + tpm_pt->tpm_op_canceled = false; + tpm_pt->tpm_executing = true; + + ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len); if (ret != in_len) { - error_report("tpm_passthrough: error while transmitting data " - "to TPM: %s (%i)\n", - strerror(errno), errno); + if (!tpm_pt->tpm_op_canceled || + (tpm_pt->tpm_op_canceled && errno != ECANCELED)) { + error_report("tpm_passthrough: error while transmitting data " + "to TPM: %s (%i)\n", + strerror(errno), errno); + } goto err_exit; } - ret = tpm_passthrough_unix_read(tpm_fd, out, out_len); + tpm_pt->tpm_executing = false; + + ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len); if (ret < 0) { - error_report("tpm_passthrough: error while reading data from " - "TPM: %s (%i)\n", - strerror(errno), errno); + if (!tpm_pt->tpm_op_canceled || + (tpm_pt->tpm_op_canceled && errno != ECANCELED)) { + error_report("tpm_passthrough: error while reading data from " + "TPM: %s (%i)\n", + strerror(errno), errno); + } } else if (ret < sizeof(struct tpm_resp_hdr) || tpm_passthrough_get_size_from_buffer(out) != ret) { ret = -1; @@ -110,13 +130,15 @@ err_exit: tpm_write_fatal_error_response(out, out_len); } + tpm_pt->tpm_executing = false; + return ret; } -static int tpm_passthrough_unix_transfer(int tpm_fd, +static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt, const TPMLocality *locty_data) { - return tpm_passthrough_unix_tx_bufs(tpm_fd, + return tpm_passthrough_unix_tx_bufs(tpm_pt, locty_data->w_buffer.buffer, locty_data->w_offset, locty_data->r_buffer.buffer, @@ -134,7 +156,7 @@ static void tpm_passthrough_worker_thread(gpointer data, switch (cmd) { case TPM_BACKEND_CMD_PROCESS_CMD: - tpm_passthrough_unix_transfer(tpm_pt->tpm_fd, + tpm_passthrough_unix_transfer(tpm_pt, thr_parms->tpm_state->locty_data); thr_parms->recv_data_callback(thr_parms->tpm_state, @@ -172,6 +194,8 @@ static void tpm_passthrough_reset(TPMBackend *tb) DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n"); + tpm_passthrough_cancel_cmd(tb); + tpm_backend_thread_end(&tpm_pt->tbt); tpm_pt->had_startup_error = false; @@ -221,7 +245,29 @@ static void tpm_passthrough_deliver_request(TPMBackend *tb) static void tpm_passthrough_cancel_cmd(TPMBackend *tb) { - /* cancelling an ongoing command is known not to work with some TPMs */ + TPMPassthruState *tpm_pt = tb->s.tpm_pt; + int n; + + /* + * As of Linux 3.7 the tpm_tis driver does not properly cancel + * commands on all TPM manufacturers' TPMs. + * Only cancel if we're busy so we don't cancel someone else's + * command, e.g., a command executed on the host. + */ + if (tpm_pt->tpm_executing) { + if (tpm_pt->cancel_fd >= 0) { + n = write(tpm_pt->cancel_fd, "-", 1); + if (n != 1) { + error_report("Canceling TPM command failed: %s\n", + strerror(errno)); + } else { + tpm_pt->tpm_op_canceled = true; + } + } else { + error_report("Cannot cancel TPM command due to missing " + "TPM sysfs cancel entry"); + } + } } static const char *tpm_passthrough_create_desc(void) @@ -281,10 +327,98 @@ static int tpm_passthrough_test_tpmdev(int fd) return 0; } +/* + * Check whether the given base path, e.g., /sys/class/misc/tpm0/device, + * is the sysfs directory of a TPM. A TPM sysfs directory should be uniquely + * recognizable by the file entries 'pcrs' and 'cancel'. + * Upon success 'true' is returned and the basebath buffer has '/cancel' + * appended. + */ +static bool tpm_passthrough_check_sysfs_cancel(char *basepath, size_t bufsz) +{ + char path[PATH_MAX]; + struct stat statbuf; + + snprintf(path, sizeof(path), "%s/pcrs", basepath); + if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) { + return false; + } + + snprintf(path, sizeof(path), "%s/cancel", basepath); + if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) { + return false; + } + + strncpy(basepath, path, bufsz); + + return true; +} + +/* + * Unless path or file descriptor set has been provided by user, + * determine the sysfs cancel file following kernel documentation + * in Documentation/ABI/stable/sysfs-class-tpm. + */ +static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) +{ + int fd = -1; + unsigned int idx; + DIR *pnp_dir; + char path[PATH_MAX]; + struct dirent entry, *result; + int len; + + if (tb->cancel_path) { + fd = qemu_open(tb->cancel_path, O_WRONLY); + if (fd < 0) { + error_report("Could not open TPM cancel path : %s", + strerror(errno)); + } + return fd; + } + + snprintf(path, sizeof(path), "/sys/class/misc"); + pnp_dir = opendir(path); + if (pnp_dir != NULL) { + while (readdir_r(pnp_dir, &entry, &result) == 0 && + result != NULL) { + /* + * only allow /sys/class/misc/tpm%u type of paths + */ + if (sscanf(entry.d_name, "tpm%u%n", &idx, &len) < 1 || + len <= strlen("tpm") || + len != strlen(entry.d_name)) { + continue; + } + + snprintf(path, sizeof(path), "/sys/class/misc/%s/device", + entry.d_name); + if (!tpm_passthrough_check_sysfs_cancel(path, sizeof(path))) { + continue; + } + + fd = qemu_open(path, O_WRONLY); + break; + } + closedir(pnp_dir); + } + + if (fd >= 0) { + tb->cancel_path = g_strdup(path); + } + + return fd; +} + static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) { const char *value; + value = qemu_opt_get(opts, "cancel-path"); + if (value) { + tb->cancel_path = g_strdup(value); + } + value = qemu_opt_get(opts, "path"); if (!value) { value = TPM_PASSTHROUGH_DEFAULT_DEVICE; @@ -339,6 +473,11 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) goto err_exit; } + tb->s.tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb); + if (tb->s.tpm_pt->cancel_fd < 0) { + goto err_exit; + } + return tb; err_exit: @@ -353,12 +492,16 @@ static void tpm_passthrough_destroy(TPMBackend *tb) { TPMPassthruState *tpm_pt = tb->s.tpm_pt; + tpm_passthrough_cancel_cmd(tb); + tpm_backend_thread_end(&tpm_pt->tbt); qemu_close(tpm_pt->tpm_fd); + qemu_close(tb->s.tpm_pt->cancel_fd); g_free(tb->id); g_free(tb->path); + g_free(tb->cancel_path); g_free(tb->s.tpm_pt->tpm_dev); g_free(tb->s.tpm_pt); g_free(tb); diff --git a/vl.c b/vl.c index 0c6c2bfa6a..3822d99425 100644 --- a/vl.c +++ b/vl.c @@ -502,6 +502,11 @@ static QemuOptsList qemu_tpmdev_opts = { .type = QEMU_OPT_STRING, .help = "Type of TPM backend", }, + { + .name = "cancel-path", + .type = QEMU_OPT_STRING, + .help = "Sysfs file entry for canceling TPM commands", + }, { .name = "path", .type = QEMU_OPT_STRING, From 1272ec881440bf579c9d3c9cd0745b2551ce6a7f Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 27 Feb 2013 12:47:55 -0500 Subject: [PATCH 1581/1634] Build TPM passthrough for i386 and x86_64 targets Build the TPM passthrough driver only for i386 and x86_64 targets using the default-configs files for those targets with softmmu. Signed-off-by: Stefan Berger Reviewed-by: Corey Bryant Reviewed-by: Joel Schopp Message-id: 1361987275-26289-8-git-send-email-stefanb@linux.vnet.ibm.com Signed-off-by: Anthony Liguori --- default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + 2 files changed, 2 insertions(+) diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index f70594d3d4..df9e126c1f 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -27,3 +27,4 @@ CONFIG_APPLESMC=y CONFIG_I8259=y CONFIG_PFLASH_CFI01=y CONFIG_TPM_TIS=y +CONFIG_TPM_PASSTHROUGH=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 66c4855418..ab3cd5fc35 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -27,3 +27,4 @@ CONFIG_APPLESMC=y CONFIG_I8259=y CONFIG_PFLASH_CFI01=y CONFIG_TPM_TIS=y +CONFIG_TPM_PASSTHROUGH=y From 4524051c32190c1dc13ec2ccd122fd120dbed736 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 8 Mar 2013 11:42:24 +0100 Subject: [PATCH 1582/1634] Add search path support for qemu data files. This patch allows to specify multiple directories where qemu should look for data files. To implement that the behavior of the -L switch is slightly different now: Instead of replacing the data directory the path specified will be appended to the data directory list. So when specifiying -L multiple times all directories specified will be checked, in the order they are specified on the command line, instead of just the last one. Additionally the default paths are always appended to the directory data list. This allows to specify a incomplete directory (such as the seabios out/ directory) via -L. Anything not found there will be loaded from the default paths, so you don't have to create a symlink farm for all the rom blobs. For trouble-shooting a tracepoint has been added, logging which blob has been loaded from which location. Signed-off-by: Gerd Hoffmann Message-id: 1362739344-8068-1-git-send-email-kraxel@redhat.com Signed-off-by: Anthony Liguori --- trace-events | 1 + vl.c | 36 +++++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/trace-events b/trace-events index 8389d83568..d6a847d18a 100644 --- a/trace-events +++ b/trace-events @@ -473,6 +473,7 @@ scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d" # vl.c vm_state_notify(int running, int reason) "running %d reason %d" +load_file(const char *name, const char *path) "name %s location %s" # block/qcow2.c qcow2_writev_start_req(void *co, int64_t sector, int nb_sectors) "co %p sector %" PRIx64 " nb_sectors %d" diff --git a/vl.c b/vl.c index 3822d99425..a621aec0a4 100644 --- a/vl.c +++ b/vl.c @@ -179,7 +179,8 @@ int main(int argc, char **argv) #define MAX_VIRTIO_CONSOLES 1 #define MAX_SCLP_CONSOLES 1 -static const char *data_dir; +static const char *data_dir[16]; +static int data_dir_idx; const char *bios_name = NULL; enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; DisplayType display_type = DT_DEFAULT; @@ -2276,14 +2277,16 @@ static int balloon_parse(const char *arg) char *qemu_find_file(int type, const char *name) { - int len; + int i; const char *subdir; char *buf; /* Try the name as a straight path first */ if (access(name, R_OK) == 0) { + trace_load_file(name, name); return g_strdup(name); } + switch (type) { case QEMU_FILE_TYPE_BIOS: subdir = ""; @@ -2294,14 +2297,16 @@ char *qemu_find_file(int type, const char *name) default: abort(); } - len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2; - buf = g_malloc0(len); - snprintf(buf, len, "%s/%s%s", data_dir, subdir, name); - if (access(buf, R_OK)) { + + for (i = 0; i < data_dir_idx; i++) { + buf = g_strdup_printf("%s/%s%s", data_dir[i], subdir, name); + if (access(buf, R_OK) == 0) { + trace_load_file(name, buf); + return buf; + } g_free(buf); - return NULL; } - return buf; + return NULL; } static int device_help_func(QemuOpts *opts, void *opaque) @@ -3285,7 +3290,9 @@ int main(int argc, char **argv, char **envp) add_device_config(DEV_GDB, optarg); break; case QEMU_OPTION_L: - data_dir = optarg; + if (data_dir_idx < ARRAY_SIZE(data_dir)) { + data_dir[data_dir_idx++] = optarg; + } break; case QEMU_OPTION_bios: bios_name = optarg; @@ -3925,12 +3932,15 @@ int main(int argc, char **argv, char **envp) /* If no data_dir is specified then try to find it relative to the executable path. */ - if (!data_dir) { - data_dir = os_find_datadir(argv[0]); + if (data_dir_idx < ARRAY_SIZE(data_dir)) { + data_dir[data_dir_idx] = os_find_datadir(argv[0]); + if (data_dir[data_dir_idx] != NULL) { + data_dir_idx++; + } } /* If all else fails use the install path specified when building. */ - if (!data_dir) { - data_dir = CONFIG_QEMU_DATADIR; + if (data_dir_idx < ARRAY_SIZE(data_dir)) { + data_dir[data_dir_idx++] = CONFIG_QEMU_DATADIR; } /* From 8ca761f661a7cc972bc6bcf938feca6c538100f0 Mon Sep 17 00:00:00 2001 From: Peter Feiner Date: Mon, 4 Mar 2013 13:54:25 -0500 Subject: [PATCH 1583/1634] exec: make -mem-path filenames deterministic Adds ramblocks' names to their backing files when using -mem-path. Eases introspection and debugging. Signed-off-by: Peter Feiner Message-id: 1362423265-15855-1-git-send-email-peter@gridcentric.ca Signed-off-by: Anthony Liguori --- exec.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 46a283071a..f84e0955dc 100644 --- a/exec.c +++ b/exec.c @@ -844,6 +844,8 @@ static void *file_ram_alloc(RAMBlock *block, const char *path) { char *filename; + char *sanitized_name; + char *c; void *area; int fd; #ifdef MAP_POPULATE @@ -865,7 +867,16 @@ static void *file_ram_alloc(RAMBlock *block, return NULL; } - filename = g_strdup_printf("%s/qemu_back_mem.XXXXXX", path); + /* Make name safe to use with mkstemp by replacing '/' with '_'. */ + sanitized_name = g_strdup(block->mr->name); + for (c = sanitized_name; *c != '\0'; c++) { + if (*c == '/') + *c = '_'; + } + + filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path, + sanitized_name); + g_free(sanitized_name); fd = mkstemp(filename); if (fd < 0) { From 2c5f488293c7d0cd095635c74157c2526e2c4947 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 21 Feb 2013 11:39:12 +0100 Subject: [PATCH 1584/1634] chardev: add support for qapi-based chardev initialization This patch add support for a new way to initialize chardev devices. Instead of calling a initialization function with a QemuOpts we will now create a (qapi) ChardevBackend, optionally call a function to fill ChardevBackend from QemuOpts, then go create the chardev using the new qapi code path which is also used by chardev-add. Signed-off-by: Gerd Hoffmann --- include/char/char.h | 2 ++ qemu-char.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/char/char.h b/include/char/char.h index 2e24270895..afe002498e 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -245,6 +245,8 @@ CharDriverState *qemu_chr_find(const char *name); QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *)); +void register_char_driver_qapi(const char *name, int kind, + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp)); /* add an eventfd to the qemu devices that are polled */ CharDriverState *qemu_chr_open_eventfd(int eventfd); diff --git a/qemu-char.c b/qemu-char.c index 83787c74c4..c2e198e858 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3204,7 +3204,11 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) typedef struct CharDriver { const char *name; + /* old, pre qapi */ CharDriverState *(*open)(QemuOpts *opts); + /* new, qapi-based */ + int kind; + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp); } CharDriver; static GSList *backends; @@ -3220,6 +3224,19 @@ void register_char_driver(const char *name, CharDriverState *(*open)(QemuOpts *) backends = g_slist_append(backends, s); } +void register_char_driver_qapi(const char *name, int kind, + void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp)) +{ + CharDriver *s; + + s = g_malloc0(sizeof(*s)); + s->name = g_strdup(name); + s->kind = kind; + s->parse = parse; + + backends = g_slist_append(backends, s); +} + CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s), Error **errp) @@ -3251,6 +3268,32 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, return NULL; } + if (!cd->open) { + /* using new, qapi init */ + ChardevBackend *backend = g_new0(ChardevBackend, 1); + ChardevReturn *ret = NULL; + const char *id = qemu_opts_id(opts); + + chr = NULL; + backend->kind = cd->kind; + if (cd->parse) { + cd->parse(opts, backend, errp); + if (error_is_set(errp)) { + goto qapi_out; + } + } + ret = qmp_chardev_add(qemu_opts_id(opts), backend, errp); + if (error_is_set(errp)) { + goto qapi_out; + } + chr = qemu_chr_find(id); + + qapi_out: + qapi_free_ChardevBackend(backend); + qapi_free_ChardevReturn(ret); + return chr; + } + chr = cd->open(opts); if (!chr) { error_setg(errp, "chardev: opening backend \"%s\" failed", From edb2fb3cc8b85ab956f366fc036ac12853984dae Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 21 Feb 2013 16:16:42 +0100 Subject: [PATCH 1585/1634] chardev: add mux chardev support to qapi This adds mux chardev support to the qapi and also makes the qapi-based chardev creation path handle the "mux=on" option correctly. --- qapi-schema.json | 14 +++++++++++++- qemu-char.c | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 4494e53693..4ad92b07f1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3184,6 +3184,17 @@ '*nodelay' : 'bool', '*telnet' : 'bool' } } +## +# @ChardevMux: +# +# Configuration info for mux chardevs. +# +# @chardev: name of the base chardev. +# +# Since: 1.5 +## +{ 'type': 'ChardevMux', 'data': { 'chardev' : 'str' } } + ## # @ChardevBackend: # @@ -3198,7 +3209,8 @@ 'parallel': 'ChardevHostdev', 'socket' : 'ChardevSocket', 'pty' : 'ChardevDummy', - 'null' : 'ChardevDummy' } } + 'null' : 'ChardevDummy', + 'mux' : 'ChardevMux' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index c2e198e858..0dc380280a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3273,6 +3273,11 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, ChardevBackend *backend = g_new0(ChardevBackend, 1); ChardevReturn *ret = NULL; const char *id = qemu_opts_id(opts); + const char *bid = NULL; + + if (qemu_opt_get_bool(opts, "mux", 0)) { + bid = g_strdup_printf("%s-base", id); + } chr = NULL; backend->kind = cd->kind; @@ -3282,10 +3287,24 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts, goto qapi_out; } } - ret = qmp_chardev_add(qemu_opts_id(opts), backend, errp); + ret = qmp_chardev_add(bid ? bid : id, backend, errp); if (error_is_set(errp)) { goto qapi_out; } + + if (bid) { + qapi_free_ChardevBackend(backend); + qapi_free_ChardevReturn(ret); + backend = g_new0(ChardevBackend, 1); + backend->mux = g_new0(ChardevMux, 1); + backend->kind = CHARDEV_BACKEND_KIND_MUX; + backend->mux->chardev = g_strdup(bid); + ret = qmp_chardev_add(id, backend, errp); + if (error_is_set(errp)) { + goto qapi_out; + } + } + chr = qemu_chr_find(id); qapi_out: @@ -3653,7 +3672,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { ChardevReturn *ret = g_new0(ChardevReturn, 1); - CharDriverState *chr = NULL; + CharDriverState *base, *chr = NULL; chr = qemu_chr_find(id); if (chr) { @@ -3691,6 +3710,15 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(NULL); break; + case CHARDEV_BACKEND_KIND_MUX: + base = qemu_chr_find(backend->mux->chardev); + if (base == NULL) { + error_setg(errp, "mux: base chardev %s not found", + backend->mux->chardev); + break; + } + chr = qemu_chr_open_mux(base); + break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); break; @@ -3701,7 +3729,8 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } if (chr) { chr->label = g_strdup(id); - chr->avail_connections = 1; + chr->avail_connections = + (backend->kind == CHARDEV_BACKEND_KIND_MUX) ? MAX_MUX : 1; QTAILQ_INSERT_TAIL(&chardevs, chr, next); return ret; } else { From 80dca9e643d11b54f1b9bafbaefeadfb1099e023 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 21 Feb 2013 11:41:26 +0100 Subject: [PATCH 1586/1634] chardev: switch null init to qapi This patch switches over the 'null' chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qemu-char.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 0dc380280a..e6f67d8c5d 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -217,7 +217,7 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) return len; } -static CharDriverState *qemu_chr_open_null(QemuOpts *opts) +static CharDriverState *qemu_chr_open_null(void) { CharDriverState *chr; @@ -3708,7 +3708,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } #endif case CHARDEV_BACKEND_KIND_NULL: - chr = qemu_chr_open_null(NULL); + chr = qemu_chr_open_null(); break; case CHARDEV_BACKEND_KIND_MUX: base = qemu_chr_find(backend->mux->chardev); @@ -3758,7 +3758,7 @@ void qmp_chardev_remove(const char *id, Error **errp) static void register_types(void) { - register_char_driver("null", qemu_chr_open_null); + register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL); register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); register_char_driver("memory", qemu_chr_open_ringbuf); From f5a51cab2afd1124f0988081207d506fbec629b4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 21 Feb 2013 11:58:44 +0100 Subject: [PATCH 1587/1634] chardev: add msmouse support to qapi This patch adds 'msmouse' support to qapi and also switches over the msmouse chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- backends/msmouse.c | 4 ++-- include/char/char.h | 3 +++ qapi-schema.json | 3 ++- qemu-char.c | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backends/msmouse.c b/backends/msmouse.c index 407ec87784..61052fe783 100644 --- a/backends/msmouse.c +++ b/backends/msmouse.c @@ -63,7 +63,7 @@ static void msmouse_chr_close (struct CharDriverState *chr) g_free (chr); } -static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) +CharDriverState *qemu_chr_open_msmouse(void) { CharDriverState *chr; @@ -78,7 +78,7 @@ static CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts) static void register_types(void) { - register_char_driver("msmouse", qemu_chr_open_msmouse); + register_char_driver_qapi("msmouse", CHARDEV_BACKEND_KIND_MSMOUSE, NULL); } type_init(register_types); diff --git a/include/char/char.h b/include/char/char.h index afe002498e..80e8e30e15 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -261,4 +261,7 @@ size_t qemu_chr_mem_osize(const CharDriverState *chr); CharDriverState *qemu_char_get_next_serial(void); +/* msmouse */ +CharDriverState *qemu_chr_open_msmouse(void); + #endif diff --git a/qapi-schema.json b/qapi-schema.json index 4ad92b07f1..86c04dc9ff 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3210,7 +3210,8 @@ 'socket' : 'ChardevSocket', 'pty' : 'ChardevDummy', 'null' : 'ChardevDummy', - 'mux' : 'ChardevMux' } } + 'mux' : 'ChardevMux', + 'msmouse': 'ChardevDummy' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index e6f67d8c5d..e860ba30aa 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3719,6 +3719,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, } chr = qemu_chr_open_mux(base); break; + case CHARDEV_BACKEND_KIND_MSMOUSE: + chr = qemu_chr_open_msmouse(); + break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); break; From 2d57286da6e57aacf3b2d0d3354d543ed100a485 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 21 Feb 2013 12:56:10 +0100 Subject: [PATCH 1588/1634] chardev: add braille support to qapi This patch adds 'braille' support to qapi and also switches over the braille chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- backends/baum.c | 4 ++-- include/char/char.h | 3 +++ qapi-schema.json | 3 ++- qemu-char.c | 5 +++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/backends/baum.c b/backends/baum.c index 9063aea2cf..d7d658c224 100644 --- a/backends/baum.c +++ b/backends/baum.c @@ -561,7 +561,7 @@ static void baum_close(struct CharDriverState *chr) g_free(baum); } -static CharDriverState *chr_baum_init(QemuOpts *opts) +CharDriverState *chr_baum_init(void) { BaumDriverState *baum; CharDriverState *chr; @@ -627,7 +627,7 @@ fail_handle: static void register_types(void) { - register_char_driver("braille", chr_baum_init); + register_char_driver_qapi("braille", CHARDEV_BACKEND_KIND_BRAILLE, NULL); } type_init(register_types); diff --git a/include/char/char.h b/include/char/char.h index 80e8e30e15..d6a03513bf 100644 --- a/include/char/char.h +++ b/include/char/char.h @@ -264,4 +264,7 @@ CharDriverState *qemu_char_get_next_serial(void); /* msmouse */ CharDriverState *qemu_chr_open_msmouse(void); +/* baum.c */ +CharDriverState *chr_baum_init(void); + #endif diff --git a/qapi-schema.json b/qapi-schema.json index 86c04dc9ff..3c5c0fbc27 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3211,7 +3211,8 @@ 'pty' : 'ChardevDummy', 'null' : 'ChardevDummy', 'mux' : 'ChardevMux', - 'msmouse': 'ChardevDummy' } } + 'msmouse': 'ChardevDummy', + 'braille': 'ChardevDummy' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index e860ba30aa..1692aa8367 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3722,6 +3722,11 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_MSMOUSE: chr = qemu_chr_open_msmouse(); break; +#ifdef CONFIG_BRLAPI + case CHARDEV_BACKEND_KIND_BRAILLE: + chr = chr_baum_init(); + break; +#endif default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); break; From 846e2e49388aa42e030af3d5dd60a6009b80a369 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 21 Feb 2013 12:07:14 +0100 Subject: [PATCH 1589/1634] chardev: switch file init to qapi This patch switches over the 'file' chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qemu-char.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 1692aa8367..4b9caca920 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -841,18 +841,6 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } -static CharDriverState *qemu_chr_open_file_out(QemuOpts *opts) -{ - int fd_out; - - TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"), - O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666)); - if (fd_out < 0) { - return NULL; - } - return qemu_chr_open_fd(-1, fd_out); -} - static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) { int fd_in, fd_out; @@ -1989,20 +1977,6 @@ static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts) return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); } -static CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts) -{ - const char *file_out = qemu_opt_get(opts, "path"); - HANDLE fd_out; - - fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd_out == INVALID_HANDLE_VALUE) { - return NULL; - } - - return qemu_chr_open_win_file(fd_out); -} - static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); @@ -3202,6 +3176,19 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) #endif +static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *path = qemu_opt_get(opts, "path"); + + if (path == NULL) { + error_setg(errp, "chardev: file: no filename given"); + return; + } + backend->file = g_new0(ChardevFile, 1); + backend->file->out = g_strdup(path); +} + typedef struct CharDriver { const char *name; /* old, pre qapi */ @@ -3770,14 +3757,14 @@ static void register_types(void) register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); register_char_driver("memory", qemu_chr_open_ringbuf); + register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE, + qemu_chr_parse_file_out); #ifdef _WIN32 - register_char_driver("file", qemu_chr_open_win_file_out); register_char_driver("pipe", qemu_chr_open_win_pipe); register_char_driver("console", qemu_chr_open_win_con); register_char_driver("serial", qemu_chr_open_win); register_char_driver("stdio", qemu_chr_open_win_stdio); #else - register_char_driver("file", qemu_chr_open_file_out); register_char_driver("pipe", qemu_chr_open_pipe); register_char_driver("stdio", qemu_chr_open_stdio); #endif From 7c358031eac9a41c215900020acf8600d33138aa Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 21 Feb 2013 12:34:58 +0100 Subject: [PATCH 1590/1634] chardev: add stdio support to qapi This patch adds 'stdio' support to qapi and also switches over the stdio chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 16 +++++++++++++++- qemu-char.c | 26 ++++++++++++++++++++------ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 3c5c0fbc27..68150b7f17 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3195,6 +3195,19 @@ ## { 'type': 'ChardevMux', 'data': { 'chardev' : 'str' } } +## +# @ChardevStdio: +# +# Configuration info for stdio chardevs. +# +# @signal: #optional Allow signals (such as SIGINT triggered by ^C) +# be delivered to qemu. Default: true in -nographic mode, +# false otherwise. +# +# Since: 1.5 +## +{ 'type': 'ChardevStdio', 'data': { '*signal' : 'bool' } } + ## # @ChardevBackend: # @@ -3212,7 +3225,8 @@ 'null' : 'ChardevDummy', 'mux' : 'ChardevMux', 'msmouse': 'ChardevDummy', - 'braille': 'ChardevDummy' } } + 'braille': 'ChardevDummy', + 'stdio' : 'ChardevStdio' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 4b9caca920..85ffd8e909 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -908,7 +908,7 @@ static void qemu_chr_close_stdio(struct CharDriverState *chr) fd_chr_close(chr); } -static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) +static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) { CharDriverState *chr; @@ -924,8 +924,10 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) chr = qemu_chr_open_fd(0, 1); chr->chr_close = qemu_chr_close_stdio; chr->chr_set_echo = qemu_chr_set_echo_stdio; - stdio_allow_signal = qemu_opt_get_bool(opts, "signal", - display_type != DT_NOGRAPHIC); + stdio_allow_signal = display_type != DT_NOGRAPHIC; + if (opts->has_signal) { + stdio_allow_signal = opts->signal; + } qemu_chr_fe_set_echo(chr, false); return chr; @@ -2114,7 +2116,7 @@ static void win_stdio_close(CharDriverState *chr) g_free(chr); } -static CharDriverState *qemu_chr_open_win_stdio(QemuOpts *opts) +static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts) { CharDriverState *chr; WinStdioCharState *stdio; @@ -3189,6 +3191,15 @@ static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, backend->file->out = g_strdup(path); } +static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + backend->stdio = g_new0(ChardevStdio, 1); + backend->stdio->has_signal = true; + backend->stdio->signal = + qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC); +} + typedef struct CharDriver { const char *name; /* old, pre qapi */ @@ -3714,6 +3725,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, chr = chr_baum_init(); break; #endif + case CHARDEV_BACKEND_KIND_STDIO: + chr = qemu_chr_open_stdio(backend->stdio); + break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); break; @@ -3759,14 +3773,14 @@ static void register_types(void) register_char_driver("memory", qemu_chr_open_ringbuf); register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE, qemu_chr_parse_file_out); + register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO, + qemu_chr_parse_stdio); #ifdef _WIN32 register_char_driver("pipe", qemu_chr_open_win_pipe); register_char_driver("console", qemu_chr_open_win_con); register_char_driver("serial", qemu_chr_open_win); - register_char_driver("stdio", qemu_chr_open_win_stdio); #else register_char_driver("pipe", qemu_chr_open_pipe); - register_char_driver("stdio", qemu_chr_open_stdio); #endif #ifdef HAVE_CHARDEV_TTY register_char_driver("tty", qemu_chr_open_tty); From 0f1cb51da7112fa62c6cde62f546714a2c672f54 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 22 Feb 2013 15:48:05 +0100 Subject: [PATCH 1591/1634] chardev: switch serial/tty init to qapi This patch switches over the serial chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qemu-char.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 85ffd8e909..3033c2dffc 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1419,18 +1419,6 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd) chr->chr_close = qemu_chr_close_tty; return chr; } - -static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) -{ - const char *filename = qemu_opt_get(opts, "path"); - int fd; - - TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK)); - if (fd < 0) { - return NULL; - } - return qemu_chr_open_tty_fd(fd); -} #endif /* __linux__ || __sun__ */ #if defined(__linux__) @@ -1855,11 +1843,6 @@ static CharDriverState *qemu_chr_open_win_path(const char *filename) return chr; } -static CharDriverState *qemu_chr_open_win(QemuOpts *opts) -{ - return qemu_chr_open_win_path(qemu_opt_get(opts, "path")); -} - static int win_chr_pipe_poll(void *opaque) { CharDriverState *chr = opaque; @@ -3200,6 +3183,19 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC); } +static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *device = qemu_opt_get(opts, "path"); + + if (device == NULL) { + error_setg(errp, "chardev: serial/tty: no device path given"); + return; + } + backend->serial = g_new0(ChardevHostdev, 1); + backend->serial->device = g_strdup(device); +} + typedef struct CharDriver { const char *name; /* old, pre qapi */ @@ -3775,16 +3771,17 @@ static void register_types(void) qemu_chr_parse_file_out); register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO, qemu_chr_parse_stdio); + register_char_driver_qapi("serial", CHARDEV_BACKEND_KIND_SERIAL, + qemu_chr_parse_serial); + register_char_driver_qapi("tty", CHARDEV_BACKEND_KIND_SERIAL, + qemu_chr_parse_serial); #ifdef _WIN32 register_char_driver("pipe", qemu_chr_open_win_pipe); register_char_driver("console", qemu_chr_open_win_con); - register_char_driver("serial", qemu_chr_open_win); #else register_char_driver("pipe", qemu_chr_open_pipe); #endif #ifdef HAVE_CHARDEV_TTY - register_char_driver("tty", qemu_chr_open_tty); - register_char_driver("serial", qemu_chr_open_tty); register_char_driver("pty", qemu_chr_open_pty); #endif #ifdef HAVE_CHARDEV_PARPORT From dc3750976914b0900446e6a5434919a0fa2ba028 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 22 Feb 2013 16:17:01 +0100 Subject: [PATCH 1592/1634] chardev: switch parallel init to qapi This patch switches over the parallel chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qemu-char.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 3033c2dffc..d8ac86b9f8 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3145,22 +3145,6 @@ fail: return NULL; } -#ifdef HAVE_CHARDEV_PARPORT - -static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) -{ - const char *filename = qemu_opt_get(opts, "path"); - int fd; - - fd = qemu_open(filename, O_RDWR); - if (fd < 0) { - return NULL; - } - return qemu_chr_open_pp_fd(fd); -} - -#endif - static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, Error **errp) { @@ -3196,6 +3180,19 @@ static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, backend->serial->device = g_strdup(device); } +static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *device = qemu_opt_get(opts, "path"); + + if (device == NULL) { + error_setg(errp, "chardev: parallel: no device path given"); + return; + } + backend->parallel = g_new0(ChardevHostdev, 1); + backend->parallel->device = g_strdup(device); +} + typedef struct CharDriver { const char *name; /* old, pre qapi */ @@ -3775,6 +3772,10 @@ static void register_types(void) qemu_chr_parse_serial); register_char_driver_qapi("tty", CHARDEV_BACKEND_KIND_SERIAL, qemu_chr_parse_serial); + register_char_driver_qapi("parallel", CHARDEV_BACKEND_KIND_PARALLEL, + qemu_chr_parse_parallel); + register_char_driver_qapi("parport", CHARDEV_BACKEND_KIND_PARALLEL, + qemu_chr_parse_parallel); #ifdef _WIN32 register_char_driver("pipe", qemu_chr_open_win_pipe); register_char_driver("console", qemu_chr_open_win_con); @@ -3784,10 +3785,6 @@ static void register_types(void) #ifdef HAVE_CHARDEV_TTY register_char_driver("pty", qemu_chr_open_pty); #endif -#ifdef HAVE_CHARDEV_PARPORT - register_char_driver("parallel", qemu_chr_open_pp); - register_char_driver("parport", qemu_chr_open_pp); -#endif } type_init(register_types); From e68c5958668596a5023e30ddf8368410878f7682 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 25 Feb 2013 10:16:46 +0100 Subject: [PATCH 1593/1634] chardev: switch pty init to qapi This patch switches over the pty chardev initialization to the new qapi code path. Bonus: Taking QemuOpts out of the loop allows some nice cleanups along the way. Signed-off-by: Gerd Hoffmann --- qemu-char.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index d8ac86b9f8..158b81edef 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1157,13 +1157,13 @@ static void pty_chr_close(struct CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pty(const char *id, + ChardevReturn *ret) { CharDriverState *chr; PtyCharDriver *s; struct termios tty; - const char *label; - int master_fd, slave_fd, len; + int master_fd, slave_fd; #if defined(__OpenBSD__) || defined(__DragonFly__) char pty_name[PATH_MAX]; #define q_ptsname(x) pty_name @@ -1184,17 +1184,12 @@ static CharDriverState *qemu_chr_open_pty(QemuOpts *opts) chr = g_malloc0(sizeof(CharDriverState)); - len = strlen(q_ptsname(master_fd)) + 5; - chr->filename = g_malloc(len); - snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd)); - qemu_opt_set(opts, "path", q_ptsname(master_fd)); + chr->filename = g_strdup_printf("pty:%s", q_ptsname(master_fd)); + ret->pty = g_strdup(q_ptsname(master_fd)); + ret->has_pty = true; - label = qemu_opts_id(opts); - fprintf(stderr, "char device redirected to %s%s%s%s\n", - q_ptsname(master_fd), - label ? " (label " : "", - label ? label : "", - label ? ")" : ""); + fprintf(stderr, "char device redirected to %s (label %s)\n", + q_ptsname(master_fd), id); s = g_malloc0(sizeof(PtyCharDriver)); chr->opaque = s; @@ -3687,16 +3682,8 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, break; #ifdef HAVE_CHARDEV_TTY case CHARDEV_BACKEND_KIND_PTY: - { - /* qemu_chr_open_pty sets "path" in opts */ - QemuOpts *opts; - opts = qemu_opts_create_nofail(qemu_find_opts("chardev")); - chr = qemu_chr_open_pty(opts); - ret->pty = g_strdup(qemu_opt_get(opts, "path")); - ret->has_pty = true; - qemu_opts_del(opts); + chr = qemu_chr_open_pty(id, ret); break; - } #endif case CHARDEV_BACKEND_KIND_NULL: chr = qemu_chr_open_null(); @@ -3776,15 +3763,13 @@ static void register_types(void) qemu_chr_parse_parallel); register_char_driver_qapi("parport", CHARDEV_BACKEND_KIND_PARALLEL, qemu_chr_parse_parallel); + register_char_driver_qapi("pty", CHARDEV_BACKEND_KIND_PTY, NULL); #ifdef _WIN32 register_char_driver("pipe", qemu_chr_open_win_pipe); register_char_driver("console", qemu_chr_open_win_con); #else register_char_driver("pipe", qemu_chr_open_pipe); #endif -#ifdef HAVE_CHARDEV_TTY - register_char_driver("pty", qemu_chr_open_pty); -#endif } type_init(register_types); From d9ac374f0def9a65340c1768c08e3271f4d7798d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 25 Feb 2013 11:48:06 +0100 Subject: [PATCH 1594/1634] chardev: add console support to qapi This patch adds 'console' support to qapi and also switches over the console chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 3 ++- qemu-char.c | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 68150b7f17..70c2c07f4c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3226,7 +3226,8 @@ 'mux' : 'ChardevMux', 'msmouse': 'ChardevDummy', 'braille': 'ChardevDummy', - 'stdio' : 'ChardevStdio' } } + 'stdio' : 'ChardevStdio', + 'console': 'ChardevDummy' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 158b81edef..c3d44207da 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1952,7 +1952,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) return chr; } -static CharDriverState *qemu_chr_open_win_con(QemuOpts *opts) +static CharDriverState *qemu_chr_open_win_con(void) { return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE)); } @@ -3708,6 +3708,11 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_STDIO: chr = qemu_chr_open_stdio(backend->stdio); break; +#ifdef _WIN32 + case CHARDEV_BACKEND_KIND_CONSOLE: + chr = qemu_chr_open_win_con(); + break; +#endif default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); break; @@ -3764,9 +3769,9 @@ static void register_types(void) register_char_driver_qapi("parport", CHARDEV_BACKEND_KIND_PARALLEL, qemu_chr_parse_parallel); register_char_driver_qapi("pty", CHARDEV_BACKEND_KIND_PTY, NULL); + register_char_driver_qapi("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL); #ifdef _WIN32 register_char_driver("pipe", qemu_chr_open_win_pipe); - register_char_driver("console", qemu_chr_open_win_con); #else register_char_driver("pipe", qemu_chr_open_pipe); #endif From 548cbb36f415d6086f5252309ab5aa7634497ab5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 25 Feb 2013 11:50:55 +0100 Subject: [PATCH 1595/1634] chardev: add pipe support to qapi This patch adds 'pipe' support to qapi and also switches over the pipe chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 3 ++- qemu-char.c | 31 ++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 70c2c07f4c..7ea32ed415 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3153,7 +3153,7 @@ ## # @ChardevHostdev: # -# Configuration info for device chardevs. +# Configuration info for device and pipe chardevs. # # @device: The name of the special file for the device, # i.e. /dev/ttyS0 on Unix or COM1: on Windows @@ -3220,6 +3220,7 @@ { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile', 'serial' : 'ChardevHostdev', 'parallel': 'ChardevHostdev', + 'pipe' : 'ChardevHostdev', 'socket' : 'ChardevSocket', 'pty' : 'ChardevDummy', 'null' : 'ChardevDummy', diff --git a/qemu-char.c b/qemu-char.c index c3d44207da..427901c0c5 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -841,11 +841,11 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) return chr; } -static CharDriverState *qemu_chr_open_pipe(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) { int fd_in, fd_out; char filename_in[256], filename_out[256]; - const char *filename = qemu_opt_get(opts, "path"); + const char *filename = opts->device; if (filename == NULL) { fprintf(stderr, "chardev: pipe: no filename given\n"); @@ -1917,9 +1917,9 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename) } -static CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts) +static CharDriverState *qemu_chr_open_pipe(ChardevHostdev *opts) { - const char *filename = qemu_opt_get(opts, "path"); + const char *filename = opts->device; CharDriverState *chr; WinCharState *s; @@ -3188,6 +3188,19 @@ static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, backend->parallel->device = g_strdup(device); } +static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *device = qemu_opt_get(opts, "path"); + + if (device == NULL) { + error_setg(errp, "chardev: pipe: no device path given"); + return; + } + backend->pipe = g_new0(ChardevHostdev, 1); + backend->pipe->device = g_strdup(device); +} + typedef struct CharDriver { const char *name; /* old, pre qapi */ @@ -3677,6 +3690,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_PARALLEL: chr = qmp_chardev_open_parallel(backend->parallel, errp); break; + case CHARDEV_BACKEND_KIND_PIPE: + chr = qemu_chr_open_pipe(backend->pipe); + break; case CHARDEV_BACKEND_KIND_SOCKET: chr = qmp_chardev_open_socket(backend->socket, errp); break; @@ -3770,11 +3786,8 @@ static void register_types(void) qemu_chr_parse_parallel); register_char_driver_qapi("pty", CHARDEV_BACKEND_KIND_PTY, NULL); register_char_driver_qapi("console", CHARDEV_BACKEND_KIND_CONSOLE, NULL); -#ifdef _WIN32 - register_char_driver("pipe", qemu_chr_open_win_pipe); -#else - register_char_driver("pipe", qemu_chr_open_pipe); -#endif + register_char_driver_qapi("pipe", CHARDEV_BACKEND_KIND_PIPE, + qemu_chr_parse_pipe); } type_init(register_types); From cd153e2aa2f0ec39c04c2b732ebebfc6d4766986 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 25 Feb 2013 12:39:06 +0100 Subject: [PATCH 1596/1634] chardev: add spice support to qapi This patch adds 'spicevmc' and 'spiceport' support to qapi and also switches over the spice chardev initialization to the new qapi code path. --- include/ui/qemu-spice.h | 7 +++-- qapi-schema.json | 26 ++++++++++++++++- qemu-char.c | 8 ++++++ spice-qemu-char.c | 62 +++++++++++++++++++++++++++-------------- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h index 5a78fd764d..eba6d77d1d 100644 --- a/include/ui/qemu-spice.h +++ b/include/ui/qemu-spice.h @@ -44,10 +44,13 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, void do_info_spice_print(Monitor *mon, const QObject *data); void do_info_spice(Monitor *mon, QObject **ret_data); -CharDriverState *qemu_chr_open_spice(QemuOpts *opts); +CharDriverState *qemu_chr_open_spice_vmc(const char *type); #if SPICE_SERVER_VERSION >= 0x000c02 -CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts); +CharDriverState *qemu_chr_open_spice_port(const char *name); void qemu_spice_register_ports(void); +#else +static inline CharDriverState *qemu_chr_open_spice_port(const char *name) +{ return NULL; } #endif #else /* CONFIG_SPICE */ diff --git a/qapi-schema.json b/qapi-schema.json index 7ea32ed415..dad4d4aed1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3208,6 +3208,28 @@ ## { 'type': 'ChardevStdio', 'data': { '*signal' : 'bool' } } +## +# @ChardevSpiceChannel: +# +# Configuration info for spice vm channel chardevs. +# +# @type: kind of channel (for example vdagent). +# +# Since: 1.5 +## +{ 'type': 'ChardevSpiceChannel', 'data': { 'type' : 'str' } } + +## +# @ChardevSpicePort: +# +# Configuration info for spice port chardevs. +# +# @fqdn: name of the channel (see docs/spice-port-fqdn.txt) +# +# Since: 1.5 +## +{ 'type': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' } } + ## # @ChardevBackend: # @@ -3228,7 +3250,9 @@ 'msmouse': 'ChardevDummy', 'braille': 'ChardevDummy', 'stdio' : 'ChardevStdio', - 'console': 'ChardevDummy' } } + 'console': 'ChardevDummy', + 'spicevmc' : 'ChardevSpiceChannel', + 'spiceport' : 'ChardevSpicePort' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 427901c0c5..f13374770a 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3728,6 +3728,14 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_CONSOLE: chr = qemu_chr_open_win_con(); break; +#endif +#ifdef CONFIG_SPICE + case CHARDEV_BACKEND_KIND_SPICEVMC: + chr = qemu_chr_open_spice_vmc(backend->spicevmc->type); + break; + case CHARDEV_BACKEND_KIND_SPICEPORT: + chr = qemu_chr_open_spice_port(backend->spiceport->fqdn); + break; #endif default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); diff --git a/spice-qemu-char.c b/spice-qemu-char.c index aea3d24e7d..0c92ca850b 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -217,16 +217,14 @@ static void print_allowed_subtypes(void) fprintf(stderr, "\n"); } -static CharDriverState *chr_open(QemuOpts *opts, const char *subtype) +static CharDriverState *chr_open(const char *subtype) { CharDriverState *chr; SpiceCharDriver *s; - uint32_t debug = qemu_opt_get_number(opts, "debug", 0); chr = g_malloc0(sizeof(CharDriverState)); s = g_malloc0(sizeof(SpiceCharDriver)); s->chr = chr; - s->debug = debug; s->active = false; s->sin.subtype = subtype; chr->opaque = s; @@ -240,35 +238,32 @@ static CharDriverState *chr_open(QemuOpts *opts, const char *subtype) return chr; } -CharDriverState *qemu_chr_open_spice(QemuOpts *opts) +CharDriverState *qemu_chr_open_spice_vmc(const char *type) { CharDriverState *chr; - const char *name = qemu_opt_get(opts, "name"); const char **psubtype = spice_server_char_device_recognized_subtypes(); - const char *subtype = NULL; - if (name == NULL) { + if (type == NULL) { fprintf(stderr, "spice-qemu-char: missing name parameter\n"); print_allowed_subtypes(); return NULL; } - for(;*psubtype != NULL; ++psubtype) { - if (strcmp(name, *psubtype) == 0) { - subtype = *psubtype; + for (; *psubtype != NULL; ++psubtype) { + if (strcmp(type, *psubtype) == 0) { break; } } - if (subtype == NULL) { - fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name); + if (*psubtype == NULL) { + fprintf(stderr, "spice-qemu-char: unsupported type: %s\n", type); print_allowed_subtypes(); return NULL; } - chr = chr_open(opts, subtype); + chr = chr_open(type); #if SPICE_SERVER_VERSION < 0x000901 /* See comment in vmc_state() */ - if (strcmp(subtype, "vdagent") == 0) { + if (strcmp(type, "vdagent") == 0) { qemu_chr_generic_open(chr); } #endif @@ -277,18 +272,17 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) } #if SPICE_SERVER_VERSION >= 0x000c02 -CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts) +CharDriverState *qemu_chr_open_spice_port(const char *name) { CharDriverState *chr; SpiceCharDriver *s; - const char *name = qemu_opt_get(opts, "name"); if (name == NULL) { fprintf(stderr, "spice-qemu-char: missing name parameter\n"); return NULL; } - chr = chr_open(opts, "port"); + chr = chr_open("port"); s = chr->opaque; s->sin.portname = name; @@ -308,12 +302,38 @@ void qemu_spice_register_ports(void) } #endif +static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *name = qemu_opt_get(opts, "name"); + + if (name == NULL) { + error_setg(errp, "chardev: spice channel: no name given"); + return; + } + backend->spicevmc = g_new0(ChardevSpiceChannel, 1); + backend->spicevmc->type = g_strdup(name); +} + +static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + const char *name = qemu_opt_get(opts, "name"); + + if (name == NULL) { + error_setg(errp, "chardev: spice port: no name given"); + return; + } + backend->spiceport = g_new0(ChardevSpicePort, 1); + backend->spiceport->fqdn = g_strdup(name); +} + static void register_types(void) { - register_char_driver("spicevmc", qemu_chr_open_spice); -#if SPICE_SERVER_VERSION >= 0x000c02 - register_char_driver("spiceport", qemu_chr_open_spice_port); -#endif + register_char_driver_qapi("spicevmc", CHARDEV_BACKEND_KIND_SPICEVMC, + qemu_chr_parse_spice_vmc); + register_char_driver_qapi("spiceport", CHARDEV_BACKEND_KIND_SPICEPORT, + qemu_chr_parse_spice_port); } type_init(register_types); From 702ec69cc1aa87a1e53d1b066a38a9eb0fa7845b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 25 Feb 2013 15:52:32 +0100 Subject: [PATCH 1597/1634] chardev: add vc support to qapi This patch adds 'vc' support to qapi and also switches over the vc chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 4 +-- qapi-schema.json | 20 ++++++++++++++- qemu-char.c | 3 +++ ui/console.c | 61 +++++++++++++++++++++++++++++++++++--------- ui/gtk.c | 2 +- 5 files changed, 74 insertions(+), 16 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index c42bca6efe..a37cf65602 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -450,9 +450,9 @@ void qemu_console_resize(DisplayState *ds, int width, int height); void qemu_console_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h); -typedef CharDriverState *(VcHandler)(QemuOpts *); +typedef CharDriverState *(VcHandler)(ChardevVC *vc); -CharDriverState *vc_init(QemuOpts *opts); +CharDriverState *vc_init(ChardevVC *vc); void register_vc_handler(VcHandler *handler); /* sdl.c */ diff --git a/qapi-schema.json b/qapi-schema.json index dad4d4aed1..4ee5650293 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3230,6 +3230,23 @@ ## { 'type': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' } } +## +# @ChardevVC: +# +# Configuration info for virtual console chardevs. +# +# @width: console width, in pixels +# @height: console height, in pixels +# @cols: console width, in chars +# @rows: console height, in chars +# +# Since: 1.5 +## +{ 'type': 'ChardevVC', 'data': { '*width' : 'int', + '*height' : 'int', + '*cols' : 'int', + '*rows' : 'int' } } + ## # @ChardevBackend: # @@ -3252,7 +3269,8 @@ 'stdio' : 'ChardevStdio', 'console': 'ChardevDummy', 'spicevmc' : 'ChardevSpiceChannel', - 'spiceport' : 'ChardevSpicePort' } } + 'spiceport' : 'ChardevSpicePort', + 'vc' : 'ChardevVC' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index f13374770a..2d62ee9e26 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -3737,6 +3737,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, chr = qemu_chr_open_spice_port(backend->spiceport->fqdn); break; #endif + case CHARDEV_BACKEND_KIND_VC: + chr = vc_init(backend->vc); + break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); break; diff --git a/ui/console.c b/ui/console.c index 83a6fa3969..27e87f8879 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1537,22 +1537,26 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) chr->init(chr); } -static CharDriverState *text_console_init(QemuOpts *opts) +static CharDriverState *text_console_init(ChardevVC *vc) { CharDriverState *chr; QemuConsole *s; - unsigned width; - unsigned height; + unsigned width = 0; + unsigned height = 0; chr = g_malloc0(sizeof(CharDriverState)); - width = qemu_opt_get_number(opts, "width", 0); - if (width == 0) - width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH; + if (vc->has_width) { + width = vc->width; + } else if (vc->has_cols) { + width = vc->cols * FONT_WIDTH; + } - height = qemu_opt_get_number(opts, "height", 0); - if (height == 0) - height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT; + if (vc->has_height) { + height = vc->height; + } else if (vc->has_rows) { + height = vc->rows * FONT_HEIGHT; + } if (width == 0 || height == 0) { s = new_console(NULL, TEXT_CONSOLE); @@ -1575,9 +1579,9 @@ static CharDriverState *text_console_init(QemuOpts *opts) static VcHandler *vc_handler = text_console_init; -CharDriverState *vc_init(QemuOpts *opts) +CharDriverState *vc_init(ChardevVC *vc) { - return vc_handler(opts); + return vc_handler(vc); } void register_vc_handler(VcHandler *handler) @@ -1740,9 +1744,42 @@ PixelFormat qemu_default_pixelformat(int bpp) return pf; } +static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + int val; + + backend->vc = g_new0(ChardevVC, 1); + + val = qemu_opt_get_number(opts, "width", 0); + if (val != 0) { + backend->vc->has_width = true; + backend->vc->width = val; + } + + val = qemu_opt_get_number(opts, "height", 0); + if (val != 0) { + backend->vc->has_height = true; + backend->vc->height = val; + } + + val = qemu_opt_get_number(opts, "cols", 0); + if (val != 0) { + backend->vc->has_cols = true; + backend->vc->cols = val; + } + + val = qemu_opt_get_number(opts, "rows", 0); + if (val != 0) { + backend->vc->has_rows = true; + backend->vc->rows = val; + } +} + static void register_types(void) { - register_char_driver("vc", text_console_init); + register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC, + qemu_chr_parse_vc); } type_init(register_types); diff --git a/ui/gtk.c b/ui/gtk.c index 544593e90d..794dab15b1 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -991,7 +991,7 @@ static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len) static int nb_vcs; static CharDriverState *vcs[MAX_VCS]; -static CharDriverState *gd_vc_handler(QemuOpts *opts) +static CharDriverState *gd_vc_handler(ChardevVC *unused) { CharDriverState *chr; From 1da48c658a26d0c1444d05d8d3a545d311e01026 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 26 Feb 2013 16:21:11 +0100 Subject: [PATCH 1598/1634] chardev: add memory (ringbuf) support to qapi This patch adds 'memory' support to qapi and also switches over the memory chardev initialization to the new qapi code path. Signed-off-by: Gerd Hoffmann --- qapi-schema.json | 14 +++++++++++++- qemu-char.c | 30 +++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 4ee5650293..8d371f178d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3247,6 +3247,17 @@ '*cols' : 'int', '*rows' : 'int' } } +## +# @ChardevRingbuf: +# +# Configuration info for memory chardevs +# +# @size: #optional Ringbuffer size, must be power of two, default is 65536 +# +# Since: 1.5 +## +{ 'type': 'ChardevRingbuf', 'data': { '*size' : 'int' } } + ## # @ChardevBackend: # @@ -3270,7 +3281,8 @@ 'console': 'ChardevDummy', 'spicevmc' : 'ChardevSpiceChannel', 'spiceport' : 'ChardevSpicePort', - 'vc' : 'ChardevVC' } } + 'vc' : 'ChardevVC', + 'memory' : 'ChardevRingbuf' } } ## # @ChardevReturn: diff --git a/qemu-char.c b/qemu-char.c index 2d62ee9e26..eb2045a5da 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2884,7 +2884,8 @@ static void ringbuf_chr_close(struct CharDriverState *chr) chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts) +static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, + Error **errp) { CharDriverState *chr; RingBufCharDriver *d; @@ -2892,14 +2893,11 @@ static CharDriverState *qemu_chr_open_ringbuf(QemuOpts *opts) chr = g_malloc0(sizeof(CharDriverState)); d = g_malloc(sizeof(*d)); - d->size = qemu_opt_get_size(opts, "size", 0); - if (d->size == 0) { - d->size = 65536; - } + d->size = opts->has_size ? opts->size : 65536; /* The size must be power of 2 */ if (d->size & (d->size - 1)) { - error_report("size of ringbuf device must be power of two"); + error_setg(errp, "size of ringbuf chardev must be power of two"); goto fail; } @@ -3201,6 +3199,20 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, backend->pipe->device = g_strdup(device); } +static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, + Error **errp) +{ + int val; + + backend->memory = g_new0(ChardevRingbuf, 1); + + val = qemu_opt_get_number(opts, "size", 0); + if (val != 0) { + backend->memory->has_size = true; + backend->memory->size = val; + } +} + typedef struct CharDriver { const char *name; /* old, pre qapi */ @@ -3740,6 +3752,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_VC: chr = vc_init(backend->vc); break; + case CHARDEV_BACKEND_KIND_MEMORY: + chr = qemu_chr_open_ringbuf(backend->memory, errp); + break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); break; @@ -3782,7 +3797,8 @@ static void register_types(void) register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL); register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); - register_char_driver("memory", qemu_chr_open_ringbuf); + register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY, + qemu_chr_parse_ringbuf); register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE, qemu_chr_parse_file_out); register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO, From 3ecc059dcd06a79495d1bf171ef7f193eff79e98 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Feb 2013 14:10:47 +0100 Subject: [PATCH 1599/1634] chardev: add udp support to qapi This patch adds 'udp' support to qapi. Signed-off-by: Gerd Hoffmann --- include/qemu/sockets.h | 1 + qapi-schema.json | 16 ++++++++++++++- qemu-char.c | 44 +++++++++++++++++++++++++----------------- util/qemu-sockets.c | 25 ++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index c5cee4bf2f..ae5c21cba3 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -71,6 +71,7 @@ SocketAddress *socket_parse(const char *str, Error **errp); int socket_connect(SocketAddress *addr, Error **errp, NonBlockingConnectHandler *callback, void *opaque); int socket_listen(SocketAddress *addr, Error **errp); +int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp); /* Old, ipv4 only bits. Don't use for new code. */ int parse_host_port(struct sockaddr_in *saddr, const char *str); diff --git a/qapi-schema.json b/qapi-schema.json index 8d371f178d..fdaa9da133 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3166,7 +3166,7 @@ ## # @ChardevSocket: # -# Configuration info for socket chardevs. +# Configuration info for (stream) socket chardevs. # # @addr: socket address to listen on (server=true) # or connect to (server=false) @@ -3184,6 +3184,19 @@ '*nodelay' : 'bool', '*telnet' : 'bool' } } +## +# @ChardevDgram: +# +# Configuration info for datagram socket chardevs. +# +# @remote: remote address +# @local: #optional local address +# +# Since: 1.5 +## +{ 'type': 'ChardevDgram', 'data': { 'remote' : 'SocketAddress', + '*local' : 'SocketAddress' } } + ## # @ChardevMux: # @@ -3272,6 +3285,7 @@ 'parallel': 'ChardevHostdev', 'pipe' : 'ChardevHostdev', 'socket' : 'ChardevSocket', + 'dgram' : 'ChardevDgram', 'pty' : 'ChardevDummy', 'null' : 'ChardevDummy', 'mux' : 'ChardevMux', diff --git a/qemu-char.c b/qemu-char.c index eb2045a5da..7e13757af6 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2261,21 +2261,14 @@ static void udp_chr_close(CharDriverState *chr) qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } -static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) +static CharDriverState *qemu_chr_open_udp_fd(int fd) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; - Error *local_err = NULL; - int fd = -1; chr = g_malloc0(sizeof(CharDriverState)); s = g_malloc0(sizeof(NetCharDriver)); - fd = inet_dgram_opts(opts, &local_err); - if (fd < 0) { - goto return_err; - } - s->fd = fd; s->chan = io_channel_from_socket(s->fd); s->bufcnt = 0; @@ -2285,18 +2278,18 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) chr->chr_update_read_handler = udp_chr_update_read_handler; chr->chr_close = udp_chr_close; return chr; +} -return_err: - if (local_err) { - qerror_report_err(local_err); - error_free(local_err); +static CharDriverState *qemu_chr_open_udp(QemuOpts *opts) +{ + Error *local_err = NULL; + int fd = -1; + + fd = inet_dgram_opts(opts, &local_err); + if (fd < 0) { + return NULL; } - g_free(chr); - g_free(s); - if (fd >= 0) { - closesocket(fd); - } - return NULL; + return qemu_chr_open_udp_fd(fd); } /***********************************************************/ @@ -3679,6 +3672,18 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock, is_telnet, is_waitconnect, errp); } +static CharDriverState *qmp_chardev_open_dgram(ChardevDgram *dgram, + Error **errp) +{ + int fd; + + fd = socket_dgram(dgram->remote, dgram->local, errp); + if (error_is_set(errp)) { + return NULL; + } + return qemu_chr_open_udp_fd(fd); +} + ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp) { @@ -3708,6 +3713,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_SOCKET: chr = qmp_chardev_open_socket(backend->socket, errp); break; + case CHARDEV_BACKEND_KIND_DGRAM: + chr = qmp_chardev_open_dgram(backend->dgram, errp); + break; #ifdef HAVE_CHARDEV_TTY case CHARDEV_BACKEND_KIND_PTY: chr = qemu_chr_open_pty(id, ret); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 3f122965ad..83e4e08e85 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -949,6 +949,31 @@ int socket_listen(SocketAddress *addr, Error **errp) return fd; } +int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) +{ + QemuOpts *opts; + int fd; + + opts = qemu_opts_create_nofail(&dummy_opts); + switch (remote->kind) { + case SOCKET_ADDRESS_KIND_INET: + qemu_opt_set(opts, "host", remote->inet->host); + qemu_opt_set(opts, "port", remote->inet->port); + if (local) { + qemu_opt_set(opts, "localaddr", local->inet->host); + qemu_opt_set(opts, "localport", local->inet->port); + } + fd = inet_dgram_opts(opts, errp); + break; + + default: + error_setg(errp, "socket type unsupported for datagram"); + return -1; + } + qemu_opts_del(opts); + return fd; +} + #ifdef _WIN32 static void socket_cleanup(void) { From 46920825402d38a4111cca8099d1261f8f80c03c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Feb 2013 08:46:10 +0100 Subject: [PATCH 1600/1634] Revert "hmp: Disable chardev-add and chardev-remove" This reverts commit 8a14952c9d2f5fa2b3caa6dc286b62ed5d26bca7. --- hmp-commands.hx | 63 ++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 4bda3fea0e..df44906ef9 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1522,38 +1522,37 @@ passed since 1970, i.e. unix epoch. @end table ETEXI -HXCOMM Disabled for now, because it isn't built on top of QMP's chardev-add -HXCOMM { -HXCOMM .name = "chardev-add", -HXCOMM .args_type = "args:s", -HXCOMM .params = "args", -HXCOMM .help = "add chardev", -HXCOMM .mhandler.cmd = hmp_chardev_add, -HXCOMM }, -HXCOMM -HXCOMM STEXI -HXCOMM @item chardev_add args -HXCOMM @findex chardev_add -HXCOMM -HXCOMM chardev_add accepts the same parameters as the -chardev command line switch. -HXCOMM -HXCOMM ETEXI -HXCOMM -HXCOMM { -HXCOMM .name = "chardev-remove", -HXCOMM .args_type = "id:s", -HXCOMM .params = "id", -HXCOMM .help = "remove chardev", -HXCOMM .mhandler.cmd = hmp_chardev_remove, -HXCOMM }, -HXCOMM -HXCOMM STEXI -HXCOMM @item chardev_remove id -HXCOMM @findex chardev_remove -HXCOMM -HXCOMM Removes the chardev @var{id}. -HXCOMM -HXCOMM ETEXI + { + .name = "chardev-add", + .args_type = "args:s", + .params = "args", + .help = "add chardev", + .mhandler.cmd = hmp_chardev_add, + }, + +STEXI +@item chardev_add args +@findex chardev_add + +chardev_add accepts the same parameters as the -chardev command line switch. + +ETEXI + + { + .name = "chardev-remove", + .args_type = "id:s", + .params = "id", + .help = "remove chardev", + .mhandler.cmd = hmp_chardev_remove, + }, + +STEXI +@item chardev_remove id +@findex chardev_remove + +Removes the chardev @var{id}. + +ETEXI { .name = "info", From e5545854dd1e2e3507b210ac0c1cbfca69ff0fcb Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Sun, 10 Mar 2013 17:58:05 +0400 Subject: [PATCH 1601/1634] qemu-char.c: fix waiting for telnet connection message Current colon position in "waiting for telnet connection" message template produces messages like: QEMU waiting for connection on: telnet::127.0.0.16666,server After moving a colon to the right, we will get a correct messages like: QEMU waiting for connection on: telnet:127.0.0.1:6666,server Signed-off-by: Igor Mitsyanko Signed-off-by: Gerd Hoffmann --- qemu-char.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index 7e13757af6..e6337971a5 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2656,7 +2656,7 @@ static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay, s->do_nodelay = do_nodelay; getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); - snprintf(chr->filename, 256, "%s:%s:%s%s%s%s", + snprintf(chr->filename, 256, "%s:%s%s%s:%s%s", is_telnet ? "telnet" : "tcp", left, host, right, serv, is_listen ? ",server" : ""); From c69b30e8301a49cd198d54bb740a0c9adcd2a34a Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Wed, 13 Mar 2013 12:21:04 -0500 Subject: [PATCH 1602/1634] gtk: fix vc initialization commit 01f45d986fb0b7c2d4f0466efe3cde9708f325be Author: Anthony Liguori Date: Tue Mar 5 23:21:32 2013 +0530 qemu-char: move text console init to console.c Broke vc initialization for GTK. It's a simple typo. Signed-off-by: Anthony Liguori --- ui/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/console.c b/ui/console.c index 83a6fa3969..0f96177797 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1742,7 +1742,7 @@ PixelFormat qemu_default_pixelformat(int bpp) static void register_types(void) { - register_char_driver("vc", text_console_init); + register_char_driver("vc", vc_init); } type_init(register_types); From 5e9b473a3d7fbb915df4b3f5487e5056762087f8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 13 Mar 2013 10:41:31 +0100 Subject: [PATCH 1603/1634] spice-qemu-char: Fix name parameter issues after qapi-ifying The strings passed in through the qapi calls are dynamic memory, since we want to have them stick around longer then just the call to qemu_chr_open_spice_* we need to strdup them. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- spice-qemu-char.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 0c92ca850b..a94f76ba2a 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -185,6 +185,11 @@ static void spice_chr_close(struct CharDriverState *chr) printf("%s\n", __func__); vmc_unregister_interface(s); QLIST_REMOVE(s, next); + + g_free((char *)s->sin.subtype); +#if SPICE_SERVER_VERSION >= 0x000c02 + g_free((char *)s->sin.portname); +#endif g_free(s); } @@ -226,7 +231,7 @@ static CharDriverState *chr_open(const char *subtype) s = g_malloc0(sizeof(SpiceCharDriver)); s->chr = chr; s->active = false; - s->sin.subtype = subtype; + s->sin.subtype = g_strdup(subtype); chr->opaque = s; chr->chr_write = spice_chr_write; chr->chr_close = spice_chr_close; @@ -284,7 +289,7 @@ CharDriverState *qemu_chr_open_spice_port(const char *name) chr = chr_open("port"); s = chr->opaque; - s->sin.portname = name; + s->sin.portname = g_strdup(name); return chr; } From 344bf1e935163d8a4c3cce3ec4c636e1ebd035ce Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 13 Mar 2013 14:59:44 +0100 Subject: [PATCH 1604/1634] spice-qemu-char: Remove dead debugging code Since commit d62e5f7036a018b2ad09f17ebd481bd28953d783 "chardev: add spice support to qapi" It is impossible to set the debug parameter, so all the dprintf calls are essentially nops. Since we've not needed the debug parameter in ages this is not a problem, if it later turns out we do need some more debugging options we can add more trace-points. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- spice-qemu-char.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index a94f76ba2a..8a9236d0a8 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -8,14 +8,6 @@ #include "qemu/osdep.h" -#define dprintf(_scd, _level, _fmt, ...) \ - do { \ - static unsigned __dprintf_counter = 0; \ - if (_scd->debug >= _level) { \ - fprintf(stderr, "scd: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\ - } \ - } while (0) - typedef struct SpiceCharDriver { CharDriverState* chr; SpiceCharDeviceInstance sin; @@ -24,7 +16,6 @@ typedef struct SpiceCharDriver { uint8_t *buffer; uint8_t *datapos; ssize_t bufsize, datalen; - uint32_t debug; QLIST_ENTRY(SpiceCharDriver) next; } SpiceCharDriver; @@ -49,7 +40,6 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) p += last_out; } - dprintf(scd, 3, "%s: %zu/%zd\n", __func__, out, len + out); trace_spice_vmc_write(out, len + out); return out; } @@ -59,7 +49,6 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); int bytes = MIN(len, scd->datalen); - dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen); if (bytes > 0) { memcpy(buf, scd->datapos, bytes); scd->datapos += bytes; @@ -84,11 +73,9 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event) chr_event = CHR_EVENT_BREAK; break; default: - dprintf(scd, 2, "%s: unknown %d\n", __func__, event); return; } - dprintf(scd, 2, "%s: %d\n", __func__, event); trace_spice_vmc_event(chr_event); qemu_chr_be_event(scd->chr, chr_event); } @@ -141,7 +128,6 @@ static void vmc_register_interface(SpiceCharDriver *scd) if (scd->active) { return; } - dprintf(scd, 1, "%s\n", __func__); scd->sin.base.sif = &vmc_interface.base; qemu_spice_add_interface(&scd->sin.base); scd->active = true; @@ -153,7 +139,6 @@ static void vmc_unregister_interface(SpiceCharDriver *scd) if (!scd->active) { return; } - dprintf(scd, 1, "%s\n", __func__); spice_server_remove_interface(&scd->sin.base); scd->active = false; trace_spice_vmc_unregister_interface(scd); @@ -164,7 +149,6 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { SpiceCharDriver *s = chr->opaque; - dprintf(s, 2, "%s: %d\n", __func__, len); vmc_register_interface(s); assert(s->datalen == 0); if (s->bufsize < len) { @@ -182,7 +166,6 @@ static void spice_chr_close(struct CharDriverState *chr) { SpiceCharDriver *s = chr->opaque; - printf("%s\n", __func__); vmc_unregister_interface(s); QLIST_REMOVE(s, next); From 4f306496183d81aed4b43762cf3bfd6e054de767 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Fri, 15 Mar 2013 15:04:39 +1000 Subject: [PATCH 1605/1634] qga/main.c: Don't use g_key_file_get/set_int64 These functions don't exist until glib version 2.26. QEMU is currently only mandating glib 2.12. This patch replaces the functions with g_key_file_get/set_integer. Unbreaks the build on Ubuntu 10.04 and RHEL 5.6. Regression was introduced by 39097daf15c42243742667607d2cad2c9dc4f764 Signed-off-by: Peter Crosthwaite Message-id: 1363323879-682-1-git-send-email-peter.crosthwaite@xilinx.com Signed-off-by: Anthony Liguori --- qga/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qga/main.c b/qga/main.c index 99346e15aa..74ef7885b2 100644 --- a/qga/main.c +++ b/qga/main.c @@ -755,7 +755,7 @@ static void persistent_state_from_keyfile(GAPersistentState *pstate, if (g_key_file_has_key(keyfile, "global", "fd_counter", NULL)) { pstate->fd_counter = - g_key_file_get_int64(keyfile, "global", "fd_counter", NULL); + g_key_file_get_integer(keyfile, "global", "fd_counter", NULL); } } @@ -765,7 +765,7 @@ static void persistent_state_to_keyfile(const GAPersistentState *pstate, g_assert(pstate); g_assert(keyfile); - g_key_file_set_int64(keyfile, "global", "fd_counter", pstate->fd_counter); + g_key_file_set_integer(keyfile, "global", "fd_counter", pstate->fd_counter); } static gboolean write_persistent_state(const GAPersistentState *pstate, From 1a86938f04b1abfd28e053b8c6f4b8ed9e4ffe08 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:01 +0100 Subject: [PATCH 1606/1634] block: Add options QDict to .bdrv_open() Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- block.c | 4 ++-- block/bochs.c | 2 +- block/cloop.c | 2 +- block/cow.c | 2 +- block/dmg.c | 2 +- block/parallels.c | 2 +- block/qcow.c | 2 +- block/qcow2.c | 4 ++-- block/qed.c | 4 ++-- block/raw.c | 2 +- block/vdi.c | 2 +- block/vmdk.c | 2 +- block/vpc.c | 2 +- include/block/block_int.h | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/block.c b/block.c index 124a9ebf65..01cee877c5 100644 --- a/block.c +++ b/block.c @@ -710,7 +710,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, } else { assert(file != NULL); bs->file = file; - ret = drv->bdrv_open(bs, open_flags); + ret = drv->bdrv_open(bs, NULL, open_flags); } if (ret < 0) { @@ -3190,7 +3190,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, if (bs->file) { drv->bdrv_close(bs); ret = bdrv_snapshot_goto(bs->file, snapshot_id); - open_ret = drv->bdrv_open(bs, bs->open_flags); + open_ret = drv->bdrv_open(bs, NULL, bs->open_flags); if (open_ret < 0) { bdrv_delete(bs->file); bs->drv = NULL; diff --git a/block/bochs.c b/block/bochs.c index a6eb33da42..d7078c0775 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -108,7 +108,7 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int bochs_open(BlockDriverState *bs, int flags) +static int bochs_open(BlockDriverState *bs, QDict *options, int flags) { BDRVBochsState *s = bs->opaque; int i; diff --git a/block/cloop.c b/block/cloop.c index 8fe13e92a1..6ea7cf4046 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -53,7 +53,7 @@ static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int cloop_open(BlockDriverState *bs, int flags) +static int cloop_open(BlockDriverState *bs, QDict *options, int flags) { BDRVCloopState *s = bs->opaque; uint32_t offsets_size, max_compressed_block_size = 1, i; diff --git a/block/cow.c b/block/cow.c index 4baf9042fe..d73e08cf92 100644 --- a/block/cow.c +++ b/block/cow.c @@ -58,7 +58,7 @@ static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int cow_open(BlockDriverState *bs, int flags) +static int cow_open(BlockDriverState *bs, QDict *options, int flags) { BDRVCowState *s = bs->opaque; struct cow_header_v2 cow_header; diff --git a/block/dmg.c b/block/dmg.c index 6d85801a84..c1066df13a 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -85,7 +85,7 @@ static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result) return 0; } -static int dmg_open(BlockDriverState *bs, int flags) +static int dmg_open(BlockDriverState *bs, QDict *options, int flags) { BDRVDMGState *s = bs->opaque; uint64_t info_begin,info_end,last_in_offset,last_out_offset; diff --git a/block/parallels.c b/block/parallels.c index 8688f6ca4c..18b3ac0b28 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -68,7 +68,7 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam return 0; } -static int parallels_open(BlockDriverState *bs, int flags) +static int parallels_open(BlockDriverState *bs, QDict *options, int flags) { BDRVParallelsState *s = bs->opaque; int i; diff --git a/block/qcow.c b/block/qcow.c index a7135eea47..f6750a5bd3 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -92,7 +92,7 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int qcow_open(BlockDriverState *bs, int flags) +static int qcow_open(BlockDriverState *bs, QDict *options, int flags) { BDRVQcowState *s = bs->opaque; int len, i, shift, ret; diff --git a/block/qcow2.c b/block/qcow2.c index 7610e569e3..4c501a5ffc 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -285,7 +285,7 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result, return ret; } -static int qcow2_open(BlockDriverState *bs, int flags) +static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) { BDRVQcowState *s = bs->opaque; int len, i, ret = 0; @@ -912,7 +912,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs) qcow2_close(bs); memset(s, 0, sizeof(BDRVQcowState)); - qcow2_open(bs, flags); + qcow2_open(bs, NULL, flags); if (crypt_method) { s->crypt_method = crypt_method; diff --git a/block/qed.c b/block/qed.c index b8515e58b3..46e12b358b 100644 --- a/block/qed.c +++ b/block/qed.c @@ -373,7 +373,7 @@ static void bdrv_qed_rebind(BlockDriverState *bs) s->bs = bs; } -static int bdrv_qed_open(BlockDriverState *bs, int flags) +static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags) { BDRVQEDState *s = bs->opaque; QEDHeader le_header; @@ -1526,7 +1526,7 @@ static void bdrv_qed_invalidate_cache(BlockDriverState *bs) bdrv_qed_close(bs); memset(s, 0, sizeof(BDRVQEDState)); - bdrv_qed_open(bs, bs->open_flags); + bdrv_qed_open(bs, NULL, bs->open_flags); } static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result, diff --git a/block/raw.c b/block/raw.c index 75812db3c2..ce10422006 100644 --- a/block/raw.c +++ b/block/raw.c @@ -3,7 +3,7 @@ #include "block/block_int.h" #include "qemu/module.h" -static int raw_open(BlockDriverState *bs, int flags) +static int raw_open(BlockDriverState *bs, QDict *options, int flags) { bs->sg = bs->file->sg; return 0; diff --git a/block/vdi.c b/block/vdi.c index 87c691b504..2662d89af6 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -364,7 +364,7 @@ static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename) return result; } -static int vdi_open(BlockDriverState *bs, int flags) +static int vdi_open(BlockDriverState *bs, QDict *options, int flags) { BDRVVdiState *s = bs->opaque; VdiHeader header; diff --git a/block/vmdk.c b/block/vmdk.c index aef1abcb4f..4a13fa69c0 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -723,7 +723,7 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, return vmdk_parse_extents(buf, bs, bs->file->filename); } -static int vmdk_open(BlockDriverState *bs, int flags) +static int vmdk_open(BlockDriverState *bs, QDict *options, int flags) { int ret; BDRVVmdkState *s = bs->opaque; diff --git a/block/vpc.c b/block/vpc.c index 82229ef5a0..3cad52e54c 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -155,7 +155,7 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int vpc_open(BlockDriverState *bs, int flags) +static int vpc_open(BlockDriverState *bs, QDict *options, int flags) { BDRVVPCState *s = bs->opaque; int i; diff --git a/include/block/block_int.h b/include/block/block_int.h index eaad53e426..4b659fa960 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -82,7 +82,7 @@ struct BlockDriver { void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); - int (*bdrv_open)(BlockDriverState *bs, int flags); + int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags); int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags); int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); From de9c0cec6c823071b903ebeebf1ee70b394ff46f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:02 +0100 Subject: [PATCH 1607/1634] block: Add options QDict to bdrv_open() prototype It doesn't do anything yet except storing the options QDict in the BlockDriverState. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- block.c | 47 +++++++++++++++++++++++++++++---------- block/blkverify.c | 2 +- block/qcow2.c | 2 +- block/vmdk.c | 2 +- block/vvfat.c | 2 +- blockdev.c | 10 +++++---- hw/xen_disk.c | 2 +- include/block/block.h | 4 ++-- include/block/block_int.h | 1 + qemu-img.c | 6 ++--- qemu-io.c | 2 +- qemu-nbd.c | 2 +- 12 files changed, 54 insertions(+), 28 deletions(-) diff --git a/block.c b/block.c index 01cee877c5..761ea860a9 100644 --- a/block.c +++ b/block.c @@ -788,7 +788,8 @@ int bdrv_open_backing_file(BlockDriverState *bs) /* backing files always opened read-only */ back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT); - ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv); + ret = bdrv_open(bs->backing_hd, backing_filename, NULL, + back_flags, back_drv); if (ret < 0) { bdrv_delete(bs->backing_hd); bs->backing_hd = NULL; @@ -800,15 +801,28 @@ int bdrv_open_backing_file(BlockDriverState *bs) /* * Opens a disk image (raw, qcow2, vmdk, ...) + * + * options is a QDict of options to pass to the block drivers, or NULL for an + * empty set of options. The reference to the QDict belongs to the block layer + * after the call (even on failure), so if the caller intends to reuse the + * dictionary, it needs to use QINCREF() before calling bdrv_open. */ -int bdrv_open(BlockDriverState *bs, const char *filename, int flags, - BlockDriver *drv) +int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, + int flags, BlockDriver *drv) { int ret; /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */ char tmp_filename[PATH_MAX + 1]; BlockDriverState *file = NULL; + /* NULL means an empty set of options */ + if (options == NULL) { + options = qdict_new(); + } + + bs->options = options; + + /* For snapshot=on, create a temporary qcow2 overlay */ if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; int64_t total_size; @@ -822,10 +836,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, /* if there is a backing file, use it */ bs1 = bdrv_new(""); - ret = bdrv_open(bs1, filename, 0, drv); + ret = bdrv_open(bs1, filename, NULL, 0, drv); if (ret < 0) { bdrv_delete(bs1); - return ret; + goto fail; } total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK; @@ -836,15 +850,17 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename)); if (ret < 0) { - return ret; + goto fail; } /* Real path is meaningless for protocols */ - if (is_protocol) + if (is_protocol) { snprintf(backing_filename, sizeof(backing_filename), "%s", filename); - else if (!realpath(filename, backing_filename)) - return -errno; + } else if (!realpath(filename, backing_filename)) { + ret = -errno; + goto fail; + } bdrv_qcow2 = bdrv_find_format("qcow2"); options = parse_option_parameters("", bdrv_qcow2->create_options, NULL); @@ -859,7 +875,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, ret = bdrv_create(bdrv_qcow2, tmp_filename, options); free_option_parameters(options); if (ret < 0) { - return ret; + goto fail; } filename = tmp_filename; @@ -874,7 +890,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, ret = bdrv_file_open(&file, filename, bdrv_open_flags(bs, flags)); if (ret < 0) { - return ret; + goto fail; } /* Find the right image format driver */ @@ -924,6 +940,10 @@ unlink_and_fail: if (bs->is_temporary) { unlink(filename); } +fail: + QDECREF(bs->options); + bs->options = NULL; + return ret; } @@ -1193,6 +1213,8 @@ void bdrv_close(BlockDriverState *bs) bs->valid_key = 0; bs->sg = 0; bs->growable = 0; + QDECREF(bs->options); + bs->options = NULL; if (bs->file != NULL) { bdrv_delete(bs->file); @@ -4594,7 +4616,8 @@ void bdrv_img_create(const char *filename, const char *fmt, bs = bdrv_new(""); - ret = bdrv_open(bs, backing_file->value.s, back_flags, backing_drv); + ret = bdrv_open(bs, backing_file->value.s, NULL, back_flags, + backing_drv); if (ret < 0) { error_setg_errno(errp, -ret, "Could not open '%s'", backing_file->value.s); diff --git a/block/blkverify.c b/block/blkverify.c index a7dd45909b..2086d97234 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -98,7 +98,7 @@ static int blkverify_open(BlockDriverState *bs, const char *filename, int flags) /* Open the test file */ s->test_file = bdrv_new(""); - ret = bdrv_open(s->test_file, filename, flags, NULL); + ret = bdrv_open(s->test_file, filename, NULL, flags, NULL); if (ret < 0) { bdrv_delete(s->test_file); s->test_file = NULL; diff --git a/block/qcow2.c b/block/qcow2.c index 4c501a5ffc..f5e4269363 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1265,7 +1265,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, */ BlockDriver* drv = bdrv_find_format("qcow2"); assert(drv != NULL); - ret = bdrv_open(bs, filename, + ret = bdrv_open(bs, filename, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv); if (ret < 0) { goto out; diff --git a/block/vmdk.c b/block/vmdk.c index 4a13fa69c0..e92104a830 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1527,7 +1527,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) if (backing_file) { char parent_filename[PATH_MAX]; BlockDriverState *bs = bdrv_new(""); - ret = bdrv_open(bs, backing_file, 0, NULL); + ret = bdrv_open(bs, backing_file, NULL, 0, NULL); if (ret != 0) { bdrv_delete(bs); return ret; diff --git a/block/vvfat.c b/block/vvfat.c index 06e6654824..b8eb38ab36 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2830,7 +2830,7 @@ static int enable_write_target(BDRVVVFATState *s) return -1; } - ret = bdrv_open(s->qcow, s->qcow_filename, + ret = bdrv_open(s->qcow, s->qcow_filename, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow); if (ret < 0) { return ret; diff --git a/blockdev.c b/blockdev.c index 0e67d06330..d67917486f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -635,7 +635,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) error_report("warning: disabling copy_on_read on readonly drive"); } - ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv); + ret = bdrv_open(dinfo->bdrv, file, NULL, bdrv_flags, drv); if (ret < 0) { if (ret == -EMEDIUMTYPE) { error_report("could not open disk image %s: not in %s format", @@ -820,7 +820,9 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp) /* We will manually add the backing_hd field to the bs later */ states->new_bs = bdrv_new(""); - ret = bdrv_open(states->new_bs, new_image_file, + /* TODO Inherit bs->options or only take explicit options with an + * extended QMP command? */ + ret = bdrv_open(states->new_bs, new_image_file, NULL, flags | BDRV_O_NO_BACKING, drv); if (ret != 0) { error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file); @@ -921,7 +923,7 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename, int bdrv_flags, BlockDriver *drv, const char *password, Error **errp) { - if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) { + if (bdrv_open(bs, filename, NULL, bdrv_flags, drv) < 0) { error_set(errp, QERR_OPEN_FILE_FAILED, filename); return; } @@ -1330,7 +1332,7 @@ void qmp_drive_mirror(const char *device, const char *target, * file. */ target_bs = bdrv_new(""); - ret = bdrv_open(target_bs, target, flags | BDRV_O_NO_BACKING, drv); + ret = bdrv_open(target_bs, target, NULL, flags | BDRV_O_NO_BACKING, drv); if (ret < 0) { bdrv_delete(target_bs); diff --git a/hw/xen_disk.c b/hw/xen_disk.c index cc09a2f1fa..83329e2e69 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -763,7 +763,7 @@ static int blk_init(struct XenDevice *xendev) xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n"); blkdev->bs = bdrv_new(blkdev->dev); if (blkdev->bs) { - if (bdrv_open(blkdev->bs, blkdev->filename, qflags, + if (bdrv_open(blkdev->bs, blkdev->filename, NULL, qflags, bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) { bdrv_delete(blkdev->bs); blkdev->bs = NULL; diff --git a/include/block/block.h b/include/block/block.h index 0f750d7da3..d4f34d6462 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -137,8 +137,8 @@ int bdrv_parse_cache_flags(const char *mode, int *flags); int bdrv_parse_discard_flags(const char *mode, int *flags); int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); int bdrv_open_backing_file(BlockDriverState *bs); -int bdrv_open(BlockDriverState *bs, const char *filename, int flags, - BlockDriver *drv); +int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, + int flags, BlockDriver *drv); BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockDriverState *bs, int flags); int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); diff --git a/include/block/block_int.h b/include/block/block_int.h index 4b659fa960..baf80e3c42 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -286,6 +286,7 @@ struct BlockDriverState { /* long-running background operation */ BlockJob *job; + QDict *options; }; int get_tmp_filename(char *filename, int size); diff --git a/qemu-img.c b/qemu-img.c index 471de7d646..31627b0da8 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -276,7 +276,7 @@ static BlockDriverState *bdrv_new_open(const char *filename, drv = NULL; } - ret = bdrv_open(bs, filename, flags, drv); + ret = bdrv_open(bs, filename, NULL, flags, drv); if (ret < 0) { error_report("Could not open '%s': %s", filename, strerror(-ret)); goto fail; @@ -2156,7 +2156,7 @@ static int img_rebase(int argc, char **argv) bs_old_backing = bdrv_new("old_backing"); bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); - ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS, + ret = bdrv_open(bs_old_backing, backing_name, NULL, BDRV_O_FLAGS, old_backing_drv); if (ret) { error_report("Could not open old backing file '%s'", backing_name); @@ -2164,7 +2164,7 @@ static int img_rebase(int argc, char **argv) } if (out_baseimg[0]) { bs_new_backing = bdrv_new("new_backing"); - ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS, + ret = bdrv_open(bs_new_backing, out_baseimg, NULL, BDRV_O_FLAGS, new_backing_drv); if (ret) { error_report("Could not open new backing file '%s'", diff --git a/qemu-io.c b/qemu-io.c index 7b3de42773..79be516953 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -1773,7 +1773,7 @@ static int openfile(char *name, int flags, int growable) } else { bs = bdrv_new("hda"); - if (bdrv_open(bs, name, flags, NULL) < 0) { + if (bdrv_open(bs, name, NULL, flags, NULL) < 0) { fprintf(stderr, "%s: can't open device %s\n", progname, name); bdrv_delete(bs); bs = NULL; diff --git a/qemu-nbd.c b/qemu-nbd.c index e7268d0a9f..ca722ed425 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -557,7 +557,7 @@ int main(int argc, char **argv) bs = bdrv_new("hda"); srcpath = argv[optind]; - if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) { + if ((ret = bdrv_open(bs, srcpath, NULL, flags, NULL)) < 0) { errno = -ret; err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]); } From b382bc9a1504c7f7c112881695d08293b906b88f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:03 +0100 Subject: [PATCH 1608/1634] Add qdict_clone_shallow() Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- include/qapi/qmp/qdict.h | 2 ++ qobject/qdict.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 6d9a4be3a5..685b2e3fcb 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -64,4 +64,6 @@ int64_t qdict_get_try_int(const QDict *qdict, const char *key, int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value); const char *qdict_get_try_str(const QDict *qdict, const char *key); +QDict *qdict_clone_shallow(const QDict *src); + #endif /* QDICT_H */ diff --git a/qobject/qdict.c b/qobject/qdict.c index 7543ccc10f..ed381f9a50 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -400,6 +400,28 @@ const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry) return ret; } +/** + * qdict_clone_shallow(): Clones a given QDict. Its entries are not copied, but + * another reference is added. + */ +QDict *qdict_clone_shallow(const QDict *src) +{ + QDict *dest; + QDictEntry *entry; + int i; + + dest = qdict_new(); + + for (i = 0; i < QDICT_BUCKET_MAX; i++) { + QLIST_FOREACH(entry, &src->table[i], next) { + qobject_incref(entry->value); + qdict_put_obj(dest, entry->key, entry->value); + } + } + + return dest; +} + /** * qentry_destroy(): Free all the memory allocated by a QDictEntry */ From b6ad491a4921557efc8815fe0ca5f11c6d8d587e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:04 +0100 Subject: [PATCH 1609/1634] block: Add options QDict to bdrv_open_common() The options are passed down to the block drivers, which are supposed to remove all options they have processed. Anything that is left over in the end is an unknown option and results in an error. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- block.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index 761ea860a9..0ab164d992 100644 --- a/block.c +++ b/block.c @@ -665,15 +665,18 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) /* * Common part for opening disk images and files + * + * Removes all processed options from *options. */ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, - const char *filename, + const char *filename, QDict *options, int flags, BlockDriver *drv) { int ret, open_flags; assert(drv != NULL); assert(bs->file == NULL); + assert(options == NULL || bs->options != options); trace_bdrv_open_common(bs, filename, flags, drv->format_name); @@ -710,7 +713,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, } else { assert(file != NULL); bs->file = file; - ret = drv->bdrv_open(bs, NULL, open_flags); + ret = drv->bdrv_open(bs, options, open_flags); } if (ret < 0) { @@ -752,7 +755,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) } bs = bdrv_new(""); - ret = bdrv_open_common(bs, NULL, filename, flags, drv); + ret = bdrv_open_common(bs, NULL, filename, NULL, flags, drv); if (ret < 0) { bdrv_delete(bs); return ret; @@ -821,6 +824,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, } bs->options = options; + options = qdict_clone_shallow(options); /* For snapshot=on, create a temporary qcow2 overlay */ if (flags & BDRV_O_SNAPSHOT) { @@ -903,7 +907,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, } /* Open the image */ - ret = bdrv_open_common(bs, file, filename, flags, drv); + ret = bdrv_open_common(bs, file, filename, options, flags, drv); if (ret < 0) { goto unlink_and_fail; } @@ -917,11 +921,22 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, if ((flags & BDRV_O_NO_BACKING) == 0) { ret = bdrv_open_backing_file(bs); if (ret < 0) { - bdrv_close(bs); - return ret; + goto close_and_fail; } } + /* Check if any unknown options were used */ + if (qdict_size(options) != 0) { + const QDictEntry *entry = qdict_first(options); + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by " + "device '%s' doesn't support the option '%s'", + drv->format_name, bs->device_name, entry->key); + + ret = -EINVAL; + goto close_and_fail; + } + QDECREF(options); + if (!bdrv_key_required(bs)) { bdrv_dev_change_media_cb(bs, true); } @@ -942,8 +957,13 @@ unlink_and_fail: } fail: QDECREF(bs->options); + QDECREF(options); bs->options = NULL; + return ret; +close_and_fail: + bdrv_close(bs); + QDECREF(options); return ret; } From 376609cc6c03c2ffc8c323d804d27f95346cac08 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:05 +0100 Subject: [PATCH 1610/1634] qemu-option: Add qemu_opts_absorb_qdict() This adds a function that adds all entries of a QDict to a QemuOpts if the keys are known, and leaves only the rest in the QDict. This way a single QDict of -drive options can be processed in multiple places (generic block layer, block driver, backing file block driver, etc.), where each part picks the options it knows. If at the end of the process the QDict isn't empty, the user specified an invalid option. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- include/qemu/option.h | 1 + util/qemu-option.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/qemu/option.h b/include/qemu/option.h index ba197cddcf..bdb6d218b4 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -149,6 +149,7 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, Error **errp); QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict); +void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp); typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque); int qemu_opts_print(QemuOpts *opts, void *dummy); diff --git a/util/qemu-option.c b/util/qemu-option.c index 5a1d03c331..8b74bf1f7a 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -1066,6 +1066,40 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, return opts; } +/* + * Adds all QDict entries to the QemuOpts that can be added and removes them + * from the QDict. When this function returns, the QDict contains only those + * entries that couldn't be added to the QemuOpts. + */ +void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) +{ + const QDictEntry *entry, *next; + + entry = qdict_first(qdict); + + while (entry != NULL) { + Error *local_err = NULL; + OptsFromQDictState state = { + .errp = &local_err, + .opts = opts, + }; + + next = qdict_next(qdict, entry); + + if (find_desc_by_name(opts->list->desc, entry->key)) { + qemu_opts_from_qdict_1(entry->key, entry->value, &state); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + return; + } else { + qdict_del(qdict, entry->key); + } + } + + entry = next; + } +} + /* * Convert from QemuOpts to QDict. * The QDict values are of type QString. From bb44619b06c0bef20b658ff532cf850c16362ae7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:06 +0100 Subject: [PATCH 1611/1634] blockdev: Keep a copy of DriveInfo.serial Pointing to a QemuOpts element is surprising and can lead to subtle use-after-free errors when the QemuOpts is freed after all options are parsed. Signed-off-by: Kevin Wolf Signed-off-by: Stefan Hajnoczi --- blockdev.c | 5 ++++- include/sysemu/blockdev.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/blockdev.c b/blockdev.c index d67917486f..acf1c32481 100644 --- a/blockdev.c +++ b/blockdev.c @@ -191,6 +191,7 @@ static void drive_uninit(DriveInfo *dinfo) bdrv_delete(dinfo->bdrv); g_free(dinfo->id); QTAILQ_REMOVE(&drives, dinfo, next); + g_free(dinfo->serial); g_free(dinfo); } @@ -566,7 +567,9 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) dinfo->trans = translation; dinfo->opts = opts; dinfo->refcount = 1; - dinfo->serial = serial; + if (serial != NULL) { + dinfo->serial = g_strdup(serial); + } QTAILQ_INSERT_TAIL(&drives, dinfo, next); bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error); diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h index 1fe533299e..804ec8839b 100644 --- a/include/sysemu/blockdev.h +++ b/include/sysemu/blockdev.h @@ -40,7 +40,7 @@ struct DriveInfo { int media_cd; int cyls, heads, secs, trans; QemuOpts *opts; - const char *serial; + char *serial; QTAILQ_ENTRY(DriveInfo) next; int refcount; }; From 0006383e1549b6f9b264575d124c553efca19d62 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:07 +0100 Subject: [PATCH 1612/1634] block: Support driver specific options in drive_init() Any non-default -drive options are now passed down to the block drivers. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- blockdev.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/blockdev.c b/blockdev.c index acf1c32481..7ae619860b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -22,6 +22,7 @@ #include "sysemu/arch_init.h" static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); +extern QemuOptsList qemu_common_drive_opts; static const char *const if_name[IF_COUNT] = { [IF_NONE] = "none", @@ -288,7 +289,7 @@ static bool do_check_io_limits(BlockIOLimit *io_limits, Error **errp) return true; } -DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) +DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) { const char *buf; const char *file = NULL; @@ -311,10 +312,36 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) bool copy_on_read; int ret; Error *error = NULL; + QemuOpts *opts; + QDict *bs_opts; + const char *id; translation = BIOS_ATA_TRANSLATION_AUTO; media = MEDIA_DISK; + /* Check common options by copying from all_opts to opts, all other options + * are stored in bs_opts. */ + id = qemu_opts_id(all_opts); + opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error); + if (error_is_set(&error)) { + qerror_report_err(error); + error_free(error); + return NULL; + } + + bs_opts = qdict_new(); + qemu_opts_to_qdict(all_opts, bs_opts); + qemu_opts_absorb_qdict(opts, bs_opts, &error); + if (error_is_set(&error)) { + qerror_report_err(error); + error_free(error); + return NULL; + } + + if (id) { + qdict_del(bs_opts, "id"); + } + /* extract parameters */ bus_id = qemu_opt_get_number(opts, "bus", 0); unit_id = qemu_opt_get_number(opts, "unit", -1); @@ -565,7 +592,7 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) dinfo->heads = heads; dinfo->secs = secs; dinfo->trans = translation; - dinfo->opts = opts; + dinfo->opts = all_opts; dinfo->refcount = 1; if (serial != NULL) { dinfo->serial = g_strdup(serial); @@ -590,17 +617,20 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) case IF_MTD: break; case IF_VIRTIO: + { /* add virtio block device */ - opts = qemu_opts_create_nofail(qemu_find_opts("device")); + QemuOpts *devopts; + devopts = qemu_opts_create_nofail(qemu_find_opts("device")); if (arch_type == QEMU_ARCH_S390X) { - qemu_opt_set(opts, "driver", "virtio-blk-s390"); + qemu_opt_set(devopts, "driver", "virtio-blk-s390"); } else { - qemu_opt_set(opts, "driver", "virtio-blk-pci"); + qemu_opt_set(devopts, "driver", "virtio-blk-pci"); } - qemu_opt_set(opts, "drive", dinfo->id); + qemu_opt_set(devopts, "drive", dinfo->id); if (devaddr) - qemu_opt_set(opts, "addr", devaddr); + qemu_opt_set(devopts, "addr", devaddr); break; + } default: abort(); } @@ -638,7 +668,9 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) error_report("warning: disabling copy_on_read on readonly drive"); } - ret = bdrv_open(dinfo->bdrv, file, NULL, bdrv_flags, drv); + ret = bdrv_open(dinfo->bdrv, file, bs_opts, bdrv_flags, drv); + bs_opts = NULL; + if (ret < 0) { if (ret == -EMEDIUMTYPE) { error_report("could not open disk image %s: not in %s format", @@ -652,9 +684,14 @@ DriveInfo *drive_init(QemuOpts *opts, BlockInterfaceType block_default_type) if (bdrv_key_required(dinfo->bdrv)) autostart = 0; + + qemu_opts_del(opts); + return dinfo; err: + qemu_opts_del(opts); + QDECREF(bs_opts); bdrv_delete(dinfo->bdrv); g_free(dinfo->id); QTAILQ_REMOVE(&drives, dinfo, next); @@ -1464,9 +1501,9 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) return dummy.next; } -QemuOptsList qemu_drive_opts = { +QemuOptsList qemu_common_drive_opts = { .name = "drive", - .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), + .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head), .desc = { { .name = "bus", @@ -1585,3 +1622,15 @@ QemuOptsList qemu_drive_opts = { { /* end of list */ } }, }; + +QemuOptsList qemu_drive_opts = { + .name = "drive", + .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + }, +}; From 74c4510a3cf7c369ee524c6f8fa8a87cf08ba608 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Mar 2013 10:35:08 +0100 Subject: [PATCH 1613/1634] qcow2: Allow lazy refcounts to be enabled on the command line qcow2 images now accept a boolean lazy_refcounts options. Use it like this: -drive file=test.qcow2,lazy_refcounts=on If the option is specified on the command line, it overrides the default specified by the qcow2 header flags that were set when creating the image. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Stefan Hajnoczi --- block/qcow2-cluster.c | 2 +- block/qcow2.c | 37 +++++++++++++++++++++++++++++++++++++ block/qcow2.h | 1 + 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 56fccf9487..ff9ae18e4a 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -668,7 +668,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) } /* Update L2 table. */ - if (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS) { + if (s->use_lazy_refcounts) { qcow2_mark_dirty(bs); } if (qcow2_need_accurate_refcounts(s)) { diff --git a/block/qcow2.c b/block/qcow2.c index f5e4269363..ad43a13cb0 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -285,11 +285,26 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result, return ret; } +static QemuOptsList qcow2_runtime_opts = { + .name = "qcow2", + .head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head), + .desc = { + { + .name = "lazy_refcounts", + .type = QEMU_OPT_BOOL, + .help = "Postpone refcount updates", + }, + { /* end of list */ } + }, +}; + static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) { BDRVQcowState *s = bs->opaque; int len, i, ret = 0; QCowHeader header; + QemuOpts *opts; + Error *local_err = NULL; uint64_t ext_end; ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); @@ -495,6 +510,28 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags) } } + /* Enable lazy_refcounts according to image and command line options */ + opts = qemu_opts_create_nofail(&qcow2_runtime_opts); + qemu_opts_absorb_qdict(opts, options, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + ret = -EINVAL; + goto fail; + } + + s->use_lazy_refcounts = qemu_opt_get_bool(opts, "lazy_refcounts", + (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS)); + + qemu_opts_del(opts); + + if (s->use_lazy_refcounts && s->qcow_version < 3) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, "Lazy refcounts require " + "a qcow2 image with at least qemu 1.1 compatibility level"); + ret = -EINVAL; + goto fail; + } + #ifdef DEBUG_ALLOC { BdrvCheckResult result = {0}; diff --git a/block/qcow2.h b/block/qcow2.h index 718b52baca..103abdb2c0 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -173,6 +173,7 @@ typedef struct BDRVQcowState { int flags; int qcow_version; + bool use_lazy_refcounts; uint64_t incompatible_features; uint64_t compatible_features; From 9991923b262dc35f6dd8393ab4853edd7fc3724f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 4 Mar 2013 15:02:30 +0100 Subject: [PATCH 1614/1634] qcow2: flush refcount cache correctly in alloc_refcount_block() update_refcount() affects the refcount cache, it does not write to disk. Therefore bdrv_flush(bs->file) does nothing. We need to flush the refcount cache in order to write out the refcount updates! While we're here also add error returns when qcow2_cache_flush() fails. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 55543edf77..e8b5d0a4ac 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -201,7 +201,10 @@ static int alloc_refcount_block(BlockDriverState *bs, *refcount_block = NULL; /* We write to the refcount table, so we might depend on L2 tables */ - qcow2_cache_flush(bs, s->l2_table_cache); + ret = qcow2_cache_flush(bs, s->l2_table_cache); + if (ret < 0) { + return ret; + } /* Allocate the refcount block itself and mark it as used */ int64_t new_block = alloc_clusters_noref(bs, s->cluster_size); @@ -237,7 +240,10 @@ static int alloc_refcount_block(BlockDriverState *bs, goto fail_block; } - bdrv_flush(bs->file); + ret = qcow2_cache_flush(bs, s->refcount_block_cache); + if (ret < 0) { + goto fail_block; + } /* Initialize the new refcount block only after updating its refcount, * update_refcount uses the refcount cache itself */ From f6977f15561973d4a67b6aa46da88aa678c505dd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 4 Mar 2013 15:02:31 +0100 Subject: [PATCH 1615/1634] qcow2: flush refcount cache correctly in qcow2_write_snapshots() Since qcow2 metadata is cached we need to flush the caches, not just the underlying file. Use bdrv_flush(bs) instead of bdrv_flush(bs->file). Also add the error return path when bdrv_flush() fails and move the flush after checking for qcow2_alloc_clusters() failure so that the qcow2_alloc_clusters() error return value takes precedence. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-snapshot.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index eb8fcd5549..f4719d9909 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -180,11 +180,14 @@ static int qcow2_write_snapshots(BlockDriverState *bs) /* Allocate space for the new snapshot list */ snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size); - bdrv_flush(bs->file); offset = snapshots_offset; if (offset < 0) { return offset; } + ret = bdrv_flush(bs); + if (ret < 0) { + return ret; + } /* Write all snapshots to the new list */ for(i = 0; i < s->nb_snapshots; i++) { From c1f5bafd70a8d9366570a3de472ef108415cd631 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 4 Mar 2013 15:02:32 +0100 Subject: [PATCH 1616/1634] qcow2: set L2 cache dependency in qcow2_alloc_bytes() Compressed writes use qcow2_alloc_bytes() to allocate space with byte granularity. The affected clusters' refcounts will be incremented but we do not need to flush yet. Set a L2 cache dependency on the refcount block cache, so that the refcounts get written out before the L2 updates. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index e8b5d0a4ac..4d9df5fe95 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -669,7 +669,11 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) } } - bdrv_flush(bs->file); + /* The cluster refcount was incremented, either by qcow2_alloc_clusters() + * or explicitly by update_cluster_refcount(). Refcount blocks must be + * flushed before the caller's L2 table updates. + */ + qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache); return offset; } From 2154f24e4e3be4435f17fa4382032f95f19e2972 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 4 Mar 2013 15:02:33 +0100 Subject: [PATCH 1617/1634] qcow2: flush in qcow2_update_snapshot_refcount() Users of qcow2_update_snapshot_refcount() do not flush consistently. qcow2_snapshot_create() flushes but qcow2_snapshot_goto() and qcow2_snapshot_delete() do not. Solve this by moving the bdrv_flush() into qcow2_update_snapshot_refcount(). Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 2 +- block/qcow2-snapshot.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 4d9df5fe95..3d29d30f03 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -851,7 +851,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, } } - ret = 0; + ret = bdrv_flush(bs); fail: if (l2_table) { qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table); diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index f4719d9909..992a5c865c 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -381,11 +381,6 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) goto fail; } - ret = bdrv_flush(bs); - if (ret < 0) { - goto fail; - } - /* Append the new snapshot to the snapshot list */ new_snapshot_list = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot)); if (s->snapshots) { From f9cb2860bd12e223036b61a1f5d1444e57b7efce Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 4 Mar 2013 15:02:34 +0100 Subject: [PATCH 1618/1634] qcow2: drop flush in update_cluster_refcount() The update_cluster_refcount() function increments/decrements a cluster's refcount and then returns the new refcount value. There is no need to flush since both update_cluster_refcount() callers already take care of this: 1. qcow2_alloc_bytes() calls update_cluster_refcount() when compressed sectors will be appended to an existing cluster with enough free space. qcow2_alloc_bytes() already flushes so there is no need to do so in update_cluster_refcount(). 2. qcow2_update_snapshot_refcount() sets a cache dependency on refcounts if it needs to update L2 entries. It also flushes before completing. Removing this flush significantly speeds up qcow2 snapshot creation: $ qemu-img create -f qcow2 test.qcow2 -o size=50G,preallocation=metadata $ time qemu-img snapshot -c new test.qcow2 Time drops from more than 3 minutes to under 1 second. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 3d29d30f03..92519ea62a 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -532,8 +532,6 @@ static int update_cluster_refcount(BlockDriverState *bs, return ret; } - bdrv_flush(bs->file); - return get_refcount(bs, cluster_index); } From 3647917919dfce5f731755f0ac5955a64bc12570 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 4 Mar 2013 15:02:35 +0100 Subject: [PATCH 1619/1634] qcow2: drop unnecessary flush in qcow2_update_snapshot_refcount() We already flush when the function completes. There is no need to flush after every compressed cluster. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 92519ea62a..9bfb390519 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -790,10 +790,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, if (ret < 0) { goto fail; } - - /* TODO Flushing once for the whole function should - * be enough */ - bdrv_flush(bs->file); } /* compressed clusters are never modified */ refcount = 2; From 381b487d54ba18c73df9db8452028a330058c505 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 6 Mar 2013 18:02:01 +0100 Subject: [PATCH 1620/1634] qcow2: make is_allocated return true for zero clusters Otherwise, live migration of the top layer will miss zero clusters and let the backing file show through. This also matches what is done in qed. QCOW2_CLUSTER_ZERO clusters are invalid in v2 image files. Check this directly in qcow2_get_cluster_offset instead of replicating the test everywhere. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- block/qcow2-cluster.c | 3 +++ block/qcow2.c | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index ff9ae18e4a..d72d063e6d 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -454,6 +454,9 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK; break; case QCOW2_CLUSTER_ZERO: + if (s->qcow_version < 3) { + return -EIO; + } c = count_contiguous_clusters(nb_clusters, s->cluster_size, &l2_table[l2_index], 0, QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO); diff --git a/block/qcow2.c b/block/qcow2.c index ad43a13cb0..1f99866cf4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -621,7 +621,7 @@ static int coroutine_fn qcow2_co_is_allocated(BlockDriverState *bs, *pnum = 0; } - return (cluster_offset != 0); + return (cluster_offset != 0) || (ret == QCOW2_CLUSTER_ZERO); } /* handle reading after the end of the backing file */ @@ -702,10 +702,6 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, break; case QCOW2_CLUSTER_ZERO: - if (s->qcow_version < 3) { - ret = -EIO; - goto fail; - } qemu_iovec_memset(&hd_qiov, 0, 0, 512 * cur_nr_sectors); break; From 0d6db300cd95339cec6b8ab2ef46bd7cdb040959 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Tue, 12 Mar 2013 16:05:42 +0900 Subject: [PATCH 1621/1634] sheepdog: use non-blocking fd in coroutine context Using a blocking socket in the coroutine context reduces the chance of switching to other work. This patch makes the sheepdog driver use a non-blocking fd always. Signed-off-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index c711c28613..27abef2129 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -468,6 +468,8 @@ static int connect_to_sdog(BDRVSheepdogState *s) if (err != NULL) { qerror_report_err(err); error_free(err); + } else { + socket_set_nonblock(fd); } return fd; @@ -523,7 +525,6 @@ static coroutine_fn void do_co_req(void *opaque) co = qemu_coroutine_self(); qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, NULL, co); - socket_set_block(sockfd); ret = send_co_req(sockfd, hdr, data, wlen); if (ret < 0) { goto out; @@ -553,7 +554,6 @@ static coroutine_fn void do_co_req(void *opaque) ret = 0; out: qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL, NULL); - socket_set_nonblock(sockfd); srco->ret = ret; srco->finished = true; @@ -776,8 +776,6 @@ static int get_sheep_fd(BDRVSheepdogState *s) return fd; } - socket_set_nonblock(fd); - qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s); return fd; } From ed9ba7246758e3250849bfa0a055b4eb98fc5152 Mon Sep 17 00:00:00 2001 From: MORITA Kazutaka Date: Tue, 12 Mar 2013 16:05:43 +0900 Subject: [PATCH 1622/1634] sheepdog: set io_flush handler in do_co_req If an io_flush handler is not set, qemu_aio_wait doesn't invoke callbacks. Signed-off-by: MORITA Kazutaka Signed-off-by: Stefan Hajnoczi --- block/sheepdog.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 27abef2129..4245328569 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -501,6 +501,13 @@ static void restart_co_req(void *opaque) qemu_coroutine_enter(co, NULL); } +static int have_co_req(void *opaque) +{ + /* this handler is set only when there is a pending request, so + * always returns 1. */ + return 1; +} + typedef struct SheepdogReqCo { int sockfd; SheepdogReq *hdr; @@ -523,14 +530,14 @@ static coroutine_fn void do_co_req(void *opaque) unsigned int *rlen = srco->rlen; co = qemu_coroutine_self(); - qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, NULL, co); + qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, have_co_req, co); ret = send_co_req(sockfd, hdr, data, wlen); if (ret < 0) { goto out; } - qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, NULL, co); + qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, have_co_req, co); ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr)); if (ret < sizeof(*hdr)) { @@ -553,6 +560,8 @@ static coroutine_fn void do_co_req(void *opaque) } ret = 0; out: + /* there is at most one request for this sockfd, so it is safe to + * set each handler to NULL. */ qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL, NULL); srco->ret = ret; From 5f3aa1ff4781f39e05b9892d58319a09fedc8918 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Mar 2013 13:41:44 +0100 Subject: [PATCH 1623/1634] main-loop: add qemu_get_aio_context() It is very useful to get the main loop AioContext, which is a static variable in main-loop.c. I'm not sure whether qemu_get_aio_context() will be necessary in the future once devices focus on using their own AioContext instead of the main loop AioContext, but for now it allows us to refactor code to support multiple AioContext while actually passing the main loop AioContext. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini --- include/qemu/main-loop.h | 5 +++++ main-loop.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 09952885a9..6f0200a7ac 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -81,6 +81,11 @@ int qemu_init_main_loop(void); */ int main_loop_wait(int nonblocking); +/** + * qemu_get_aio_context: Return the main loop's AioContext + */ +AioContext *qemu_get_aio_context(void); + /** * qemu_notify_event: Force processing of pending events. * diff --git a/main-loop.c b/main-loop.c index 8c9b58c14c..eb80ff369f 100644 --- a/main-loop.c +++ b/main-loop.c @@ -109,6 +109,11 @@ static int qemu_signal_init(void) static AioContext *qemu_aio_context; +AioContext *qemu_get_aio_context(void) +{ + return qemu_aio_context; +} + void qemu_notify_event(void) { if (!qemu_aio_context) { From b811203cf2fbf83e26f8e8feb2c77784259a4cbd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Mar 2013 13:41:45 +0100 Subject: [PATCH 1624/1634] threadpool: move globals into struct ThreadPool Move global variables into a struct so multiple thread pools can be supported in the future. This patch does not change thread-pool.h interfaces. There is still a global thread pool and it is not yet possible to create/destroy individual thread pools. Moving the variables into a struct first makes later patches easier to review. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini --- thread-pool.c | 184 +++++++++++++++++++++++++++++--------------------- trace-events | 4 +- 2 files changed, 109 insertions(+), 79 deletions(-) diff --git a/thread-pool.c b/thread-pool.c index e3ca64d790..a0aecd08fe 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -24,7 +24,9 @@ #include "qemu/event_notifier.h" #include "block/thread-pool.h" -static void do_spawn_thread(void); +typedef struct ThreadPool ThreadPool; + +static void do_spawn_thread(ThreadPool *pool); typedef struct ThreadPoolElement ThreadPoolElement; @@ -37,6 +39,7 @@ enum ThreadState { struct ThreadPoolElement { BlockDriverAIOCB common; + ThreadPool *pool; ThreadPoolFunc *func; void *arg; @@ -54,49 +57,56 @@ struct ThreadPoolElement { QLIST_ENTRY(ThreadPoolElement) all; }; -static EventNotifier notifier; -static QemuMutex lock; -static QemuCond check_cancel; -static QemuSemaphore sem; -static int max_threads = 64; -static QEMUBH *new_thread_bh; +struct ThreadPool { + EventNotifier notifier; + QemuMutex lock; + QemuCond check_cancel; + QemuSemaphore sem; + int max_threads; + QEMUBH *new_thread_bh; -/* The following variables are protected by the global mutex. */ -static QLIST_HEAD(, ThreadPoolElement) head; + /* The following variables are only accessed from one AioContext. */ + QLIST_HEAD(, ThreadPoolElement) head; -/* The following variables are protected by lock. */ -static QTAILQ_HEAD(, ThreadPoolElement) request_list; -static int cur_threads; -static int idle_threads; -static int new_threads; /* backlog of threads we need to create */ -static int pending_threads; /* threads created but not running yet */ -static int pending_cancellations; /* whether we need a cond_broadcast */ + /* The following variables are protected by lock. */ + QTAILQ_HEAD(, ThreadPoolElement) request_list; + int cur_threads; + int idle_threads; + int new_threads; /* backlog of threads we need to create */ + int pending_threads; /* threads created but not running yet */ + int pending_cancellations; /* whether we need a cond_broadcast */ +}; -static void *worker_thread(void *unused) +/* Currently there is only one thread pool instance. */ +static ThreadPool global_pool; + +static void *worker_thread(void *opaque) { - qemu_mutex_lock(&lock); - pending_threads--; - do_spawn_thread(); + ThreadPool *pool = opaque; + + qemu_mutex_lock(&pool->lock); + pool->pending_threads--; + do_spawn_thread(pool); while (1) { ThreadPoolElement *req; int ret; do { - idle_threads++; - qemu_mutex_unlock(&lock); - ret = qemu_sem_timedwait(&sem, 10000); - qemu_mutex_lock(&lock); - idle_threads--; - } while (ret == -1 && !QTAILQ_EMPTY(&request_list)); + pool->idle_threads++; + qemu_mutex_unlock(&pool->lock); + ret = qemu_sem_timedwait(&pool->sem, 10000); + qemu_mutex_lock(&pool->lock); + pool->idle_threads--; + } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list)); if (ret == -1) { break; } - req = QTAILQ_FIRST(&request_list); - QTAILQ_REMOVE(&request_list, req, reqs); + req = QTAILQ_FIRST(&pool->request_list); + QTAILQ_REMOVE(&pool->request_list, req, reqs); req->state = THREAD_ACTIVE; - qemu_mutex_unlock(&lock); + qemu_mutex_unlock(&pool->lock); ret = req->func(req->arg); @@ -105,45 +115,47 @@ static void *worker_thread(void *unused) smp_wmb(); req->state = THREAD_DONE; - qemu_mutex_lock(&lock); - if (pending_cancellations) { - qemu_cond_broadcast(&check_cancel); + qemu_mutex_lock(&pool->lock); + if (pool->pending_cancellations) { + qemu_cond_broadcast(&pool->check_cancel); } - event_notifier_set(¬ifier); + event_notifier_set(&pool->notifier); } - cur_threads--; - qemu_mutex_unlock(&lock); + pool->cur_threads--; + qemu_mutex_unlock(&pool->lock); return NULL; } -static void do_spawn_thread(void) +static void do_spawn_thread(ThreadPool *pool) { QemuThread t; /* Runs with lock taken. */ - if (!new_threads) { + if (!pool->new_threads) { return; } - new_threads--; - pending_threads++; + pool->new_threads--; + pool->pending_threads++; - qemu_thread_create(&t, worker_thread, NULL, QEMU_THREAD_DETACHED); + qemu_thread_create(&t, worker_thread, pool, QEMU_THREAD_DETACHED); } static void spawn_thread_bh_fn(void *opaque) { - qemu_mutex_lock(&lock); - do_spawn_thread(); - qemu_mutex_unlock(&lock); + ThreadPool *pool = opaque; + + qemu_mutex_lock(&pool->lock); + do_spawn_thread(pool); + qemu_mutex_unlock(&pool->lock); } -static void spawn_thread(void) +static void spawn_thread(ThreadPool *pool) { - cur_threads++; - new_threads++; + pool->cur_threads++; + pool->new_threads++; /* If there are threads being created, they will spawn new workers, so * we don't spend time creating many threads in a loop holding a mutex or * starving the current vcpu. @@ -151,23 +163,25 @@ static void spawn_thread(void) * If there are no idle threads, ask the main thread to create one, so we * inherit the correct affinity instead of the vcpu affinity. */ - if (!pending_threads) { - qemu_bh_schedule(new_thread_bh); + if (!pool->pending_threads) { + qemu_bh_schedule(pool->new_thread_bh); } } static void event_notifier_ready(EventNotifier *notifier) { + ThreadPool *pool = container_of(notifier, ThreadPool, notifier); ThreadPoolElement *elem, *next; event_notifier_test_and_clear(notifier); restart: - QLIST_FOREACH_SAFE(elem, &head, all, next) { + QLIST_FOREACH_SAFE(elem, &pool->head, all, next) { if (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) { continue; } if (elem->state == THREAD_DONE) { - trace_thread_pool_complete(elem, elem->common.opaque, elem->ret); + trace_thread_pool_complete(pool, elem, elem->common.opaque, + elem->ret); } if (elem->state == THREAD_DONE && elem->common.cb) { QLIST_REMOVE(elem, all); @@ -186,34 +200,36 @@ restart: static int thread_pool_active(EventNotifier *notifier) { - return !QLIST_EMPTY(&head); + ThreadPool *pool = container_of(notifier, ThreadPool, notifier); + return !QLIST_EMPTY(&pool->head); } static void thread_pool_cancel(BlockDriverAIOCB *acb) { ThreadPoolElement *elem = (ThreadPoolElement *)acb; + ThreadPool *pool = elem->pool; trace_thread_pool_cancel(elem, elem->common.opaque); - qemu_mutex_lock(&lock); + qemu_mutex_lock(&pool->lock); if (elem->state == THREAD_QUEUED && /* No thread has yet started working on elem. we can try to "steal" * the item from the worker if we can get a signal from the * semaphore. Because this is non-blocking, we can do it with * the lock taken and ensure that elem will remain THREAD_QUEUED. */ - qemu_sem_timedwait(&sem, 0) == 0) { - QTAILQ_REMOVE(&request_list, elem, reqs); + qemu_sem_timedwait(&pool->sem, 0) == 0) { + QTAILQ_REMOVE(&pool->request_list, elem, reqs); elem->state = THREAD_CANCELED; - event_notifier_set(¬ifier); + event_notifier_set(&pool->notifier); } else { - pending_cancellations++; + pool->pending_cancellations++; while (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) { - qemu_cond_wait(&check_cancel, &lock); + qemu_cond_wait(&pool->check_cancel, &pool->lock); } - pending_cancellations--; + pool->pending_cancellations--; } - qemu_mutex_unlock(&lock); + qemu_mutex_unlock(&pool->lock); } static const AIOCBInfo thread_pool_aiocb_info = { @@ -224,24 +240,26 @@ static const AIOCBInfo thread_pool_aiocb_info = { BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, BlockDriverCompletionFunc *cb, void *opaque) { + ThreadPool *pool = &global_pool; ThreadPoolElement *req; req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque); req->func = func; req->arg = arg; req->state = THREAD_QUEUED; + req->pool = pool; - QLIST_INSERT_HEAD(&head, req, all); + QLIST_INSERT_HEAD(&pool->head, req, all); - trace_thread_pool_submit(req, arg); + trace_thread_pool_submit(pool, req, arg); - qemu_mutex_lock(&lock); - if (idle_threads == 0 && cur_threads < max_threads) { - spawn_thread(); + qemu_mutex_lock(&pool->lock); + if (pool->idle_threads == 0 && pool->cur_threads < pool->max_threads) { + spawn_thread(pool); } - QTAILQ_INSERT_TAIL(&request_list, req, reqs); - qemu_mutex_unlock(&lock); - qemu_sem_post(&sem); + QTAILQ_INSERT_TAIL(&pool->request_list, req, reqs); + qemu_mutex_unlock(&pool->lock); + qemu_sem_post(&pool->sem); return &req->common; } @@ -272,18 +290,30 @@ void thread_pool_submit(ThreadPoolFunc *func, void *arg) thread_pool_submit_aio(func, arg, NULL, NULL); } +static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) +{ + if (!ctx) { + ctx = qemu_get_aio_context(); + } + + memset(pool, 0, sizeof(*pool)); + event_notifier_init(&pool->notifier, false); + qemu_mutex_init(&pool->lock); + qemu_cond_init(&pool->check_cancel); + qemu_sem_init(&pool->sem, 0); + pool->max_threads = 64; + pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); + + QLIST_INIT(&pool->head); + QTAILQ_INIT(&pool->request_list); + + aio_set_event_notifier(ctx, &pool->notifier, event_notifier_ready, + thread_pool_active); +} + static void thread_pool_init(void) { - QLIST_INIT(&head); - event_notifier_init(¬ifier, false); - qemu_mutex_init(&lock); - qemu_cond_init(&check_cancel); - qemu_sem_init(&sem, 0); - qemu_aio_set_event_notifier(¬ifier, event_notifier_ready, - thread_pool_active); - - QTAILQ_INIT(&request_list); - new_thread_bh = qemu_bh_new(spawn_thread_bh_fn, NULL); + thread_pool_init_one(&global_pool, NULL); } block_init(thread_pool_init) diff --git a/trace-events b/trace-events index d6a847d18a..cd73b7f3ea 100644 --- a/trace-events +++ b/trace-events @@ -115,8 +115,8 @@ virtio_blk_data_plane_complete_request(void *s, unsigned int head, int ret) "dat vring_setup(uint64_t physical, void *desc, void *avail, void *used) "vring physical %#"PRIx64" desc %p avail %p used %p" # thread-pool.c -thread_pool_submit(void *req, void *opaque) "req %p opaque %p" -thread_pool_complete(void *req, void *opaque, int ret) "req %p opaque %p ret %d" +thread_pool_submit(void *pool, void *req, void *opaque) "pool %p req %p opaque %p" +thread_pool_complete(void *pool, void *req, void *opaque, int ret) "pool %p req %p opaque %p ret %d" thread_pool_cancel(void *req, void *opaque) "req %p opaque %p" # posix-aio-compat.c From f7311ccc630d925e7351e9440b7ad8bc6f0a51de Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Mar 2013 13:41:46 +0100 Subject: [PATCH 1625/1634] threadpool: add thread_pool_new() and thread_pool_free() ThreadPool is tied to an AioContext through its event notifier, which dictates in which AioContext the work item's callback function will be invoked. In order to support multiple AioContexts we need to support multiple ThreadPool instances. This patch adds the new/free functions. The free function deserves special attention because it quiesces remaining worker threads. This requires a new condition variable and a "stopping" flag to let workers know they should terminate once idle. We never needed to do this before since the global threadpool was not explicitly destroyed until process termination. Also stash the AioContext pointer in ThreadPool so that we can call aio_set_event_notifier() in thread_pool_free(). We didn't need to hold onto AioContext previously since there was no free function. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini --- include/block/thread-pool.h | 5 ++++ thread-pool.c | 52 ++++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h index 200703e35f..e1453c685d 100644 --- a/include/block/thread-pool.h +++ b/include/block/thread-pool.h @@ -26,6 +26,11 @@ typedef int ThreadPoolFunc(void *opaque); +typedef struct ThreadPool ThreadPool; + +ThreadPool *thread_pool_new(struct AioContext *ctx); +void thread_pool_free(ThreadPool *pool); + BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, BlockDriverCompletionFunc *cb, void *opaque); int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg); diff --git a/thread-pool.c b/thread-pool.c index a0aecd08fe..d1e4570829 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -24,8 +24,6 @@ #include "qemu/event_notifier.h" #include "block/thread-pool.h" -typedef struct ThreadPool ThreadPool; - static void do_spawn_thread(ThreadPool *pool); typedef struct ThreadPoolElement ThreadPoolElement; @@ -59,8 +57,10 @@ struct ThreadPoolElement { struct ThreadPool { EventNotifier notifier; + AioContext *ctx; QemuMutex lock; QemuCond check_cancel; + QemuCond worker_stopped; QemuSemaphore sem; int max_threads; QEMUBH *new_thread_bh; @@ -75,6 +75,7 @@ struct ThreadPool { int new_threads; /* backlog of threads we need to create */ int pending_threads; /* threads created but not running yet */ int pending_cancellations; /* whether we need a cond_broadcast */ + bool stopping; }; /* Currently there is only one thread pool instance. */ @@ -88,7 +89,7 @@ static void *worker_thread(void *opaque) pool->pending_threads--; do_spawn_thread(pool); - while (1) { + while (!pool->stopping) { ThreadPoolElement *req; int ret; @@ -99,7 +100,7 @@ static void *worker_thread(void *opaque) qemu_mutex_lock(&pool->lock); pool->idle_threads--; } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list)); - if (ret == -1) { + if (ret == -1 || pool->stopping) { break; } @@ -124,6 +125,7 @@ static void *worker_thread(void *opaque) } pool->cur_threads--; + qemu_cond_signal(&pool->worker_stopped); qemu_mutex_unlock(&pool->lock); return NULL; } @@ -298,8 +300,10 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) memset(pool, 0, sizeof(*pool)); event_notifier_init(&pool->notifier, false); + pool->ctx = ctx; qemu_mutex_init(&pool->lock); qemu_cond_init(&pool->check_cancel); + qemu_cond_init(&pool->worker_stopped); qemu_sem_init(&pool->sem, 0); pool->max_threads = 64; pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool); @@ -311,6 +315,46 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) thread_pool_active); } +ThreadPool *thread_pool_new(AioContext *ctx) +{ + ThreadPool *pool = g_new(ThreadPool, 1); + thread_pool_init_one(pool, ctx); + return pool; +} + +void thread_pool_free(ThreadPool *pool) +{ + if (!pool) { + return; + } + + assert(QLIST_EMPTY(&pool->head)); + + qemu_mutex_lock(&pool->lock); + + /* Stop new threads from spawning */ + qemu_bh_delete(pool->new_thread_bh); + pool->cur_threads -= pool->new_threads; + pool->new_threads = 0; + + /* Wait for worker threads to terminate */ + pool->stopping = true; + while (pool->cur_threads > 0) { + qemu_sem_post(&pool->sem); + qemu_cond_wait(&pool->worker_stopped, &pool->lock); + } + + qemu_mutex_unlock(&pool->lock); + + aio_set_event_notifier(pool->ctx, &pool->notifier, NULL, NULL); + qemu_sem_destroy(&pool->sem); + qemu_cond_destroy(&pool->check_cancel); + qemu_cond_destroy(&pool->worker_stopped); + qemu_mutex_destroy(&pool->lock); + event_notifier_cleanup(&pool->notifier); + g_free(pool); +} + static void thread_pool_init(void) { thread_pool_init_one(&global_pool, NULL); From 9b34277d23a6fb15eb9513006c96d8026beeea1f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Mar 2013 13:41:47 +0100 Subject: [PATCH 1626/1634] aio: add a ThreadPool instance to AioContext This patch adds a ThreadPool to AioContext. It's possible that some AioContext instances will never use the ThreadPool, so defer creation until aio_get_thread_pool(). The reason why AioContext should have the ThreadPool is because the ThreadPool is bound to a AioContext instance where the work item's callback function is invoked. It doesn't make sense to keep the ThreadPool pointer anywhere other than AioContext. For example, block/raw-posix.c can get its AioContext's ThreadPool and submit work. Special note about headers: I used struct ThreadPool in aio.h because there is a circular dependency if aio.h includes thread-pool.h. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini --- async.c | 11 +++++++++++ include/block/aio.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/async.c b/async.c index f2d47ba96d..90fe906539 100644 --- a/async.c +++ b/async.c @@ -24,6 +24,7 @@ #include "qemu-common.h" #include "block/aio.h" +#include "block/thread-pool.h" #include "qemu/main-loop.h" /***********************************************************/ @@ -172,6 +173,7 @@ aio_ctx_finalize(GSource *source) { AioContext *ctx = (AioContext *) source; + thread_pool_free(ctx->thread_pool); aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL); event_notifier_cleanup(&ctx->notifier); g_array_free(ctx->pollfds, TRUE); @@ -190,6 +192,14 @@ GSource *aio_get_g_source(AioContext *ctx) return &ctx->source; } +ThreadPool *aio_get_thread_pool(AioContext *ctx) +{ + if (!ctx->thread_pool) { + ctx->thread_pool = thread_pool_new(ctx); + } + return ctx->thread_pool; +} + void aio_notify(AioContext *ctx) { event_notifier_set(&ctx->notifier); @@ -200,6 +210,7 @@ AioContext *aio_context_new(void) AioContext *ctx; ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext)); ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD)); + ctx->thread_pool = NULL; event_notifier_init(&ctx->notifier, false); aio_set_event_notifier(ctx, &ctx->notifier, (EventNotifierHandler *) diff --git a/include/block/aio.h b/include/block/aio.h index 5b54d383fc..183679374f 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -66,6 +66,9 @@ typedef struct AioContext { /* GPollFDs for aio_poll() */ GArray *pollfds; + + /* Thread pool for performing work and receiving completion callbacks */ + struct ThreadPool *thread_pool; } AioContext; /* Returns 1 if there are still outstanding AIO requests; 0 otherwise */ @@ -223,6 +226,9 @@ void aio_set_event_notifier(AioContext *ctx, */ GSource *aio_get_g_source(AioContext *ctx); +/* Return the ThreadPool bound to this AioContext */ +struct ThreadPool *aio_get_thread_pool(AioContext *ctx); + /* Functions to operate on the main QEMU AioContext. */ bool qemu_aio_wait(void); From 85d126f3ee666702ac514c66606c62d276c4341c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Mar 2013 13:41:48 +0100 Subject: [PATCH 1627/1634] block: add bdrv_get_aio_context() For now bdrv_get_aio_context() is just a stub that calls qemu_aio_get_context() since the block layer is currently tied to the main loop AioContext. Add the stub now so that the block layer can begin accessing its AioContext. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini --- block.c | 6 ++++++ include/block/block_int.h | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/block.c b/block.c index 0ab164d992..037e15e065 100644 --- a/block.c +++ b/block.c @@ -4681,3 +4681,9 @@ out: bdrv_delete(bs); } } + +AioContext *bdrv_get_aio_context(BlockDriverState *bs) +{ + /* Currently BlockDriverState always uses the main loop AioContext */ + return qemu_get_aio_context(); +} diff --git a/include/block/block_int.h b/include/block/block_int.h index baf80e3c42..ce0aa26b8e 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -294,6 +294,13 @@ int get_tmp_filename(char *filename, int size); void bdrv_set_io_limits(BlockDriverState *bs, BlockIOLimit *io_limits); +/** + * bdrv_get_aio_context: + * + * Returns: the currently bound #AioContext + */ +AioContext *bdrv_get_aio_context(BlockDriverState *bs); + #ifdef _WIN32 int is_windows_drive(const char *filename); #endif From c4d9d19645a484298a67e9021060bc7c2b081d0f Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Mar 2013 13:41:49 +0100 Subject: [PATCH 1628/1634] threadpool: drop global thread pool Now that each AioContext has a ThreadPool and the main loop AioContext can be fetched with bdrv_get_aio_context(), we can eliminate the concept of a global thread pool from thread-pool.c. The submit functions must take a ThreadPool* argument. block/raw-posix.c and block/raw-win32.c use aio_get_thread_pool(bdrv_get_aio_context(bs)) to fetch the main loop's ThreadPool. tests/test-thread-pool.c must be updated to reflect the new thread_pool_submit() function prototypes. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini --- block/raw-posix.c | 8 +++++-- block/raw-win32.c | 4 +++- include/block/thread-pool.h | 10 +++++---- tests/test-thread-pool.c | 44 ++++++++++++++++++------------------- thread-pool.c | 23 ++++++------------- 5 files changed, 43 insertions(+), 46 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 4dfdf985b0..8a3cdbc1f3 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -750,6 +750,7 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd, BlockDriverCompletionFunc *cb, void *opaque, int type) { RawPosixAIOData *acb = g_slice_new(RawPosixAIOData); + ThreadPool *pool; acb->bs = bs; acb->aio_type = type; @@ -763,7 +764,8 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd, acb->aio_offset = sector_num * 512; trace_paio_submit(acb, opaque, sector_num, nb_sectors, type); - return thread_pool_submit_aio(aio_worker, acb, cb, opaque); + pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); + return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); } static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs, @@ -1413,6 +1415,7 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs, { BDRVRawState *s = bs->opaque; RawPosixAIOData *acb; + ThreadPool *pool; if (fd_open(bs) < 0) return NULL; @@ -1424,7 +1427,8 @@ static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs, acb->aio_offset = 0; acb->aio_ioctl_buf = buf; acb->aio_ioctl_cmd = req; - return thread_pool_submit_aio(aio_worker, acb, cb, opaque); + pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); + return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) diff --git a/block/raw-win32.c b/block/raw-win32.c index b89ac19ffa..18e0068b26 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -144,6 +144,7 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, BlockDriverCompletionFunc *cb, void *opaque, int type) { RawWin32AIOData *acb = g_slice_new(RawWin32AIOData); + ThreadPool *pool; acb->bs = bs; acb->hfile = hfile; @@ -157,7 +158,8 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile, acb->aio_offset = sector_num * 512; trace_paio_submit(acb, opaque, sector_num, nb_sectors, type); - return thread_pool_submit_aio(aio_worker, acb, cb, opaque); + pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); + return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); } int qemu_ftruncate64(int fd, int64_t length) diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h index e1453c685d..32afcdd1d6 100644 --- a/include/block/thread-pool.h +++ b/include/block/thread-pool.h @@ -31,9 +31,11 @@ typedef struct ThreadPool ThreadPool; ThreadPool *thread_pool_new(struct AioContext *ctx); void thread_pool_free(ThreadPool *pool); -BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, - BlockDriverCompletionFunc *cb, void *opaque); -int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg); -void thread_pool_submit(ThreadPoolFunc *func, void *arg); +BlockDriverAIOCB *thread_pool_submit_aio(ThreadPool *pool, + ThreadPoolFunc *func, void *arg, + BlockDriverCompletionFunc *cb, void *opaque); +int coroutine_fn thread_pool_submit_co(ThreadPool *pool, + ThreadPoolFunc *func, void *arg); +void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg); #endif diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c index 9998e031f2..22915aac10 100644 --- a/tests/test-thread-pool.c +++ b/tests/test-thread-pool.c @@ -4,6 +4,8 @@ #include "block/thread-pool.h" #include "block/block.h" +static AioContext *ctx; +static ThreadPool *pool; static int active; typedef struct { @@ -38,19 +40,10 @@ static void done_cb(void *opaque, int ret) active--; } -/* A non-blocking poll of the main AIO context (we cannot use aio_poll - * because we do not know the AioContext). - */ -static void qemu_aio_wait_nonblocking(void) -{ - qemu_notify_event(); - qemu_aio_wait(); -} - /* Wait until all aio and bh activity has finished */ static void qemu_aio_wait_all(void) { - while (qemu_aio_wait()) { + while (aio_poll(ctx, true)) { /* Do nothing */ } } @@ -58,7 +51,7 @@ static void qemu_aio_wait_all(void) static void test_submit(void) { WorkerTestData data = { .n = 0 }; - thread_pool_submit(worker_cb, &data); + thread_pool_submit(pool, worker_cb, &data); qemu_aio_wait_all(); g_assert_cmpint(data.n, ==, 1); } @@ -66,7 +59,8 @@ static void test_submit(void) static void test_submit_aio(void) { WorkerTestData data = { .n = 0, .ret = -EINPROGRESS }; - data.aiocb = thread_pool_submit_aio(worker_cb, &data, done_cb, &data); + data.aiocb = thread_pool_submit_aio(pool, worker_cb, &data, + done_cb, &data); /* The callbacks are not called until after the first wait. */ active = 1; @@ -84,7 +78,7 @@ static void co_test_cb(void *opaque) active = 1; data->n = 0; data->ret = -EINPROGRESS; - thread_pool_submit_co(worker_cb, data); + thread_pool_submit_co(pool, worker_cb, data); /* The test continues in test_submit_co, after qemu_coroutine_enter... */ @@ -126,12 +120,12 @@ static void test_submit_many(void) for (i = 0; i < 100; i++) { data[i].n = 0; data[i].ret = -EINPROGRESS; - thread_pool_submit_aio(worker_cb, &data[i], done_cb, &data[i]); + thread_pool_submit_aio(pool, worker_cb, &data[i], done_cb, &data[i]); } active = 100; while (active > 0) { - qemu_aio_wait(); + aio_poll(ctx, true); } for (i = 0; i < 100; i++) { g_assert_cmpint(data[i].n, ==, 1); @@ -154,7 +148,7 @@ static void test_cancel(void) for (i = 0; i < 100; i++) { data[i].n = 0; data[i].ret = -EINPROGRESS; - data[i].aiocb = thread_pool_submit_aio(long_cb, &data[i], + data[i].aiocb = thread_pool_submit_aio(pool, long_cb, &data[i], done_cb, &data[i]); } @@ -162,7 +156,8 @@ static void test_cancel(void) * run, but do not waste too much time... */ active = 100; - qemu_aio_wait_nonblocking(); + aio_notify(ctx); + aio_poll(ctx, false); /* Wait some time for the threads to start, with some sanity * testing on the behavior of the scheduler... @@ -208,11 +203,10 @@ static void test_cancel(void) int main(int argc, char **argv) { - /* These should be removed once each AioContext has its thread pool. - * The test should create its own AioContext. - */ - qemu_init_main_loop(); - bdrv_init(); + int ret; + + ctx = aio_context_new(); + pool = aio_get_thread_pool(ctx); g_test_init(&argc, &argv, NULL); g_test_add_func("/thread-pool/submit", test_submit); @@ -220,5 +214,9 @@ int main(int argc, char **argv) g_test_add_func("/thread-pool/submit-co", test_submit_co); g_test_add_func("/thread-pool/submit-many", test_submit_many); g_test_add_func("/thread-pool/cancel", test_cancel); - return g_test_run(); + + ret = g_test_run(); + + aio_context_unref(ctx); + return ret; } diff --git a/thread-pool.c b/thread-pool.c index d1e4570829..0ebd4c2964 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -78,9 +78,6 @@ struct ThreadPool { bool stopping; }; -/* Currently there is only one thread pool instance. */ -static ThreadPool global_pool; - static void *worker_thread(void *opaque) { ThreadPool *pool = opaque; @@ -239,10 +236,10 @@ static const AIOCBInfo thread_pool_aiocb_info = { .cancel = thread_pool_cancel, }; -BlockDriverAIOCB *thread_pool_submit_aio(ThreadPoolFunc *func, void *arg, +BlockDriverAIOCB *thread_pool_submit_aio(ThreadPool *pool, + ThreadPoolFunc *func, void *arg, BlockDriverCompletionFunc *cb, void *opaque) { - ThreadPool *pool = &global_pool; ThreadPoolElement *req; req = qemu_aio_get(&thread_pool_aiocb_info, NULL, cb, opaque); @@ -278,18 +275,19 @@ static void thread_pool_co_cb(void *opaque, int ret) qemu_coroutine_enter(co->co, NULL); } -int coroutine_fn thread_pool_submit_co(ThreadPoolFunc *func, void *arg) +int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func, + void *arg) { ThreadPoolCo tpc = { .co = qemu_coroutine_self(), .ret = -EINPROGRESS }; assert(qemu_in_coroutine()); - thread_pool_submit_aio(func, arg, thread_pool_co_cb, &tpc); + thread_pool_submit_aio(pool, func, arg, thread_pool_co_cb, &tpc); qemu_coroutine_yield(); return tpc.ret; } -void thread_pool_submit(ThreadPoolFunc *func, void *arg) +void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg) { - thread_pool_submit_aio(func, arg, NULL, NULL); + thread_pool_submit_aio(pool, func, arg, NULL, NULL); } static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx) @@ -354,10 +352,3 @@ void thread_pool_free(ThreadPool *pool) event_notifier_cleanup(&pool->notifier); g_free(pool); } - -static void thread_pool_init(void) -{ - thread_pool_init_one(&global_pool, NULL); -} - -block_init(thread_pool_init) From 28f082469650a0f4c0e37b4ccd6f9514b1a0698d Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Mar 2013 13:41:50 +0100 Subject: [PATCH 1629/1634] coroutine: use AioContext for CoQueue BH CoQueue uses a BH to awake coroutines that were made ready to run again using qemu_co_queue_next() or qemu_co_queue_restart_all(). The BH currently runs in the iothread AioContext and would break coroutines that run in a different AioContext. This is a slightly tricky problem because the lifetime of the BH exceeds that of the CoQueue. This means coroutines can be awoken after CoQueue itself has been freed. Also, there is no qemu_co_queue_destroy() function which we could use to handle freeing resources. Introducing qemu_co_queue_destroy() has a ripple effect of requiring us to also add qemu_co_mutex_destroy() and qemu_co_rwlock_destroy(), as well as updating all callers. Avoid doing that. We also cannot switch from BH to GIdle function because aio_poll() does not dispatch GIdle functions. (GIdle functions make memory management slightly easier because they free themselves.) Finally, I don't want to move unlock_queue and unlock_bh into AioContext. That would break encapsulation - AioContext isn't supposed to know about CoQueue. This patch implements a different solution: each qemu_co_queue_next() or qemu_co_queue_restart_all() call creates a new BH and list of coroutines to wake up. Callers tend to invoke qemu_co_queue_next() and qemu_co_queue_restart_all() occasionally after blocking I/O, so creating a new BH for each call shouldn't be massively inefficient. Note that this patch does not add an interface for specifying the AioContext. That is left to future patches which will convert CoQueue, CoMutex, and CoRwlock to expose AioContext. Signed-off-by: Stefan Hajnoczi Reviewed-by: Paolo Bonzini --- include/block/coroutine.h | 1 + qemu-coroutine-lock.c | 59 ++++++++++++++++++++++++++------------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/include/block/coroutine.h b/include/block/coroutine.h index c31fae3f3c..a978162a3f 100644 --- a/include/block/coroutine.h +++ b/include/block/coroutine.h @@ -104,6 +104,7 @@ bool qemu_in_coroutine(void); */ typedef struct CoQueue { QTAILQ_HEAD(, Coroutine) entries; + AioContext *ctx; } CoQueue; /** diff --git a/qemu-coroutine-lock.c b/qemu-coroutine-lock.c index 97ef01c796..86efe1f86a 100644 --- a/qemu-coroutine-lock.c +++ b/qemu-coroutine-lock.c @@ -29,28 +29,36 @@ #include "block/aio.h" #include "trace.h" -static QTAILQ_HEAD(, Coroutine) unlock_bh_queue = - QTAILQ_HEAD_INITIALIZER(unlock_bh_queue); -static QEMUBH* unlock_bh; +/* Coroutines are awoken from a BH to allow the current coroutine to complete + * its flow of execution. The BH may run after the CoQueue has been destroyed, + * so keep BH data in a separate heap-allocated struct. + */ +typedef struct { + QEMUBH *bh; + QTAILQ_HEAD(, Coroutine) entries; +} CoQueueNextData; static void qemu_co_queue_next_bh(void *opaque) { + CoQueueNextData *data = opaque; Coroutine *next; trace_qemu_co_queue_next_bh(); - while ((next = QTAILQ_FIRST(&unlock_bh_queue))) { - QTAILQ_REMOVE(&unlock_bh_queue, next, co_queue_next); + while ((next = QTAILQ_FIRST(&data->entries))) { + QTAILQ_REMOVE(&data->entries, next, co_queue_next); qemu_coroutine_enter(next, NULL); } + + qemu_bh_delete(data->bh); + g_slice_free(CoQueueNextData, data); } void qemu_co_queue_init(CoQueue *queue) { QTAILQ_INIT(&queue->entries); - if (!unlock_bh) { - unlock_bh = qemu_bh_new(qemu_co_queue_next_bh, NULL); - } + /* This will be exposed to callers once there are multiple AioContexts */ + queue->ctx = qemu_get_aio_context(); } void coroutine_fn qemu_co_queue_wait(CoQueue *queue) @@ -69,26 +77,39 @@ void coroutine_fn qemu_co_queue_wait_insert_head(CoQueue *queue) assert(qemu_in_coroutine()); } -bool qemu_co_queue_next(CoQueue *queue) +static bool qemu_co_queue_do_restart(CoQueue *queue, bool single) { Coroutine *next; + CoQueueNextData *data; - next = QTAILQ_FIRST(&queue->entries); - if (next) { - QTAILQ_REMOVE(&queue->entries, next, co_queue_next); - QTAILQ_INSERT_TAIL(&unlock_bh_queue, next, co_queue_next); - trace_qemu_co_queue_next(next); - qemu_bh_schedule(unlock_bh); + if (QTAILQ_EMPTY(&queue->entries)) { + return false; } - return (next != NULL); + data = g_slice_new(CoQueueNextData); + data->bh = aio_bh_new(queue->ctx, qemu_co_queue_next_bh, data); + QTAILQ_INIT(&data->entries); + qemu_bh_schedule(data->bh); + + while ((next = QTAILQ_FIRST(&queue->entries)) != NULL) { + QTAILQ_REMOVE(&queue->entries, next, co_queue_next); + QTAILQ_INSERT_TAIL(&data->entries, next, co_queue_next); + trace_qemu_co_queue_next(next); + if (single) { + break; + } + } + return true; +} + +bool qemu_co_queue_next(CoQueue *queue) +{ + return qemu_co_queue_do_restart(queue, true); } void qemu_co_queue_restart_all(CoQueue *queue) { - while (qemu_co_queue_next(queue)) { - /* Do nothing */ - } + qemu_co_queue_do_restart(queue, false); } bool qemu_co_queue_empty(CoQueue *queue) From 485e3ce88e8af0e5311dd626f399b3a1e0846dd6 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 13 Mar 2013 15:14:15 +0100 Subject: [PATCH 1630/1634] dataplane: fix hang introduced by AioContext transition The bug is that the EventNotifiers do have a NULL io_flush callback. Because _none_ of the callbacks on the dataplane AioContext have such a callback, aio_poll will simply do nothing. Fixed by adding the callbacks: the ioeventfd will always be polled (this can change in the future to pause/resume the processing during live snapshots or similar operations); the ioqueue will be polled if there are outstanding requests. I must admit I have screwed up my testing somehow, because commit 2c20e71 does not work even if cherry-picked on top of 1.4.0, and this patch fixes it there as well. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- hw/dataplane/virtio-blk.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c index dfe5f9b9cd..1242d61e71 100644 --- a/hw/dataplane/virtio-blk.c +++ b/hw/dataplane/virtio-blk.c @@ -263,6 +263,11 @@ static int process_request(IOQueue *ioq, struct iovec iov[], } } +static int flush_true(EventNotifier *e) +{ + return true; +} + static void handle_notify(EventNotifier *e) { VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, @@ -342,6 +347,14 @@ static void handle_notify(EventNotifier *e) } } +static int flush_io(EventNotifier *e) +{ + VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, + io_notifier); + + return s->num_reqs > 0; +} + static void handle_io(EventNotifier *e) { VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, @@ -472,7 +485,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) exit(1); } s->host_notifier = *virtio_queue_get_host_notifier(vq); - aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify, NULL); + aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify, flush_true); /* Set up ioqueue */ ioq_init(&s->ioqueue, s->fd, REQ_MAX); @@ -480,7 +493,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb); } s->io_notifier = *ioq_get_notifier(&s->ioqueue); - aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io, NULL); + aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io, flush_io); s->started = true; trace_virtio_blk_data_plane_start(s); From acbf30ec601b1f817febc4500025b7c4181312c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 13 Mar 2013 15:58:13 +0100 Subject: [PATCH 1631/1634] qemu-iotests: add tests for rebasing zero clusters If zero clusters are erroneously treated as unallocated, "qemu-img rebase" will copy the backing file's contents onto the cluster. The bug existed also in image streaming, but since the root cause was in qcow2's is_allocated implementation it is enough to test it with qemu-img. Signed-off-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/050 | 75 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/050.out | 17 +++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 93 insertions(+) create mode 100755 tests/qemu-iotests/050 create mode 100644 tests/qemu-iotests/050.out diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050 new file mode 100755 index 0000000000..05793e2d4b --- /dev/null +++ b/tests/qemu-iotests/050 @@ -0,0 +1,75 @@ +#!/bin/bash +# +# Test qemu-img rebase with zero clusters +# +# Copyright (C) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# creator +owner=pbonzini@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f $TEST_IMG.old + rm -f $TEST_IMG.new +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 qed +_supported_proto file +_supported_os Linux + +if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then + IMGOPTS=compat=1.1 +fi + +echo +echo "== Creating images ==" + +size=10M +_make_test_img $size +$QEMU_IO -c "write -P 0x40 0 1048576" $TEST_IMG | _filter_qemu_io +mv $TEST_IMG $TEST_IMG.old + +_make_test_img $size +$QEMU_IO -c "write -P 0x5a 0 1048576" $TEST_IMG | _filter_qemu_io +mv $TEST_IMG $TEST_IMG.new + +_make_test_img -b $TEST_IMG.old $size +$QEMU_IO -c "write -z 0 1048576" $TEST_IMG | _filter_qemu_io + +echo +echo "== Rebasing the image ==" + +$QEMU_IMG rebase -b $TEST_IMG.new $TEST_IMG +$QEMU_IO -c "read -P 0x00 0 1048576" $TEST_IMG | _filter_qemu_io + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/050.out b/tests/qemu-iotests/050.out new file mode 100644 index 0000000000..3f5f7e1e7b --- /dev/null +++ b/tests/qemu-iotests/050.out @@ -0,0 +1,17 @@ +QA output created by 050 + +== Creating images == +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file='TEST_DIR/t.IMGFMT.old' +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Rebasing the image == +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index fcf57e0510..1d7e4f31a0 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -56,3 +56,4 @@ 047 rw auto 048 img auto quick 049 rw auto +050 rw auto backing quick From 804dd41792c8bdc0c8b34c8e580882ff8ef736d8 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 14 Mar 2013 17:06:55 +0100 Subject: [PATCH 1632/1634] qemu-iotests: use -nographic in test case 007 A comment explains that -nographic hangs test case 007. This is no longer the case so add -nographic. This makes the test suite faster and more pleasant to run since no windows pop up. I am not sure exactly when -nographic starting working for this case but there is no fundamental reason why graphics are needed here. Make sure the serial port is not on stdio, it would conflict with the monitor. Also remove unnecessary trailing whitespace on these lines. Signed-off-by: Stefan Hajnoczi Tested-by: Kevin Wolf --- tests/qemu-iotests/007 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007 index 0139264c4f..c454f2c8ec 100755 --- a/tests/qemu-iotests/007 +++ b/tests/qemu-iotests/007 @@ -50,10 +50,9 @@ _make_test_img 1M for i in `seq 1 10`; do echo "savevm $i" - # XXX(hch): adding -nographic would be good, but hangs the test - $QEMU -hda $TEST_IMG -monitor stdio >/dev/null 2>&1 </dev/null 2>&1 < Date: Thu, 14 Mar 2013 13:59:53 +0100 Subject: [PATCH 1633/1634] blockdev: Fix up copyright and permission notice Screwed up in commit 666daa68. Thanks to Kevin Wolf for reminding me to fix this. Signed-off-by: Markus Armbruster Signed-off-by: Stefan Hajnoczi --- blockdev.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/blockdev.c b/blockdev.c index 7ae619860b..09f76b782f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -5,6 +5,29 @@ * * This work is licensed under the terms of the GNU GPL, version 2 or * later. See the COPYING file in the top-level directory. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * 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 "sysemu/blockdev.h" From b1999e87b4d42305419329cae459e1b43f706d96 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 12 Mar 2013 13:57:28 +1100 Subject: [PATCH 1634/1634] Fix TAGS creation Currently the Makefile creates TAGS for emacs with the command: find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags That works only if xargs ends up invoking etags just once. If xargs runs etags several times, as it will if there are enough files, then the later invocations will overwrite the output from the earlier invocations. This patch uses the etags --append option to fix the bug. Signed-off-by: David Gibson Message-id: 1363057048-21534-1-git-send-email-david@gibson.dropbear.id.au Signed-off-by: Anthony Liguori --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 12c7662667..69151787ff 100644 --- a/Makefile +++ b/Makefile @@ -334,7 +334,8 @@ test speed: all .PHONY: TAGS TAGS: - find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags + rm -f $@ + find "$(SRC_PATH)" -name '*.[hc]' -exec etags --append {} + cscope: rm -f ./cscope.*