diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/a15mpcore.c | 46 | ||||
-rw-r--r-- | hw/a9mpcore.c | 72 | ||||
-rw-r--r-- | hw/arm11mpcore.c | 56 | ||||
-rw-r--r-- | hw/arm_gic.c | 157 | ||||
-rw-r--r-- | hw/armv7m_nvic.c | 24 | ||||
-rw-r--r-- | hw/exynos4210.c | 30 | ||||
-rw-r--r-- | hw/exynos4210.h | 3 | ||||
-rw-r--r-- | hw/exynos4210_combiner.c | 10 | ||||
-rw-r--r-- | hw/exynos4210_gic.c | 48 | ||||
-rw-r--r-- | hw/exynos4210_uart.c | 6 | ||||
-rw-r--r-- | hw/exynos4_boards.c | 1 | ||||
-rw-r--r-- | hw/ivshmem.c | 8 | ||||
-rw-r--r-- | hw/kvm/clock.c | 16 | ||||
-rw-r--r-- | hw/pc.c | 8 | ||||
-rw-r--r-- | hw/ps2.h | 29 | ||||
-rw-r--r-- | hw/realview_gic.c | 46 | ||||
-rw-r--r-- | hw/rtl8139.c | 26 | ||||
-rw-r--r-- | hw/spapr.h | 2 | ||||
-rw-r--r-- | hw/spapr_llan.c | 26 | ||||
-rw-r--r-- | hw/spapr_pci.c | 117 | ||||
-rw-r--r-- | hw/spapr_rtas.c | 17 | ||||
-rw-r--r-- | hw/spapr_vio.c | 62 | ||||
-rw-r--r-- | hw/spapr_vio.h | 5 | ||||
-rw-r--r-- | hw/spapr_vscsi.c | 15 | ||||
-rw-r--r-- | hw/spapr_vty.c | 4 | ||||
-rw-r--r-- | hw/xen.h | 1 | ||||
-rw-r--r-- | hw/xen_apic.c | 90 | ||||
-rw-r--r-- | hw/xen_backend.c | 17 | ||||
-rw-r--r-- | hw/xen_disk.c | 4 |
29 files changed, 665 insertions, 281 deletions
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c index 71142e51f5..5a7b365548 100644 --- a/hw/a15mpcore.c +++ b/hw/a15mpcore.c @@ -20,36 +20,38 @@ #include "sysbus.h" -/* Configuration for arm_gic.c: - * max number of CPUs, how to ID current CPU - */ -#define NCPU 4 - -static inline int gic_get_current_cpu(void) -{ - return cpu_single_env->cpu_index; -} - -#include "arm_gic.c" - /* A15MP private memory region. */ typedef struct A15MPPrivState { - gic_state gic; + SysBusDevice busdev; uint32_t num_cpu; uint32_t num_irq; MemoryRegion container; + DeviceState *gic; } A15MPPrivState; +static void a15mp_priv_set_irq(void *opaque, int irq, int level) +{ + A15MPPrivState *s = (A15MPPrivState *)opaque; + qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); +} + static int a15mp_priv_init(SysBusDevice *dev) { - A15MPPrivState *s = FROM_SYSBUSGIC(A15MPPrivState, dev); + A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev); + SysBusDevice *busdev; + + s->gic = qdev_create(NULL, "arm_gic"); + qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); + qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq); + qdev_init_nofail(s->gic); + busdev = sysbus_from_qdev(s->gic); - if (s->num_cpu > NCPU) { - hw_error("a15mp_priv_init: num-cpu may not be more than %d\n", NCPU); - } + /* Pass through outbound IRQ lines from the GIC */ + sysbus_pass_irq(dev, busdev); - gic_init(&s->gic, s->num_cpu, s->num_irq); + /* Pass through inbound GPIO lines to the GIC */ + qdev_init_gpio_in(&s->busdev.qdev, a15mp_priv_set_irq, s->num_irq - 32); /* Memory map (addresses are offsets from PERIPHBASE): * 0x0000-0x0fff -- reserved @@ -60,8 +62,10 @@ static int a15mp_priv_init(SysBusDevice *dev) * 0x6000-0x7fff -- GIC virtual CPU interface (not modelled) */ memory_region_init(&s->container, "a15mp-priv-container", 0x8000); - memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem); - memory_region_add_subregion(&s->container, 0x2000, &s->gic.cpuiomem[0]); + memory_region_add_subregion(&s->container, 0x1000, + sysbus_mmio_get_region(busdev, 0)); + memory_region_add_subregion(&s->container, 0x2000, + sysbus_mmio_get_region(busdev, 1)); sysbus_init_mmio(dev, &s->container); return 0; @@ -85,7 +89,7 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = a15mp_priv_init; dc->props = a15mp_priv_properties; - /* We currently have no savable state outside the common GIC state */ + /* We currently have no savable state */ } static TypeInfo a15mp_priv_info = { diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 03b128ce5b..c2ff74d4b6 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -10,32 +10,19 @@ #include "sysbus.h" -/* Configuration for arm_gic.c: - * max number of CPUs, how to ID current CPU - */ -#define NCPU 4 - -static inline int -gic_get_current_cpu(void) -{ - return cpu_single_env->cpu_index; -} - -#include "arm_gic.c" - /* A9MP private memory region. */ typedef struct a9mp_priv_state { - gic_state gic; + SysBusDevice busdev; uint32_t scu_control; uint32_t scu_status; uint32_t old_timer_status[8]; uint32_t num_cpu; - qemu_irq *timer_irq; MemoryRegion scu_iomem; MemoryRegion ptimer_iomem; MemoryRegion container; DeviceState *mptimer; + DeviceState *gic; uint32_t num_irq; } a9mp_priv_state; @@ -124,18 +111,9 @@ static const MemoryRegionOps a9_scu_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void a9mpcore_timer_irq_handler(void *opaque, int irq, int level) -{ - a9mp_priv_state *s = (a9mp_priv_state *)opaque; - if (level && !s->old_timer_status[irq]) { - gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1)); - } - s->old_timer_status[irq] = level; -} - static void a9mp_priv_reset(DeviceState *dev) { - a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, sysbus_from_qdev(dev)); + a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, sysbus_from_qdev(dev)); int i; s->scu_control = 0; for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) { @@ -143,17 +121,29 @@ static void a9mp_priv_reset(DeviceState *dev) } } +static void a9mp_priv_set_irq(void *opaque, int irq, int level) +{ + a9mp_priv_state *s = (a9mp_priv_state *)opaque; + qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); +} + static int a9mp_priv_init(SysBusDevice *dev) { - a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, dev); - SysBusDevice *busdev; + a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, dev); + SysBusDevice *busdev, *gicbusdev; int i; - if (s->num_cpu > NCPU) { - hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU); - } + s->gic = qdev_create(NULL, "arm_gic"); + qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); + qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq); + qdev_init_nofail(s->gic); + gicbusdev = sysbus_from_qdev(s->gic); - gic_init(&s->gic, s->num_cpu, s->num_irq); + /* Pass through outbound IRQ lines from the GIC */ + sysbus_pass_irq(dev, gicbusdev); + + /* Pass through inbound GPIO lines to the GIC */ + qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32); s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); @@ -175,7 +165,8 @@ static int a9mp_priv_init(SysBusDevice *dev) memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100); memory_region_add_subregion(&s->container, 0, &s->scu_iomem); /* GIC CPU interface */ - memory_region_add_subregion(&s->container, 0x100, &s->gic.cpuiomem[0]); + memory_region_add_subregion(&s->container, 0x100, + sysbus_mmio_get_region(gicbusdev, 1)); /* Note that the A9 exposes only the "timer/watchdog for this core" * memory region, not the "timer/watchdog for core X" ones 11MPcore has. */ @@ -183,15 +174,20 @@ static int a9mp_priv_init(SysBusDevice *dev) sysbus_mmio_get_region(busdev, 0)); memory_region_add_subregion(&s->container, 0x620, sysbus_mmio_get_region(busdev, 1)); - memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem); + memory_region_add_subregion(&s->container, 0x1000, + sysbus_mmio_get_region(gicbusdev, 0)); sysbus_init_mmio(dev, &s->container); - /* Wire up the interrupt from each watchdog and timer. */ - s->timer_irq = qemu_allocate_irqs(a9mpcore_timer_irq_handler, - s, (s->num_cpu + 1) * 2); - for (i = 0; i < s->num_cpu * 2; i++) { - sysbus_connect_irq(busdev, i, s->timer_irq[i]); + /* Wire up the interrupt from each watchdog and timer. + * For each core the timer is PPI 29 and the watchdog PPI 30. + */ + for (i = 0; i < s->num_cpu; i++) { + int ppibase = (s->num_irq - 32) + i * 32; + sysbus_connect_irq(busdev, i * 2, + qdev_get_gpio_in(s->gic, ppibase + 29)); + sysbus_connect_irq(busdev, i * 2 + 1, + qdev_get_gpio_in(s->gic, ppibase + 30)); } return 0; } diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index ba6a89d3ed..c528d7aa01 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -10,28 +10,18 @@ #include "sysbus.h" #include "qemu-timer.h" -#define NCPU 4 - -static inline int -gic_get_current_cpu(void) -{ - return cpu_single_env->cpu_index; -} - -#include "arm_gic.c" - /* MPCore private memory region. */ typedef struct mpcore_priv_state { - gic_state gic; + SysBusDevice busdev; uint32_t scu_control; int iomemtype; uint32_t old_timer_status[8]; uint32_t num_cpu; - qemu_irq *timer_irq; MemoryRegion iomem; MemoryRegion container; DeviceState *mptimer; + DeviceState *gic; uint32_t num_irq; } mpcore_priv_state; @@ -81,18 +71,16 @@ static const MemoryRegionOps mpcore_scu_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void mpcore_timer_irq_handler(void *opaque, int irq, int level) +static void mpcore_priv_set_irq(void *opaque, int irq, int level) { mpcore_priv_state *s = (mpcore_priv_state *)opaque; - if (level && !s->old_timer_status[irq]) { - gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1)); - } - s->old_timer_status[irq] = level; + qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } static void mpcore_priv_map_setup(mpcore_priv_state *s) { int i; + SysBusDevice *gicbusdev = sysbus_from_qdev(s->gic); SysBusDevice *busdev = sysbus_from_qdev(s->mptimer); memory_region_init(&s->container, "mpcode-priv-container", 0x2000); memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100); @@ -102,31 +90,47 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s) */ for (i = 0; i < (s->num_cpu + 1); i++) { target_phys_addr_t offset = 0x100 + (i * 0x100); - memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]); + memory_region_add_subregion(&s->container, offset, + sysbus_mmio_get_region(gicbusdev, i + 1)); } /* Add the regions for timer and watchdog for "current CPU" and * for each specific CPU. */ - s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler, - s, (s->num_cpu + 1) * 2); for (i = 0; i < (s->num_cpu + 1) * 2; i++) { /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */ target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20; memory_region_add_subregion(&s->container, offset, sysbus_mmio_get_region(busdev, i)); } - memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem); - /* Wire up the interrupt from each watchdog and timer. */ - for (i = 0; i < s->num_cpu * 2; i++) { - sysbus_connect_irq(busdev, i, s->timer_irq[i]); + memory_region_add_subregion(&s->container, 0x1000, + sysbus_mmio_get_region(gicbusdev, 0)); + /* Wire up the interrupt from each watchdog and timer. + * For each core the timer is PPI 29 and the watchdog PPI 30. + */ + for (i = 0; i < s->num_cpu; i++) { + int ppibase = (s->num_irq - 32) + i * 32; + sysbus_connect_irq(busdev, i * 2, + qdev_get_gpio_in(s->gic, ppibase + 29)); + sysbus_connect_irq(busdev, i * 2 + 1, + qdev_get_gpio_in(s->gic, ppibase + 30)); } } static int mpcore_priv_init(SysBusDevice *dev) { - mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); + mpcore_priv_state *s = FROM_SYSBUS(mpcore_priv_state, dev); + + s->gic = qdev_create(NULL, "arm_gic"); + qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); + qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq); + qdev_init_nofail(s->gic); + + /* Pass through outbound IRQ lines from the GIC */ + sysbus_pass_irq(dev, sysbus_from_qdev(s->gic)); + + /* Pass through inbound GPIO lines to the GIC */ + qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32); - gic_init(&s->gic, s->num_cpu, s->num_irq); s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); qdev_init_nofail(s->mptimer); diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 6b34c06a8f..72298b4b41 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -8,13 +8,29 @@ */ /* This file contains implementation code for the RealView EB interrupt - controller, MPCore distributed interrupt controller and ARMv7-M - Nested Vectored Interrupt Controller. */ + * controller, MPCore distributed interrupt controller and ARMv7-M + * Nested Vectored Interrupt Controller. + * It is compiled in two ways: + * (1) as a standalone file to produce a sysbus device which is a GIC + * that can be used on the realview board and as one of the builtin + * private peripherals for the ARM MP CPUs (11MPCore, A9, etc) + * (2) by being directly #included into armv7m_nvic.c to produce the + * armv7m_nvic device. + */ + +#include "sysbus.h" /* Maximum number of possible interrupts, determined by the GIC architecture */ #define GIC_MAXIRQ 1020 /* First 32 are private to each CPU (SGIs and PPIs). */ #define GIC_INTERNAL 32 +/* Maximum number of possible CPU interfaces, determined by GIC architecture */ +#ifdef NVIC +#define NCPU 1 +#else +#define NCPU 8 +#endif + //#define DEBUG_GIC #ifdef DEBUG_GIC @@ -50,7 +66,7 @@ typedef struct gic_irq_state unsigned trigger:1; /* nonzero = edge triggered. */ } gic_irq_state; -#define ALL_CPU_MASK ((1 << NCPU) - 1) +#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1))) #if NCPU > 1 #define NUM_CPU(s) ((s)->num_cpu) #else @@ -105,7 +121,7 @@ typedef struct gic_state int current_pending[NCPU]; #if NCPU > 1 - int num_cpu; + uint32_t num_cpu; #endif MemoryRegion iomem; /* Distributor */ @@ -119,6 +135,16 @@ typedef struct gic_state uint32_t num_irq; } gic_state; +static inline int gic_get_current_cpu(gic_state *s) +{ +#if NCPU > 1 + if (s->num_cpu > 1) { + return cpu_single_env->cpu_index; + } +#endif + return 0; +} + /* TODO: Many places that call this routine could be optimized. */ /* Update interrupt status after enabled or pending bits have been changed. */ static void gic_update(gic_state *s) @@ -134,7 +160,7 @@ static void gic_update(gic_state *s) cm = 1 << cpu; s->current_pending[cpu] = 1023; if (!s->enabled || !s->cpu_enabled[cpu]) { - qemu_irq_lower(s->parent_irq[cpu]); + qemu_irq_lower(s->parent_irq[cpu]); return; } best_prio = 0x100; @@ -159,8 +185,8 @@ static void gic_update(gic_state *s) } } -static void __attribute__((unused)) -gic_set_pending_private(gic_state *s, int cpu, int irq) +#ifdef NVIC +static void gic_set_pending_private(gic_state *s, int cpu, int irq) { int cm = 1 << cpu; @@ -171,24 +197,45 @@ gic_set_pending_private(gic_state *s, int cpu, int irq) GIC_SET_PENDING(irq, cm); gic_update(s); } +#endif /* Process a change in an external IRQ input. */ static void gic_set_irq(void *opaque, int irq, int level) { + /* Meaning of the 'irq' parameter: + * [0..N-1] : external interrupts + * [N..N+31] : PPI (internal) interrupts for CPU 0 + * [N+32..N+63] : PPI (internal interrupts for CPU 1 + * ... + */ gic_state *s = (gic_state *)opaque; - /* The first external input line is internal interrupt 32. */ - irq += GIC_INTERNAL; - if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK)) + int cm, target; + if (irq < (s->num_irq - GIC_INTERNAL)) { + /* The first external input line is internal interrupt 32. */ + cm = ALL_CPU_MASK; + irq += GIC_INTERNAL; + target = GIC_TARGET(irq); + } else { + int cpu; + irq -= (s->num_irq - GIC_INTERNAL); + cpu = irq / GIC_INTERNAL; + irq %= GIC_INTERNAL; + cm = 1 << cpu; + target = cm; + } + + if (level == GIC_TEST_LEVEL(irq, cm)) { return; + } if (level) { - GIC_SET_LEVEL(irq, ALL_CPU_MASK); - if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, ALL_CPU_MASK)) { - DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq)); - GIC_SET_PENDING(irq, GIC_TARGET(irq)); + GIC_SET_LEVEL(irq, cm); + if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { + DPRINTF("Set %d pending mask %x\n", irq, target); + GIC_SET_PENDING(irq, target); } } else { - GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK); + GIC_CLEAR_LEVEL(irq, cm); } gic_update(s); } @@ -278,7 +325,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) int cm; int mask; - cpu = gic_get_current_cpu(); + cpu = gic_get_current_cpu(s); cm = 1 << cpu; if (offset < 0x100) { #ifndef NVIC @@ -413,7 +460,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, int i; int cpu; - cpu = gic_get_current_cpu(); + cpu = gic_get_current_cpu(s); if (offset < 0x100) { #ifdef NVIC goto bad_reg; @@ -575,7 +622,7 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset, int irq; int mask; - cpu = gic_get_current_cpu(); + cpu = gic_get_current_cpu(s); irq = value & 0x3ff; switch ((value >> 24) & 3) { case 0: @@ -658,14 +705,14 @@ static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr, unsigned size) { gic_state *s = (gic_state *)opaque; - return gic_cpu_read(s, gic_get_current_cpu(), addr); + return gic_cpu_read(s, gic_get_current_cpu(s), addr); } static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { gic_state *s = (gic_state *)opaque; - gic_cpu_write(s, gic_get_current_cpu(), addr, value); + gic_cpu_write(s, gic_get_current_cpu(s), addr, value); } /* Wrappers to read/write the GIC CPU interface for a specific CPU. @@ -702,8 +749,9 @@ static const MemoryRegionOps gic_cpu_ops = { }; #endif -static void gic_reset(gic_state *s) +static void gic_reset(DeviceState *dev) { + gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev)); int i; memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < NUM_CPU(s); i++) { @@ -813,6 +861,10 @@ static void gic_init(gic_state *s, int num_irq) #if NCPU > 1 s->num_cpu = num_cpu; + if (s->num_cpu > NCPU) { + hw_error("requested %u CPUs exceeds GIC maximum %d\n", + num_cpu, NCPU); + } #endif s->num_irq = num_irq + GIC_BASE_IRQ; if (s->num_irq > GIC_MAXIRQ) { @@ -828,7 +880,18 @@ static void gic_init(gic_state *s, int num_irq) num_irq); } - qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - GIC_INTERNAL); + i = s->num_irq - GIC_INTERNAL; +#ifndef NVIC + /* 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 * num_cpu); +#endif + qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i); for (i = 0; i < NUM_CPU(s); i++) { sysbus_init_irq(&s->busdev, &s->parent_irq[i]); } @@ -851,6 +914,54 @@ static void gic_init(gic_state *s, int num_irq) } #endif - gic_reset(s); register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s); } + +#ifndef NVIC + +static int arm_gic_init(SysBusDevice *dev) +{ + /* Device instance init function for the GIC sysbus device */ + int i; + gic_state *s = FROM_SYSBUS(gic_state, dev); + gic_init(s, s->num_cpu, s->num_irq); + /* Distributor */ + sysbus_init_mmio(dev, &s->iomem); + /* cpu interfaces (one for "current cpu" plus one per cpu) */ + for (i = 0; i <= NUM_CPU(s); i++) { + sysbus_init_mmio(dev, &s->cpuiomem[i]); + } + return 0; +} + +static Property arm_gic_properties[] = { + DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1), + DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32), + DEFINE_PROP_END_OF_LIST(), +}; + +static void arm_gic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + sbc->init = arm_gic_init; + dc->props = arm_gic_properties; + dc->reset = gic_reset; + dc->no_user = 1; +} + +static TypeInfo arm_gic_info = { + .name = "arm_gic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(gic_state), + .class_init = arm_gic_class_init, +}; + +static void arm_gic_register_types(void) +{ + type_register_static(&arm_gic_info); +} + +type_init(arm_gic_register_types) + +#endif diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index 3210129c3f..986a6bbd0c 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -15,16 +15,8 @@ #include "arm-misc.h" #include "exec-memory.h" -#define NCPU 1 #define NVIC 1 -/* Only a single "CPU" interface is present. */ -static inline int -gic_get_current_cpu(void) -{ - return 0; -} - static uint32_t nvic_readl(void *opaque, uint32_t offset); static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); @@ -83,6 +75,14 @@ static void systick_timer_tick(void * opaque) } } +static void systick_reset(nvic_state *s) +{ + s->systick.control = 0; + s->systick.reload = 0; + s->systick.tick = 0; + qemu_del_timer(s->systick.timer); +} + /* The external routines use the hardware vector numbering, ie. the first IRQ is #16. The internal GIC routines use #32 as the first IRQ. */ void armv7m_nvic_set_pending(void *opaque, int irq) @@ -378,6 +378,13 @@ static const VMStateDescription vmstate_nvic = { } }; +static void armv7m_nvic_reset(DeviceState *dev) +{ + nvic_state *s = FROM_SYSBUSGIC(nvic_state, sysbus_from_qdev(dev)); + gic_reset(&s->gic.busdev.qdev); + systick_reset(s); +} + static int armv7m_nvic_init(SysBusDevice *dev) { nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev); @@ -407,6 +414,7 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data) sdc->init = armv7m_nvic_init; dc->vmsd = &vmstate_nvic; + dc->reset = armv7m_nvic_reset; dc->props = armv7m_nvic_properties; } diff --git a/hw/exynos4210.c b/hw/exynos4210.c index f904370505..afc4bdc7e0 100644 --- a/hw/exynos4210.c +++ b/hw/exynos4210.c @@ -25,6 +25,7 @@ #include "sysemu.h" #include "sysbus.h" #include "arm-misc.h" +#include "loader.h" #include "exynos4210.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@ -64,6 +65,35 @@ static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; +void exynos4210_write_secondary(CPUARMState *env, + const struct arm_boot_info *info) +{ + int n; + uint32_t smpboot[] = { + 0xe59f3024, /* ldr r3, External gic_cpu_if */ + 0xe59f2024, /* ldr r2, Internal gic_cpu_if */ + 0xe59f0024, /* ldr r0, startaddr */ + 0xe3a01001, /* mov r1, #1 */ + 0xe5821000, /* str r1, [r2] */ + 0xe5831000, /* str r1, [r3] */ + 0xe320f003, /* wfi */ + 0xe5901000, /* ldr r1, [r0] */ + 0xe1110001, /* tst r1, r1 */ + 0x0afffffb, /* beq <wfi> */ + 0xe12fff11, /* bx r1 */ + EXYNOS4210_EXT_GIC_CPU_BASE_ADDR, + 0, /* gic_cpu_if: base address of Internal GIC CPU interface */ + 0 /* bootreg: Boot register address is held here */ + }; + smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; + smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start); +} + Exynos4210State *exynos4210_init(MemoryRegion *system_mem, unsigned long ram_size) { diff --git a/hw/exynos4210.h b/hw/exynos4210.h index c112e03bfb..f7c7027302 100644 --- a/hw/exynos4210.h +++ b/hw/exynos4210.h @@ -97,6 +97,9 @@ typedef struct Exynos4210State { MemoryRegion bootreg_mem; } Exynos4210State; +void exynos4210_write_secondary(CPUARMState *env, + const struct arm_boot_info *info); + Exynos4210State *exynos4210_init(MemoryRegion *system_mem, unsigned long ram_size); diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c index 6110c19d5d..80af22cc33 100644 --- a/hw/exynos4210_combiner.c +++ b/hw/exynos4210_combiner.c @@ -184,11 +184,6 @@ exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned size) uint32_t reg_n; /* Register number inside the quad */ uint32_t val; - if (s->external && (offset > 0x3c && offset != 0x100)) { - hw_error("exynos4210.combiner: unallowed read access at offset 0x" - TARGET_FMT_plx "\n", offset); - } - req_quad_base_n = offset >> 4; grp_quad_base_n = req_quad_base_n << 2; reg_n = (offset - (req_quad_base_n << 4)) >> 2; @@ -281,11 +276,6 @@ static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset, uint32_t grp_quad_base_n; /* Base of group quad */ uint32_t reg_n; /* Register number inside the quad */ - if (s->external && (offset > 0x3c && offset != 0x100)) { - hw_error("exynos4210.combiner: unallowed write access at offset 0x" - TARGET_FMT_plx "\n", offset); - } - req_quad_base_n = offset >> 4; grp_quad_base_n = req_quad_base_n << 2; reg_n = (offset - (req_quad_base_n << 4)) >> 2; diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c index ec13140f9f..e1b215eff0 100644 --- a/hw/exynos4210_gic.c +++ b/hw/exynos4210_gic.c @@ -174,7 +174,6 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { }; #define EXYNOS4210_GIC_NIRQ 160 -#define NCPU EXYNOS4210_NCPUS #define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000 #define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000 @@ -263,33 +262,44 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) /********* GIC part *********/ -static inline int -gic_get_current_cpu(void) -{ - return cpu_single_env->cpu_index; -} - -#include "arm_gic.c" - typedef struct { - gic_state gic; + SysBusDevice busdev; MemoryRegion cpu_container; MemoryRegion dist_container; - MemoryRegion cpu_alias[NCPU]; - MemoryRegion dist_alias[NCPU]; + MemoryRegion cpu_alias[EXYNOS4210_NCPUS]; + MemoryRegion dist_alias[EXYNOS4210_NCPUS]; uint32_t num_cpu; + DeviceState *gic; } Exynos4210GicState; +static void exynos4210_gic_set_irq(void *opaque, int irq, int level) +{ + Exynos4210GicState *s = (Exynos4210GicState *)opaque; + qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); +} + static int exynos4210_gic_init(SysBusDevice *dev) { - Exynos4210GicState *s = FROM_SYSBUSGIC(Exynos4210GicState, dev); + Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev); uint32_t i; const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; const char dist_prefix[] = "exynos4210-gic-alias_dist"; char cpu_alias_name[sizeof(cpu_prefix) + 3]; char dist_alias_name[sizeof(cpu_prefix) + 3]; + SysBusDevice *busdev; + + s->gic = qdev_create(NULL, "arm_gic"); + qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu); + qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ); + qdev_init_nofail(s->gic); + busdev = sysbus_from_qdev(s->gic); - gic_init(&s->gic, s->num_cpu, EXYNOS4210_GIC_NIRQ); + /* Pass through outbound IRQ lines from the GIC */ + sysbus_pass_irq(dev, busdev); + + /* Pass through inbound GPIO lines to the GIC */ + qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq, + EXYNOS4210_GIC_NIRQ - 32); memory_region_init(&s->cpu_container, "exynos4210-cpu-container", EXYNOS4210_EXT_GIC_CPU_REGION_SIZE); @@ -301,7 +311,7 @@ static int exynos4210_gic_init(SysBusDevice *dev) sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); memory_region_init_alias(&s->cpu_alias[i], cpu_alias_name, - &s->gic.cpuiomem[0], + sysbus_mmio_get_region(busdev, 1), 0, EXYNOS4210_GIC_CPU_REGION_SIZE); memory_region_add_subregion(&s->cpu_container, @@ -311,7 +321,7 @@ static int exynos4210_gic_init(SysBusDevice *dev) sprintf(dist_alias_name, "%s%x", dist_prefix, i); memory_region_init_alias(&s->dist_alias[i], dist_alias_name, - &s->gic.iomem, + sysbus_mmio_get_region(busdev, 0), 0, EXYNOS4210_GIC_DIST_REGION_SIZE); memory_region_add_subregion(&s->dist_container, @@ -321,8 +331,6 @@ static int exynos4210_gic_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->cpu_container); sysbus_init_mmio(dev, &s->dist_container); - gic_cpu_write(&s->gic, 1, 0, 1); - return 0; } @@ -361,7 +369,7 @@ type_init(exynos4210_gic_register_types) typedef struct { SysBusDevice busdev; - qemu_irq pic_irq[NCPU]; /* output IRQs to PICs */ + qemu_irq pic_irq[EXYNOS4210_NCPUS]; /* output IRQs to PICs */ uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */ } Exynos4210IRQGateState; @@ -426,7 +434,7 @@ static int exynos4210_irq_gate_init(SysBusDevice *dev) EXYNOS4210_IRQ_GATE_NINPUTS); /* Connect SysBusDev irqs to device specific irqs */ - for (i = 0; i < NCPU; i++) { + for (i = 0; i < EXYNOS4210_NCPUS; i++) { sysbus_init_irq(dev, &s->pic_irq[i]); } diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c index 73a9c18f30..ccc47804f9 100644 --- a/hw/exynos4210_uart.c +++ b/hw/exynos4210_uart.c @@ -246,7 +246,7 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s) uint32_t level = 0; uint32_t reg; - reg = (s->reg[I_(UFCON)] && UFCON_Tx_FIFO_TRIGGER_LEVEL) >> + reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >> UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT; switch (s->channel) { @@ -275,9 +275,9 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s) * The Tx interrupt is always requested if the number of data in the * transmit FIFO is smaller than the trigger level. */ - if (s->reg[I_(UFCON)] && UFCON_FIFO_ENABLE) { + if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) { - uint32_t count = (s->reg[I_(UFSTAT)] && UFSTAT_Tx_FIFO_COUNT) >> + uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >> UFSTAT_Tx_FIFO_COUNT_SHIFT; if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) { diff --git a/hw/exynos4_boards.c b/hw/exynos4_boards.c index 553a02b910..ea32c51dcc 100644 --- a/hw/exynos4_boards.c +++ b/hw/exynos4_boards.c @@ -70,6 +70,7 @@ static struct arm_boot_info exynos4_board_binfo = { .loader_start = EXYNOS4210_BASE_BOOT_ADDR, .smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR, .nb_cpus = EXYNOS4210_NCPUS, + .write_secondary_boot = exynos4210_write_secondary, }; static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS]; diff --git a/hw/ivshmem.c b/hw/ivshmem.c index c2bdd926c5..d48e5f9906 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -354,8 +354,8 @@ static void close_guest_eventfds(IVShmemState *s, int posn) guest_curr_max = s->peers[posn].nb_eventfds; for (i = 0; i < guest_curr_max; i++) { - kvm_set_ioeventfd_mmio_long(s->peers[posn].eventfds[i], - s->mmio_addr + DOORBELL, (posn << 16) | i, 0); + kvm_set_ioeventfd_mmio(s->peers[posn].eventfds[i], + s->mmio_addr + DOORBELL, (posn << 16) | i, 0, 4); close(s->peers[posn].eventfds[i]); } @@ -500,8 +500,8 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) } if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) { - if (kvm_set_ioeventfd_mmio_long(incoming_fd, s->mmio_addr + DOORBELL, - (incoming_posn << 16) | guest_max_eventfd, 1) < 0) { + if (kvm_set_ioeventfd_mmio(incoming_fd, s->mmio_addr + DOORBELL, + (incoming_posn << 16) | guest_max_eventfd, 1, 4) < 0) { fprintf(stderr, "ivshmem: ioeventfd not available\n"); } } diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c index 446bd62176..824b978397 100644 --- a/hw/kvm/clock.c +++ b/hw/kvm/clock.c @@ -65,9 +65,25 @@ static void kvmclock_vm_state_change(void *opaque, int running, RunState state) { KVMClockState *s = opaque; + CPUArchState *penv = first_cpu; + int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL); + int ret; if (running) { s->clock_valid = false; + + if (!cap_clock_ctrl) { + return; + } + for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) { + ret = kvm_vcpu_ioctl(penv, KVM_KVMCLOCK_CTRL, 0); + if (ret) { + if (ret != -EINVAL) { + fprintf(stderr, "%s: %s\n", __func__, strerror(-ret)); + } + return; + } + } } } @@ -42,6 +42,7 @@ #include "sysbus.h" #include "sysemu.h" #include "kvm.h" +#include "xen.h" #include "blockdev.h" #include "ui/qemu-spice.h" #include "memory.h" @@ -891,9 +892,12 @@ static DeviceState *apic_init(void *env, uint8_t apic_id) if (kvm_irqchip_in_kernel()) { dev = qdev_create(NULL, "kvm-apic"); + } else if (xen_enabled()) { + dev = qdev_create(NULL, "xen-apic"); } else { dev = qdev_create(NULL, "apic"); } + qdev_prop_set_uint8(dev, "id", apic_id); qdev_prop_set_ptr(dev, "cpu_env", env); qdev_init_nofail(dev); @@ -912,6 +916,10 @@ static DeviceState *apic_init(void *env, uint8_t apic_id) msi_supported = true; } + if (xen_enabled()) { + msi_supported = true; + } + return dev; } @@ -1,3 +1,30 @@ +/* + * QEMU PS/2 keyboard/mouse emulation + * + * Copyright (C) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_PS2_H +#define HW_PS2_H + /* ps2.c */ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); @@ -7,3 +34,5 @@ uint32_t ps2_read_data(void *); void ps2_queue(void *, int b); void ps2_keyboard_set_translation(void *opaque, int mode); void ps2_mouse_fake_event(void *opaque); + +#endif /* !HW_PS2_H */ diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 071ef13c9e..5bc37a7120 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -9,39 +9,45 @@ #include "sysbus.h" -#define NCPU 1 - -/* Only a single "CPU" interface is present. */ -static inline int -gic_get_current_cpu(void) -{ - return 0; -} - -#include "arm_gic.c" - typedef struct { - gic_state gic; + SysBusDevice busdev; + DeviceState *gic; MemoryRegion container; } RealViewGICState; -static void realview_gic_map_setup(RealViewGICState *s) +static void realview_gic_set_irq(void *opaque, int irq, int level) { - memory_region_init(&s->container, "realview-gic-container", 0x2000); - memory_region_add_subregion(&s->container, 0, &s->gic.cpuiomem[0]); - memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem); + RealViewGICState *s = (RealViewGICState *)opaque; + qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } static int realview_gic_init(SysBusDevice *dev) { - RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev); - + RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev); + SysBusDevice *busdev; /* The GICs on the RealView boards have a fixed nonconfigurable * number of interrupt lines, so we don't need to expose this as * a qdev property. */ - gic_init(&s->gic, 96); - realview_gic_map_setup(s); + int numirq = 96; + + s->gic = qdev_create(NULL, "arm_gic"); + qdev_prop_set_uint32(s->gic, "num-cpu", 1); + qdev_prop_set_uint32(s->gic, "num-irq", numirq); + qdev_init_nofail(s->gic); + busdev = sysbus_from_qdev(s->gic); + + /* Pass through outbound IRQ lines from the GIC */ + sysbus_pass_irq(dev, busdev); + + /* Pass through inbound GPIO lines to the GIC */ + qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32); + + memory_region_init(&s->container, "realview-gic-container", 0x2000); + memory_region_add_subregion(&s->container, 0, + sysbus_mmio_get_region(busdev, 1)); + memory_region_add_subregion(&s->container, 0x1000, + sysbus_mmio_get_region(busdev, 0)); sysbus_init_mmio(dev, &s->container); return 0; } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 4d553a8a59..4d0f5ba518 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -2482,15 +2482,17 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32 rtl8139_transmit(s); } -static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint8_t addr, int size) +static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[], + uint32_t base, uint8_t addr, + int size) { - uint32_t reg = (addr - TxStatus0) / 4; + uint32_t reg = (addr - base) / 4; uint32_t offset = addr & 0x3; uint32_t ret = 0; if (addr & (size - 1)) { - DPRINTF("not implemented read for TxStatus addr=0x%x size=0x%x\n", addr, - size); + DPRINTF("not implemented read for TxStatus/TxAddr " + "addr=0x%x size=0x%x\n", addr, size); return ret; } @@ -2498,12 +2500,12 @@ static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint8_t addr, int size) case 1: /* fall through */ case 2: /* fall through */ case 4: - ret = (s->TxStatus[reg] >> offset * 8) & ((1 << (size * 8)) - 1); - DPRINTF("TxStatus[%d] read addr=0x%x size=0x%x val=0x%08x\n", reg, addr, - size, ret); + ret = (regs[reg] >> offset * 8) & ((1 << (size * 8)) - 1); + DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n", + reg, addr, size, ret); break; default: - DPRINTF("unsupported size 0x%x of TxStatus reading\n", size); + DPRINTF("unsupported size 0x%x of TxStatus/TxAddr reading\n", size); break; } @@ -2977,7 +2979,8 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) ret = s->mult[addr - MAR0]; break; case TxStatus0 ... TxStatus0+4*4-1: - ret = rtl8139_TxStatus_read(s, addr, 1); + ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0, + addr, 1); break; case ChipCmd: ret = rtl8139_ChipCmd_read(s); @@ -3043,7 +3046,7 @@ static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) switch (addr) { case TxAddr0 ... TxAddr0+4*4-1: - ret = rtl8139_TxStatus_read(s, addr, 2); + ret = rtl8139_TxStatus_TxAddr_read(s, s->TxAddr, TxAddr0, addr, 2); break; case IntrMask: ret = rtl8139_IntrMask_read(s); @@ -3135,7 +3138,8 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) break; case TxStatus0 ... TxStatus0+4*4-1: - ret = rtl8139_TxStatus_read(s, addr, 4); + ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0, + addr, 4); break; case TxAddr0 ... TxAddr0+4*4-1: diff --git a/hw/spapr.h b/hw/spapr.h index 11160b02da..654a7a8a34 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -272,7 +272,7 @@ extern sPAPREnvironment *spapr; #ifdef DEBUG_SPAPR_HCALLS #define hcall_dprintf(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) + do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0) #else #define hcall_dprintf(fmt, ...) \ do { } while (0) diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index cfc777804b..e18d2eb901 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -182,6 +182,15 @@ static NetClientInfo net_spapr_vlan_info = { .receive = spapr_vlan_receive, }; +static void spapr_vlan_reset(VIOsPAPRDevice *sdev) +{ + VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev); + + dev->buf_list = 0; + dev->rx_bufs = 0; + dev->isopen = 0; +} + static int spapr_vlan_init(VIOsPAPRDevice *sdev) { VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; @@ -279,21 +288,19 @@ static target_ulong h_register_logical_lan(CPUPPCState *env, if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE), SPAPR_VIO_TCE_PAGE_SIZE) < 0) { - hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for " - "H_REGISTER_LOGICAL_LAN\n", buf_list); + hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list); return H_PARAMETER; } filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE); if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) { - hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for " - "H_REGISTER_LOGICAL_LAN\n", filter_list); + hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list); return H_PARAMETER; } if (!(rec_queue & VLAN_BD_VALID) || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) { - hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n"); + hcall_dprintf("Bad receive queue\n"); return H_PARAMETER; } @@ -337,9 +344,7 @@ static target_ulong h_free_logical_lan(CPUPPCState *env, sPAPREnvironment *spapr return H_RESOURCE; } - dev->buf_list = 0; - dev->rx_bufs = 0; - dev->isopen = 0; + spapr_vlan_reset(sdev); return H_SUCCESS; } @@ -358,13 +363,13 @@ static target_ulong h_add_logical_lan_buffer(CPUPPCState *env, ", 0x" TARGET_FMT_lx ")\n", reg, buf); if (!sdev) { - hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n"); + hcall_dprintf("Bad device\n"); return H_PARAMETER; } if ((check_bd(dev, buf, 4) < 0) || (VLAN_BD_LEN(buf) < 16)) { - hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n"); + hcall_dprintf("Bad buffer enqueued\n"); return H_PARAMETER; } @@ -486,6 +491,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); k->init = spapr_vlan_init; + k->reset = spapr_vlan_reset; k->devnode = spapr_vlan_devnode; k->dt_name = "l-lan"; k->dt_type = "network"; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index e7ef551c1c..a564c007b4 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -57,26 +57,38 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, static uint32_t rtas_pci_cfgaddr(uint32_t arg) { + /* This handles the encoding of extended config space addresses */ return ((arg >> 20) & 0xf00) | (arg & 0xff); } -static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t len) +static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid, + uint32_t addr, uint32_t size, + target_ulong rets) { - if ((addr + len) <= limit) { - return pci_host_config_read_common(pci_dev, addr, limit, len); - } else { - return ~0x0; + PCIDevice *pci_dev; + uint32_t val; + + if ((size != 1) && (size != 2) && (size != 4)) { + /* access must be 1, 2 or 4 bytes */ + rtas_st(rets, 0, -1); + return; } -} -static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr, - uint32_t limit, uint32_t val, - uint32_t len) -{ - if ((addr + len) <= limit) { - pci_host_config_write_common(pci_dev, addr, limit, val, len); + pci_dev = find_dev(spapr, buid, addr); + addr = rtas_pci_cfgaddr(addr); + + if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { + /* Access must be to a valid device, within bounds and + * naturally aligned */ + rtas_st(rets, 0, -1); + return; } + + val = pci_host_config_read_common(pci_dev, addr, + pci_config_size(pci_dev), size); + + rtas_st(rets, 0, 0); + rtas_st(rets, 1, val); } static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, @@ -84,19 +96,19 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, target_ulong args, uint32_t nret, target_ulong rets) { - uint32_t val, size, addr; - uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); - PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); + uint64_t buid; + uint32_t size, addr; - if (!dev) { + if ((nargs != 4) || (nret != 2)) { rtas_st(rets, 0, -1); return; } + + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); size = rtas_ld(args, 3); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); - rtas_st(rets, 0, 0); - rtas_st(rets, 1, val); + addr = rtas_ld(args, 0); + + finish_read_pci_config(spapr, buid, addr, size, rets); } static void rtas_read_pci_config(sPAPREnvironment *spapr, @@ -104,18 +116,45 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr, target_ulong args, uint32_t nret, target_ulong rets) { - uint32_t val, size, addr; - PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); + uint32_t size, addr; - if (!dev) { + if ((nargs != 2) || (nret != 2)) { rtas_st(rets, 0, -1); return; } + size = rtas_ld(args, 1); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); + addr = rtas_ld(args, 0); + + finish_read_pci_config(spapr, 0, addr, size, rets); +} + +static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid, + uint32_t addr, uint32_t size, + uint32_t val, target_ulong rets) +{ + PCIDevice *pci_dev; + + if ((size != 1) && (size != 2) && (size != 4)) { + /* access must be 1, 2 or 4 bytes */ + rtas_st(rets, 0, -1); + return; + } + + pci_dev = find_dev(spapr, buid, addr); + addr = rtas_pci_cfgaddr(addr); + + if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) { + /* Access must be to a valid device, within bounds and + * naturally aligned */ + rtas_st(rets, 0, -1); + return; + } + + pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev), + val, size); + rtas_st(rets, 0, 0); - rtas_st(rets, 1, val); } static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, @@ -123,19 +162,20 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, target_ulong args, uint32_t nret, target_ulong rets) { + uint64_t buid; uint32_t val, size, addr; - uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); - PCIDevice *dev = find_dev(spapr, buid, rtas_ld(args, 0)); - if (!dev) { + if ((nargs != 5) || (nret != 1)) { rtas_st(rets, 0, -1); return; } + + buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); val = rtas_ld(args, 4); size = rtas_ld(args, 3); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); - rtas_st(rets, 0, 0); + addr = rtas_ld(args, 0); + + finish_write_pci_config(spapr, buid, addr, size, val, rets); } static void rtas_write_pci_config(sPAPREnvironment *spapr, @@ -144,17 +184,18 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { uint32_t val, size, addr; - PCIDevice *dev = find_dev(spapr, 0, rtas_ld(args, 0)); - if (!dev) { + if ((nargs != 3) || (nret != 1)) { rtas_st(rets, 0, -1); return; } + + val = rtas_ld(args, 2); size = rtas_ld(args, 1); - addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); - rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); - rtas_st(rets, 0, 0); + addr = rtas_ld(args, 0); + + finish_write_pci_config(spapr, 0, addr, size, val, rets); } static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num) diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 09465853ba..ae18595150 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -44,8 +44,7 @@ static void rtas_display_character(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { uint8_t c = rtas_ld(args, 0); - VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, - SPAPR_VTY_BASE_ADDRESS); + VIOsPAPRDevice *sdev = vty_lookup(spapr, 0); if (!sdev) { rtas_st(rets, 0, -1); @@ -112,6 +111,19 @@ static void rtas_power_off(sPAPREnvironment *spapr, rtas_st(rets, 0, 0); } +static void rtas_system_reboot(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + if (nargs != 0 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + qemu_system_reset_request(); + rtas_st(rets, 0, 0); +} + static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, @@ -294,6 +306,7 @@ static void core_rtas_register_types(void) spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); spapr_rtas_register("set-time-of-day", rtas_set_time_of_day); spapr_rtas_register("power-off", rtas_power_off); + spapr_rtas_register("system-reboot", rtas_system_reboot); spapr_rtas_register("query-cpu-stopped-state", rtas_query_cpu_stopped_state); spapr_rtas_register("start-cpu", rtas_start_cpu); diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index dbf5a9017e..fccf48bd67 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -204,8 +204,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPR_RTCE *rtce; if (!dev) { - hcall_dprintf("spapr_vio_put_tce on non-existent LIOBN " - TARGET_FMT_lx "\n", liobn); + hcall_dprintf("LIOBN 0x" TARGET_FMT_lx " does not exist\n", liobn); return H_PARAMETER; } @@ -217,8 +216,7 @@ static target_ulong h_put_tce(CPUPPCState *env, sPAPREnvironment *spapr, #endif if (ioba >= dev->rtce_window_size) { - hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x" - TARGET_FMT_lx "\n", ioba); + hcall_dprintf("Out-of-bounds IOBA 0x" TARGET_FMT_lx "\n", ioba); return H_PARAMETER; } @@ -414,33 +412,32 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); if (!dev) { - hcall_dprintf("h_reg_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } /* We can't grok a queue size bigger than 256M for now */ if (queue_len < 0x1000 || queue_len > 0x10000000) { - hcall_dprintf("h_reg_crq, queue size too small or too big (0x%llx)\n", - (unsigned long long)queue_len); + hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx + ")\n", queue_len); return H_PARAMETER; } /* Check queue alignment */ if (queue_addr & 0xfff) { - hcall_dprintf("h_reg_crq, queue not aligned (0x%llx)\n", - (unsigned long long)queue_addr); + hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr); return H_PARAMETER; } /* Check if device supports CRQs */ if (!dev->crq.SendFunc) { + hcall_dprintf("Device does not support CRQ\n"); return H_NOT_FOUND; } - /* Already a queue ? */ if (dev->crq.qsize) { + hcall_dprintf("CRQ already registered\n"); return H_RESOURCE; } dev->crq.qladdr = queue_addr; @@ -453,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr, return H_SUCCESS; } +static target_ulong free_crq(VIOsPAPRDevice *dev) +{ + dev->crq.qladdr = 0; + dev->crq.qsize = 0; + dev->crq.qnext = 0; + + dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg); + + return H_SUCCESS; +} + static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -460,18 +468,11 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); if (!dev) { - hcall_dprintf("h_free_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } - dev->crq.qladdr = 0; - dev->crq.qsize = 0; - dev->crq.qnext = 0; - - dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg); - - return H_SUCCESS; + return free_crq(dev); } static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr, @@ -484,8 +485,7 @@ static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr, uint64_t crq_mangle[2]; if (!dev) { - hcall_dprintf("h_send_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } crq_mangle[0] = cpu_to_be64(msg_hi); @@ -505,8 +505,7 @@ static target_ulong h_enable_crq(CPUPPCState *env, sPAPREnvironment *spapr, VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); if (!dev) { - hcall_dprintf("h_enable_crq on non-existent unit 0x" - TARGET_FMT_lx "\n", reg); + hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); return H_PARAMETER; } @@ -649,6 +648,20 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev) return 0; } +static void spapr_vio_busdev_reset(DeviceState *qdev) +{ + VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + + if (dev->crq.qsize) { + free_crq(dev); + } + + if (pc->reset) { + pc->reset(dev); + } +} + static int spapr_vio_busdev_init(DeviceState *qdev) { VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; @@ -766,6 +779,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = spapr_vio_busdev_init; + k->reset = spapr_vio_busdev_reset; k->bus_info = &spapr_vio_bus_info; } diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index d8527bed90..10ab3594c0 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -64,7 +64,7 @@ typedef struct VIOsPAPRDeviceClass { const char *dt_name, *dt_type, *dt_compatible; target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); - void (*hcalls)(VIOsPAPRBus *bus); + void (*reset)(VIOsPAPRDevice *dev); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); } VIOsPAPRDeviceClass; @@ -89,8 +89,6 @@ struct VIOsPAPRDevice { struct VIOsPAPRBus { BusState bus; - const char *dt_name, *dt_type, *dt_compatible; - target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); }; @@ -119,6 +117,7 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr); int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq); +VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg); void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len); void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev); void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 21670170e8..538e0b7938 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -99,10 +99,6 @@ typedef struct { vscsi_req reqs[VSCSI_REQ_LIMIT]; } VSCSIState; -/* XXX Debug only */ -static VSCSIState *dbg_vscsi_state; - - static struct vscsi_req *vscsi_get_req(VSCSIState *s) { vscsi_req *req; @@ -897,18 +893,20 @@ static const struct SCSIBusInfo vscsi_scsi_info = { .cancel = vscsi_request_cancelled }; -static int spapr_vscsi_init(VIOsPAPRDevice *dev) +static void spapr_vscsi_reset(VIOsPAPRDevice *dev) { VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); int i; - dbg_vscsi_state = s; - - /* Initialize qemu request tags */ memset(s->reqs, 0, sizeof(s->reqs)); for (i = 0; i < VSCSI_REQ_LIMIT; i++) { s->reqs[i].qtag = i; } +} + +static int spapr_vscsi_init(VIOsPAPRDevice *dev) +{ + VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); dev->crq.SendFunc = vscsi_do_crq; @@ -958,6 +956,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); k->init = spapr_vscsi_init; + k->reset = spapr_vscsi_reset; k->devnode = spapr_vscsi_devnode; k->dt_name = "v-scsi"; k->dt_type = "vscsi"; diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index 60e22b1600..a30c040b97 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -70,8 +70,6 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) } /* Forward declaration */ -static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg); - static target_ulong h_put_term_char(CPUPPCState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -195,7 +193,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) return selected; } -static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) +VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) { VIOsPAPRDevice *sdev; @@ -34,6 +34,7 @@ static inline int xen_enabled(void) int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num); void xen_piix3_set_irq(void *opaque, int irq_num, int level); void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len); +void xen_hvm_inject_msi(uint64_t addr, uint32_t data); void xen_cmos_set_s3_resume(void *opaque, int irq, int level); qemu_irq *xen_interrupt_controller_init(void); diff --git a/hw/xen_apic.c b/hw/xen_apic.c new file mode 100644 index 0000000000..1725ff67dd --- /dev/null +++ b/hw/xen_apic.c @@ -0,0 +1,90 @@ +/* + * Xen basic APIC support + * + * Copyright (c) 2012 Citrix + * + * Authors: + * Wei Liu <wei.liu2@citrix.com> + * + * This work is licensed under the terms of the GNU GPL version 2 or + * later. See the COPYING file in the top-level directory. + */ +#include "hw/apic_internal.h" +#include "hw/msi.h" +#include "xen.h" + +static uint64_t xen_apic_mem_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + return ~(uint64_t)0; +} + +static void xen_apic_mem_write(void *opaque, target_phys_addr_t addr, + uint64_t data, unsigned size) +{ + if (size != sizeof(uint32_t)) { + fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size); + return; + } + + xen_hvm_inject_msi(addr, data); +} + +static const MemoryRegionOps xen_apic_io_ops = { + .read = xen_apic_mem_read, + .write = xen_apic_mem_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void xen_apic_init(APICCommonState *s) +{ + memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi", + MSI_SPACE_SIZE); +} + +static void xen_apic_set_base(APICCommonState *s, uint64_t val) +{ +} + +static void xen_apic_set_tpr(APICCommonState *s, uint8_t val) +{ +} + +static uint8_t xen_apic_get_tpr(APICCommonState *s) +{ + return 0; +} + +static void xen_apic_vapic_base_update(APICCommonState *s) +{ +} + +static void xen_apic_external_nmi(APICCommonState *s) +{ +} + +static void xen_apic_class_init(ObjectClass *klass, void *data) +{ + APICCommonClass *k = APIC_COMMON_CLASS(klass); + + k->init = xen_apic_init; + k->set_base = xen_apic_set_base; + k->set_tpr = xen_apic_set_tpr; + k->get_tpr = xen_apic_get_tpr; + k->vapic_base_update = xen_apic_vapic_base_update; + k->external_nmi = xen_apic_external_nmi; +} + +static TypeInfo xen_apic_info = { + .name = "xen-apic", + .parent = TYPE_APIC_COMMON, + .instance_size = sizeof(APICCommonState), + .class_init = xen_apic_class_init, +}; + +static void xen_apic_register_types(void) +{ + type_register_static(&xen_apic_info); +} + +type_init(xen_apic_register_types) diff --git a/hw/xen_backend.c b/hw/xen_backend.c index 2673ace185..66cb144397 100644 --- a/hw/xen_backend.c +++ b/hw/xen_backend.c @@ -592,7 +592,7 @@ static void xenstore_update_be(char *watch, char *type, int dom, struct XenDevOps *ops) { struct XenDevice *xendev; - char path[XEN_BUFSIZE], *dom0; + char path[XEN_BUFSIZE], *dom0, *bepath; unsigned int len, dev; dom0 = xs_get_domain_path(xenstore, 0); @@ -611,15 +611,16 @@ static void xenstore_update_be(char *watch, char *type, int dom, return; } - if (0) { - /* FIXME: detect devices being deleted from xenstore ... */ - xen_be_del_xendev(dom, dev); - } - xendev = xen_be_get_xendev(type, dom, dev, ops); if (xendev != NULL) { - xen_be_backend_changed(xendev, path); - xen_be_check_state(xendev); + bepath = xs_read(xenstore, 0, xendev->be, &len); + if (bepath == NULL) { + xen_be_del_xendev(dom, dev); + } else { + free(bepath); + xen_be_backend_changed(xendev, path); + xen_be_check_state(xendev); + } } } diff --git a/hw/xen_disk.c b/hw/xen_disk.c index 9719395b09..22dbd10303 100644 --- a/hw/xen_disk.c +++ b/hw/xen_disk.c @@ -745,6 +745,10 @@ static int blk_free(struct XenDevice *xendev) struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); struct ioreq *ioreq; + if (blkdev->bs || blkdev->sring) { + blk_disconnect(xendev); + } + while (!QLIST_EMPTY(&blkdev->freelist)) { ioreq = QLIST_FIRST(&blkdev->freelist); QLIST_REMOVE(ioreq, list); |