diff options
83 files changed, 2025 insertions, 1061 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 978b7174f3..a059d5de3b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -645,13 +645,15 @@ S: Supported F: include/hw/pci/* F: hw/pci/* -ACPI +ACPI/SMBIOS M: Michael S. Tsirkin <mst@redhat.com> M: Igor Mammedov <imammedo@redhat.com> S: Supported F: include/hw/acpi/* +F: include/hw/smbios/* F: hw/mem/* F: hw/acpi/* +F: hw/smbios/* F: hw/i386/acpi-build.[hc] F: hw/i386/*dsl F: hw/arm/virt-acpi-build.c @@ -1 +1 @@ -2.3.93 +2.4.50 diff --git a/arch_init.c b/arch_init.c index 725c638ece..38f5fb9c22 100644 --- a/arch_init.c +++ b/arch_init.c @@ -26,7 +26,7 @@ #include "sysemu/arch_init.h" #include "hw/pci/pci.h" #include "hw/audio/audio.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qmp-commands.h" diff --git a/block/mirror.c b/block/mirror.c index fc4d8f561e..94744432eb 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -60,6 +60,7 @@ typedef struct MirrorBlockJob { int sectors_in_flight; int ret; bool unmap; + bool waiting_for_io; } MirrorBlockJob; typedef struct MirrorOp { @@ -114,11 +115,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret) qemu_iovec_destroy(&op->qiov); g_slice_free(MirrorOp, op); - /* Enter coroutine when it is not sleeping. The coroutine sleeps to - * rate-limit itself. The coroutine will eventually resume since there is - * a sleep timeout so don't wake it early. - */ - if (s->common.busy) { + if (s->waiting_for_io) { qemu_coroutine_enter(s->common.co, NULL); } } @@ -203,7 +200,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) /* Wait for I/O to this cluster (from a previous iteration) to be done. */ while (test_bit(next_chunk, s->in_flight_bitmap)) { trace_mirror_yield_in_flight(s, sector_num, s->in_flight); + s->waiting_for_io = true; qemu_coroutine_yield(); + s->waiting_for_io = false; } do { @@ -239,12 +238,18 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) */ while (nb_chunks == 0 && s->buf_free_count < added_chunks) { trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight); + s->waiting_for_io = true; qemu_coroutine_yield(); + s->waiting_for_io = false; } if (s->buf_free_count < nb_chunks + added_chunks) { trace_mirror_break_buf_busy(s, nb_chunks, s->in_flight); break; } + if (IOV_MAX < nb_chunks + added_chunks) { + trace_mirror_break_iov_max(s, nb_chunks, added_chunks); + break; + } /* We have enough free space to copy these sectors. */ bitmap_set(s->in_flight_bitmap, next_chunk, added_chunks); @@ -333,7 +338,9 @@ static void mirror_free_init(MirrorBlockJob *s) static void mirror_drain(MirrorBlockJob *s) { while (s->in_flight > 0) { + s->waiting_for_io = true; qemu_coroutine_yield(); + s->waiting_for_io = false; } } @@ -506,7 +513,9 @@ static void coroutine_fn mirror_run(void *opaque) 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); + s->waiting_for_io = true; qemu_coroutine_yield(); + s->waiting_for_io = false; continue; } else if (cnt != 0) { delay_ns = mirror_iteration(s); diff --git a/block/quorum.c b/block/quorum.c index 4e66221461..2f6c45f760 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -865,12 +865,6 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags, int i; int ret = 0; - if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) { - error_setg(errp, - "SHA256 hash support is required for quorum device"); - return -EINVAL; - } - qdict_flatten(options); /* count how many different children are present */ @@ -1061,6 +1055,10 @@ static BlockDriver bdrv_quorum = { static void bdrv_quorum_init(void) { + if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) { + /* SHA256 hash support is required for quorum device */ + return; + } bdrv_register(&bdrv_quorum); } diff --git a/blockdev.c b/blockdev.c index 62a4586cd6..4125ff642a 100644 --- a/blockdev.c +++ b/blockdev.c @@ -337,6 +337,12 @@ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp) return false; } + if (throttle_max_is_missing_limit(cfg)) { + error_setg(errp, "bps_max/iops_max require corresponding" + " bps/iops values"); + return false; + } + return true; } @@ -1337,7 +1337,6 @@ disabled with --disable-FEATURE, default is enabled if available: vnc-sasl SASL encryption for VNC server vnc-jpeg JPEG lossy compression for VNC server vnc-png PNG compression for VNC server - vnc-ws Websockets support for VNC server cocoa Cocoa UI (Mac OS X only) virtfs VirtFS xen xen backend driver support diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 48b57623f7..5eaafa18d0 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -49,3 +49,4 @@ CONFIG_MEM_HOTPLUG=y CONFIG_XIO3130=y CONFIG_IOH3420=y CONFIG_I82801B11=y +CONFIG_SMBIOS=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 4962ed70af..28e2099187 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -50,3 +50,4 @@ CONFIG_MEM_HOTPLUG=y CONFIG_XIO3130=y CONFIG_IOH3420=y CONFIG_I82801B11=y +CONFIG_SMBIOS=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 73afa41b32..7e7c241104 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -31,6 +31,7 @@ devices-dirs-$(CONFIG_VIRTIO) += virtio/ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/ devices-dirs-$(CONFIG_SOFTMMU) += xen/ devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/ +devices-dirs-$(CONFIG_SMBIOS) += smbios/ devices-dirs-y += core/ common-obj-y += $(devices-dirs-y) obj-y += $(devices-dirs-y) diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 5be0369a50..d7af230925 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -22,6 +22,7 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/char/serial.h" +#include "hw/intc/imx_avic.h" #include "hw/arm/imx.h" /* Memory map for Kzm Emulation Baseboard: @@ -106,7 +107,7 @@ static void kzm_init(MachineState *machine) memory_region_init_ram(sram, NULL, "kzm.sram", 0x4000, &error_abort); memory_region_add_subregion(address_space_mem, 0x1FFFC000, sram); - dev = sysbus_create_varargs("imx_avic", 0x68000000, + dev = sysbus_create_varargs(TYPE_IMX_AVIC, 0x68000000, qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ), qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ), NULL); @@ -114,7 +115,7 @@ static void kzm_init(MachineState *machine) imx_serial_create(0, 0x43f90000, qdev_get_gpio_in(dev, 45)); imx_serial_create(1, 0x43f94000, qdev_get_gpio_in(dev, 32)); - ccm = sysbus_create_simple("imx_ccm", 0x53f80000, NULL); + ccm = sysbus_create_simple(TYPE_IMX_CCM, 0x53f80000, NULL); imx_timerp_create(0x53f94000, qdev_get_gpio_in(dev, 28), ccm); imx_timerp_create(0x53f98000, qdev_get_gpio_in(dev, 27), ccm); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 484689264c..d5a84175c9 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -48,6 +48,8 @@ #include "hw/arm/sysbus-fdt.h" #include "hw/platform-bus.h" #include "hw/arm/fdt.h" +#include "hw/intc/arm_gic_common.h" +#include "kvm_arm.h" /* Number of external interrupt lines to configure the GIC with */ #define NUM_IRQS 256 @@ -365,12 +367,10 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) /* We create a standalone GIC v2 */ DeviceState *gicdev; SysBusDevice *gicbusdev; - const char *gictype = "arm_gic"; + const char *gictype; int i; - if (kvm_irqchip_in_kernel()) { - gictype = "kvm-arm-gic"; - } + gictype = gic_class_name(); gicdev = qdev_create(NULL, gictype); qdev_prop_set_uint32(gicdev, "revision", 2); @@ -390,15 +390,23 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) */ for (i = 0; i < smp_cpus; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); - int ppibase = NUM_IRQS + i * 32; - /* physical timer; we wire it up to the non-secure timer's ID, - * since a real A15 always has TrustZone but QEMU doesn't. + int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS; + int irq; + /* Mapping from the output timer irq lines from the CPU to the + * GIC PPI inputs we use for the virt board. */ - qdev_connect_gpio_out(cpudev, 0, - qdev_get_gpio_in(gicdev, ppibase + 30)); - /* virtual timer */ - qdev_connect_gpio_out(cpudev, 1, - qdev_get_gpio_in(gicdev, ppibase + 27)); + const int timer_irq[] = { + [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ, + [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ, + [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ, + [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ, + }; + + for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { + qdev_connect_gpio_out(cpudev, irq, + qdev_get_gpio_in(gicdev, + ppibase + timer_irq[irq])); + } sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); sysbus_connect_irq(gicbusdev, i + smp_cpus, diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index f3fbc776be..801156db2d 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -4,6 +4,7 @@ * Copyright (c) 2008 OKL * Originally Written by Hans Jiang * Copyright (c) 2011 NICTA Pty Ltd. + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -17,8 +18,7 @@ * is a real serial device. */ -#include "hw/hw.h" -#include "hw/sysbus.h" +#include "hw/char/imx_serial.h" #include "sysemu/sysemu.h" #include "sysemu/char.h" #include "hw/arm/imx.h" @@ -26,7 +26,7 @@ //#define DEBUG_SERIAL 1 #ifdef DEBUG_SERIAL #define DPRINTF(fmt, args...) \ -do { printf("imx_serial: " fmt , ##args); } while (0) +do { printf("%s: " fmt , TYPE_IMX_SERIAL, ##args); } while (0) #else #define DPRINTF(fmt, args...) do {} while (0) #endif @@ -38,42 +38,13 @@ do { printf("imx_serial: " fmt , ##args); } while (0) //#define DEBUG_IMPLEMENTATION 1 #ifdef DEBUG_IMPLEMENTATION # define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0) + do { fprintf(stderr, "%s: " fmt, TYPE_IMX_SERIAL, ##args); } while (0) #else # define IPRINTF(fmt, args...) do {} while (0) #endif -#define TYPE_IMX_SERIAL "imx-serial" -#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL) - -typedef struct IMXSerialState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - int32_t readbuff; - - uint32_t usr1; - uint32_t usr2; - uint32_t ucr1; - uint32_t ucr2; - uint32_t uts1; - - /* - * The registers below are implemented just so that the - * guest OS sees what it has written - */ - uint32_t onems; - uint32_t ufcr; - uint32_t ubmr; - uint32_t ubrc; - uint32_t ucr3; - - qemu_irq irq; - CharDriverState *chr; -} IMXSerialState; - static const VMStateDescription vmstate_imx_serial = { - .name = "imx-serial", + .name = TYPE_IMX_SERIAL, .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { @@ -91,55 +62,6 @@ static const VMStateDescription vmstate_imx_serial = { }, }; - -#define URXD_CHARRDY (1<<15) /* character read is valid */ -#define URXD_ERR (1<<14) /* Character has error */ -#define URXD_BRK (1<<11) /* Break received */ - -#define USR1_PARTYER (1<<15) /* Parity Error */ -#define USR1_RTSS (1<<14) /* RTS pin status */ -#define USR1_TRDY (1<<13) /* Tx ready */ -#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */ -#define USR1_ESCF (1<<11) /* Escape sequence interrupt */ -#define USR1_FRAMERR (1<<10) /* Framing error */ -#define USR1_RRDY (1<<9) /* receiver ready */ -#define USR1_AGTIM (1<<8) /* Aging timer interrupt */ -#define USR1_DTRD (1<<7) /* DTR changed */ -#define USR1_RXDS (1<<6) /* Receiver is idle */ -#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */ -#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */ - -#define USR2_ADET (1<<15) /* Autobaud complete */ -#define USR2_TXFE (1<<14) /* Transmit FIFO empty */ -#define USR2_DTRF (1<<13) /* DTR/DSR transition */ -#define USR2_IDLE (1<<12) /* UART has been idle for too long */ -#define USR2_ACST (1<<11) /* Autobaud counter stopped */ -#define USR2_RIDELT (1<<10) /* Ring Indicator delta */ -#define USR2_RIIN (1<<9) /* Ring Indicator Input */ -#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */ -#define USR2_WAKE (1<<7) /* Start bit detected */ -#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */ -#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */ -#define USR2_RTSF (1<<4) /* RTS transition */ -#define USR2_TXDC (1<<3) /* Transmission complete */ -#define USR2_BRCD (1<<2) /* Break condition detected */ -#define USR2_ORE (1<<1) /* Overrun error */ -#define USR2_RDR (1<<0) /* Receive data ready */ - -#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */ -#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */ -#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */ -#define UCR1_UARTEN (1<<0) /* UART Enable */ - -#define UCR2_TXEN (1<<2) /* Transmitter enable */ -#define UCR2_RXEN (1<<1) /* Receiver enable */ -#define UCR2_SRST (1<<0) /* Reset complete */ - -#define UTS1_TXEMPTY (1<<6) -#define UTS1_RXEMPTY (1<<5) -#define UTS1_TXFULL (1<<4) -#define UTS1_RXFULL (1<<3) - static void imx_update(IMXSerialState *s) { uint32_t flags; @@ -203,7 +125,9 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset, s->usr2 &= ~USR2_RDR; s->uts1 |= UTS1_RXEMPTY; imx_update(s); - qemu_chr_accept_input(s->chr); + if (s->chr) { + qemu_chr_accept_input(s->chr); + } } return c; @@ -242,13 +166,13 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset, return 0x0; /* TODO */ default: - IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset); + IPRINTF("%s: bad offset: 0x%x\n", __func__, (int)offset); return 0; } } static void imx_serial_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) + uint64_t value, unsigned size) { IMXSerialState *s = (IMXSerialState *)opaque; unsigned char ch; @@ -290,7 +214,9 @@ static void imx_serial_write(void *opaque, hwaddr offset, } if (value & UCR2_RXEN) { if (!(s->ucr2 & UCR2_RXEN)) { - qemu_chr_accept_input(s->chr); + if (s->chr) { + qemu_chr_accept_input(s->chr); + } } } s->ucr2 = value & 0xffff; @@ -298,25 +224,25 @@ static void imx_serial_write(void *opaque, hwaddr offset, case 0x25: /* USR1 */ value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM | - USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER; + USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER; s->usr1 &= ~value; break; case 0x26: /* USR2 */ - /* - * Writing 1 to some bits clears them; all other - * values are ignored - */ + /* + * Writing 1 to some bits clears them; all other + * values are ignored + */ value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST | - USR2_RIDELT | USR2_IRINT | USR2_WAKE | - USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE; + USR2_RIDELT | USR2_IRINT | USR2_WAKE | + USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE; s->usr2 &= ~value; break; - /* - * Linux expects to see what it writes to these registers - * We don't currently alter the baud rate - */ + /* + * Linux expects to see what it writes to these registers + * We don't currently alter the baud rate + */ case 0x29: /* UBIR */ s->ubrc = value & 0xffff; break; @@ -344,7 +270,7 @@ static void imx_serial_write(void *opaque, hwaddr offset, break; default: - IPRINTF("imx_serial_write: Bad offset 0x%x\n", (int)offset); + IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset); } } @@ -384,16 +310,10 @@ static const struct MemoryRegionOps imx_serial_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int imx_serial_init(SysBusDevice *dev) +static void imx_serial_realize(DeviceState *dev, Error **errp) { IMXSerialState *s = IMX_SERIAL(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &imx_serial_ops, s, - "imx-serial", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - if (s->chr) { qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive, imx_event, s); @@ -401,8 +321,17 @@ static int imx_serial_init(SysBusDevice *dev) DPRINTF("No char dev for uart at 0x%lx\n", (unsigned long)s->iomem.ram_addr); } +} - return 0; +static void imx_serial_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + IMXSerialState *s = IMX_SERIAL(obj); + + memory_region_init_io(&s->iomem, obj, &imx_serial_ops, s, + TYPE_IMX_SERIAL, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); } void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq) @@ -439,7 +368,7 @@ void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq) } -static Property imx32_serial_properties[] = { +static Property imx_serial_properties[] = { DEFINE_PROP_CHR("chardev", IMXSerialState, chr), DEFINE_PROP_END_OF_LIST(), }; @@ -447,21 +376,21 @@ static Property imx32_serial_properties[] = { static void imx_serial_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = imx_serial_init; + dc->realize = imx_serial_realize; dc->vmsd = &vmstate_imx_serial; dc->reset = imx_serial_reset_at_boot; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "i.MX series UART"; - dc->props = imx32_serial_properties; + dc->props = imx_serial_properties; } static const TypeInfo imx_serial_info = { - .name = TYPE_IMX_SERIAL, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXSerialState), - .class_init = imx_serial_class_init, + .name = TYPE_IMX_SERIAL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMXSerialState), + .instance_init = imx_serial_init, + .class_init = imx_serial_class_init, }; static void imx_serial_register_types(void) diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index acc419e11a..58ac02e610 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -20,6 +20,7 @@ #include "hw/cpu/a15mpcore.h" #include "sysemu/kvm.h" +#include "kvm_arm.h" static void a15mp_priv_set_irq(void *opaque, int irq, int level) { @@ -33,16 +34,11 @@ static void a15mp_priv_initfn(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); A15MPPrivState *s = A15MPCORE_PRIV(obj); DeviceState *gicdev; - const char *gictype = "arm_gic"; - - if (kvm_irqchip_in_kernel()) { - gictype = "kvm-arm-gic"; - } memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000); sysbus_init_mmio(sbd, &s->container); - object_initialize(&s->gic, sizeof(s->gic), gictype); + object_initialize(&s->gic, sizeof(s->gic), gic_class_name()); gicdev = DEVICE(&s->gic); qdev_set_parent_bus(gicdev, sysbus_get_default()); qdev_prop_set_uint32(gicdev, "revision", 2); @@ -79,14 +75,21 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_cpu; i++) { DeviceState *cpudev = DEVICE(qemu_get_cpu(i)); int ppibase = s->num_irq - 32 + i * 32; - /* physical timer; we wire it up to the non-secure timer's ID, - * since a real A15 always has TrustZone but QEMU doesn't. + int irq; + /* Mapping from the output timer irq lines from the CPU to the + * GIC PPI inputs used on the A15: */ - qdev_connect_gpio_out(cpudev, 0, - qdev_get_gpio_in(gicdev, ppibase + 30)); - /* virtual timer */ - qdev_connect_gpio_out(cpudev, 1, - qdev_get_gpio_in(gicdev, ppibase + 27)); + const int timer_irq[] = { + [GTIMER_PHYS] = 30, + [GTIMER_VIRT] = 27, + [GTIMER_HYP] = 26, + [GTIMER_SEC] = 29, + }; + for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) { + qdev_connect_gpio_out(cpudev, irq, + qdev_get_gpio_in(gicdev, + ppibase + timer_irq[irq])); + } } /* Memory map (addresses are offsets from PERIPHBASE): diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index bd4f147f9d..ebd1015a08 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,5 +1,5 @@ obj-$(CONFIG_KVM) += kvm/ -obj-y += multiboot.o smbios.o +obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o @@ -7,8 +7,14 @@ obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o obj-y += acpi-build.o + +gen-hex-y += hw/i386/acpi-dsdt.hex +gen-hex-y += hw/i386/q35-acpi-dsdt.hex + hw/i386/acpi-build.o: hw/i386/acpi-build.c \ - hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex + $(gen-hex-y) + +-include $(gen-hex-y:.hex=.d) iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \ ; then echo "$(2)"; else echo "$(3)"; fi ;) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 46eddb8e48..95e0c657a7 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -169,6 +169,7 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) Object *obj = NULL; QObject *o; + pm->cpu_hp_io_base = 0; pm->pcihp_io_base = 0; pm->pcihp_io_len = 0; if (piix) { diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl index a2d84ecf8f..8dba096dd8 100644 --- a/hw/i386/acpi-dsdt.dsl +++ b/hw/i386/acpi-dsdt.dsl @@ -43,7 +43,6 @@ DefinitionBlock ( #include "acpi-dsdt-hpet.dsl" - /**************************************************************** * PIIX4 PM ****************************************************************/ diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 7661ea9cdf..9f2924e5df 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -33,7 +33,7 @@ #include "hw/pci/pci_bus.h" #include "hw/nvram/fw_cfg.h" #include "hw/timer/hpet.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/loader.h" #include "elf.h" #include "multiboot.h" @@ -428,26 +428,24 @@ static void pc_cmos_init_late(void *opaque) qemu_unregister_reset(pc_cmos_init_late, opaque); } -void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, MachineState *machine, +void pc_cmos_init(PCMachineState *pcms, BusState *idebus0, BusState *idebus1, ISADevice *s) { int val; static pc_cmos_init_late_arg arg; - PCMachineState *pc_machine = PC_MACHINE(machine); Error *local_err = NULL; /* various important CMOS locations needed by PC/Bochs bios */ /* memory size */ /* base memory (first MiB) */ - val = MIN(ram_size / 1024, 640); + val = MIN(pcms->below_4g_mem_size / 1024, 640); rtc_set_memory(s, 0x15, val); rtc_set_memory(s, 0x16, val >> 8); /* extended memory (next 64MiB) */ - if (ram_size > 1024 * 1024) { - val = (ram_size - 1024 * 1024) / 1024; + if (pcms->below_4g_mem_size > 1024 * 1024) { + val = (pcms->below_4g_mem_size - 1024 * 1024) / 1024; } else { val = 0; } @@ -458,8 +456,8 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); /* memory between 16MiB and 4GiB */ - if (ram_size > 16 * 1024 * 1024) { - val = (ram_size - 16 * 1024 * 1024) / 65536; + if (pcms->below_4g_mem_size > 16 * 1024 * 1024) { + val = (pcms->below_4g_mem_size - 16 * 1024 * 1024) / 65536; } else { val = 0; } @@ -468,7 +466,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); /* memory above 4GiB */ - val = above_4g_mem_size / 65536; + val = pcms->above_4g_mem_size / 65536; rtc_set_memory(s, 0x5b, val); rtc_set_memory(s, 0x5c, val >> 8); rtc_set_memory(s, 0x5d, val >> 16); @@ -476,15 +474,15 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, /* set the number of CPU */ rtc_set_memory(s, 0x5f, smp_cpus - 1); - object_property_add_link(OBJECT(machine), "rtc_state", + object_property_add_link(OBJECT(pcms), "rtc_state", TYPE_ISA_DEVICE, - (Object **)&pc_machine->rtc, + (Object **)&pcms->rtc, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); - object_property_set_link(OBJECT(machine), OBJECT(s), + object_property_set_link(OBJECT(pcms), OBJECT(s), "rtc_state", &error_abort); - set_boot_dev(s, boot_device, &local_err); + set_boot_dev(s, MACHINE(pcms)->boot_order, &local_err); if (local_err) { error_report_err(local_err); exit(1); @@ -718,11 +716,46 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus) return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; } -static FWCfgState *bochs_bios_init(void) +static void pc_build_smbios(FWCfgState *fw_cfg) { - FWCfgState *fw_cfg; uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; + struct smbios_phys_mem_area *mem_array; + unsigned i, array_count; + + smbios_tables = smbios_get_table_legacy(&smbios_tables_len); + if (smbios_tables) { + fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, + smbios_tables, smbios_tables_len); + } + + /* build the array of physical mem area from e820 table */ + mem_array = g_malloc0(sizeof(*mem_array) * e820_get_num_entries()); + for (i = 0, array_count = 0; i < e820_get_num_entries(); i++) { + uint64_t addr, len; + + if (e820_get_entry(i, E820_RAM, &addr, &len)) { + mem_array[array_count].address = addr; + mem_array[array_count].length = len; + array_count++; + } + } + smbios_get_tables(mem_array, array_count, + &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len); + g_free(mem_array); + + if (smbios_anchor) { + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } +} + +static FWCfgState *bochs_bios_init(void) +{ + FWCfgState *fw_cfg; uint64_t *numa_fw_cfg; int i, j; unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); @@ -748,20 +781,7 @@ static FWCfgState *bochs_bios_init(void) acpi_tables, acpi_tables_len); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); - smbios_tables = smbios_get_table_legacy(&smbios_tables_len); - if (smbios_tables) { - fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, - smbios_tables, smbios_tables_len); - } - - smbios_get_tables(&smbios_tables, &smbios_tables_len, - &smbios_anchor, &smbios_anchor_len); - if (smbios_anchor) { - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", - smbios_tables, smbios_tables_len); - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", - smbios_anchor, smbios_anchor_len); - } + pc_build_smbios(fw_cfg); fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, &e820_reserve, sizeof(e820_reserve)); @@ -809,11 +829,8 @@ static long get_file_size(FILE *f) return size; } -static void load_linux(FWCfgState *fw_cfg, - const char *kernel_filename, - const char *initrd_filename, - const char *kernel_cmdline, - hwaddr max_ram_size) +static void load_linux(PCMachineState *pcms, + FWCfgState *fw_cfg) { uint16_t protocol; int setup_size, kernel_size, initrd_size = 0, cmdline_size; @@ -822,6 +839,10 @@ static void load_linux(FWCfgState *fw_cfg, hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; FILE *f; char *vmode; + MachineState *machine = MACHINE(pcms); + const char *kernel_filename = machine->kernel_filename; + const char *initrd_filename = machine->initrd_filename; + const char *kernel_cmdline = machine->kernel_cmdline; /* Align to 16 bytes as a paranoia measure */ cmdline_size = (strlen(kernel_cmdline)+16) & ~15; @@ -886,8 +907,8 @@ static void load_linux(FWCfgState *fw_cfg, initrd_max = 0x37ffffff; } - if (initrd_max >= max_ram_size - acpi_data_size) { - initrd_max = max_ram_size - acpi_data_size - 1; + if (initrd_max >= pcms->below_4g_mem_size - acpi_data_size) { + initrd_max = pcms->below_4g_mem_size - acpi_data_size - 1; } fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); @@ -1189,15 +1210,14 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data) acpi_setup(&guest_info_state->info); } -PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size) +PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) { PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); PcGuestInfo *guest_info = &guest_info_state->info; int i, j; - guest_info->ram_size_below_4g = below_4g_mem_size; - guest_info->ram_size = below_4g_mem_size + above_4g_mem_size; + guest_info->ram_size_below_4g = pcms->below_4g_mem_size; + guest_info->ram_size = pcms->below_4g_mem_size + pcms->above_4g_mem_size; guest_info->apic_id_limit = pc_apic_id_limit(max_cpus); guest_info->apic_xrupt_override = kvm_allows_irq0_override(); guest_info->numa_nodes = nb_numa_nodes; @@ -1264,22 +1284,18 @@ void pc_acpi_init(const char *default_dsdt) } } -FWCfgState *xen_load_linux(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - ram_addr_t below_4g_mem_size, +FWCfgState *xen_load_linux(PCMachineState *pcms, PcGuestInfo *guest_info) { int i; FWCfgState *fw_cfg; - assert(kernel_filename != NULL); + assert(MACHINE(pcms)->kernel_filename != NULL); fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT); rom_set_fw(fw_cfg); - load_linux(fw_cfg, kernel_filename, initrd_filename, - kernel_cmdline, below_4g_mem_size); + load_linux(pcms, fw_cfg); for (i = 0; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "multiboot.bin")); @@ -1289,10 +1305,8 @@ FWCfgState *xen_load_linux(const char *kernel_filename, return fw_cfg; } -FWCfgState *pc_memory_init(MachineState *machine, +FWCfgState *pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, MemoryRegion *rom_memory, MemoryRegion **ram_memory, PcGuestInfo *guest_info) @@ -1301,9 +1315,10 @@ FWCfgState *pc_memory_init(MachineState *machine, MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; FWCfgState *fw_cfg; - PCMachineState *pcms = PC_MACHINE(machine); + MachineState *machine = MACHINE(pcms); - assert(machine->ram_size == below_4g_mem_size + above_4g_mem_size); + assert(machine->ram_size == pcms->below_4g_mem_size + + pcms->above_4g_mem_size); linux_boot = (machine->kernel_filename != NULL); @@ -1317,16 +1332,17 @@ FWCfgState *pc_memory_init(MachineState *machine, *ram_memory = ram; ram_below_4g = g_malloc(sizeof(*ram_below_4g)); memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ram, - 0, below_4g_mem_size); + 0, pcms->below_4g_mem_size); memory_region_add_subregion(system_memory, 0, ram_below_4g); - e820_add_entry(0, below_4g_mem_size, E820_RAM); - if (above_4g_mem_size > 0) { + e820_add_entry(0, pcms->below_4g_mem_size, E820_RAM); + if (pcms->above_4g_mem_size > 0) { ram_above_4g = g_malloc(sizeof(*ram_above_4g)); memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g", ram, - below_4g_mem_size, above_4g_mem_size); + pcms->below_4g_mem_size, + pcms->above_4g_mem_size); memory_region_add_subregion(system_memory, 0x100000000ULL, ram_above_4g); - e820_add_entry(0x100000000ULL, above_4g_mem_size, E820_RAM); + e820_add_entry(0x100000000ULL, pcms->above_4g_mem_size, E820_RAM); } if (!guest_info->has_reserved_memory && @@ -1359,7 +1375,7 @@ FWCfgState *pc_memory_init(MachineState *machine, } pcms->hotplug_memory.base = - ROUND_UP(0x100000000ULL + above_4g_mem_size, 1ULL << 30); + ROUND_UP(0x100000000ULL + pcms->above_4g_mem_size, 1ULL << 30); if (pcms->enforce_aligned_dimm) { /* size hotplug region assuming 1G page max alignment per slot */ @@ -1401,8 +1417,7 @@ FWCfgState *pc_memory_init(MachineState *machine, } if (linux_boot) { - load_linux(fw_cfg, machine->kernel_filename, machine->initrd_filename, - machine->kernel_cmdline, below_4g_mem_size); + load_linux(pcms, fw_cfg); } for (i = 0; i < nb_option_roms; i++) { @@ -1886,39 +1901,39 @@ static void pc_machine_initfn(Object *obj) object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int", pc_machine_get_hotplug_memory_region_size, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, &error_abort); pcms->max_ram_below_4g = 1ULL << 32; /* 4G */ object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size", pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g, - NULL, NULL, NULL); + NULL, NULL, &error_abort); object_property_set_description(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "Maximum ram below the 4G boundary (32bit boundary)", - NULL); + &error_abort); pcms->smm = ON_OFF_AUTO_AUTO; object_property_add(obj, PC_MACHINE_SMM, "OnOffAuto", pc_machine_get_smm, pc_machine_set_smm, - NULL, NULL, NULL); + NULL, NULL, &error_abort); object_property_set_description(obj, PC_MACHINE_SMM, "Enable SMM (pc & q35)", - NULL); + &error_abort); pcms->vmport = ON_OFF_AUTO_AUTO; object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto", pc_machine_get_vmport, pc_machine_set_vmport, - NULL, NULL, NULL); + NULL, NULL, &error_abort); object_property_set_description(obj, PC_MACHINE_VMPORT, "Enable vmport (pc & q35)", - NULL); + &error_abort); pcms->enforce_aligned_dimm = true; object_property_add_bool(obj, PC_MACHINE_ENFORCE_ALIGNED_DIMM, pc_machine_get_aligned_dimm, - NULL, NULL); + NULL, &error_abort); } static unsigned pc_cpu_index_to_socket_id(unsigned cpu_index) @@ -1938,6 +1953,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) pcmc->get_hotplug_handler = mc->get_hotplug_handler; mc->get_hotplug_handler = pc_get_hotpug_handler; mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id; + mc->default_boot_order = "cad"; + mc->hot_add_cpu = pc_hot_add_cpu; + mc->max_cpus = 255; hc->plug = pc_machine_device_plug_cb; hc->unplug_request = pc_machine_device_unplug_request_cb; hc->unplug = pc_machine_device_unplug_cb; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a896624f89..95584676e2 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -28,7 +28,7 @@ #include "hw/loader.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/pci/pci.h" #include "hw/pci/pci_ids.h" #include "hw/usb.h" @@ -78,11 +78,10 @@ static bool kvmclock_enabled = true; /* PC hardware initialisation */ static void pc_init1(MachineState *machine) { - PCMachineState *pc_machine = PC_MACHINE(machine); + PCMachineState *pcms = PC_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_io = get_system_io(); int i; - ram_addr_t below_4g_mem_size, above_4g_mem_size; PCIBus *pci_bus; ISABus *isa_bus; PCII440FXState *i440fx_state; @@ -117,25 +116,26 @@ static void pc_init1(MachineState *machine) /* Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). */ - if (lowmem > pc_machine->max_ram_below_4g) { - lowmem = pc_machine->max_ram_below_4g; + if (lowmem > pcms->max_ram_below_4g) { + lowmem = pcms->max_ram_below_4g; if (machine->ram_size - lowmem > lowmem && lowmem & ((1ULL << 30) - 1)) { error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64 ") not a multiple of 1G; possible bad performance.", - pc_machine->max_ram_below_4g); + pcms->max_ram_below_4g); } } if (machine->ram_size >= lowmem) { - above_4g_mem_size = machine->ram_size - lowmem; - below_4g_mem_size = lowmem; + pcms->above_4g_mem_size = machine->ram_size - lowmem; + pcms->below_4g_mem_size = lowmem; } else { - above_4g_mem_size = 0; - below_4g_mem_size = machine->ram_size; + pcms->above_4g_mem_size = 0; + pcms->below_4g_mem_size = machine->ram_size; } - if (xen_enabled() && xen_hvm_init(&below_4g_mem_size, &above_4g_mem_size, + if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size, + &pcms->above_4g_mem_size, &ram_memory) != 0) { fprintf(stderr, "xen hardware virtual machine initialisation failed\n"); exit(1); @@ -160,7 +160,7 @@ static void pc_init1(MachineState *machine) rom_memory = system_memory; } - guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); + guest_info = pc_guest_info_init(pcms); guest_info->has_acpi_build = has_acpi_build; guest_info->legacy_acpi_table_size = legacy_acpi_table_size; @@ -178,16 +178,11 @@ static void pc_init1(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { - pc_memory_init(machine, system_memory, - below_4g_mem_size, above_4g_mem_size, + pc_memory_init(pcms, system_memory, rom_memory, &ram_memory, guest_info); } else if (machine->kernel_filename != NULL) { /* For xen HVM direct kernel boot, load linux here */ - xen_load_linux(machine->kernel_filename, - machine->kernel_cmdline, - machine->initrd_filename, - below_4g_mem_size, - guest_info); + xen_load_linux(pcms, guest_info); } gsi_state = g_malloc0(sizeof(*gsi_state)); @@ -202,8 +197,8 @@ static void pc_init1(MachineState *machine) if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, system_memory, system_io, machine->ram_size, - below_4g_mem_size, - above_4g_mem_size, + pcms->below_4g_mem_size, + pcms->above_4g_mem_size, pci_memory, ram_memory); } else { pci_bus = NULL; @@ -234,14 +229,14 @@ static void pc_init1(MachineState *machine) pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); - assert(pc_machine->vmport != ON_OFF_AUTO_MAX); - if (pc_machine->vmport == ON_OFF_AUTO_AUTO) { - pc_machine->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; + assert(pcms->vmport != ON_OFF_AUTO_MAX); + if (pcms->vmport == ON_OFF_AUTO_AUTO) { + pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; } /* init basic PC hardware */ pc_basic_device_init(isa_bus, gsi, &rtc_state, true, - (pc_machine->vmport != ON_OFF_AUTO_ON), 0x4); + (pcms->vmport != ON_OFF_AUTO_ON), 0x4); pc_nic_init(isa_bus, pci_bus); @@ -271,8 +266,7 @@ static void pc_init1(MachineState *machine) } } - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order, - machine, idebus[0], idebus[1], rtc_state); + pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); if (pci_enabled && usb_enabled()) { pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); @@ -286,13 +280,13 @@ static void pc_init1(MachineState *machine) /* TODO: Populate SPD eeprom data. */ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, gsi[9], smi_irq, - pc_machine_is_smm_enabled(pc_machine), + pc_machine_is_smm_enabled(pcms), &piix4_pm); smbus_eeprom_init(smbus, 8, NULL, 0); object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, TYPE_HOTPLUG_HANDLER, - (Object **)&pc_machine->acpi_dev, + (Object **)&pcms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); object_property_set_link(OBJECT(machine), OBJECT(piix4_pm), @@ -319,24 +313,6 @@ static void pc_compat_2_2(MachineState *machine) { pc_compat_2_3(machine); rsdp_in_ram = false; - x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Conroe", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Penryn", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Nehalem", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Westmere", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("SandyBridge", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Broadwell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G1", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G2", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G3", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G4", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G5", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); machine->suppress_vmdesc = true; } @@ -346,8 +322,6 @@ static void pc_compat_2_1(MachineState *machine) pc_compat_2_2(machine); smbios_uuid_encoded = false; - x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0); - x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0); x86_cpu_compat_kvm_no_autodisable(FEAT_8000_0001_ECX, CPUID_EXT3_SVM); pcms->enforce_aligned_dimm = false; } @@ -402,8 +376,6 @@ static void pc_compat_1_5(MachineState *machine) static void pc_compat_1_4(MachineState *machine) { pc_compat_1_5(machine); - x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); - x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } static void pc_compat_1_3(MachineState *machine) @@ -471,7 +443,6 @@ static void pc_xen_hvm_init(MachineState *machine) static void pc_i440fx_machine_options(MachineClass *m) { - pc_default_machine_options(m); m->family = "pc_piix"; m->desc = "Standard PC (i440FX + PIIX, 1996)"; m->hot_add_cpu = pc_hot_add_cpu; @@ -909,7 +880,6 @@ DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13, static void isapc_machine_options(MachineClass *m) { - pc_common_machine_options(m); m->desc = "ISA-only PC"; m->max_cpus = 1; } @@ -921,7 +891,6 @@ DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa, #ifdef CONFIG_XEN static void xenfv_machine_options(MachineClass *m) { - pc_common_machine_options(m); m->desc = "Xen Fully-virtualized PC"; m->max_cpus = HVM_MAX_VCPUS; m->default_machine_opts = "accel=xen"; diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 974aead5a9..c07d65bc46 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -39,7 +39,7 @@ #include "hw/pci-host/q35.h" #include "exec/address-spaces.h" #include "hw/i386/ich9.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/ide/pci.h" #include "hw/ide/ahci.h" #include "hw/usb.h" @@ -65,8 +65,7 @@ static bool has_reserved_memory = true; /* PC hardware initialisation */ static void pc_q35_init(MachineState *machine) { - PCMachineState *pc_machine = PC_MACHINE(machine); - ram_addr_t below_4g_mem_size, above_4g_mem_size; + PCMachineState *pcms = PC_MACHINE(machine); Q35PCIHost *q35_host; PCIHostState *phb; PCIBus *host_bus; @@ -108,25 +107,26 @@ static void pc_q35_init(MachineState *machine) /* Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). */ - if (lowmem > pc_machine->max_ram_below_4g) { - lowmem = pc_machine->max_ram_below_4g; + if (lowmem > pcms->max_ram_below_4g) { + lowmem = pcms->max_ram_below_4g; if (machine->ram_size - lowmem > lowmem && lowmem & ((1ULL << 30) - 1)) { error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64 ") not a multiple of 1G; possible bad performance.", - pc_machine->max_ram_below_4g); + pcms->max_ram_below_4g); } } if (machine->ram_size >= lowmem) { - above_4g_mem_size = machine->ram_size - lowmem; - below_4g_mem_size = lowmem; + pcms->above_4g_mem_size = machine->ram_size - lowmem; + pcms->below_4g_mem_size = lowmem; } else { - above_4g_mem_size = 0; - below_4g_mem_size = machine->ram_size; + pcms->above_4g_mem_size = 0; + pcms->below_4g_mem_size = machine->ram_size; } - if (xen_enabled() && xen_hvm_init(&below_4g_mem_size, &above_4g_mem_size, + if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size, + &pcms->above_4g_mem_size, &ram_memory) != 0) { fprintf(stderr, "xen hardware virtual machine initialisation failed\n"); exit(1); @@ -151,7 +151,7 @@ static void pc_q35_init(MachineState *machine) rom_memory = get_system_memory(); } - guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); + guest_info = pc_guest_info_init(pcms); guest_info->isapc_ram_fw = false; guest_info->has_acpi_build = has_acpi_build; guest_info->has_reserved_memory = has_reserved_memory; @@ -170,8 +170,7 @@ static void pc_q35_init(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { - pc_memory_init(machine, get_system_memory(), - below_4g_mem_size, above_4g_mem_size, + pc_memory_init(pcms, get_system_memory(), rom_memory, &ram_memory, guest_info); } @@ -193,8 +192,8 @@ static void pc_q35_init(MachineState *machine) q35_host->mch.pci_address_space = pci_memory; q35_host->mch.system_memory = get_system_memory(); q35_host->mch.address_space_io = get_system_io(); - q35_host->mch.below_4g_mem_size = below_4g_mem_size; - q35_host->mch.above_4g_mem_size = above_4g_mem_size; + q35_host->mch.below_4g_mem_size = pcms->below_4g_mem_size; + q35_host->mch.above_4g_mem_size = pcms->above_4g_mem_size; q35_host->mch.guest_info = guest_info; /* pci */ qdev_init_nofail(DEVICE(q35_host)); @@ -207,7 +206,7 @@ static void pc_q35_init(MachineState *machine) object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, TYPE_HOTPLUG_HANDLER, - (Object **)&pc_machine->acpi_dev, + (Object **)&pcms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); object_property_set_link(OBJECT(machine), OBJECT(lpc), @@ -242,17 +241,17 @@ static void pc_q35_init(MachineState *machine) pc_register_ferr_irq(gsi[13]); - assert(pc_machine->vmport != ON_OFF_AUTO_MAX); - if (pc_machine->vmport == ON_OFF_AUTO_AUTO) { - pc_machine->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; + assert(pcms->vmport != ON_OFF_AUTO_MAX); + if (pcms->vmport == ON_OFF_AUTO_AUTO) { + pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; } /* init basic PC hardware */ pc_basic_device_init(isa_bus, gsi, &rtc_state, !mc->no_floppy, - (pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104); + (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104); /* connect pm stuff to lpc */ - ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pc_machine), !mc->no_tco); + ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), !mc->no_tco); /* ahci and SATA device, for q35 1 ahci controller is built-in */ ahci = pci_create_simple_multifunction(host_bus, @@ -276,8 +275,7 @@ static void pc_q35_init(MachineState *machine) 0xb100), 8, NULL, 0); - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order, - machine, idebus[0], idebus[1], rtc_state); + pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); /* the rest devices to which pci devfn is automatically assigned */ pc_vga_init(isa_bus, host_bus); @@ -302,24 +300,6 @@ static void pc_compat_2_2(MachineState *machine) { pc_compat_2_3(machine); rsdp_in_ram = false; - x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Conroe", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Penryn", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Nehalem", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Westmere", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("SandyBridge", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Broadwell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G1", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G2", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G3", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G4", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G5", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); machine->suppress_vmdesc = true; } @@ -330,8 +310,6 @@ static void pc_compat_2_1(MachineState *machine) pc_compat_2_2(machine); pcms->enforce_aligned_dimm = false; smbios_uuid_encoded = false; - x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0); - x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0); x86_cpu_compat_kvm_no_autodisable(FEAT_8000_0001_ECX, CPUID_EXT3_SVM); } @@ -367,8 +345,6 @@ static void pc_compat_1_5(MachineState *machine) static void pc_compat_1_4(MachineState *machine) { pc_compat_1_5(machine); - x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); - x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } #define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \ @@ -385,7 +361,6 @@ static void pc_compat_1_4(MachineState *machine) static void pc_q35_machine_options(MachineClass *m) { - pc_default_machine_options(m); m->family = "pc_q35"; m->desc = "Standard PC (Q35 + ICH9, 2009)"; m->hot_add_cpu = pc_hot_add_cpu; diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl index 16eaca3fae..7be7b37b87 100644 --- a/hw/i386/q35-acpi-dsdt.dsl +++ b/hw/i386/q35-acpi-dsdt.dsl @@ -22,6 +22,7 @@ * Based on acpi-dsdt.dsl, but heavily modified for q35 chipset. */ + ACPI_EXTRACT_ALL_CODE Q35AcpiDsdtAmlCode DefinitionBlock ( diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 68d5074b33..79a463d93c 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -127,7 +127,7 @@ #define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */ #define PORT_CMD_START (1 << 0) /* Enable port DMA engine */ -#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */ +#define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */ #define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */ #define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */ #define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */ diff --git a/hw/ide/macio.c b/hw/ide/macio.c index a55a479da6..66ac2baa94 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -208,6 +208,33 @@ static void pmac_dma_write(BlockBackend *blk, cb, io); } +static void pmac_dma_trim(BlockBackend *blk, + int64_t offset, int bytes, + void (*cb)(void *opaque, int ret), void *opaque) +{ + DBDMA_io *io = opaque; + MACIOIDEState *m = io->opaque; + IDEState *s = idebus_active_if(&m->bus); + dma_addr_t dma_addr, dma_len; + void *mem; + + qemu_iovec_destroy(&io->iov); + qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1); + + dma_addr = io->addr; + dma_len = io->len; + mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len, + DMA_DIRECTION_TO_DEVICE); + + qemu_iovec_add(&io->iov, mem, io->len); + s->io_buffer_size -= io->len; + s->io_buffer_index += io->len; + io->len = 0; + + m->aiocb = ide_issue_trim(blk, (offset >> 9), &io->iov, (bytes >> 9), + cb, io); +} + static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) { DBDMA_io *io = opaque; @@ -313,6 +340,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) pmac_dma_write(s->blk, offset, io->len, pmac_ide_transfer_cb, io); break; case IDE_DMA_TRIM: + pmac_dma_trim(s->blk, offset, io->len, pmac_ide_transfer_cb, io); break; } diff --git a/hw/ide/piix.c b/hw/ide/piix.c index adb664957c..5a26c86a8a 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -169,6 +169,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev) PCIIDEState *pci_ide; DriveInfo *di; int i; + IDEDevice *idedev; pci_ide = PCI_IDE(dev); @@ -181,6 +182,12 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev) blk_detach_dev(blk, ds); } pci_ide->bus[di->bus].ifs[di->unit].blk = NULL; + if (!(i % 2)) { + idedev = pci_ide->bus[di->bus].master; + } else { + idedev = pci_ide->bus[di->bus].slave; + } + idedev->conf.blk = NULL; blk_unref(blk); } } diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 454bfd7df5..a8c5d19448 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -922,12 +922,6 @@ static MemTxResult gic_dist_write(void *opaque, hwaddr offset, uint64_t data, } } -static const MemoryRegionOps gic_dist_ops = { - .read_with_attrs = gic_dist_read, - .write_with_attrs = gic_dist_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, uint64_t *data, MemTxAttrs attrs) { @@ -1056,10 +1050,17 @@ static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, return gic_cpu_write(s, id, addr, value, attrs); } -static const MemoryRegionOps gic_thiscpu_ops = { - .read_with_attrs = gic_thiscpu_read, - .write_with_attrs = gic_thiscpu_write, - .endianness = DEVICE_NATIVE_ENDIAN, +static const MemoryRegionOps gic_ops[2] = { + { + .read_with_attrs = gic_dist_read, + .write_with_attrs = gic_dist_write, + .endianness = DEVICE_NATIVE_ENDIAN, + }, + { + .read_with_attrs = gic_thiscpu_read, + .write_with_attrs = gic_thiscpu_write, + .endianness = DEVICE_NATIVE_ENDIAN, + } }; static const MemoryRegionOps gic_cpu_ops = { @@ -1068,31 +1069,10 @@ static const MemoryRegionOps gic_cpu_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +/* This function is used by nvic model */ void gic_init_irqs_and_distributor(GICState *s) { - SysBusDevice *sbd = SYS_BUS_DEVICE(s); - int i; - - 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 - * ... - */ - if (s->revision != REV_NVIC) { - i += (GIC_INTERNAL * s->num_cpu); - } - qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); - for (i = 0; i < NUM_CPU(s); i++) { - sysbus_init_irq(sbd, &s->parent_irq[i]); - } - for (i = 0; i < NUM_CPU(s); i++) { - sysbus_init_irq(sbd, &s->parent_fiq[i]); - } - memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, - "gic_dist", 0x1000); + gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); } static void arm_gic_realize(DeviceState *dev, Error **errp) @@ -1110,28 +1090,22 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) return; } - gic_init_irqs_and_distributor(s); + /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ + gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); - /* Memory regions for the CPU interfaces (NVIC doesn't have these): - * a region for "CPU interface for this core", then a region for - * "CPU interface for core 0", "for core 1", ... + /* Extra core-specific regions for the CPU interfaces. This is + * necessary for "franken-GIC" implementations, for example on + * Exynos 4. * NB that the memory region size of 0x100 applies for the 11MPCore * and also cores following the GIC v1 spec (ie A9). * GIC v2 defines a larger memory region (0x1000) so this will need * to be extended when we implement A15. */ - memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s, - "gic_cpu", 0x100); for (i = 0; i < NUM_CPU(s); i++) { s->backref[i] = s; memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, &s->backref[i], "gic_cpu", 0x100); - } - /* Distributor */ - 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(sbd, &s->cpuiomem[i]); + sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); } } diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index a64d0714ea..fe64b51cff 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -84,6 +84,47 @@ static const VMStateDescription vmstate_gic = { } }; +void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler, + const MemoryRegionOps *ops) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(s); + int 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 + * ... + */ + if (s->revision != REV_NVIC) { + i += (GIC_INTERNAL * s->num_cpu); + } + qdev_init_gpio_in(DEVICE(s), handler, i); + + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->parent_irq[i]); + } + for (i = 0; i < s->num_cpu; i++) { + sysbus_init_irq(sbd, &s->parent_fiq[i]); + } + + /* Distributor */ + memory_region_init_io(&s->iomem, OBJECT(s), ops, s, "gic_dist", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + + if (s->revision != REV_NVIC) { + /* This is the main CPU interface "for this core". It is always + * present because it is required by both software emulation and KVM. + * NVIC is not handled here because its CPU interface is different, + * neither it can use KVM. + */ + memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL, + s, "gic_cpu", s->revision == 2 ? 0x1000 : 0x100); + sysbus_init_mmio(sbd, &s->cpuiomem[0]); + } +} + static void arm_gic_common_realize(DeviceState *dev, Error **errp) { GICState *s = ARM_GIC_COMMON(dev); diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index f56bff1afb..e5d0f67186 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -543,7 +543,6 @@ 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); Error *local_err = NULL; int ret; @@ -560,32 +559,13 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **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); + gic_init_irqs_and_mmio(s, kvm_arm_gic_set_irq, NULL); for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) { qemu_irq irq = qdev_get_gpio_in(dev, i); kvm_irqchip_set_qemuirq_gsi(kvm_state, irq, i); } - /* We never use our outbound IRQ/FIQ 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]); - } - for (i = 0; i < s->num_cpu; i++) { - sysbus_init_irq(sbd, &s->parent_fiq[i]); - } - /* Try to create the device via the device control API */ s->dev_fd = -1; ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false); @@ -609,9 +589,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) } /* Distributor */ - memory_region_init_reservation(&s->iomem, OBJECT(s), - "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, @@ -622,9 +599,6 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) * provide the "interface for core #N" memory regions, because * cores with a VGIC don't have those. */ - memory_region_init_reservation(&s->cpuiomem[0], OBJECT(s), - "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, diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c index e48f66c8fa..96c376b6af 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -7,6 +7,7 @@ * Copyright (c) 2008 OKL * Copyright (c) 2011 NICTA Pty Ltd * Originally written by Hans Jiang + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * * This code is licensed under the GPL version 2 or later. See * the COPYING file in the top-level directory. @@ -14,16 +15,14 @@ * TODO: implement vectors. */ -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "qemu/host-utils.h" +#include "hw/intc/imx_avic.h" #define DEBUG_INT 1 #undef DEBUG_INT /* comment out for debugging */ #ifdef DEBUG_INT #define DPRINTF(fmt, args...) \ -do { printf("imx_avic: " fmt , ##args); } while (0) +do { printf("%s: " fmt , TYPE_IMX_AVIC, ##args); } while (0) #else #define DPRINTF(fmt, args...) do {} while (0) #endif @@ -35,46 +34,13 @@ do { printf("imx_avic: " fmt , ##args); } while (0) #define DEBUG_IMPLEMENTATION 1 #if DEBUG_IMPLEMENTATION # define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0) + do { fprintf(stderr, "%s: " fmt, TYPE_IMX_AVIC, ##args); } while (0) #else # define IPRINTF(fmt, args...) do {} while (0) #endif -#define IMX_AVIC_NUM_IRQS 64 - -/* Interrupt Control Bits */ -#define ABFLAG (1<<25) -#define ABFEN (1<<24) -#define NIDIS (1<<22) /* Normal Interrupt disable */ -#define FIDIS (1<<21) /* Fast interrupt disable */ -#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */ -#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */ -#define NM (1<<18) /* Normal interrupt mode */ - - -#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4) -#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD) - -#define TYPE_IMX_AVIC "imx_avic" -#define IMX_AVIC(obj) \ - OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC) - -typedef struct IMXAVICState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint64_t pending; - uint64_t enabled; - uint64_t is_fiq; - uint32_t intcntl; - uint32_t intmask; - qemu_irq irq; - qemu_irq fiq; - uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */ -} IMXAVICState; - static const VMStateDescription vmstate_imx_avic = { - .name = "imx-avic", + .name = TYPE_IMX_AVIC, .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { @@ -88,8 +54,6 @@ static const VMStateDescription vmstate_imx_avic = { }, }; - - static inline int imx_avic_prio(IMXAVICState *s, int irq) { uint32_t word = irq / PRIO_PER_WORD; @@ -249,7 +213,7 @@ static uint64_t imx_avic_read(void *opaque, return 0x4; default: - IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset); + IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset); return 0; } } @@ -261,12 +225,12 @@ static void imx_avic_write(void *opaque, hwaddr offset, /* Vector Registers not yet supported */ if (offset >= 0x100 && offset <= 0x2fc) { - IPRINTF("imx_avic_write to vector register %d ignored\n", + IPRINTF("%s to vector register %d ignored\n", __func__, (unsigned int)((offset - 0x100) >> 2)); return; } - DPRINTF("imx_avic_write(0x%x) = %x\n", + DPRINTF("%s(0x%x) = %x\n", __func__, (unsigned int)offset>>2, (unsigned int)val); switch (offset >> 2) { case 0: /* Interrupt Control Register, INTCNTL */ @@ -341,7 +305,7 @@ static void imx_avic_write(void *opaque, hwaddr offset, return; default: - IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset); + IPRINTF("%s: Bad offset %x\n", __func__, (int)offset); } imx_avic_update(s); } @@ -370,7 +334,7 @@ static int imx_avic_init(SysBusDevice *sbd) IMXAVICState *s = IMX_AVIC(dev); memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s, - "imx_avic", 0x1000); + TYPE_IMX_AVIC, 0x1000); sysbus_init_mmio(sbd, &s->iomem); qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS); diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 0920288634..2e19dbb1bb 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -2,6 +2,7 @@ * IMX31 Clock Control Module * * Copyright (C) 2012 NICTA + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -10,51 +11,23 @@ * the CCM. */ -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "hw/arm/imx.h" +#include "hw/misc/imx_ccm.h" #define CKIH_FREQ 26000000 /* 26MHz crystal input */ #define CKIL_FREQ 32768 /* nominal 32khz clock */ - //#define DEBUG_CCM 1 #ifdef DEBUG_CCM #define DPRINTF(fmt, args...) \ -do { printf("imx_ccm: " fmt , ##args); } while (0) +do { printf("%s: " fmt , TYPE_IMX_CCM, ##args); } while (0) #else #define DPRINTF(fmt, args...) do {} while (0) #endif static int imx_ccm_post_load(void *opaque, int version_id); -#define TYPE_IMX_CCM "imx_ccm" -#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM) - -typedef struct IMXCCMState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - uint32_t ccmr; - uint32_t pdr0; - uint32_t pdr1; - uint32_t mpctl; - uint32_t spctl; - uint32_t cgr[3]; - uint32_t pmcr0; - uint32_t pmcr1; - - /* Frequencies precalculated on register changes */ - uint32_t pll_refclk_freq; - uint32_t mcu_clk_freq; - uint32_t hsp_clk_freq; - uint32_t ipg_clk_freq; -} IMXCCMState; - static const VMStateDescription vmstate_imx_ccm = { - .name = "imx-ccm", + .name = TYPE_IMX_CCM, .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { @@ -72,44 +45,6 @@ static const VMStateDescription vmstate_imx_ccm = { .post_load = imx_ccm_post_load, }; -/* CCMR */ -#define CCMR_FPME (1<<0) -#define CCMR_MPE (1<<3) -#define CCMR_MDS (1<<7) -#define CCMR_FPMF (1<<26) -#define CCMR_PRCS (3<<1) - -/* PDR0 */ -#define PDR0_MCU_PODF_SHIFT (0) -#define PDR0_MCU_PODF_MASK (0x7) -#define PDR0_MAX_PODF_SHIFT (3) -#define PDR0_MAX_PODF_MASK (0x7) -#define PDR0_IPG_PODF_SHIFT (6) -#define PDR0_IPG_PODF_MASK (0x3) -#define PDR0_NFC_PODF_SHIFT (8) -#define PDR0_NFC_PODF_MASK (0x7) -#define PDR0_HSP_PODF_SHIFT (11) -#define PDR0_HSP_PODF_MASK (0x7) -#define PDR0_PER_PODF_SHIFT (16) -#define PDR0_PER_PODF_MASK (0x1f) -#define PDR0_CSI_PODF_SHIFT (23) -#define PDR0_CSI_PODF_MASK (0x1ff) - -#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \ - & PDR0_##name##_PODF_MASK) -#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \ - PDR0_##name##_PODF_SHIFT) -/* PLL control registers */ -#define PD(v) (((v) >> 26) & 0xf) -#define MFD(v) (((v) >> 16) & 0x3ff) -#define MFI(v) (((v) >> 10) & 0xf); -#define MFN(v) ((v) & 0x3ff) - -#define PLL_PD(x) (((x) & 0xf) << 26) -#define PLL_MFD(x) (((x) & 0x3ff) << 16) -#define PLL_MFI(x) (((x) & 0xf) << 10) -#define PLL_MFN(x) (((x) & 0x3ff) << 0) - uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock) { IMXCCMState *s = IMX_CCM(dev); @@ -174,7 +109,7 @@ static void update_clocks(IMXCCMState *s) s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP)); s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG)); - DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n", + DPRINTF("%s: mcu %uMHz, HSP %uMHz, IPG %uHz\n", __func__, s->mcu_clk_freq / 1000000, s->hsp_clk_freq / 1000000, s->ipg_clk_freq); @@ -200,7 +135,7 @@ static uint64_t imx_ccm_read(void *opaque, hwaddr offset, { IMXCCMState *s = (IMXCCMState *)opaque; - DPRINTF("read(offset=%x)", offset >> 2); + DPRINTF("%s(offset=%x)", __func__, offset >> 2); switch (offset >> 2) { case 0: /* CCMR */ DPRINTF(" ccmr = 0x%x\n", s->ccmr); @@ -241,7 +176,7 @@ static void imx_ccm_write(void *opaque, hwaddr offset, { IMXCCMState *s = (IMXCCMState *)opaque; - DPRINTF("write(offset=%x, value = %x)\n", + DPRINTF("%s(offset=%x, value = %x)\n", __func__, offset >> 2, (unsigned int)value); switch (offset >> 2) { case 0: @@ -286,7 +221,7 @@ static int imx_ccm_init(SysBusDevice *dev) IMXCCMState *s = IMX_CCM(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s, - "imx_ccm", 0x1000); + TYPE_IMX_CCM, 0x1000); sysbus_init_mmio(dev, &s->iomem); return 0; diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index e0db4727ae..edbb61ccf3 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -2150,6 +2150,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) { DPRINTF("+++ C+ mode offloaded task checksum\n"); + /* Large enough for Ethernet and IP headers? */ + if (saved_size < ETH_HLEN + sizeof(ip_header)) { + goto skip_offload; + } + /* ip packet header */ ip_header *ip = NULL; int hlen = 0; @@ -2160,223 +2165,235 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s) size_t eth_payload_len = 0; int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); - if (proto == ETH_P_IP) + if (proto != ETH_P_IP) { - DPRINTF("+++ C+ mode has IP packet\n"); - - /* not aligned */ - eth_payload_data = saved_buffer + ETH_HLEN; - eth_payload_len = saved_size - ETH_HLEN; - - ip = (ip_header*)eth_payload_data; - - if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { - DPRINTF("+++ C+ mode packet has bad IP version %d " - "expected %d\n", IP_HEADER_VERSION(ip), - IP_HEADER_VERSION_4); - ip = NULL; - } else { - hlen = IP_HEADER_LENGTH(ip); - ip_protocol = ip->ip_p; - ip_data_len = be16_to_cpu(ip->ip_len) - hlen; - } + goto skip_offload; + } + + DPRINTF("+++ C+ mode has IP packet\n"); + + /* not aligned */ + eth_payload_data = saved_buffer + ETH_HLEN; + eth_payload_len = saved_size - ETH_HLEN; + + ip = (ip_header*)eth_payload_data; + + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + DPRINTF("+++ C+ mode packet has bad IP version %d " + "expected %d\n", IP_HEADER_VERSION(ip), + IP_HEADER_VERSION_4); + goto skip_offload; } - if (ip) + hlen = IP_HEADER_LENGTH(ip); + if (hlen < sizeof(ip_header) || hlen > eth_payload_len) { + goto skip_offload; + } + + ip_protocol = ip->ip_p; + + ip_data_len = be16_to_cpu(ip->ip_len); + if (ip_data_len < hlen || ip_data_len > eth_payload_len) { + goto skip_offload; + } + ip_data_len -= hlen; + + if (txdw0 & CP_TX_IPCS) { - if (txdw0 & CP_TX_IPCS) - { - DPRINTF("+++ C+ mode need IP checksum\n"); + DPRINTF("+++ C+ mode need IP checksum\n"); - if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */ - /* bad packet header len */ - /* or packet too short */ - } - else - { - ip->ip_sum = 0; - ip->ip_sum = ip_checksum(ip, hlen); - DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n", - hlen, ip->ip_sum); - } + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(ip, hlen); + DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n", + hlen, ip->ip_sum); + } + + if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) + { + /* Large enough for the TCP header? */ + if (ip_data_len < sizeof(tcp_header)) { + goto skip_offload; } - if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) - { - int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; - DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " - "frame data %d specified MSS=%d\n", ETH_MTU, - ip_data_len, saved_size - ETH_HLEN, large_send_mss); + DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " + "frame data %d specified MSS=%d\n", ETH_MTU, + ip_data_len, saved_size - ETH_HLEN, large_send_mss); - int tcp_send_offset = 0; - int send_count = 0; + int tcp_send_offset = 0; + int send_count = 0; - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; - /* save IP header template; data area is used in tcp checksum calculation */ - memcpy(saved_ip_header, eth_payload_data, hlen); + /* save IP header template; data area is used in tcp checksum calculation */ + memcpy(saved_ip_header, eth_payload_data, hlen); - /* a placeholder for checksum calculation routine in tcp case */ - uint8_t *data_to_checksum = eth_payload_data + hlen - 12; - // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + /* a placeholder for checksum calculation routine in tcp case */ + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; - /* pointer to TCP header */ - tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + /* pointer to TCP header */ + tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); - int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); - /* ETH_MTU = ip header len + tcp header len + payload */ - int tcp_data_len = ip_data_len - tcp_hlen; - int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; + /* Invalid TCP data offset? */ + if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) { + goto skip_offload; + } - DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " - "data len %d TCP chunk size %d\n", ip_data_len, - tcp_hlen, tcp_data_len, tcp_chunk_size); + /* ETH_MTU = ip header len + tcp header len + payload */ + int tcp_data_len = ip_data_len - tcp_hlen; + int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; - /* note the cycle below overwrites IP header data, - but restores it from saved_ip_header before sending packet */ + DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " + "data len %d TCP chunk size %d\n", ip_data_len, + tcp_hlen, tcp_data_len, tcp_chunk_size); - int is_last_frame = 0; + /* note the cycle below overwrites IP header data, + but restores it from saved_ip_header before sending packet */ - for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) - { - uint16_t chunk_size = tcp_chunk_size; - - /* check if this is the last frame */ - if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) - { - is_last_frame = 1; - chunk_size = tcp_data_len - tcp_send_offset; - } - - DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", - be32_to_cpu(p_tcp_hdr->th_seq)); - - /* add 4 TCP pseudoheader fields */ - /* copy IP source and destination fields */ - memcpy(data_to_checksum, saved_ip_header + 12, 8); - - DPRINTF("+++ C+ mode TSO calculating TCP checksum for " - "packet with %d bytes data\n", tcp_hlen + - chunk_size); - - if (tcp_send_offset) - { - memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); - } - - /* keep PUSH and FIN flags only for the last frame */ - if (!is_last_frame) - { - TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); - } - - /* recalculate TCP checksum */ - ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_tcpip_hdr->zeros = 0; - p_tcpip_hdr->ip_proto = IP_PROTO_TCP; - p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); - - p_tcp_hdr->th_sum = 0; - - int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); - DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", - tcp_checksum); - - p_tcp_hdr->th_sum = tcp_checksum; - - /* restore IP header */ - memcpy(eth_payload_data, saved_ip_header, hlen); - - /* set IP data length and recalculate IP checksum */ - ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); - - /* increment IP id for subsequent frames */ - ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); - - ip->ip_sum = 0; - ip->ip_sum = ip_checksum(eth_payload_data, hlen); - DPRINTF("+++ C+ mode TSO IP header len=%d " - "checksum=%04x\n", hlen, ip->ip_sum); - - int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; - DPRINTF("+++ C+ mode TSO transferring packet size " - "%d\n", tso_send_size); - rtl8139_transfer_frame(s, saved_buffer, tso_send_size, - 0, (uint8_t *) dot1q_buffer); - - /* add transferred count to TCP sequence number */ - p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); - ++send_count; - } + int is_last_frame = 0; - /* Stop sending this frame */ - saved_size = 0; - } - else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) { - DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); + uint16_t chunk_size = tcp_chunk_size; - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; - memcpy(saved_ip_header, eth_payload_data, hlen); + /* check if this is the last frame */ + if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) + { + is_last_frame = 1; + chunk_size = tcp_data_len - tcp_send_offset; + } - uint8_t *data_to_checksum = eth_payload_data + hlen - 12; - // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", + be32_to_cpu(p_tcp_hdr->th_seq)); /* add 4 TCP pseudoheader fields */ /* copy IP source and destination fields */ memcpy(data_to_checksum, saved_ip_header + 12, 8); - if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) + DPRINTF("+++ C+ mode TSO calculating TCP checksum for " + "packet with %d bytes data\n", tcp_hlen + + chunk_size); + + if (tcp_send_offset) + { + memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); + } + + /* keep PUSH and FIN flags only for the last frame */ + if (!is_last_frame) { - DPRINTF("+++ C+ mode calculating TCP checksum for " - "packet with %d bytes data\n", ip_data_len); + TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); + } - ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_tcpip_hdr->zeros = 0; - p_tcpip_hdr->ip_proto = IP_PROTO_TCP; - p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + /* recalculate TCP checksum */ + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); - tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); + p_tcp_hdr->th_sum = 0; - p_tcp_hdr->th_sum = 0; + int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); + DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", + tcp_checksum); - int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DPRINTF("+++ C+ mode TCP checksum %04x\n", - tcp_checksum); + p_tcp_hdr->th_sum = tcp_checksum; - p_tcp_hdr->th_sum = tcp_checksum; - } - else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) - { - DPRINTF("+++ C+ mode calculating UDP checksum for " - "packet with %d bytes data\n", ip_data_len); + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); - ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_udpip_hdr->zeros = 0; - p_udpip_hdr->ip_proto = IP_PROTO_UDP; - p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + /* set IP data length and recalculate IP checksum */ + ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); - udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); + /* increment IP id for subsequent frames */ + ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); - p_udp_hdr->uh_sum = 0; + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(eth_payload_data, hlen); + DPRINTF("+++ C+ mode TSO IP header len=%d " + "checksum=%04x\n", hlen, ip->ip_sum); - int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DPRINTF("+++ C+ mode UDP checksum %04x\n", - udp_checksum); + int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; + DPRINTF("+++ C+ mode TSO transferring packet size " + "%d\n", tso_send_size); + rtl8139_transfer_frame(s, saved_buffer, tso_send_size, + 0, (uint8_t *) dot1q_buffer); - p_udp_hdr->uh_sum = udp_checksum; - } + /* add transferred count to TCP sequence number */ + p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); + ++send_count; + } - /* restore IP header */ - memcpy(eth_payload_data, saved_ip_header, hlen); + /* Stop sending this frame */ + saved_size = 0; + } + else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + { + DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + memcpy(saved_ip_header, eth_payload_data, hlen); + + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) + { + DPRINTF("+++ C+ mode calculating TCP checksum for " + "packet with %d bytes data\n", ip_data_len); + + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DPRINTF("+++ C+ mode TCP checksum %04x\n", + tcp_checksum); + + p_tcp_hdr->th_sum = tcp_checksum; } + else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) + { + DPRINTF("+++ C+ mode calculating UDP checksum for " + "packet with %d bytes data\n", ip_data_len); + + ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_udpip_hdr->zeros = 0; + p_udpip_hdr->ip_proto = IP_PROTO_UDP; + p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); + + p_udp_hdr->uh_sum = 0; + + int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DPRINTF("+++ C+ mode UDP checksum %04x\n", + udp_checksum); + + p_udp_hdr->uh_sum = udp_checksum; + } + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); } } +skip_offload: /* update tally counter */ ++s->tally_counters.TxOk; diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1510839547..8d28e45afc 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1124,7 +1124,7 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) virtqueue_push(q->tx_vq, &q->async_tx.elem, 0); virtio_notify(vdev, q->tx_vq); - q->async_tx.elem.out_num = q->async_tx.len = 0; + q->async_tx.elem.out_num = 0; virtio_queue_set_notification(q->tx_vq, 1); virtio_net_flush_tx(q); @@ -1148,7 +1148,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) } while (virtqueue_pop(q->tx_vq, &elem)) { - ssize_t ret, len; + ssize_t ret; unsigned int out_num = elem.out_num; struct iovec *out_sg = &elem.out_sg[0]; struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1]; @@ -1196,18 +1196,14 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) out_sg = sg; } - len = n->guest_hdr_len; - 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; - q->async_tx.len = len; return -EBUSY; } - len += ret; drop: virtqueue_push(q->tx_vq, &elem, 0); virtio_notify(vdev, q->tx_vq); diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 59b06b8412..071feebf15 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -927,9 +927,9 @@ static void vmxnet3_rx_need_csum_calculate(struct VmxnetRxPkt *pkt, /* Validate packet len: csum_start + scum_offset + length of csum field */ if (pkt_len < (vhdr->csum_start + vhdr->csum_offset + 2)) { - VMW_PKPRN("packet len:%d < csum_start(%d) + csum_offset(%d) + 2, " + VMW_PKPRN("packet len:%lu < csum_start(%d) + csum_offset(%d) + 2, " "cannot calculate checksum", - len, vhdr->csum_start, vhdr->csum_offset); + pkt_len, vhdr->csum_start, vhdr->csum_offset); return; } diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 3a731fe18d..4139a2c468 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -355,6 +355,10 @@ static uint64_t bonito_ldma_readl(void *opaque, hwaddr addr, uint32_t val; PCIBonitoState *s = opaque; + if (addr >= sizeof(s->bonldma)) { + return 0; + } + val = ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)]; return val; @@ -365,6 +369,10 @@ static void bonito_ldma_writel(void *opaque, hwaddr addr, { PCIBonitoState *s = opaque; + if (addr >= sizeof(s->bonldma)) { + return; + } + ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)] = val & 0xffffffff; } @@ -384,6 +392,10 @@ static uint64_t bonito_cop_readl(void *opaque, hwaddr addr, uint32_t val; PCIBonitoState *s = opaque; + if (addr >= sizeof(s->boncop)) { + return 0; + } + val = ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)]; return val; @@ -394,6 +406,10 @@ static void bonito_cop_writel(void *opaque, hwaddr addr, { PCIBonitoState *s = opaque; + if (addr >= sizeof(s->boncop)) { + return; + } + ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)] = val & 0xffffffff; } diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index ad55f99663..1cb25f3fa6 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -117,6 +117,11 @@ struct PCII440FXState { #define I440FX_PAM_SIZE 7 #define I440FX_SMRAM 0x72 +/* Older coreboot versions (4.0 and older) read a config register that doesn't + * exist in real hardware, to get the RAM size from QEMU. + */ +#define I440FX_COREBOOT_RAM_SIZE 0x57 + static void piix3_set_irq(void *opaque, int pirq, int level); static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx); static void piix3_write_config_xen(PCIDevice *dev, @@ -394,7 +399,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, if (ram_size > 255) { ram_size = 255; } - d->config[0x57] = ram_size; + d->config[I440FX_COREBOOT_RAM_SIZE] = ram_size; i440fx_update_memory_mappings(f); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index a017614d48..9f57aeaeba 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -38,6 +38,7 @@ #include "hw/pci/msix.h" #include "exec/address-spaces.h" #include "hw/hotplug.h" +#include "hw/boards.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -1065,6 +1066,10 @@ static pcibus_t pci_bar_address(PCIDevice *d, pcibus_t new_addr, last_addr; int bar = pci_bar(d, reg); uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); + Object *machine = qdev_get_machine(); + ObjectClass *oc = object_get_class(machine); + MachineClass *mc = MACHINE_CLASS(oc); + bool allow_0_address = mc->pci_allow_0_address; if (type & PCI_BASE_ADDRESS_SPACE_IO) { if (!(cmd & PCI_COMMAND_IO)) { @@ -1075,7 +1080,8 @@ static pcibus_t pci_bar_address(PCIDevice *d, /* Check if 32 bit BAR wraps around explicitly. * TODO: make priorities correct and remove this work around. */ - if (last_addr <= new_addr || new_addr == 0 || last_addr >= UINT32_MAX) { + if (last_addr <= new_addr || last_addr >= UINT32_MAX || + (!allow_0_address && new_addr == 0)) { return PCI_BAR_UNMAPPED; } return new_addr; @@ -1099,8 +1105,8 @@ static pcibus_t pci_bar_address(PCIDevice *d, /* XXX: as we cannot support really dynamic mappings, we handle specific values as invalid mappings. */ - if (last_addr <= new_addr || new_addr == 0 || - last_addr == PCI_BAR_UNMAPPED) { + if (last_addr <= new_addr || last_addr == PCI_BAR_UNMAPPED || + (!allow_0_address && new_addr == 0)) { return PCI_BAR_UNMAPPED; } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index a6f19473cf..bf0c64f2d4 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1835,6 +1835,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 512 * M_BYTE; mc->kvm_type = spapr_kvm_type; mc->has_dynamic_sysbus = true; + mc->pci_allow_0_address = true; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; diff --git a/hw/smbios/Makefile.objs b/hw/smbios/Makefile.objs new file mode 100644 index 0000000000..f69a92f967 --- /dev/null +++ b/hw/smbios/Makefile.objs @@ -0,0 +1 @@ +common-obj-$(CONFIG_SMBIOS) += smbios.o diff --git a/hw/i386/smbios.c b/hw/smbios/smbios.c index 1341e02344..efdbb5de6f 100644 --- a/hw/i386/smbios.c +++ b/hw/smbios/smbios.c @@ -19,10 +19,9 @@ #include "qemu/error-report.h" #include "sysemu/sysemu.h" #include "sysemu/cpus.h" -#include "hw/i386/pc.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/loader.h" - +#include "exec/cpu-common.h" /* legacy structures and constants for <= 2.0 machines */ struct smbios_header { @@ -831,10 +830,12 @@ static void smbios_entry_point_setup(void) ep.structure_table_address = cpu_to_le32(0); } -void smbios_get_tables(uint8_t **tables, size_t *tables_len, +void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, + const unsigned int mem_array_size, + uint8_t **tables, size_t *tables_len, uint8_t **anchor, size_t *anchor_len) { - unsigned i, dimm_cnt, instance; + unsigned i, dimm_cnt; if (smbios_legacy) { *tables = *anchor = NULL; @@ -867,11 +868,9 @@ void smbios_get_tables(uint8_t **tables, size_t *tables_len, smbios_build_type_17_table(i, GET_DIMM_SZ); } - for (i = 0, instance = 0; i < e820_get_num_entries(); i++) { - uint64_t address, length; - if (e820_get_entry(i, E820_RAM, &address, &length)) { - smbios_build_type_19_table(instance++, address, length); - } + for (i = 0; i < mem_array_size; i++) { + smbios_build_type_19_table(i, mem_array[i].address, + mem_array[i].length); } smbios_build_type_32_table(); diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index ffefc22f43..10c5d2b91e 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -5,23 +5,18 @@ * Copyright (c) 2011 NICTA Pty Ltd * Originally written by Hans Jiang * Updated by Peter Chubb - * Updated by Jean-Christophe Dubois + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. * */ -#include "hw/hw.h" -#include "qemu/bitops.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "hw/sysbus.h" #include "hw/arm/imx.h" +#include "hw/timer/imx_epit.h" +#include "hw/misc/imx_ccm.h" #include "qemu/main-loop.h" -#define TYPE_IMX_EPIT "imx.epit" - #define DEBUG_TIMER 0 #if DEBUG_TIMER @@ -61,30 +56,6 @@ static char const *imx_epit_reg_name(uint32_t reg) # define IPRINTF(fmt, args...) do {} while (0) #endif -#define IMX_EPIT(obj) \ - OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT) - -/* - * EPIT: Enhanced periodic interrupt timer - */ - -#define CR_EN (1 << 0) -#define CR_ENMOD (1 << 1) -#define CR_OCIEN (1 << 2) -#define CR_RLD (1 << 3) -#define CR_PRESCALE_SHIFT (4) -#define CR_PRESCALE_MASK (0xfff) -#define CR_SWR (1 << 16) -#define CR_IOVW (1 << 17) -#define CR_DBGEN (1 << 18) -#define CR_WAITEN (1 << 19) -#define CR_DOZEN (1 << 20) -#define CR_STOPEN (1 << 21) -#define CR_CLKSRC_SHIFT (24) -#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) - -#define EPIT_TIMER_MAX 0XFFFFFFFFUL - /* * Exact clock frequencies vary from board to board. * These are typical. @@ -96,23 +67,6 @@ static const IMXClk imx_epit_clocks[] = { CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */ }; -typedef struct { - SysBusDevice busdev; - ptimer_state *timer_reload; - ptimer_state *timer_cmp; - MemoryRegion iomem; - DeviceState *ccm; - - uint32_t cr; - uint32_t sr; - uint32_t lr; - uint32_t cmp; - uint32_t cnt; - - uint32_t freq; - qemu_irq irq; -} IMXEPITState; - /* * Update interrupt status */ @@ -174,9 +128,9 @@ static void imx_epit_reset(DeviceState *dev) static uint32_t imx_epit_update_count(IMXEPITState *s) { - s->cnt = ptimer_get_count(s->timer_reload); + s->cnt = ptimer_get_count(s->timer_reload); - return s->cnt; + return s->cnt; } static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) @@ -344,13 +298,13 @@ void imx_timerp_create(const hwaddr addr, qemu_irq irq, DeviceState *ccm) } static const MemoryRegionOps imx_epit_ops = { - .read = imx_epit_read, - .write = imx_epit_write, - .endianness = DEVICE_NATIVE_ENDIAN, + .read = imx_epit_read, + .write = imx_epit_write, + .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_imx_timer_epit = { - .name = "imx.epit", + .name = TYPE_IMX_EPIT, .version_id = 2, .minimum_version_id = 2, .fields = (VMStateField[]) { diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 3b3101084b..01f802e8f1 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -5,23 +5,18 @@ * Copyright (c) 2011 NICTA Pty Ltd * Originally written by Hans Jiang * Updated by Peter Chubb - * Updated by Jean-Christophe Dubois + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * * This code is licensed under GPL version 2 or later. See * the COPYING file in the top-level directory. * */ -#include "hw/hw.h" -#include "qemu/bitops.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "hw/sysbus.h" #include "hw/arm/imx.h" +#include "hw/timer/imx_gpt.h" +#include "hw/misc/imx_ccm.h" #include "qemu/main-loop.h" -#define TYPE_IMX_GPT "imx.gpt" - /* * Define to 1 for debug messages */ @@ -74,76 +69,8 @@ static char const *imx_gpt_reg_name(uint32_t reg) # define IPRINTF(fmt, args...) do {} while (0) #endif -#define IMX_GPT(obj) \ - OBJECT_CHECK(IMXGPTState, (obj), TYPE_IMX_GPT) -/* - * GPT : General purpose timer - * - * This timer counts up continuously while it is enabled, resetting itself - * to 0 when it reaches GPT_TIMER_MAX (in freerun mode) or when it - * reaches the value of one of the ocrX (in periodic mode). - */ - -#define GPT_TIMER_MAX 0XFFFFFFFFUL - -/* Control register. Not all of these bits have any effect (yet) */ -#define GPT_CR_EN (1 << 0) /* GPT Enable */ -#define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ -#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ -#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ -#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ -#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ -#define GPT_CR_CLKSRC_SHIFT (6) -#define GPT_CR_CLKSRC_MASK (0x7) - -#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ -#define GPT_CR_SWR (1 << 15) /* Software Reset */ -#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ -#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ -#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ -#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ -#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ -#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ -#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ -#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ - -#define GPT_SR_OF1 (1 << 0) -#define GPT_SR_OF2 (1 << 1) -#define GPT_SR_OF3 (1 << 2) -#define GPT_SR_ROV (1 << 5) - -#define GPT_IR_OF1IE (1 << 0) -#define GPT_IR_OF2IE (1 << 1) -#define GPT_IR_OF3IE (1 << 2) -#define GPT_IR_ROVIE (1 << 5) - -typedef struct { - SysBusDevice busdev; - ptimer_state *timer; - MemoryRegion iomem; - DeviceState *ccm; - - uint32_t cr; - uint32_t pr; - uint32_t sr; - uint32_t ir; - uint32_t ocr1; - uint32_t ocr2; - uint32_t ocr3; - uint32_t icr1; - uint32_t icr2; - uint32_t cnt; - - uint32_t next_timeout; - uint32_t next_int; - - uint32_t freq; - - qemu_irq irq; -} IMXGPTState; - static const VMStateDescription vmstate_imx_timer_gpt = { - .name = "imx.gpt", + .name = TYPE_IMX_GPT, .version_id = 3, .minimum_version_id = 3, .fields = (VMStateField[]) { @@ -180,7 +107,7 @@ static void imx_gpt_set_freq(IMXGPTState *s) { uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); uint32_t freq = imx_clock_frequency(s->ccm, imx_gpt_clocks[clksrc]) - / (1 + s->pr); + / (1 + s->pr); s->freq = freq; DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq); @@ -207,7 +134,7 @@ static uint32_t imx_gpt_update_count(IMXGPTState *s) } static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, - uint32_t timeout) + uint32_t timeout) { if ((count < reg) && (timeout > reg)) { timeout = reg; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index ee4e07c5e7..788b556a74 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1049,6 +1049,61 @@ static bool virtio_64bit_features_needed(void *opaque) return (vdev->host_features >> 32) != 0; } +static bool virtio_virtqueue_needed(void *opaque) +{ + VirtIODevice *vdev = opaque; + + return virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1); +} + +static void put_virtqueue_state(QEMUFile *f, void *pv, size_t size) +{ + VirtIODevice *vdev = pv; + int i; + + for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { + qemu_put_be64(f, vdev->vq[i].vring.avail); + qemu_put_be64(f, vdev->vq[i].vring.used); + } +} + +static int get_virtqueue_state(QEMUFile *f, void *pv, size_t size) +{ + VirtIODevice *vdev = pv; + int i; + + for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { + vdev->vq[i].vring.avail = qemu_get_be64(f); + vdev->vq[i].vring.used = qemu_get_be64(f); + } + return 0; +} + +static VMStateInfo vmstate_info_virtqueue = { + .name = "virtqueue_state", + .get = get_virtqueue_state, + .put = put_virtqueue_state, +}; + +static const VMStateDescription vmstate_virtio_virtqueues = { + .name = "virtio/virtqueues", + .version_id = 1, + .minimum_version_id = 1, + .needed = &virtio_virtqueue_needed, + .fields = (VMStateField[]) { + { + .name = "virtqueues", + .version_id = 0, + .field_exists = NULL, + .size = 0, + .info = &vmstate_info_virtqueue, + .flags = VMS_SINGLE, + .offset = 0, + }, + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_virtio_device_endian = { .name = "virtio/device_endian", .version_id = 1, @@ -1082,6 +1137,7 @@ static const VMStateDescription vmstate_virtio = { .subsections = (const VMStateDescription*[]) { &vmstate_virtio_device_endian, &vmstate_virtio_64bit_features, + &vmstate_virtio_virtqueues, NULL } }; diff --git a/include/exec/memory.h b/include/exec/memory.h index 94d20eae05..b18b351e33 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -437,6 +437,9 @@ void memory_region_init_alias(MemoryRegion *mr, * memory_region_init_rom_device: Initialize a ROM memory region. Writes are * handled via callbacks. * + * If NULL callbacks pointer is given, then I/O space is not supposed to be + * handled by QEMU itself. Any access via the memory API will cause an abort(). + * * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count * @ops: callbacks for write access handling. @@ -459,16 +462,21 @@ void memory_region_init_rom_device(MemoryRegion *mr, * A reservation region primariy serves debugging purposes. It claims I/O * space that is not supposed to be handled by QEMU itself. Any access via * the memory API will cause an abort(). + * This function is deprecated. Use memory_region_init_io() with NULL + * callbacks instead. * * @mr: the #MemoryRegion to be initialized * @owner: the object that tracks the region's reference count * @name: used for debugging; not visible to the user or ABI * @size: size of the region. */ -void memory_region_init_reservation(MemoryRegion *mr, - struct Object *owner, +static inline void memory_region_init_reservation(MemoryRegion *mr, + Object *owner, const char *name, - uint64_t size); + uint64_t size) +{ + memory_region_init_io(mr, owner, NULL, mr, name, size); +} /** * memory_region_init_iommu: Initialize a memory region that translates diff --git a/include/hw/arm/imx.h b/include/hw/arm/imx.h index ea9e093277..b1885603c3 100644 --- a/include/hw/arm/imx.h +++ b/include/hw/arm/imx.h @@ -11,17 +11,9 @@ #ifndef IMX_H #define IMX_H -void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq); - -typedef enum { - NOCLK, - MCU, - HSP, - IPG, - CLK_32k -} IMXClk; +#include "hw/misc/imx_ccm.h" -uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock); +void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq); void imx_timerp_create(const hwaddr addr, qemu_irq irq, diff --git a/include/hw/boards.h b/include/hw/boards.h index 2aec9cbb12..3f84afdf1c 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -100,7 +100,8 @@ struct MachineClass { no_cdrom:1, no_sdcard:1, has_dynamic_sysbus:1, - no_tco:1; + no_tco:1, + pci_allow_0_address:1; int is_default; const char *default_machine_opts; const char *default_boot_order; diff --git a/include/hw/char/imx_serial.h b/include/hw/char/imx_serial.h new file mode 100644 index 0000000000..6cd75c0ba7 --- /dev/null +++ b/include/hw/char/imx_serial.h @@ -0,0 +1,102 @@ +/* + * Device model for i.MX UART + * + * Copyright (c) 2008 OKL + * Originally Written by Hans Jiang + * Copyright (c) 2011 NICTA Pty Ltd. + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef IMX_SERIAL_H +#define IMX_SERIAL_H + +#include "hw/sysbus.h" + +#define TYPE_IMX_SERIAL "imx.serial" +#define IMX_SERIAL(obj) OBJECT_CHECK(IMXSerialState, (obj), TYPE_IMX_SERIAL) + +#define URXD_CHARRDY (1<<15) /* character read is valid */ +#define URXD_ERR (1<<14) /* Character has error */ +#define URXD_BRK (1<<11) /* Break received */ + +#define USR1_PARTYER (1<<15) /* Parity Error */ +#define USR1_RTSS (1<<14) /* RTS pin status */ +#define USR1_TRDY (1<<13) /* Tx ready */ +#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */ +#define USR1_ESCF (1<<11) /* Escape sequence interrupt */ +#define USR1_FRAMERR (1<<10) /* Framing error */ +#define USR1_RRDY (1<<9) /* receiver ready */ +#define USR1_AGTIM (1<<8) /* Aging timer interrupt */ +#define USR1_DTRD (1<<7) /* DTR changed */ +#define USR1_RXDS (1<<6) /* Receiver is idle */ +#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */ +#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */ + +#define USR2_ADET (1<<15) /* Autobaud complete */ +#define USR2_TXFE (1<<14) /* Transmit FIFO empty */ +#define USR2_DTRF (1<<13) /* DTR/DSR transition */ +#define USR2_IDLE (1<<12) /* UART has been idle for too long */ +#define USR2_ACST (1<<11) /* Autobaud counter stopped */ +#define USR2_RIDELT (1<<10) /* Ring Indicator delta */ +#define USR2_RIIN (1<<9) /* Ring Indicator Input */ +#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */ +#define USR2_WAKE (1<<7) /* Start bit detected */ +#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */ +#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */ +#define USR2_RTSF (1<<4) /* RTS transition */ +#define USR2_TXDC (1<<3) /* Transmission complete */ +#define USR2_BRCD (1<<2) /* Break condition detected */ +#define USR2_ORE (1<<1) /* Overrun error */ +#define USR2_RDR (1<<0) /* Receive data ready */ + +#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */ +#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */ +#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */ +#define UCR1_UARTEN (1<<0) /* UART Enable */ + +#define UCR2_TXEN (1<<2) /* Transmitter enable */ +#define UCR2_RXEN (1<<1) /* Receiver enable */ +#define UCR2_SRST (1<<0) /* Reset complete */ + +#define UTS1_TXEMPTY (1<<6) +#define UTS1_RXEMPTY (1<<5) +#define UTS1_TXFULL (1<<4) +#define UTS1_RXFULL (1<<3) + +typedef struct IMXSerialState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + int32_t readbuff; + + uint32_t usr1; + uint32_t usr2; + uint32_t ucr1; + uint32_t ucr2; + uint32_t uts1; + + /* + * The registers below are implemented just so that the + * guest OS sees what it has written + */ + uint32_t onems; + uint32_t ufcr; + uint32_t ubmr; + uint32_t ubrc; + uint32_t ucr3; + + qemu_irq irq; + CharDriverState *chr; +} IMXSerialState; + +#endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c4165740cf..d0cad87d21 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -2,6 +2,7 @@ #define HW_PC_H #include "qemu-common.h" +#include "qemu/typedefs.h" #include "exec/memory.h" #include "hw/boards.h" #include "hw/isa/isa.h" @@ -39,6 +40,7 @@ struct PCMachineState { OnOffAuto vmport; OnOffAuto smm; bool enforce_aligned_dimm; + ram_addr_t below_4g_mem_size, above_4g_mem_size; }; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" @@ -61,9 +63,6 @@ struct PCMachineClass { DeviceState *dev); }; -typedef struct PCMachineState PCMachineState; -typedef struct PCMachineClass PCMachineClass; - #define TYPE_PC_MACHINE "generic-pc-machine" #define PC_MACHINE(obj) \ OBJECT_CHECK(PCMachineState, (obj), TYPE_PC_MACHINE) @@ -166,8 +165,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge); void pc_hot_add_cpu(const int64_t id, Error **errp); void pc_acpi_init(const char *default_dsdt); -PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size); +PcGuestInfo *pc_guest_info_init(PCMachineState *pcms); void pc_set_legacy_acpi_data_size(void); @@ -182,15 +180,10 @@ void pc_set_legacy_acpi_data_size(void); void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, MemoryRegion *pci_address_space); -FWCfgState *xen_load_linux(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - ram_addr_t below_4g_mem_size, +FWCfgState *xen_load_linux(PCMachineState *pcms, PcGuestInfo *guest_info); -FWCfgState *pc_memory_init(MachineState *machine, +FWCfgState *pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, MemoryRegion *rom_memory, MemoryRegion **ram_memory, PcGuestInfo *guest_info); @@ -202,8 +195,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, bool no_vmport, uint32 hpet_irqs); void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); -void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, MachineState *machine, +void pc_cmos_init(PCMachineState *pcms, BusState *ide0, BusState *ide1, ISADevice *s); void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus); @@ -351,6 +343,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .property = "xlevel",\ .value = stringify(0x8000000a),\ },{\ + .driver = "IvyBridge" "-" TYPE_X86_CPU,\ + .property = "xlevel",\ + .value = stringify(0x8000000a),\ + },{\ .driver = "Haswell" "-" TYPE_X86_CPU,\ .property = "xlevel",\ .value = stringify(0x8000000a),\ @@ -370,11 +366,111 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); #define PC_COMPAT_2_2 \ PC_COMPAT_2_3 \ - HW_COMPAT_2_2 + HW_COMPAT_2_2 \ + {\ + .driver = "kvm64" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "kvm32" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Conroe" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Penryn" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Nehalem" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Westmere" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "SandyBridge" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Haswell" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Broadwell" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Haswell" "-" TYPE_X86_CPU,\ + .property = "f16c",\ + .value = "off",\ + },\ + {\ + .driver = "Haswell" "-" TYPE_X86_CPU,\ + .property = "rdrand",\ + .value = "off",\ + },\ + {\ + .driver = "Broadwell" "-" TYPE_X86_CPU,\ + .property = "f16c",\ + .value = "off",\ + },\ + {\ + .driver = "Broadwell" "-" TYPE_X86_CPU,\ + .property = "rdrand",\ + .value = "off",\ + }, #define PC_COMPAT_2_1 \ PC_COMPAT_2_2 \ - HW_COMPAT_2_1 + HW_COMPAT_2_1 \ + {\ + .driver = "coreduo" "-" TYPE_X86_CPU,\ + .property = "vmx",\ + .value = "on",\ + },\ + {\ + .driver = "core2duo" "-" TYPE_X86_CPU,\ + .property = "vmx",\ + .value = "on",\ + }, #define PC_COMPAT_2_0 \ PC_COMPAT_2_1 \ @@ -585,20 +681,18 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .driver = "486-" TYPE_X86_CPU,\ .property = "model",\ .value = stringify(0),\ + },\ + {\ + .driver = "n270" "-" TYPE_X86_CPU,\ + .property = "movbe",\ + .value = "off",\ + },\ + {\ + .driver = "Westmere" "-" TYPE_X86_CPU,\ + .property = "pclmulqdq",\ + .value = "off",\ }, -static inline void pc_common_machine_options(MachineClass *m) -{ - m->default_boot_order = "cad"; -} - -static inline void pc_default_machine_options(MachineClass *m) -{ - pc_common_machine_options(m); - m->hot_add_cpu = pc_hot_add_cpu; - m->max_cpus = 255; -} - #define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \ static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \ { \ diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index 899db3d7a0..edca3e08e9 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -138,4 +138,7 @@ typedef struct ARMGICCommonClass { void (*post_load)(GICState *s); } ARMGICCommonClass; +void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler, + const MemoryRegionOps *ops); + #endif diff --git a/include/hw/intc/imx_avic.h b/include/hw/intc/imx_avic.h new file mode 100644 index 0000000000..1b80769018 --- /dev/null +++ b/include/hw/intc/imx_avic.h @@ -0,0 +1,55 @@ +/* + * i.MX31 Vectored Interrupt Controller + * + * Note this is NOT the PL192 provided by ARM, but + * a custom implementation by Freescale. + * + * Copyright (c) 2008 OKL + * Copyright (c) 2011 NICTA Pty Ltd + * Originally written by Hans Jiang + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + * + * TODO: implement vectors. + */ +#ifndef IMX_AVIC_H +#define IMX_AVIC_H + +#include "hw/sysbus.h" + +#define TYPE_IMX_AVIC "imx.avic" +#define IMX_AVIC(obj) OBJECT_CHECK(IMXAVICState, (obj), TYPE_IMX_AVIC) + +#define IMX_AVIC_NUM_IRQS 64 + +/* Interrupt Control Bits */ +#define ABFLAG (1<<25) +#define ABFEN (1<<24) +#define NIDIS (1<<22) /* Normal Interrupt disable */ +#define FIDIS (1<<21) /* Fast interrupt disable */ +#define NIAD (1<<20) /* Normal Interrupt Arbiter Rise ARM level */ +#define FIAD (1<<19) /* Fast Interrupt Arbiter Rise ARM level */ +#define NM (1<<18) /* Normal interrupt mode */ + +#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4) +#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD) + +typedef struct IMXAVICState{ + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + uint64_t pending; + uint64_t enabled; + uint64_t is_fiq; + uint32_t intcntl; + uint32_t intmask; + qemu_irq irq; + qemu_irq fiq; + uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */ +} IMXAVICState; + +#endif /* IMX_AVIC_H */ diff --git a/include/hw/misc/imx_ccm.h b/include/hw/misc/imx_ccm.h new file mode 100644 index 0000000000..0f2e469b23 --- /dev/null +++ b/include/hw/misc/imx_ccm.h @@ -0,0 +1,91 @@ +/* + * IMX31 Clock Control Module + * + * Copyright (C) 2012 NICTA + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * + * 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 IMX_CCM_H +#define IMX_CCM_H + +#include "hw/sysbus.h" + +/* CCMR */ +#define CCMR_FPME (1<<0) +#define CCMR_MPE (1<<3) +#define CCMR_MDS (1<<7) +#define CCMR_FPMF (1<<26) +#define CCMR_PRCS (3<<1) + +/* PDR0 */ +#define PDR0_MCU_PODF_SHIFT (0) +#define PDR0_MCU_PODF_MASK (0x7) +#define PDR0_MAX_PODF_SHIFT (3) +#define PDR0_MAX_PODF_MASK (0x7) +#define PDR0_IPG_PODF_SHIFT (6) +#define PDR0_IPG_PODF_MASK (0x3) +#define PDR0_NFC_PODF_SHIFT (8) +#define PDR0_NFC_PODF_MASK (0x7) +#define PDR0_HSP_PODF_SHIFT (11) +#define PDR0_HSP_PODF_MASK (0x7) +#define PDR0_PER_PODF_SHIFT (16) +#define PDR0_PER_PODF_MASK (0x1f) +#define PDR0_CSI_PODF_SHIFT (23) +#define PDR0_CSI_PODF_MASK (0x1ff) + +#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \ + & PDR0_##name##_PODF_MASK) +#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \ + PDR0_##name##_PODF_SHIFT) + +/* PLL control registers */ +#define PD(v) (((v) >> 26) & 0xf) +#define MFD(v) (((v) >> 16) & 0x3ff) +#define MFI(v) (((v) >> 10) & 0xf); +#define MFN(v) ((v) & 0x3ff) + +#define PLL_PD(x) (((x) & 0xf) << 26) +#define PLL_MFD(x) (((x) & 0x3ff) << 16) +#define PLL_MFI(x) (((x) & 0xf) << 10) +#define PLL_MFN(x) (((x) & 0x3ff) << 0) + +#define TYPE_IMX_CCM "imx.ccm" +#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM) + +typedef struct IMXCCMState { + /* <private> */ + SysBusDevice parent_obj; + + /* <public> */ + MemoryRegion iomem; + + uint32_t ccmr; + uint32_t pdr0; + uint32_t pdr1; + uint32_t mpctl; + uint32_t spctl; + uint32_t cgr[3]; + uint32_t pmcr0; + uint32_t pmcr1; + + /* Frequencies precalculated on register changes */ + uint32_t pll_refclk_freq; + uint32_t mcu_clk_freq; + uint32_t hsp_clk_freq; + uint32_t ipg_clk_freq; +} IMXCCMState; + +typedef enum { + NOCLK, + MCU, + HSP, + IPG, + CLK_32k +} IMXClk; + +uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock); + +#endif /* IMX_CCM_H */ diff --git a/include/hw/i386/smbios.h b/include/hw/smbios/smbios.h index d2850bed2c..4269aabe4a 100644 --- a/include/hw/i386/smbios.h +++ b/include/hw/smbios/smbios.h @@ -17,13 +17,21 @@ #define SMBIOS_MAX_TYPE 127 +/* memory area description, used by type 19 table */ +struct smbios_phys_mem_area { + uint64_t address; + uint64_t length; +}; + void smbios_entry_add(QemuOpts *opts); void smbios_set_cpuid(uint32_t version, uint32_t features); void smbios_set_defaults(const char *manufacturer, const char *product, const char *version, bool legacy_mode, bool uuid_encoded); uint8_t *smbios_get_table_legacy(size_t *length); -void smbios_get_tables(uint8_t **tables, size_t *tables_len, +void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, + const unsigned int mem_array_size, + uint8_t **tables, size_t *tables_len, uint8_t **anchor, size_t *anchor_len); /* diff --git a/include/hw/timer/imx_epit.h b/include/hw/timer/imx_epit.h new file mode 100644 index 0000000000..c5328aefe1 --- /dev/null +++ b/include/hw/timer/imx_epit.h @@ -0,0 +1,79 @@ +/* + * i.MX EPIT Timer + * + * Copyright (c) 2008 OK Labs + * Copyright (c) 2011 NICTA Pty Ltd + * Originally written by Hans Jiang + * Updated by Peter Chubb + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * + * 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 IMX_EPIT_H +#define IMX_EPIT_H + +#include "hw/sysbus.h" +#include "hw/ptimer.h" + +/* + * EPIT: Enhanced periodic interrupt timer + */ + +#define CR_EN (1 << 0) +#define CR_ENMOD (1 << 1) +#define CR_OCIEN (1 << 2) +#define CR_RLD (1 << 3) +#define CR_PRESCALE_SHIFT (4) +#define CR_PRESCALE_MASK (0xfff) +#define CR_SWR (1 << 16) +#define CR_IOVW (1 << 17) +#define CR_DBGEN (1 << 18) +#define CR_WAITEN (1 << 19) +#define CR_DOZEN (1 << 20) +#define CR_STOPEN (1 << 21) +#define CR_CLKSRC_SHIFT (24) +#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) + +#define EPIT_TIMER_MAX 0XFFFFFFFFUL + +#define TYPE_IMX_EPIT "imx.epit" +#define IMX_EPIT(obj) OBJECT_CHECK(IMXEPITState, (obj), TYPE_IMX_EPIT) + +typedef struct IMXEPITState{ + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + ptimer_state *timer_reload; + ptimer_state *timer_cmp; + MemoryRegion iomem; + DeviceState *ccm; + + uint32_t cr; + uint32_t sr; + uint32_t lr; + uint32_t cmp; + uint32_t cnt; + + uint32_t freq; + qemu_irq irq; +} IMXEPITState; + +#endif /* IMX_EPIT_H */ diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h new file mode 100644 index 0000000000..3f02d3b337 --- /dev/null +++ b/include/hw/timer/imx_gpt.h @@ -0,0 +1,107 @@ +/* + * i.MX GPT Timer + * + * Copyright (c) 2008 OK Labs + * Copyright (c) 2011 NICTA Pty Ltd + * Originally written by Hans Jiang + * Updated by Peter Chubb + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * + * 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 IMX_GPT_H +#define IMX_GPT_H + +#include "hw/sysbus.h" +#include "hw/ptimer.h" + +/* + * GPT : General purpose timer + * + * This timer counts up continuously while it is enabled, resetting itself + * to 0 when it reaches GPT_TIMER_MAX (in freerun mode) or when it + * reaches the value of one of the ocrX (in periodic mode). + */ + +#define GPT_TIMER_MAX 0XFFFFFFFFUL + +/* Control register. Not all of these bits have any effect (yet) */ +#define GPT_CR_EN (1 << 0) /* GPT Enable */ +#define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ +#define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ +#define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ +#define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ +#define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ +#define GPT_CR_CLKSRC_SHIFT (6) +#define GPT_CR_CLKSRC_MASK (0x7) + +#define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ +#define GPT_CR_SWR (1 << 15) /* Software Reset */ +#define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ +#define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ +#define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ +#define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ +#define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ +#define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ +#define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ +#define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ + +#define GPT_SR_OF1 (1 << 0) +#define GPT_SR_OF2 (1 << 1) +#define GPT_SR_OF3 (1 << 2) +#define GPT_SR_ROV (1 << 5) + +#define GPT_IR_OF1IE (1 << 0) +#define GPT_IR_OF2IE (1 << 1) +#define GPT_IR_OF3IE (1 << 2) +#define GPT_IR_ROVIE (1 << 5) + +#define TYPE_IMX_GPT "imx.gpt" +#define IMX_GPT(obj) OBJECT_CHECK(IMXGPTState, (obj), TYPE_IMX_GPT) + +typedef struct IMXGPTState{ + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + ptimer_state *timer; + MemoryRegion iomem; + DeviceState *ccm; + + uint32_t cr; + uint32_t pr; + uint32_t sr; + uint32_t ir; + uint32_t ocr1; + uint32_t ocr2; + uint32_t ocr3; + uint32_t icr1; + uint32_t icr2; + uint32_t cnt; + + uint32_t next_timeout; + uint32_t next_int; + + uint32_t freq; + + qemu_irq irq; +} IMXGPTState; + +#endif /* IMX_GPT_H */ diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 60b11d5c2c..f3cc25feca 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -48,7 +48,6 @@ typedef struct VirtIONetQueue { int tx_waiting; struct { VirtQueueElement elem; - ssize_t len; } async_tx; struct VirtIONet *n; } VirtIONetQueue; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 59f0763ed8..cccae89d83 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -272,6 +272,12 @@ static inline bool virtio_has_feature(VirtIODevice *vdev, unsigned int fbit) return __virtio_has_feature(vdev->guest_features, fbit); } +static inline bool virtio_host_has_feature(VirtIODevice *vdev, + unsigned int fbit) +{ + return __virtio_has_feature(vdev->host_features, fbit); +} + static inline bool virtio_is_big_endian(VirtIODevice *vdev) { if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { diff --git a/include/migration/migration.h b/include/migration/migration.h index a2f8ed093c..83346210b1 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -203,4 +203,5 @@ void register_global_state(void); void global_state_set_optional(void); void savevm_skip_configuration(void); int global_state_store(void); +void global_state_store_running(void); #endif diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h index 995b2d5957..12faaad959 100644 --- a/include/qemu/throttle.h +++ b/include/qemu/throttle.h @@ -114,6 +114,8 @@ bool throttle_conflicting(ThrottleConfig *cfg); bool throttle_is_valid(ThrottleConfig *cfg); +bool throttle_max_is_missing_limit(ThrottleConfig *cfg); + void throttle_config(ThrottleState *ts, ThrottleTimers *tt, ThrottleConfig *cfg); diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 6fdcbcd524..f8a9dd6f10 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -58,6 +58,8 @@ typedef struct PCIESlot PCIESlot; typedef struct PCIExpressDevice PCIExpressDevice; typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIHostState PCIHostState; +typedef struct PCMachineState PCMachineState; +typedef struct PCMachineClass PCMachineClass; typedef struct PCMCIACardState PCMCIACardState; typedef struct PixelFormat PixelFormat; typedef struct PropertyInfo PropertyInfo; @@ -1182,7 +1182,7 @@ void memory_region_init_io(MemoryRegion *mr, uint64_t size) { memory_region_init(mr, owner, name, size); - mr->ops = ops; + mr->ops = ops ? ops : &unassigned_mem_ops; mr->opaque = opaque; mr->terminates = true; } @@ -1300,14 +1300,6 @@ void memory_region_init_iommu(MemoryRegion *mr, notifier_list_init(&mr->iommu_notify); } -void memory_region_init_reservation(MemoryRegion *mr, - Object *owner, - const char *name, - uint64_t size) -{ - memory_region_init_io(mr, owner, &unassigned_mem_ops, mr, name, size); -} - static void memory_region_finalize(Object *obj) { MemoryRegion *mr = MEMORY_REGION(obj); diff --git a/migration/migration.c b/migration/migration.c index fd4f99b84e..662e77e4eb 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -122,6 +122,13 @@ int global_state_store(void) return 0; } +void global_state_store_running(void) +{ + const char *state = RunState_lookup[RUN_STATE_RUNNING]; + strncpy((char *)global_state.runstate, + state, sizeof(global_state.runstate)); +} + static bool global_state_received(void) { return global_state.received; diff --git a/migration/savevm.c b/migration/savevm.c index 81dbe5879f..60712153fa 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1394,6 +1394,7 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp) saved_vm_running = runstate_is_running(); vm_stop(RUN_STATE_SAVE_VM); + global_state_store_running(); f = qemu_fopen(filename, "wb"); if (!f) { @@ -17,7 +17,7 @@ MAKEFLAGS += -rR QEMU_CXXFLAGS = -D__STDC_LIMIT_MACROS $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls, $(QEMU_CFLAGS)) # Flags for dependency generation -QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d +QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d # Same as -I$(SRC_PATH) -I., but for the nested source/object directories QEMU_INCLUDES += -I$(<D) -I$(@D) @@ -368,6 +368,6 @@ define unnest-vars $(error $o added in $v but $o-objs is not set))) $(shell mkdir -p ./ $(sort $(dir $($v)))) # Include all the .d files - $(eval -include $(addsuffix *.d, $(sort $(dir $($v))))) + $(eval -include $(patsubst %.o,%.d,$(patsubst %.mo,%.d,$($v)))) $(eval $v := $(filter-out %/,$($v)))) endef diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 3cbc4a0061..00c0716f7d 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -224,6 +224,8 @@ int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); /* Callback functions for the generic timer's timers. */ void arm_gt_ptimer_cb(void *opaque); void arm_gt_vtimer_cb(void *opaque); +void arm_gt_htimer_cb(void *opaque); +void arm_gt_stimer_cb(void *opaque); #ifdef TARGET_AARCH64 int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 8b4323dd08..cc6c6f3d4c 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -79,6 +79,27 @@ static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque) } } +static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque) +{ + /* Purely an assertion check: we've already done reset once, + * so now check that running the reset for the cpreg doesn't + * change its value. This traps bugs where two different cpregs + * both try to reset the same state field but to different values. + */ + ARMCPRegInfo *ri = value; + ARMCPU *cpu = opaque; + uint64_t oldvalue, newvalue; + + if (ri->type & (ARM_CP_SPECIAL | ARM_CP_ALIAS | ARM_CP_NO_RAW)) { + return; + } + + oldvalue = read_raw_cp_reg(&cpu->env, ri); + cp_reg_reset(key, value, opaque); + newvalue = read_raw_cp_reg(&cpu->env, ri); + assert(oldvalue == newvalue); +} + /* CPUClass::reset() */ static void arm_cpu_reset(CPUState *s) { @@ -90,6 +111,8 @@ static void arm_cpu_reset(CPUState *s) memset(env, 0, offsetof(CPUARMState, features)); g_hash_table_foreach(cpu->cp_regs, cp_reg_reset, cpu); + g_hash_table_foreach(cpu->cp_regs, cp_reg_check_reset, cpu); + env->vfp.xregs[ARM_VFP_FPSID] = cpu->reset_fpsid; env->vfp.xregs[ARM_VFP_MVFR0] = cpu->mvfr0; env->vfp.xregs[ARM_VFP_MVFR1] = cpu->mvfr1; @@ -453,6 +476,10 @@ static void arm_cpu_initfn(Object *obj) arm_gt_ptimer_cb, cpu); cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, arm_gt_vtimer_cb, cpu); + cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, + arm_gt_htimer_cb, cpu); + cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE, + arm_gt_stimer_cb, cpu); qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs, ARRAY_SIZE(cpu->gt_timer_outputs)); #endif diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7e89152bde..2e680da1fc 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -113,7 +113,9 @@ typedef struct ARMGenericTimer { #define GTIMER_PHYS 0 #define GTIMER_VIRT 1 -#define NUM_GTIMERS 2 +#define GTIMER_HYP 2 +#define GTIMER_SEC 3 +#define NUM_GTIMERS 4 typedef struct { uint64_t raw_tcr; @@ -358,6 +360,8 @@ typedef struct CPUARMState { }; uint64_t c14_cntfrq; /* Counter Frequency register */ uint64_t c14_cntkctl; /* Timer Control register */ + uint32_t cnthctl_el2; /* Counter/Timer Hyp Control register */ + uint64_t cntvoff_el2; /* Counter Virtual Offset register */ ARMGenericTimer c14_timer[NUM_GTIMERS]; uint32_t c15_cpar; /* XScale Coprocessor Access Register */ uint32_t c15_ticonfig; /* TI925T configuration byte. */ @@ -1445,6 +1449,9 @@ static inline bool cp_access_ok(int current_el, return (ri->access >> ((current_el * 2) + isread)) & 1; } +/* Raw read of a coprocessor register (as needed for migration, etc) */ +uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri); + /** * write_list_to_cpustate * @cpu: ARMCPU diff --git a/target-arm/helper.c b/target-arm/helper.c index 01f0d0dac9..1568aa6617 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -144,7 +144,7 @@ static void *raw_ptr(CPUARMState *env, const ARMCPRegInfo *ri) return (char *)env + ri->fieldoffset; } -static uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri) +uint64_t read_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri) { /* Raw read of a coprocessor register (as needed for migration, etc). */ if (ri->type & ARM_CP_CONST) { @@ -1154,23 +1154,41 @@ static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri) static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx) { + unsigned int cur_el = arm_current_el(env); + bool secure = arm_is_secure(env); + /* CNT[PV]CT: not visible from PL0 if ELO[PV]CTEN is zero */ - if (arm_current_el(env) == 0 && + if (cur_el == 0 && !extract32(env->cp15.c14_cntkctl, timeridx, 1)) { return CP_ACCESS_TRAP; } + + if (arm_feature(env, ARM_FEATURE_EL2) && + timeridx == GTIMER_PHYS && !secure && cur_el < 2 && + !extract32(env->cp15.cnthctl_el2, 0, 1)) { + return CP_ACCESS_TRAP_EL2; + } return CP_ACCESS_OK; } static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx) { + unsigned int cur_el = arm_current_el(env); + bool secure = arm_is_secure(env); + /* CNT[PV]_CVAL, CNT[PV]_CTL, CNT[PV]_TVAL: not visible from PL0 if * EL0[PV]TEN is zero. */ - if (arm_current_el(env) == 0 && + if (cur_el == 0 && !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) { return CP_ACCESS_TRAP; } + + if (arm_feature(env, ARM_FEATURE_EL2) && + timeridx == GTIMER_PHYS && !secure && cur_el < 2 && + !extract32(env->cp15.cnthctl_el2, 1, 1)) { + return CP_ACCESS_TRAP_EL2; + } return CP_ACCESS_OK; } @@ -1196,6 +1214,32 @@ static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri) return gt_timer_access(env, GTIMER_VIRT); } +static CPAccessResult gt_stimer_access(CPUARMState *env, + const ARMCPRegInfo *ri) +{ + /* The AArch64 register view of the secure physical timer is + * always accessible from EL3, and configurably accessible from + * Secure EL1. + */ + switch (arm_current_el(env)) { + case 1: + if (!arm_is_secure(env)) { + return CP_ACCESS_TRAP; + } + if (!(env->cp15.scr_el3 & SCR_ST)) { + return CP_ACCESS_TRAP_EL3; + } + return CP_ACCESS_OK; + case 0: + case 2: + return CP_ACCESS_TRAP; + case 3: + return CP_ACCESS_OK; + default: + g_assert_not_reached(); + } +} + static uint64_t gt_get_countervalue(CPUARMState *env) { return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / GTIMER_SCALE; @@ -1209,9 +1253,11 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) /* Timer enabled: calculate and set current ISTATUS, irq, and * reset timer to when ISTATUS next has to change */ + uint64_t offset = timeridx == GTIMER_VIRT ? + cpu->env.cp15.cntvoff_el2 : 0; uint64_t count = gt_get_countervalue(&cpu->env); /* Note that this must be unsigned 64 bit arithmetic: */ - int istatus = count >= gt->cval; + int istatus = count - offset >= gt->cval; uint64_t nexttick; gt->ctl = deposit32(gt->ctl, 2, 1, istatus); @@ -1222,7 +1268,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) nexttick = UINT64_MAX; } else { /* Next transition is when we hit cval */ - nexttick = gt->cval; + nexttick = gt->cval + offset; } /* Note that the desired next expiry time might be beyond the * signed-64-bit range of a QEMUTimer -- in this case we just @@ -1241,10 +1287,10 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx) } } -static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri) +static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri, + int timeridx) { ARMCPU *cpu = arm_env_get_cpu(env); - int timeridx = ri->opc1 & 1; timer_del(cpu->gt_timer[timeridx]); } @@ -1254,38 +1300,44 @@ static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) return gt_get_countervalue(env); } +static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return gt_get_countervalue(env) - env->cp15.cntvoff_el2; +} + static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, + int timeridx, uint64_t value) { - int timeridx = ri->opc1 & 1; - env->cp15.c14_timer[timeridx].cval = value; gt_recalc_timer(arm_env_get_cpu(env), timeridx); } -static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri) +static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri, + int timeridx) { - int timeridx = ri->crm & 1; + uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0; return (uint32_t)(env->cp15.c14_timer[timeridx].cval - - gt_get_countervalue(env)); + (gt_get_countervalue(env) - offset)); } static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, + int timeridx, uint64_t value) { - int timeridx = ri->crm & 1; + uint64_t offset = timeridx == GTIMER_VIRT ? env->cp15.cntvoff_el2 : 0; - env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) + + env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset + sextract64(value, 0, 32); gt_recalc_timer(arm_env_get_cpu(env), timeridx); } static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, + int timeridx, uint64_t value) { ARMCPU *cpu = arm_env_get_cpu(env); - int timeridx = ri->crm & 1; uint32_t oldval = env->cp15.c14_timer[timeridx].ctl; env->cp15.c14_timer[timeridx].ctl = deposit64(oldval, 0, 2, value); @@ -1301,6 +1353,127 @@ static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, } } +static void gt_phys_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + gt_timer_reset(env, ri, GTIMER_PHYS); +} + +static void gt_phys_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_cval_write(env, ri, GTIMER_PHYS, value); +} + +static uint64_t gt_phys_tval_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return gt_tval_read(env, ri, GTIMER_PHYS); +} + +static void gt_phys_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_tval_write(env, ri, GTIMER_PHYS, value); +} + +static void gt_phys_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_ctl_write(env, ri, GTIMER_PHYS, value); +} + +static void gt_virt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + gt_timer_reset(env, ri, GTIMER_VIRT); +} + +static void gt_virt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_cval_write(env, ri, GTIMER_VIRT, value); +} + +static uint64_t gt_virt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return gt_tval_read(env, ri, GTIMER_VIRT); +} + +static void gt_virt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_tval_write(env, ri, GTIMER_VIRT, value); +} + +static void gt_virt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_ctl_write(env, ri, GTIMER_VIRT, value); +} + +static void gt_cntvoff_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + ARMCPU *cpu = arm_env_get_cpu(env); + + raw_write(env, ri, value); + gt_recalc_timer(cpu, GTIMER_VIRT); +} + +static void gt_hyp_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + gt_timer_reset(env, ri, GTIMER_HYP); +} + +static void gt_hyp_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_cval_write(env, ri, GTIMER_HYP, value); +} + +static uint64_t gt_hyp_tval_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return gt_tval_read(env, ri, GTIMER_HYP); +} + +static void gt_hyp_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_tval_write(env, ri, GTIMER_HYP, value); +} + +static void gt_hyp_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_ctl_write(env, ri, GTIMER_HYP, value); +} + +static void gt_sec_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri) +{ + gt_timer_reset(env, ri, GTIMER_SEC); +} + +static void gt_sec_cval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_cval_write(env, ri, GTIMER_SEC, value); +} + +static uint64_t gt_sec_tval_read(CPUARMState *env, const ARMCPRegInfo *ri) +{ + return gt_tval_read(env, ri, GTIMER_SEC); +} + +static void gt_sec_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_tval_write(env, ri, GTIMER_SEC, value); +} + +static void gt_sec_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) +{ + gt_ctl_write(env, ri, GTIMER_SEC, value); +} + void arm_gt_ptimer_cb(void *opaque) { ARMCPU *cpu = opaque; @@ -1315,6 +1488,20 @@ void arm_gt_vtimer_cb(void *opaque) gt_recalc_timer(cpu, GTIMER_VIRT); } +void arm_gt_htimer_cb(void *opaque) +{ + ARMCPU *cpu = opaque; + + gt_recalc_timer(cpu, GTIMER_HYP); +} + +void arm_gt_stimer_cb(void *opaque) +{ + ARMCPU *cpu = opaque; + + gt_recalc_timer(cpu, GTIMER_SEC); +} + static const ARMCPRegInfo generic_timer_cp_reginfo[] = { /* Note that CNTFRQ is purely reads-as-written for the benefit * of software; writing it doesn't actually change the timer frequency. @@ -1340,11 +1527,21 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { }, /* per-timer control */ { .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1, + .secure = ARM_CP_SECSTATE_NS, .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R, .accessfn = gt_ptimer_access, .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), - .writefn = gt_ctl_write, .raw_writefn = raw_write, + .writefn = gt_phys_ctl_write, .raw_writefn = raw_write, + }, + { .name = "CNTP_CTL(S)", + .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1, + .secure = ARM_CP_SECSTATE_S, + .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R, + .accessfn = gt_ptimer_access, + .fieldoffset = offsetoflow32(CPUARMState, + cp15.c14_timer[GTIMER_SEC].ctl), + .writefn = gt_sec_ctl_write, .raw_writefn = raw_write, }, { .name = "CNTP_CTL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 1, @@ -1352,14 +1549,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .accessfn = gt_ptimer_access, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl), .resetvalue = 0, - .writefn = gt_ctl_write, .raw_writefn = raw_write, + .writefn = gt_phys_ctl_write, .raw_writefn = raw_write, }, { .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1, .type = ARM_CP_IO | ARM_CP_ALIAS, .access = PL1_RW | PL0_R, .accessfn = gt_vtimer_access, .fieldoffset = offsetoflow32(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), - .writefn = gt_ctl_write, .raw_writefn = raw_write, + .writefn = gt_virt_ctl_write, .raw_writefn = raw_write, }, { .name = "CNTV_CTL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 1, @@ -1367,30 +1564,38 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .accessfn = gt_vtimer_access, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl), .resetvalue = 0, - .writefn = gt_ctl_write, .raw_writefn = raw_write, + .writefn = gt_virt_ctl_write, .raw_writefn = raw_write, }, /* TimerValue views: a 32 bit downcounting view of the underlying state */ { .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0, + .secure = ARM_CP_SECSTATE_NS, .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, .accessfn = gt_ptimer_access, - .readfn = gt_tval_read, .writefn = gt_tval_write, + .readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write, + }, + { .name = "CNTP_TVAL(S)", + .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0, + .secure = ARM_CP_SECSTATE_S, + .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .accessfn = gt_ptimer_access, + .readfn = gt_sec_tval_read, .writefn = gt_sec_tval_write, }, { .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0, .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, - .accessfn = gt_ptimer_access, - .readfn = gt_tval_read, .writefn = gt_tval_write, + .accessfn = gt_ptimer_access, .resetfn = gt_phys_timer_reset, + .readfn = gt_phys_tval_read, .writefn = gt_phys_tval_write, }, { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0, .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, .accessfn = gt_vtimer_access, - .readfn = gt_tval_read, .writefn = gt_tval_write, + .readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write, }, { .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0, .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, - .accessfn = gt_vtimer_access, - .readfn = gt_tval_read, .writefn = gt_tval_write, + .accessfn = gt_vtimer_access, .resetfn = gt_virt_timer_reset, + .readfn = gt_virt_tval_read, .writefn = gt_virt_tval_write, }, /* The counter itself */ { .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0, @@ -1401,27 +1606,34 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { { .name = "CNTPCT_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 1, .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO, - .accessfn = gt_pct_access, - .readfn = gt_cnt_read, .resetfn = gt_cnt_reset, + .accessfn = gt_pct_access, .readfn = gt_cnt_read, }, { .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1, .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO, .accessfn = gt_vct_access, - .readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore, + .readfn = gt_virt_cnt_read, .resetfn = arm_cp_reset_ignore, }, { .name = "CNTVCT_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 2, .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO, - .accessfn = gt_vct_access, - .readfn = gt_cnt_read, .resetfn = gt_cnt_reset, + .accessfn = gt_vct_access, .readfn = gt_virt_cnt_read, }, /* Comparison value, indicating when the timer goes off */ { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2, + .secure = ARM_CP_SECSTATE_NS, .access = PL1_RW | PL0_R, .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), .accessfn = gt_ptimer_access, - .writefn = gt_cval_write, .raw_writefn = raw_write, + .writefn = gt_phys_cval_write, .raw_writefn = raw_write, + }, + { .name = "CNTP_CVAL(S)", .cp = 15, .crm = 14, .opc1 = 2, + .secure = ARM_CP_SECSTATE_S, + .access = PL1_RW | PL0_R, + .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval), + .accessfn = gt_ptimer_access, + .writefn = gt_sec_cval_write, .raw_writefn = raw_write, }, { .name = "CNTP_CVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 2, @@ -1429,14 +1641,14 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), .resetvalue = 0, .accessfn = gt_ptimer_access, - .writefn = gt_cval_write, .raw_writefn = raw_write, + .writefn = gt_phys_cval_write, .raw_writefn = raw_write, }, { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3, .access = PL1_RW | PL0_R, .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_ALIAS, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), .accessfn = gt_vtimer_access, - .writefn = gt_cval_write, .raw_writefn = raw_write, + .writefn = gt_virt_cval_write, .raw_writefn = raw_write, }, { .name = "CNTV_CVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 2, @@ -1444,7 +1656,33 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval), .resetvalue = 0, .accessfn = gt_vtimer_access, - .writefn = gt_cval_write, .raw_writefn = raw_write, + .writefn = gt_virt_cval_write, .raw_writefn = raw_write, + }, + /* Secure timer -- this is actually restricted to only EL3 + * and configurably Secure-EL1 via the accessfn. + */ + { .name = "CNTPS_TVAL_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 0, + .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW, + .accessfn = gt_stimer_access, + .readfn = gt_sec_tval_read, + .writefn = gt_sec_tval_write, + .resetfn = gt_sec_timer_reset, + }, + { .name = "CNTPS_CTL_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 1, + .type = ARM_CP_IO, .access = PL1_RW, + .accessfn = gt_stimer_access, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].ctl), + .resetvalue = 0, + .writefn = gt_sec_ctl_write, .raw_writefn = raw_write, + }, + { .name = "CNTPS_CVAL_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 7, .crn = 14, .crm = 2, .opc2 = 2, + .type = ARM_CP_IO, .access = PL1_RW, + .accessfn = gt_stimer_access, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_SEC].cval), + .writefn = gt_sec_cval_write, .raw_writefn = raw_write, }, REGINFO_SENTINEL }; @@ -2613,6 +2851,27 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { { .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2, .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14, + .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, + .resetvalue = 0 }, + { .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14, + .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST, + .resetvalue = 0 }, + { .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -2724,6 +2983,46 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1, .type = ARM_CP_NO_RAW, .access = PL2_W, .writefn = tlbi_aa64_vaa_write }, +#ifndef CONFIG_USER_ONLY + { .name = "CNTHCTL_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 1, .opc2 = 0, + /* ARMv7 requires bit 0 and 1 to reset to 1. ARMv8 defines the + * reset values as IMPDEF. We choose to reset to 3 to comply with + * both ARMv7 and ARMv8. + */ + .access = PL2_RW, .resetvalue = 3, + .fieldoffset = offsetof(CPUARMState, cp15.cnthctl_el2) }, + { .name = "CNTVOFF_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 3, + .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0, + .writefn = gt_cntvoff_write, + .fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) }, + { .name = "CNTVOFF", .cp = 15, .opc1 = 4, .crm = 14, + .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS | ARM_CP_IO, + .writefn = gt_cntvoff_write, + .fieldoffset = offsetof(CPUARMState, cp15.cntvoff_el2) }, + { .name = "CNTHP_CVAL_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 2, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].cval), + .type = ARM_CP_IO, .access = PL2_RW, + .writefn = gt_hyp_cval_write, .raw_writefn = raw_write }, + { .name = "CNTHP_CVAL", .cp = 15, .opc1 = 6, .crm = 14, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].cval), + .access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_IO, + .writefn = gt_hyp_cval_write, .raw_writefn = raw_write }, + { .name = "CNTHP_TVAL_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 0, + .type = ARM_CP_IO, .access = PL2_RW, + .resetfn = gt_hyp_timer_reset, + .readfn = gt_hyp_tval_read, .writefn = gt_hyp_tval_write }, + { .name = "CNTHP_CTL_EL2", .state = ARM_CP_STATE_BOTH, + .type = ARM_CP_IO, + .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 2, .opc2 = 1, + .access = PL2_RW, + .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_HYP].ctl), + .resetvalue = 0, + .writefn = gt_hyp_ctl_write, .raw_writefn = raw_write }, +#endif REGINFO_SENTINEL }; diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index 7912d7433d..b3e0ab7e7c 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -191,4 +191,9 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu); #endif +static inline const char *gic_class_name(void) +{ + return kvm_irqchip_in_kernel() ? "kvm-arm-gic" : "arm_gic"; +} + #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 7a779b1653..cfb8aa7e4e 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1392,32 +1392,6 @@ static X86CPUDefinition builtin_x86_defs[] = { }, }; -/** - * x86_cpu_compat_set_features: - * @cpu_model: CPU model name to be changed. If NULL, all CPU models are changed - * @w: Identifies the feature word to be changed. - * @feat_add: Feature bits to be added to feature word - * @feat_remove: Feature bits to be removed from feature word - * - * Change CPU model feature bits for compatibility. - * - * This function may be used by machine-type compatibility functions - * to enable or disable feature bits on specific CPU models. - */ -void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w, - uint32_t feat_add, uint32_t feat_remove) -{ - X86CPUDefinition *def; - int i; - for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { - def = &builtin_x86_defs[i]; - if (!cpu_model || !strcmp(cpu_model, def->name)) { - def->features[w] |= feat_add; - def->features[w] &= ~feat_remove; - } - } -} - static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, bool migratable_only); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index ead28325bd..74b674d524 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1332,9 +1332,6 @@ void cpu_smm_update(X86CPU *cpu); void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); -void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w, - uint32_t feat_add, uint32_t feat_remove); - void x86_cpu_compat_kvm_no_autoenable(FeatureWord w, uint32_t features); void x86_cpu_compat_kvm_no_autodisable(FeatureWord w, uint32_t features); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 075c561c81..c91883d5e1 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -395,7 +395,7 @@ struct CPUMIPSState { #define CP0C0_K23 28 #define CP0C0_KU 25 #define CP0C0_MDU 20 -#define CP0C0_MM 17 +#define CP0C0_MM 18 #define CP0C0_BM 16 #define CP0C0_BE 15 #define CP0C0_AT 13 diff --git a/target-mips/helper.c b/target-mips/helper.c index 04ba19fd44..f44edbbdbb 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -127,10 +127,6 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical, /* effective address (modified for KVM T&E kernel segments) */ target_ulong address = real_address; -#if 0 - qemu_log("user mode %d h %08x\n", user_mode, env->hflags); -#endif - #define USEG_LIMIT 0x7FFFFFFFUL #define KSEG0_BASE 0x80000000UL #define KSEG1_BASE 0xA0000000UL @@ -227,11 +223,6 @@ static int get_physical_address (CPUMIPSState *env, hwaddr *physical, ret = TLBRET_BADADDR; } } -#if 0 - qemu_log(TARGET_FMT_lx " %d %d => %" HWADDR_PRIx " %d (%d)\n", - address, rw, access_type, *physical, *prot, ret); -#endif - return ret; } #endif @@ -487,14 +478,16 @@ void mips_cpu_do_interrupt(CPUState *cs) int cause = -1; const char *name; - if (qemu_log_enabled() && cs->exception_index != EXCP_EXT_INTERRUPT) { + if (qemu_loglevel_mask(CPU_LOG_INT) + && cs->exception_index != EXCP_EXT_INTERRUPT) { if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) { name = "unknown"; } else { name = excp_names[cs->exception_index]; } - qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n", + qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx + " %s exception\n", __func__, env->active_tc.PC, env->CP0_EPC, name); } if (cs->exception_index == EXCP_EXT_INTERRUPT && @@ -747,16 +740,15 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC); break; default: - qemu_log("Invalid MIPS exception %d. Exiting\n", cs->exception_index); - printf("Invalid MIPS exception %d. Exiting\n", cs->exception_index); - exit(1); + abort(); } - if (qemu_log_enabled() && cs->exception_index != EXCP_EXT_INTERRUPT) { + if (qemu_loglevel_mask(CPU_LOG_INT) + && cs->exception_index != EXCP_EXT_INTERRUPT) { qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n" - " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", - __func__, env->active_tc.PC, env->CP0_EPC, cause, - env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, - env->CP0_DEPC); + " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n", + __func__, env->active_tc.PC, env->CP0_EPC, cause, + env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, + env->CP0_DEPC); } #endif cs->exception_index = EXCP_NONE; diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index db4f6b9463..809a061e29 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -38,7 +38,8 @@ static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, CPUState *cs = CPU(mips_env_get_cpu(env)); if (exception < EXCP_SC) { - qemu_log("%s: %d %d\n", __func__, exception, error_code); + qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n", + __func__, exception, error_code); } cs->exception_index = exception; env->error_code = error_code; diff --git a/target-mips/translate.c b/target-mips/translate.c index d1de35ad30..98cf72de74 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -2153,11 +2153,10 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, tcg_gen_andi_tl(t0, t0, ~7); tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ); tcg_gen_shl_tl(t0, t0, t1); - tcg_gen_xori_tl(t1, t1, 63); - t2 = tcg_const_tl(0x7fffffffffffffffull); - tcg_gen_shr_tl(t2, t2, t1); + t2 = tcg_const_tl(-1); + tcg_gen_shl_tl(t2, t2, t1); gen_load_gpr(t1, rt); - tcg_gen_and_tl(t1, t1, t2); + tcg_gen_andc_tl(t1, t1, t2); tcg_temp_free(t2); tcg_gen_or_tl(t0, t0, t1); tcg_temp_free(t1); @@ -2246,11 +2245,10 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, tcg_gen_andi_tl(t0, t0, ~3); tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL); tcg_gen_shl_tl(t0, t0, t1); - tcg_gen_xori_tl(t1, t1, 31); - t2 = tcg_const_tl(0x7fffffffull); - tcg_gen_shr_tl(t2, t2, t1); + t2 = tcg_const_tl(-1); + tcg_gen_shl_tl(t2, t2, t1); gen_load_gpr(t1, rt); - tcg_gen_and_tl(t1, t1, t2); + tcg_gen_andc_tl(t1, t1, t2); tcg_temp_free(t2); tcg_gen_or_tl(t0, t0, t1); tcg_temp_free(t1); @@ -4750,48 +4748,53 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt, gen_load_gpr(t1, rs); switch (opc) { case OPC_EXT: - if (lsb + msb > 31) + if (lsb + msb > 31) { goto fail; + } tcg_gen_shri_tl(t0, t1, lsb); if (msb != 31) { - tcg_gen_andi_tl(t0, t0, (1 << (msb + 1)) - 1); + tcg_gen_andi_tl(t0, t0, (1U << (msb + 1)) - 1); } else { tcg_gen_ext32s_tl(t0, t0); } break; #if defined(TARGET_MIPS64) - case OPC_DEXTM: - tcg_gen_shri_tl(t0, t1, lsb); - if (msb != 31) { - tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1 + 32)) - 1); - } - break; case OPC_DEXTU: - tcg_gen_shri_tl(t0, t1, lsb + 32); - tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); - break; + lsb += 32; + goto do_dext; + case OPC_DEXTM: + msb += 32; + goto do_dext; case OPC_DEXT: + do_dext: + if (lsb + msb > 63) { + goto fail; + } tcg_gen_shri_tl(t0, t1, lsb); - tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); + if (msb != 63) { + tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1); + } break; #endif case OPC_INS: - if (lsb > msb) + if (lsb > msb) { goto fail; + } gen_load_gpr(t0, rt); tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); tcg_gen_ext32s_tl(t0, t0); break; #if defined(TARGET_MIPS64) - case OPC_DINSM: - gen_load_gpr(t0, rt); - tcg_gen_deposit_tl(t0, t0, t1, lsb, msb + 32 - lsb + 1); - break; case OPC_DINSU: - gen_load_gpr(t0, rt); - tcg_gen_deposit_tl(t0, t0, t1, lsb + 32, msb - lsb + 1); - break; + lsb += 32; + /* FALLTHRU */ + case OPC_DINSM: + msb += 32; + /* FALLTHRU */ case OPC_DINS: + if (lsb > msb) { + goto fail; + } gen_load_gpr(t0, rt); tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); break; @@ -13278,10 +13281,14 @@ static void gen_pool16c_r6_insn(DisasContext *ctx) break; case R6_SDBBP16: /* SDBBP16 */ - if (ctx->hflags & MIPS_HFLAG_SBRI) { - generate_exception(ctx, EXCP_RI); + if (is_uhi(extract32(ctx->opcode, 6, 4))) { + gen_helper_do_semihosting(cpu_env); } else { - generate_exception(ctx, EXCP_DBp); + if (ctx->hflags & MIPS_HFLAG_SBRI) { + generate_exception(ctx, EXCP_RI); + } else { + generate_exception(ctx, EXCP_DBp); + } } break; } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 9304e746b4..1b45884e9b 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -389,39 +389,44 @@ static const mips_def_t mips_defs[] = .mmu_type = MMU_TYPE_R4000, }, { - /* A generic CPU providing MIPS32 Release 5 features. - FIXME: Eventually this should be replaced by a real CPU model. */ - .name = "mips32r5-generic", - .CP0_PRid = 0x00019700, - .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | + /* FIXME: + * Config3: CMGCR, SC, PW, VZ, CTXTC, CDMM, TL + * Config4: MMUExtDef + * Config5: EVA, MRP + * FIR(FCR0): Has2008 + * */ + .name = "P5600", + .CP0_PRid = 0x0001A800, + .CP0_Config0 = MIPS_CONFIG0 | (1 << CP0C0_MM) | (1 << CP0C0_AR) | (MMU_TYPE_R4000 << CP0C0_MT), - .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) | - (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | - (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA) | - (1 << CP0C1_CA), + .CP0_Config1 = MIPS_CONFIG1 | (0x3F << CP0C1_MMU) | + (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) | + (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_FP), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) | - (1 << CP0C3_LPA), - .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M), + (1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) | + (1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt), + .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) | + (0x1c << CP0C4_KScrExist), .CP0_Config4_rw_bitmask = 0, - .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_UFR) | (1 << CP0C5_LLB) | - (1 << CP0C5_MVH), - .CP0_Config5_rw_bitmask = (0 << CP0C5_M) | (1 << CP0C5_K) | - (1 << CP0C5_CV) | (0 << CP0C5_EVA) | - (1 << CP0C5_MSAEn) | (1 << CP0C5_UFR) | - (0 << CP0C5_NFExists), + .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_MVH) | (1 << CP0C5_LLB), + .CP0_Config5_rw_bitmask = (1 << CP0C5_K) | (1 << CP0C5_CV) | + (1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) | + (1 << CP0C5_FRE) | (1 << CP0C5_UFR), .CP0_LLAddr_rw_bitmask = 0, - .CP0_LLAddr_shift = 4, + .CP0_LLAddr_shift = 0, .SYNCI_Step = 32, .CCRes = 2, - .CP0_Status_rw_bitmask = 0x3778FF1F, - .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA), - .CP1_fcr0 = (1 << FCR0_UFRP) | (1 << FCR0_F64) | (1 << FCR0_L) | - (1 << FCR0_W) | (1 << FCR0_D) | (1 << FCR0_S) | - (0x93 << FCR0_PRID), + .CP0_Status_rw_bitmask = 0x3C68FF1F, + .CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) | + (1 << CP0PG_ELPA) | (1 << CP0PG_IEC), + .CP1_fcr0 = (1 << FCR0_FREP) | (1 << FCR0_UFRP) | (1 << FCR0_F64) | + (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) | + (1 << FCR0_S) | (0x03 << FCR0_PRID), .SEGBITS = 32, .PABITS = 40, - .insn_flags = CPU_MIPS32R5 | ASE_MIPS16 | ASE_MSA, + .insn_flags = CPU_MIPS32R5 | ASE_MSA, .mmu_type = MMU_TYPE_R4000, }, { diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 668029977c..e97980df0b 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -963,9 +963,11 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl, } /* Load the tlb comparator. */ - tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF); if (TARGET_LONG_BITS == 64) { + tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF); tcg_out_opc_imm(s, OPC_LW, base, TCG_REG_A0, cmp_off + HI_OFF); + } else { + tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off); } /* Mask the page bits, keeping the alignment bits to compare against. @@ -1103,7 +1105,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, TCGReg base, TCGMemOp opc) { - switch (opc) { + switch (opc & (MO_SSIZE | MO_BSWAP)) { case MO_UB: tcg_out_opc_imm(s, OPC_LBU, datalo, base, 0); break; @@ -1193,7 +1195,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, TCGReg base, TCGMemOp opc) { - switch (opc) { + switch (opc & (MO_SIZE | MO_BSWAP)) { case MO_8: tcg_out_opc_imm(s, OPC_SB, datalo, base, 0); break; @@ -1269,6 +1271,9 @@ static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al, if (cbl) { tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl); tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl); + } else if (rl == al && rl == bl) { + tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, 31); + tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl); } else { tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl); tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl)); diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 921991ebfa..aa718eca0c 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -1390,7 +1390,7 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest) static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data, TCGReg base, TCGReg index, int disp) { - switch (opc) { + switch (opc & (MO_SSIZE | MO_BSWAP)) { case MO_UB: tcg_out_insn(s, RXY, LLGC, data, base, index, disp); break; @@ -1449,7 +1449,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data, static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc, TCGReg data, TCGReg base, TCGReg index, int disp) { - switch (opc) { + switch (opc & (MO_SIZE | MO_BSWAP)) { case MO_UB: if (disp >= 0 && disp < 0x1000) { tcg_out_insn(s, RX, STC, data, base, index, disp); diff --git a/tests/Makefile b/tests/Makefile index 749458224a..52711237ca 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -381,7 +381,7 @@ tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y) tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y) -tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) +tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y) tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y) tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y) tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 0de1742d7d..613867ab99 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -18,7 +18,7 @@ #include "libqtest.h" #include "qemu/compiler.h" #include "hw/acpi/acpi-defs.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "qemu/bitmap.h" #define MACHINE_PC "pc" diff --git a/tests/test-throttle.c b/tests/test-throttle.c index 016844546a..85c9b6ceed 100644 --- a/tests/test-throttle.c +++ b/tests/test-throttle.c @@ -329,6 +329,26 @@ static void test_is_valid(void) test_is_valid_for_value(1, true); } +static void test_max_is_missing_limit(void) +{ + int i; + + for (i = 0; i < BUCKETS_COUNT; i++) { + memset(&cfg, 0, sizeof(cfg)); + cfg.buckets[i].max = 100; + cfg.buckets[i].avg = 0; + g_assert(throttle_max_is_missing_limit(&cfg)); + + cfg.buckets[i].max = 0; + cfg.buckets[i].avg = 0; + g_assert(!throttle_max_is_missing_limit(&cfg)); + + cfg.buckets[i].max = 0; + cfg.buckets[i].avg = 100; + g_assert(!throttle_max_is_missing_limit(&cfg)); + } +} + static void test_have_timer(void) { /* zero structures */ @@ -591,6 +611,7 @@ int main(int argc, char **argv) g_test_add_func("/throttle/config/enabled", test_enabled); g_test_add_func("/throttle/config/conflicting", test_conflicting_config); g_test_add_func("/throttle/config/is_valid", test_is_valid); + g_test_add_func("/throttle/config/max", test_max_is_missing_limit); g_test_add_func("/throttle/config_functions", test_config_functions); g_test_add_func("/throttle/accounting", test_accounting); g_test_add_func("/throttle/groups", test_groups); diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c index ea7478c278..982d77a14b 100644 --- a/tests/virtio-net-test.c +++ b/tests/virtio-net-test.c @@ -10,20 +10,242 @@ #include <glib.h> #include <string.h> #include "libqtest.h" +#include "qemu-common.h" +#include "qemu/sockets.h" #include "qemu/osdep.h" -#include "libqos/pci.h" +#include "qemu/iov.h" +#include "libqos/pci-pc.h" +#include "libqos/virtio.h" +#include "libqos/virtio-pci.h" +#include "libqos/malloc.h" +#include "libqos/malloc-pc.h" +#include "libqos/malloc-generic.h" +#include "qemu/bswap.h" +#include "hw/virtio/virtio-net.h" #define PCI_SLOT_HP 0x06 +#define PCI_SLOT 0x04 +#define PCI_FN 0x00 -/* Tests only initialization so far. TODO: Replace with functional tests */ -static void pci_nop(void) +#define QVIRTIO_NET_TIMEOUT_US (30 * 1000 * 1000) +#define VNET_HDR_SIZE sizeof(struct virtio_net_hdr_mrg_rxbuf) + +static void test_end(void) +{ + qtest_end(); +} + +#ifndef _WIN32 + +static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot) +{ + QVirtioPCIDevice *dev; + + dev = qvirtio_pci_device_find(bus, QVIRTIO_NET_DEVICE_ID); + g_assert(dev != NULL); + g_assert_cmphex(dev->vdev.device_type, ==, QVIRTIO_NET_DEVICE_ID); + + qvirtio_pci_device_enable(dev); + qvirtio_reset(&qvirtio_pci, &dev->vdev); + qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev); + qvirtio_set_driver(&qvirtio_pci, &dev->vdev); + + return dev; +} + +static QPCIBus *pci_test_start(int socket) +{ + char *cmdline; + + cmdline = g_strdup_printf("-netdev socket,fd=%d,id=hs0 -device " + "virtio-net-pci,netdev=hs0", socket); + qtest_start(cmdline); + g_free(cmdline); + + return qpci_init_pc(); +} + +static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev) +{ + uint32_t features; + + features = qvirtio_get_features(bus, dev); + features = features & ~(QVIRTIO_F_BAD_FEATURE | + QVIRTIO_F_RING_INDIRECT_DESC | + QVIRTIO_F_RING_EVENT_IDX); + qvirtio_set_features(bus, dev, features); + + qvirtio_set_driver_ok(bus, dev); +} + +static void rx_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *vq, + int socket) +{ + uint64_t req_addr; + uint32_t free_head; + char test[] = "TEST"; + char buffer[64]; + int len = htonl(sizeof(test)); + struct iovec iov[] = { + { + .iov_base = &len, + .iov_len = sizeof(len), + }, { + .iov_base = test, + .iov_len = sizeof(test), + }, + }; + int ret; + + req_addr = guest_alloc(alloc, 64); + + free_head = qvirtqueue_add(vq, req_addr, 64, true, false); + qvirtqueue_kick(bus, dev, vq, free_head); + + ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test)); + g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len)); + + qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US); + memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); + g_assert_cmpstr(buffer, ==, "TEST"); + + guest_free(alloc, req_addr); +} + +static void tx_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *vq, + int socket) +{ + uint64_t req_addr; + uint32_t free_head; + uint32_t len; + char buffer[64]; + int ret; + + req_addr = guest_alloc(alloc, 64); + memwrite(req_addr + VNET_HDR_SIZE, "TEST", 4); + + free_head = qvirtqueue_add(vq, req_addr, 64, false, false); + qvirtqueue_kick(bus, dev, vq, free_head); + + qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US); + guest_free(alloc, req_addr); + + ret = qemu_recv(socket, &len, sizeof(len), 0); + g_assert_cmpint(ret, ==, sizeof(len)); + len = ntohl(len); + + ret = qemu_recv(socket, buffer, len, 0); + g_assert_cmpstr(buffer, ==, "TEST"); +} + +static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *vq, + int socket) +{ + uint64_t req_addr; + uint32_t free_head; + char test[] = "TEST"; + char buffer[64]; + int len = htonl(sizeof(test)); + struct iovec iov[] = { + { + .iov_base = &len, + .iov_len = sizeof(len), + }, { + .iov_base = test, + .iov_len = sizeof(test), + }, + }; + int ret; + + req_addr = guest_alloc(alloc, 64); + + free_head = qvirtqueue_add(vq, req_addr, 64, true, false); + qvirtqueue_kick(bus, dev, vq, free_head); + + qmp("{ 'execute' : 'stop'}"); + + ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test)); + g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len)); + + /* We could check the status, but this command is more importantly to + * ensure the packet data gets queued in QEMU, before we do 'cont'. + */ + qmp("{ 'execute' : 'query-status'}"); + qmp("{ 'execute' : 'cont'}"); + + qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US); + memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); + g_assert_cmpstr(buffer, ==, "TEST"); + + guest_free(alloc, req_addr); +} + +static void send_recv_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *rvq, + QVirtQueue *tvq, int socket) { + rx_test(bus, dev, alloc, rvq, socket); + tx_test(bus, dev, alloc, tvq, socket); } +static void stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *rvq, + QVirtQueue *tvq, int socket) +{ + rx_stop_cont_test(bus, dev, alloc, rvq, socket); +} + +static void pci_basic(gconstpointer data) +{ + QVirtioPCIDevice *dev; + QPCIBus *bus; + QVirtQueuePCI *tx, *rx; + QGuestAllocator *alloc; + void (*func) (const QVirtioBus *bus, + QVirtioDevice *dev, + QGuestAllocator *alloc, + QVirtQueue *rvq, + QVirtQueue *tvq, + int socket) = data; + int sv[2], ret; + + ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv); + g_assert_cmpint(ret, !=, -1); + + bus = pci_test_start(sv[1]); + dev = virtio_net_pci_init(bus, PCI_SLOT); + + alloc = pc_alloc_init(); + rx = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev, + alloc, 0); + tx = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev, + alloc, 1); + + driver_init(&qvirtio_pci, &dev->vdev); + func(&qvirtio_pci, &dev->vdev, alloc, &rx->vq, &tx->vq, sv[0]); + + /* End test */ + close(sv[0]); + guest_free(alloc, tx->vq.desc); + pc_alloc_uninit(alloc); + qvirtio_pci_device_disable(dev); + g_free(dev); + qpci_free_pc(bus); + test_end(); +} +#endif + static void hotplug(void) { + qtest_start("-device virtio-net-pci"); + qpci_plug_device_test("virtio-net-pci", "net1", PCI_SLOT_HP, NULL); qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP); + + test_end(); } int main(int argc, char **argv) @@ -31,13 +253,14 @@ int main(int argc, char **argv) int ret; g_test_init(&argc, &argv, NULL); - qtest_add_func("/virtio/net/pci/nop", pci_nop); +#ifndef _WIN32 + qtest_add_data_func("/virtio/net/pci/basic", send_recv_test, pci_basic); + qtest_add_data_func("/virtio/net/pci/rx_stop_cont", + stop_cont_test, pci_basic); +#endif qtest_add_func("/virtio/net/pci/hotplug", hotplug); - qtest_start("-device virtio-net-pci"); ret = g_test_run(); - qtest_end(); - return ret; } diff --git a/trace-events b/trace-events index 94bf3bb184..8f9614adb5 100644 --- a/trace-events +++ b/trace-events @@ -94,6 +94,7 @@ mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirt 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" +mirror_break_iov_max(void *s, int nb_chunks, int added_chunks) "s %p requested chunks %d added_chunks %d" # block/backup.c backup_do_cow_enter(void *job, int64_t start, int64_t sector_num, int nb_sectors) "job %p start %"PRId64" sector_num %"PRId64" nb_sectors %d" diff --git a/util/throttle.c b/util/throttle.c index 706c13111e..1113671ecf 100644 --- a/util/throttle.c +++ b/util/throttle.c @@ -300,6 +300,21 @@ bool throttle_is_valid(ThrottleConfig *cfg) return !invalid; } +/* check if bps_max/iops_max is used without bps/iops + * @cfg: the throttling configuration to inspect + */ +bool throttle_max_is_missing_limit(ThrottleConfig *cfg) +{ + int i; + + for (i = 0; i < BUCKETS_COUNT; i++) { + if (cfg->buckets[i].max && !cfg->buckets[i].avg) { + return true; + } + } + return false; +} + /* fix bucket parameters */ static void throttle_fix_bucket(LeakyBucket *bkt) { @@ -68,7 +68,7 @@ int main(int argc, char **argv) #include "hw/isa/isa.h" #include "hw/bt.h" #include "sysemu/watchdog.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/xen/xen.h" #include "hw/qdev.h" #include "hw/loader.h" diff --git a/xen-common.c b/xen-common.c index 56359ca725..0dcdbc39f4 100644 --- a/xen-common.c +++ b/xen-common.c @@ -12,6 +12,7 @@ #include "qmp-commands.h" #include "sysemu/char.h" #include "sysemu/accel.h" +#include "migration/migration.h" //#define DEBUG_XEN @@ -119,6 +120,10 @@ static int xen_init(MachineState *ms) } qemu_add_vm_change_state_handler(xen_change_state_handler, NULL); + global_state_set_optional(); + savevm_skip_configuration(); + savevm_skip_section_footers(); + return 0; } |