diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/musicpal.c | 6 | ||||
-rw-r--r-- | hw/arm/pxa2xx.c | 6 | ||||
-rw-r--r-- | hw/audio/hda-codec.c | 60 | ||||
-rw-r--r-- | hw/dma/pl330.c | 55 | ||||
-rw-r--r-- | hw/intc/arm_gic_kvm.c | 446 | ||||
-rw-r--r-- | hw/intc/exynos4210_combiner.c | 2 | ||||
-rw-r--r-- | hw/intc/gic_internal.h | 2 | ||||
-rw-r--r-- | hw/misc/arm_sysctl.c | 4 | ||||
-rw-r--r-- | hw/net/stellaris_enet.c | 3 | ||||
-rw-r--r-- | hw/net/vhost_net.c | 6 | ||||
-rw-r--r-- | hw/net/virtio-net.c | 16 | ||||
-rw-r--r-- | hw/net/vmxnet3.c | 22 | ||||
-rw-r--r-- | hw/timer/arm_timer.c | 2 |
13 files changed, 542 insertions, 88 deletions
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 50a3b8fe4f..cce7127598 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -92,8 +92,6 @@ #define MP_ETH_CRDP3 0x4AC #define MP_ETH_CTDP0 0x4E0 #define MP_ETH_CTDP1 0x4E4 -#define MP_ETH_CTDP2 0x4E8 -#define MP_ETH_CTDP3 0x4EC /* MII PHY access */ #define MP_ETH_SMIR_DATA 0x0000FFFF @@ -308,7 +306,7 @@ static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset, case MP_ETH_CRDP0 ... MP_ETH_CRDP3: return s->rx_queue[(offset - MP_ETH_CRDP0)/4]; - case MP_ETH_CTDP0 ... MP_ETH_CTDP3: + case MP_ETH_CTDP0 ... MP_ETH_CTDP1: return s->tx_queue[(offset - MP_ETH_CTDP0)/4]; default: @@ -362,7 +360,7 @@ static void mv88w8618_eth_write(void *opaque, hwaddr offset, s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value; break; - case MP_ETH_CTDP0 ... MP_ETH_CTDP3: + case MP_ETH_CTDP0 ... MP_ETH_CTDP1: s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value; break; } diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 45a99c819d..904277a9da 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -272,11 +272,11 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri, goto message; case 3: - s->cpu->env.uncached_cpsr = - ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; + s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC; + s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I; s->cpu->env.cp15.c1_sys = 0; s->cpu->env.cp15.c1_coproc = 0; - s->cpu->env.cp15.c2_base0 = 0; + s->cpu->env.cp15.ttbr0_el1 = 0; s->cpu->env.cp15.c3 = 0; s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index 986f2a9c92..a67ca91ca7 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -157,6 +157,9 @@ struct HDAAudioStream { uint32_t bpos; }; +#define TYPE_HDA_AUDIO "hda-audio" +#define HDA_AUDIO(obj) OBJECT_CHECK(HDAAudioState, (obj), TYPE_HDA_AUDIO) + struct HDAAudioState { HDACodecDevice hda; const char *name; @@ -288,7 +291,7 @@ static void hda_audio_setup(HDAAudioStream *st) static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioState *a = HDA_AUDIO(hda); HDAAudioStream *st; const desc_node *node = NULL; const desc_param *param; @@ -448,7 +451,7 @@ fail: static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioState *a = HDA_AUDIO(hda); int s; a->running_compat[stnr] = running; @@ -469,7 +472,7 @@ static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, b static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioState *a = HDA_AUDIO(hda); HDAAudioStream *st; const desc_node *node; const desc_param *param; @@ -514,7 +517,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) static int hda_audio_exit(HDACodecDevice *hda) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioState *a = HDA_AUDIO(hda); HDAAudioStream *st; int i; @@ -561,7 +564,7 @@ static int hda_audio_post_load(void *opaque, int version) static void hda_audio_reset(DeviceState *dev) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda.qdev, dev); + HDAAudioState *a = HDA_AUDIO(dev); HDAAudioStream *st; int i; @@ -613,7 +616,7 @@ static Property hda_audio_properties[] = { static int hda_audio_init_output(HDACodecDevice *hda) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioState *a = HDA_AUDIO(hda); if (!a->mixer) { return hda_audio_init(hda, &output_nomixemu); @@ -624,7 +627,7 @@ static int hda_audio_init_output(HDACodecDevice *hda) static int hda_audio_init_duplex(HDACodecDevice *hda) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioState *a = HDA_AUDIO(hda); if (!a->mixer) { return hda_audio_init(hda, &duplex_nomixemu); @@ -635,7 +638,7 @@ static int hda_audio_init_duplex(HDACodecDevice *hda) static int hda_audio_init_micro(HDACodecDevice *hda) { - HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda); + HDAAudioState *a = HDA_AUDIO(hda); if (!a->mixer) { return hda_audio_init(hda, µ_nomixemu); @@ -644,25 +647,39 @@ static int hda_audio_init_micro(HDACodecDevice *hda) } } -static void hda_audio_output_class_init(ObjectClass *klass, void *data) +static void hda_audio_base_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); - k->init = hda_audio_init_output; k->exit = hda_audio_exit; k->command = hda_audio_command; k->stream = hda_audio_stream; set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "HDA Audio Codec, output-only (line-out)"; dc->reset = hda_audio_reset; dc->vmsd = &vmstate_hda_audio; dc->props = hda_audio_properties; } +static const TypeInfo hda_audio_info = { + .name = TYPE_HDA_AUDIO, + .parent = TYPE_HDA_CODEC_DEVICE, + .class_init = hda_audio_base_class_init, + .abstract = true, +}; + +static void hda_audio_output_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); + + k->init = hda_audio_init_output; + dc->desc = "HDA Audio Codec, output-only (line-out)"; +} + static const TypeInfo hda_audio_output_info = { .name = "hda-output", - .parent = TYPE_HDA_CODEC_DEVICE, + .parent = TYPE_HDA_AUDIO, .instance_size = sizeof(HDAAudioState), .class_init = hda_audio_output_class_init, }; @@ -673,19 +690,12 @@ static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); k->init = hda_audio_init_duplex; - k->exit = hda_audio_exit; - k->command = hda_audio_command; - k->stream = hda_audio_stream; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, duplex (line-out, line-in)"; - dc->reset = hda_audio_reset; - dc->vmsd = &vmstate_hda_audio; - dc->props = hda_audio_properties; } static const TypeInfo hda_audio_duplex_info = { .name = "hda-duplex", - .parent = TYPE_HDA_CODEC_DEVICE, + .parent = TYPE_HDA_AUDIO, .instance_size = sizeof(HDAAudioState), .class_init = hda_audio_duplex_class_init, }; @@ -696,25 +706,19 @@ static void hda_audio_micro_class_init(ObjectClass *klass, void *data) HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); k->init = hda_audio_init_micro; - k->exit = hda_audio_exit; - k->command = hda_audio_command; - k->stream = hda_audio_stream; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, duplex (speaker, microphone)"; - dc->reset = hda_audio_reset; - dc->vmsd = &vmstate_hda_audio; - dc->props = hda_audio_properties; } static const TypeInfo hda_audio_micro_info = { .name = "hda-micro", - .parent = TYPE_HDA_CODEC_DEVICE, + .parent = TYPE_HDA_AUDIO, .instance_size = sizeof(HDAAudioState), .class_init = hda_audio_micro_class_init, }; static void hda_audio_register_types(void) { + type_register_static(&hda_audio_info); type_register_static(&hda_audio_output_info); type_register_static(&hda_audio_duplex_info); type_register_static(&hda_audio_micro_info); diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index 401399d330..608a58c47d 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -227,7 +227,8 @@ static const VMStateDescription vmstate_pl330_queue = { }; struct PL330State { - SysBusDevice busdev; + SysBusDevice parent_obj; + MemoryRegion iomem; qemu_irq irq_abort; qemu_irq *irq; @@ -577,7 +578,7 @@ static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag) static inline void pl330_fault(PL330Chan *ch, uint32_t flags) { - DB_PRINT("ch: %p, flags: %x\n", ch, flags); + DB_PRINT("ch: %p, flags: %" PRIx32 "\n", ch, flags); ch->fault_type |= flags; if (ch->state == pl330_chan_fault) { return; @@ -600,10 +601,12 @@ static inline void pl330_fault(PL330Chan *ch, uint32_t flags) * LEN - number of elements in ARGS array */ -static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +static void pl330_dmaadxh(PL330Chan *ch, uint8_t *args, bool ra, bool neg) { - uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]); - uint8_t ra = (opcode >> 1) & 1; + uint32_t im = (args[1] << 8) | args[0]; + if (neg) { + im |= 0xffffu << 16; + } if (ch->is_manager) { pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); @@ -616,6 +619,16 @@ static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) } } +static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), false); +} + +static void pl330_dmaadnh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), true); +} + static void pl330_dmaend(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) { @@ -723,7 +736,8 @@ static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src, size, num, inc, 0, ch->tag); if (!ch->stall) { - DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n", + DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32 + " num:%" PRId32 " %c\n", ch->tag, ch->src, size, num, inc ? 'Y' : 'N'); ch->src += inc ? size * num - (ch->src & (size - 1)) : 0; } @@ -868,9 +882,10 @@ static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) } if (ch->parent->inten & (1 << ev_id)) { ch->parent->int_status |= (1 << ev_id); - DB_PRINT("event interrupt raised %d\n", ev_id); + DB_PRINT("event interrupt raised %" PRId8 "\n", ev_id); qemu_irq_raise(ch->parent->irq[ev_id]); } + DB_PRINT("event raised %" PRId8 "\n", ev_id); ch->parent->ev_status |= (1 << ev_id); } @@ -895,7 +910,8 @@ static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst, size, num, inc, 0, ch->tag); if (!ch->stall) { - DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n", + DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32 + " num:%" PRId32 " %c\n", ch->tag, ch->dst, size, num, inc ? 'Y' : 'N'); ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0; } @@ -972,6 +988,7 @@ static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode, } } ch->parent->ev_status &= ~(1 << ev_id); + DB_PRINT("event lowered %" PRIx8 "\n", ev_id); } else { ch->stall = 1; } @@ -1037,6 +1054,7 @@ static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode, /* NULL terminated array of the instruction descriptions. */ static const PL330InsnDesc insn_desc[] = { { .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, }, + { .opcode = 0x5c, .opmask = 0xFD, .size = 3, .exec = pl330_dmaadnh, }, { .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, }, { .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, }, { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, }, @@ -1108,7 +1126,6 @@ static int pl330_chan_exec(PL330Chan *ch) ch->state != pl330_chan_waiting_periph && ch->state != pl330_chan_at_barrier && ch->state != pl330_chan_waiting_event) { - DB_PRINT("%d\n", ch->state); return 0; } ch->stall = 0; @@ -1155,7 +1172,7 @@ static int pl330_exec_cycle(PL330Chan *channel) dma_memory_read(&address_space_memory, q->addr, buf, len); if (PL330_ERR_DEBUG > 1) { - DB_PRINT("PL330 read from memory @%08x (size = %08x):\n", + DB_PRINT("PL330 read from memory @%08" PRIx32 " (size = %08x):\n", q->addr, len); qemu_hexdump((char *)buf, stderr, "", len); } @@ -1187,8 +1204,8 @@ static int pl330_exec_cycle(PL330Chan *channel) if (fifo_res == PL330_FIFO_OK || q->z) { dma_memory_write(&address_space_memory, q->addr, buf, len); if (PL330_ERR_DEBUG > 1) { - DB_PRINT("PL330 read from memory @%08x (size = %08x):\n", - q->addr, len); + DB_PRINT("PL330 read from memory @%08" PRIx32 + " (size = %08x):\n", q->addr, len); qemu_hexdump((char *)buf, stderr, "", len); } if (q->inc) { @@ -1277,7 +1294,7 @@ static void pl330_debug_exec(PL330State *s) args[2] = (s->dbg[1] >> 8) & 0xff; args[3] = (s->dbg[1] >> 16) & 0xff; args[4] = (s->dbg[1] >> 24) & 0xff; - DB_PRINT("chan id: %d\n", chan_id); + DB_PRINT("chan id: %" PRIx8 "\n", chan_id); if (s->dbg[0] & 1) { ch = &s->chan[chan_id]; } else { @@ -1311,7 +1328,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { PL330State *s = (PL330State *) opaque; - uint32_t i; + int i; DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value); @@ -1467,8 +1484,8 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque, static uint64_t pl330_iomem_read(void *opaque, hwaddr offset, unsigned size) { - int ret = pl330_iomem_read_imp(opaque, offset); - DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret); + uint32_t ret = pl330_iomem_read_imp(opaque, offset); + DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset, ret); return ret; } @@ -1554,7 +1571,7 @@ static void pl330_realize(DeviceState *dev, Error **errp) s->cfg[1] |= 5; break; default: - error_setg(errp, "Bad value for i-cache_len property: %d\n", + error_setg(errp, "Bad value for i-cache_len property: %" PRIx8 "\n", s->i_cache_len); return; } @@ -1589,7 +1606,7 @@ static void pl330_realize(DeviceState *dev, Error **errp) s->cfg[CFG_CRD] |= 0x4; break; default: - error_setg(errp, "Bad value for data_width property: %d\n", + error_setg(errp, "Bad value for data_width property: %" PRIx8 "\n", s->data_width); return; } @@ -1602,7 +1619,7 @@ static void pl330_realize(DeviceState *dev, Error **errp) pl330_queue_init(&s->read_queue, s->rd_q_dep, s); pl330_queue_init(&s->write_queue, s->wr_q_dep, s); - pl330_fifo_init(&s->fifo, s->data_buffer_dep); + pl330_fifo_init(&s->fifo, s->data_width / 4 * s->data_buffer_dep); } static Property pl330_properties[] = { diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 59a3da5a6b..100b6bf3de 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -3,6 +3,7 @@ * * Copyright (c) 2012 Linaro Limited * Written by Peter Maydell + * Save/Restore logic added by Christoffer Dall. * * 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 @@ -23,6 +24,20 @@ #include "kvm_arm.h" #include "gic_internal.h" +//#define DEBUG_GIC_KVM + +#ifdef DEBUG_GIC_KVM +static const int debug_gic_kvm = 1; +#else +static const int debug_gic_kvm = 0; +#endif + +#define DPRINTF(fmt, ...) do { \ + if (debug_gic_kvm) { \ + printf("arm_gic: " fmt , ## __VA_ARGS__); \ + } \ + } while (0) + #define TYPE_KVM_ARM_GIC "kvm-arm-gic" #define KVM_ARM_GIC(obj) \ OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC) @@ -72,14 +87,419 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level) kvm_set_irq(kvm_state, kvm_irq, !!level); } +static bool kvm_arm_gic_can_save_restore(GICState *s) +{ + return s->dev_fd >= 0; +} + +static void kvm_gic_access(GICState *s, int group, int offset, + int cpu, uint32_t *val, bool write) +{ + struct kvm_device_attr attr; + int type; + int err; + + cpu = cpu & 0xff; + + attr.flags = 0; + attr.group = group; + attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) & + KVM_DEV_ARM_VGIC_CPUID_MASK) | + (((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) & + KVM_DEV_ARM_VGIC_OFFSET_MASK); + attr.addr = (uintptr_t)val; + + if (write) { + type = KVM_SET_DEVICE_ATTR; + } else { + type = KVM_GET_DEVICE_ATTR; + } + + err = kvm_device_ioctl(s->dev_fd, type, &attr); + if (err < 0) { + fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n", + strerror(-err)); + abort(); + } +} + +static void kvm_gicd_access(GICState *s, int offset, int cpu, + uint32_t *val, bool write) +{ + kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, + offset, cpu, val, write); +} + +static void kvm_gicc_access(GICState *s, int offset, int cpu, + uint32_t *val, bool write) +{ + kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS, + offset, cpu, val, write); +} + +#define for_each_irq_reg(_ctr, _max_irq, _field_width) \ + for (_ctr = 0; _ctr < ((_max_irq) / (32 / (_field_width))); _ctr++) + +/* + * Translate from the in-kernel field for an IRQ value to/from the qemu + * representation. + */ +typedef void (*vgic_translate_fn)(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel); + +/* synthetic translate function used for clear/set registers to completely + * clear a setting using a clear-register before setting the remaing bits + * using a set-register */ +static void translate_clear(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = ~0; + } else { + /* does not make sense: qemu model doesn't use set/clear regs */ + abort(); + } +} + +static void translate_enabled(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + + if (to_kernel) { + *field = GIC_TEST_ENABLED(irq, cm); + } else { + if (*field & 1) { + GIC_SET_ENABLED(irq, cm); + } + } +} + +static void translate_pending(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + + if (to_kernel) { + *field = gic_test_pending(s, irq, cm); + } else { + if (*field & 1) { + GIC_SET_PENDING(irq, cm); + /* TODO: Capture is level-line is held high in the kernel */ + } + } +} + +static void translate_active(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + + if (to_kernel) { + *field = GIC_TEST_ACTIVE(irq, cm); + } else { + if (*field & 1) { + GIC_SET_ACTIVE(irq, cm); + } + } +} + +static void translate_trigger(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = (GIC_TEST_EDGE_TRIGGER(irq)) ? 0x2 : 0x0; + } else { + if (*field & 0x2) { + GIC_SET_EDGE_TRIGGER(irq); + } + } +} + +static void translate_priority(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = GIC_GET_PRIORITY(irq, cpu) & 0xff; + } else { + gic_set_priority(s, cpu, irq, *field & 0xff); + } +} + +static void translate_targets(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = s->irq_target[irq] & 0xff; + } else { + s->irq_target[irq] = *field & 0xff; + } +} + +static void translate_sgisource(GICState *s, int irq, int cpu, + uint32_t *field, bool to_kernel) +{ + if (to_kernel) { + *field = s->sgi_pending[irq][cpu] & 0xff; + } else { + s->sgi_pending[irq][cpu] = *field & 0xff; + } +} + +/* Read a register group from the kernel VGIC */ +static void kvm_dist_get(GICState *s, uint32_t offset, int width, + int maxirq, vgic_translate_fn translate_fn) +{ + uint32_t reg; + int i; + int j; + int irq; + int cpu; + int regsz = 32 / width; /* irqs per kernel register */ + uint32_t field; + + for_each_irq_reg(i, maxirq, width) { + irq = i * regsz; + cpu = 0; + while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) { + kvm_gicd_access(s, offset, cpu, ®, false); + for (j = 0; j < regsz; j++) { + field = extract32(reg, j * width, width); + translate_fn(s, irq + j, cpu, &field, false); + } + + cpu++; + } + offset += 4; + } +} + +/* Write a register group to the kernel VGIC */ +static void kvm_dist_put(GICState *s, uint32_t offset, int width, + int maxirq, vgic_translate_fn translate_fn) +{ + uint32_t reg; + int i; + int j; + int irq; + int cpu; + int regsz = 32 / width; /* irqs per kernel register */ + uint32_t field; + + for_each_irq_reg(i, maxirq, width) { + irq = i * regsz; + cpu = 0; + while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) { + reg = 0; + for (j = 0; j < regsz; j++) { + translate_fn(s, irq + j, cpu, &field, true); + reg = deposit32(reg, j * width, width, field); + } + kvm_gicd_access(s, offset, cpu, ®, true); + + cpu++; + } + offset += 4; + } +} + static void kvm_arm_gic_put(GICState *s) { - /* TODO: there isn't currently a kernel interface to set the GIC state */ + uint32_t reg; + int i; + int cpu; + int num_cpu; + int num_irq; + + if (!kvm_arm_gic_can_save_restore(s)) { + DPRINTF("Cannot put kernel gic state, no kernel interface"); + return; + } + + /* Note: We do the restore in a slightly different order than the save + * (where the order doesn't matter and is simply ordered according to the + * register offset values */ + + /***************************************************************** + * Distributor State + */ + + /* s->enabled -> GICD_CTLR */ + reg = s->enabled; + kvm_gicd_access(s, 0x0, 0, ®, true); + + /* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */ + kvm_gicd_access(s, 0x4, 0, ®, false); + num_irq = ((reg & 0x1f) + 1) * 32; + num_cpu = ((reg & 0xe0) >> 5) + 1; + + if (num_irq < s->num_irq) { + fprintf(stderr, "Restoring %u IRQs, but kernel supports max %d\n", + s->num_irq, num_irq); + abort(); + } else if (num_cpu != s->num_cpu) { + fprintf(stderr, "Restoring %u CPU interfaces, kernel only has %d\n", + s->num_cpu, num_cpu); + /* Did we not create the VCPUs in the kernel yet? */ + abort(); + } + + /* TODO: Consider checking compatibility with the IIDR ? */ + + /* irq_state[n].enabled -> GICD_ISENABLERn */ + kvm_dist_put(s, 0x180, 1, s->num_irq, translate_clear); + kvm_dist_put(s, 0x100, 1, s->num_irq, translate_enabled); + + /* s->irq_target[irq] -> GICD_ITARGETSRn + * (restore targets before pending to ensure the pending state is set on + * the appropriate CPU interfaces in the kernel) */ + kvm_dist_put(s, 0x800, 8, s->num_irq, translate_targets); + + /* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */ + kvm_dist_put(s, 0x280, 1, s->num_irq, translate_clear); + kvm_dist_put(s, 0x200, 1, s->num_irq, translate_pending); + + /* irq_state[n].active -> GICD_ISACTIVERn */ + kvm_dist_put(s, 0x380, 1, s->num_irq, translate_clear); + kvm_dist_put(s, 0x300, 1, s->num_irq, translate_active); + + /* irq_state[n].trigger -> GICD_ICFRn */ + kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger); + + /* s->priorityX[irq] -> ICD_IPRIORITYRn */ + kvm_dist_put(s, 0x400, 8, s->num_irq, translate_priority); + + /* s->sgi_pending -> ICD_CPENDSGIRn */ + kvm_dist_put(s, 0xf10, 8, GIC_NR_SGIS, translate_clear); + kvm_dist_put(s, 0xf20, 8, GIC_NR_SGIS, translate_sgisource); + + + /***************************************************************** + * CPU Interface(s) State + */ + + for (cpu = 0; cpu < s->num_cpu; cpu++) { + /* s->cpu_enabled[cpu] -> GICC_CTLR */ + reg = s->cpu_enabled[cpu]; + kvm_gicc_access(s, 0x00, cpu, ®, true); + + /* s->priority_mask[cpu] -> GICC_PMR */ + reg = (s->priority_mask[cpu] & 0xff); + kvm_gicc_access(s, 0x04, cpu, ®, true); + + /* s->bpr[cpu] -> GICC_BPR */ + reg = (s->bpr[cpu] & 0x7); + kvm_gicc_access(s, 0x08, cpu, ®, true); + + /* s->abpr[cpu] -> GICC_ABPR */ + reg = (s->abpr[cpu] & 0x7); + kvm_gicc_access(s, 0x1c, cpu, ®, true); + + /* s->apr[n][cpu] -> GICC_APRn */ + for (i = 0; i < 4; i++) { + reg = s->apr[i][cpu]; + kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, true); + } + } } static void kvm_arm_gic_get(GICState *s) { - /* TODO: there isn't currently a kernel interface to get the GIC state */ + uint32_t reg; + int i; + int cpu; + + if (!kvm_arm_gic_can_save_restore(s)) { + DPRINTF("Cannot get kernel gic state, no kernel interface"); + return; + } + + /***************************************************************** + * Distributor State + */ + + /* GICD_CTLR -> s->enabled */ + kvm_gicd_access(s, 0x0, 0, ®, false); + s->enabled = reg & 1; + + /* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */ + kvm_gicd_access(s, 0x4, 0, ®, false); + s->num_irq = ((reg & 0x1f) + 1) * 32; + s->num_cpu = ((reg & 0xe0) >> 5) + 1; + + if (s->num_irq > GIC_MAXIRQ) { + fprintf(stderr, "Too many IRQs reported from the kernel: %d\n", + s->num_irq); + abort(); + } + + /* GICD_IIDR -> ? */ + kvm_gicd_access(s, 0x8, 0, ®, false); + + /* Verify no GROUP 1 interrupts configured in the kernel */ + for_each_irq_reg(i, s->num_irq, 1) { + kvm_gicd_access(s, 0x80 + (i * 4), 0, ®, false); + if (reg != 0) { + fprintf(stderr, "Unsupported GICD_IGROUPRn value: %08x\n", + reg); + abort(); + } + } + + /* Clear all the IRQ settings */ + for (i = 0; i < s->num_irq; i++) { + memset(&s->irq_state[i], 0, sizeof(s->irq_state[0])); + } + + /* GICD_ISENABLERn -> irq_state[n].enabled */ + kvm_dist_get(s, 0x100, 1, s->num_irq, translate_enabled); + + /* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */ + kvm_dist_get(s, 0x200, 1, s->num_irq, translate_pending); + + /* GICD_ISACTIVERn -> irq_state[n].active */ + kvm_dist_get(s, 0x300, 1, s->num_irq, translate_active); + + /* GICD_ICFRn -> irq_state[n].trigger */ + kvm_dist_get(s, 0xc00, 2, s->num_irq, translate_trigger); + + /* GICD_IPRIORITYRn -> s->priorityX[irq] */ + kvm_dist_get(s, 0x400, 8, s->num_irq, translate_priority); + + /* GICD_ITARGETSRn -> s->irq_target[irq] */ + kvm_dist_get(s, 0x800, 8, s->num_irq, translate_targets); + + /* GICD_CPENDSGIRn -> s->sgi_pending */ + kvm_dist_get(s, 0xf10, 8, GIC_NR_SGIS, translate_sgisource); + + + /***************************************************************** + * CPU Interface(s) State + */ + + for (cpu = 0; cpu < s->num_cpu; cpu++) { + /* GICC_CTLR -> s->cpu_enabled[cpu] */ + kvm_gicc_access(s, 0x00, cpu, ®, false); + s->cpu_enabled[cpu] = (reg & 1); + + /* GICC_PMR -> s->priority_mask[cpu] */ + kvm_gicc_access(s, 0x04, cpu, ®, false); + s->priority_mask[cpu] = (reg & 0xff); + + /* GICC_BPR -> s->bpr[cpu] */ + kvm_gicc_access(s, 0x08, cpu, ®, false); + s->bpr[cpu] = (reg & 0x7); + + /* GICC_ABPR -> s->abpr[cpu] */ + kvm_gicc_access(s, 0x1c, cpu, ®, false); + s->abpr[cpu] = (reg & 0x7); + + /* GICC_APRn -> s->apr[n][cpu] */ + for (i = 0; i < 4; i++) { + kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, false); + s->apr[i][cpu] = reg; + } + } } static void kvm_arm_gic_reset(DeviceState *dev) @@ -97,6 +517,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) GICState *s = KVM_ARM_GIC(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); + int ret; kgc->parent_realize(dev, errp); if (error_is_set(errp)) { @@ -119,13 +540,27 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_cpu; i++) { sysbus_init_irq(sbd, &s->parent_irq[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); + if (ret >= 0) { + s->dev_fd = ret; + } else if (ret != -ENODEV && ret != -ENOTSUP) { + error_setg_errno(errp, -ret, "error creating in-kernel VGIC"); + return; + } + /* 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); + | KVM_VGIC_V2_ADDR_TYPE_DIST, + KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V2_ADDR_TYPE_DIST, + s->dev_fd); /* CPU interface for current core. Unlike arm_gic, we don't * provide the "interface for core #N" memory regions, because * cores with a VGIC don't have those. @@ -135,7 +570,10 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) 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); + | KVM_VGIC_V2_ADDR_TYPE_CPU, + KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V2_ADDR_TYPE_CPU, + s->dev_fd); } static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index ef5e8eb22f..3287479456 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -418,7 +418,7 @@ static int exynos4210_combiner_init(SysBusDevice *sbd) qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ); /* Connect SysBusDev irqs to device specific irqs */ - for (i = 0; i < IIC_NIRQ; i++) { + for (i = 0; i < IIC_NGRP; i++) { sysbus_init_irq(sbd, &s->output_irq[i]); } diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 92a6f7a3ff..48a58d7890 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -40,7 +40,7 @@ #define GIC_SET_MODEL(irq) s->irq_state[irq].model = true #define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false #define GIC_TEST_MODEL(irq) s->irq_state[irq].model -#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm) +#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level |= (cm) #define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm) #define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0) #define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c index 0fc26d29a5..3fad6f86de 100644 --- a/hw/misc/arm_sysctl.c +++ b/hw/misc/arm_sysctl.c @@ -276,7 +276,7 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, } break; case SYS_CFG_OSC: - if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) { /* motherboard clock */ *val = s->mb_clock[device]; return true; @@ -324,7 +324,7 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, switch (function) { case SYS_CFG_OSC: - if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) { /* motherboard clock */ s->mb_clock[device] = val; return true; diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index 9dd77f7571..d04e6a46f8 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -176,7 +176,8 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, return val; case 0x14: /* IA0 */ return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8) - | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24); + | (s->conf.macaddr.a[2] << 16) + | ((uint32_t)s->conf.macaddr.a[3] << 24); case 0x18: /* IA1 */ return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8); case 0x1c: /* THR */ diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 854997d9ba..a1de2f43a0 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -106,7 +106,7 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, goto fail; } net->nc = backend; - net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 : + net->dev.backend_features = qemu_has_vnet_hdr(backend) ? 0 : (1 << VHOST_NET_F_VIRTIO_NET_HDR); net->backend = r; @@ -117,8 +117,8 @@ struct vhost_net *vhost_net_init(NetClientState *backend, int devfd, if (r < 0) { goto fail; } - if (!tap_has_vnet_hdr_len(backend, - sizeof(struct virtio_net_hdr_mrg_rxbuf))) { + if (!qemu_has_vnet_hdr_len(backend, + sizeof(struct virtio_net_hdr_mrg_rxbuf))) { net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF); } if (~net->dev.features & net->dev.backend_features) { diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 36266083b2..3c0342e17a 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -325,11 +325,7 @@ static void peer_test_vnet_hdr(VirtIONet *n) return; } - if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { - return; - } - - n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer); + n->has_vnet_hdr = qemu_has_vnet_hdr(nc->peer); } static int peer_has_vnet_hdr(VirtIONet *n) @@ -342,7 +338,7 @@ static int peer_has_ufo(VirtIONet *n) if (!peer_has_vnet_hdr(n)) return 0; - n->has_ufo = tap_has_ufo(qemu_get_queue(n->nic)->peer); + n->has_ufo = qemu_has_ufo(qemu_get_queue(n->nic)->peer); return n->has_ufo; } @@ -361,8 +357,8 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs) nc = qemu_get_subqueue(n->nic, i); if (peer_has_vnet_hdr(n) && - tap_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) { - tap_set_vnet_hdr_len(nc->peer, n->guest_hdr_len); + qemu_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) { + qemu_set_vnet_hdr_len(nc->peer, n->guest_hdr_len); n->host_hdr_len = n->guest_hdr_len; } } @@ -463,7 +459,7 @@ static uint32_t virtio_net_bad_features(VirtIODevice *vdev) static void virtio_net_apply_guest_offloads(VirtIONet *n) { - tap_set_offload(qemu_get_subqueue(n->nic, 0)->peer, + qemu_set_offload(qemu_get_queue(n->nic)->peer, !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_CSUM)), !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)), !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)), @@ -1544,7 +1540,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) peer_test_vnet_hdr(n); if (peer_has_vnet_hdr(n)) { for (i = 0; i < n->max_queues; i++) { - tap_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true); + qemu_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true); } n->host_hdr_len = sizeof(struct virtio_net_hdr); } else { diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 19687aa03c..5be807ce82 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -1290,12 +1290,12 @@ static void vmxnet3_update_features(VMXNET3State *s) s->lro_supported, rxcso_supported, s->rx_vlan_stripping); if (s->peer_has_vhdr) { - tap_set_offload(qemu_get_queue(s->nic)->peer, - rxcso_supported, - s->lro_supported, - s->lro_supported, - 0, - 0); + qemu_set_offload(qemu_get_queue(s->nic)->peer, + rxcso_supported, + s->lro_supported, + s->lro_supported, + 0, + 0); } } @@ -1883,11 +1883,9 @@ static NetClientInfo net_vmxnet3_info = { static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s) { - NetClientState *peer = qemu_get_queue(s->nic)->peer; + NetClientState *nc = qemu_get_queue(s->nic); - if ((NULL != peer) && - (peer->info->type == NET_CLIENT_OPTIONS_KIND_TAP) && - tap_has_vnet_hdr(peer)) { + if (qemu_has_vnet_hdr(nc->peer)) { return true; } @@ -1935,10 +1933,10 @@ static void vmxnet3_net_init(VMXNET3State *s) s->lro_supported = false; if (s->peer_has_vhdr) { - tap_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer, + qemu_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer, sizeof(struct virtio_net_hdr)); - tap_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1); + qemu_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1); } qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index a47afde23a..fb0a45c889 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -320,6 +320,7 @@ static uint64_t icp_pit_read(void *opaque, hwaddr offset, n = offset >> 8; if (n > 2) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n); + return 0; } return arm_timer_read(s->timer[n], offset & 0xff); @@ -334,6 +335,7 @@ static void icp_pit_write(void *opaque, hwaddr offset, n = offset >> 8; if (n > 2) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n); + return; } arm_timer_write(s->timer[n], offset & 0xff, value); |