summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/musicpal.c6
-rw-r--r--hw/arm/pxa2xx.c6
-rw-r--r--hw/audio/hda-codec.c60
-rw-r--r--hw/display/Makefile.objs1
-rw-r--r--hw/display/cg3.c385
-rw-r--r--hw/dma/pl330.c55
-rw-r--r--hw/i386/kvm/pci-assign.c1
-rw-r--r--hw/intc/arm_gic_kvm.c446
-rw-r--r--hw/intc/exynos4210_combiner.c2
-rw-r--r--hw/intc/gic_internal.h2
-rw-r--r--hw/misc/arm_sysctl.c4
-rw-r--r--hw/misc/vfio.c79
-rw-r--r--hw/net/stellaris_enet.c3
-rw-r--r--hw/net/vhost_net.c6
-rw-r--r--hw/net/virtio-net.c16
-rw-r--r--hw/net/vmxnet3.c22
-rw-r--r--hw/scsi/scsi-bus.c7
-rw-r--r--hw/scsi/scsi-disk.c29
-rw-r--r--hw/scsi/scsi-generic.c2
-rw-r--r--hw/scsi/spapr_vscsi.c1
-rw-r--r--hw/sparc/sun4m.c62
-rw-r--r--hw/timer/arm_timer.c2
-rw-r--r--hw/timer/slavio_timer.c25
23 files changed, 1109 insertions, 113 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, &micro_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/display/Makefile.objs b/hw/display/Makefile.objs
index 540df82600..7ed76a9c24 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -28,6 +28,7 @@ obj-$(CONFIG_OMAP) += omap_lcdc.o
obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
obj-$(CONFIG_SM501) += sm501.o
obj-$(CONFIG_TCX) += tcx.o
+obj-$(CONFIG_CG3) += cg3.o
obj-$(CONFIG_VGA) += vga.o
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
new file mode 100644
index 0000000000..6db8ca362a
--- /dev/null
+++ b/hw/display/cg3.c
@@ -0,0 +1,385 @@
+/*
+ * QEMU CG3 Frame buffer
+ *
+ * Copyright (c) 2012 Bob Breuer
+ * Copyright (c) 2013 Mark Cave-Ayland
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "ui/console.h"
+#include "hw/sysbus.h"
+#include "hw/loader.h"
+
+/* Change to 1 to enable debugging */
+#define DEBUG_CG3 0
+
+#define CG3_ROM_FILE "QEMU,cgthree.bin"
+#define FCODE_MAX_ROM_SIZE 0x10000
+
+#define CG3_REG_SIZE 0x20
+
+#define CG3_REG_BT458_ADDR 0x0
+#define CG3_REG_BT458_COLMAP 0x4
+#define CG3_REG_FBC_CTRL 0x10
+#define CG3_REG_FBC_STATUS 0x11
+#define CG3_REG_FBC_CURSTART 0x12
+#define CG3_REG_FBC_CUREND 0x13
+#define CG3_REG_FBC_VCTRL 0x14
+
+/* Control register flags */
+#define CG3_CR_ENABLE_INTS 0x80
+
+/* Status register flags */
+#define CG3_SR_PENDING_INT 0x80
+#define CG3_SR_1152_900_76_B 0x60
+#define CG3_SR_ID_COLOR 0x01
+
+#define CG3_VRAM_SIZE 0x100000
+#define CG3_VRAM_OFFSET 0x800000
+
+#define DPRINTF(fmt, ...) do { \
+ if (DEBUG_CG3) { \
+ printf("CG3: " fmt , ## __VA_ARGS__); \
+ } \
+} while (0);
+
+#define TYPE_CG3 "cgthree"
+#define CG3(obj) OBJECT_CHECK(CG3State, (obj), TYPE_CG3)
+
+typedef struct CG3State {
+ SysBusDevice parent_obj;
+
+ QemuConsole *con;
+ qemu_irq irq;
+ hwaddr prom_addr;
+ MemoryRegion vram_mem;
+ MemoryRegion rom;
+ MemoryRegion reg;
+ uint32_t vram_size;
+ int full_update;
+ uint8_t regs[16];
+ uint8_t r[256], g[256], b[256];
+ uint16_t width, height, depth;
+ uint8_t dac_index, dac_state;
+} CG3State;
+
+static void cg3_update_display(void *opaque)
+{
+ CG3State *s = opaque;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ const uint8_t *pix;
+ uint32_t *data;
+ uint32_t dval;
+ int x, y, y_start;
+ unsigned int width, height;
+ ram_addr_t page, page_min, page_max;
+
+ if (surface_bits_per_pixel(surface) != 32) {
+ return;
+ }
+ width = s->width;
+ height = s->height;
+
+ y_start = -1;
+ page_min = -1;
+ page_max = 0;
+ page = 0;
+ pix = memory_region_get_ram_ptr(&s->vram_mem);
+ data = (uint32_t *)surface_data(surface);
+
+ for (y = 0; y < height; y++) {
+ int update = s->full_update;
+
+ page = (y * width) & TARGET_PAGE_MASK;
+ update |= memory_region_get_dirty(&s->vram_mem, page, page + width,
+ DIRTY_MEMORY_VGA);
+ if (update) {
+ if (y_start < 0) {
+ y_start = y;
+ }
+ if (page < page_min) {
+ page_min = page;
+ }
+ if (page > page_max) {
+ page_max = page;
+ }
+
+ for (x = 0; x < width; x++) {
+ dval = *pix++;
+ dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval];
+ *data++ = dval;
+ }
+ } else {
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ y_start = -1;
+ }
+ pix += width;
+ data += width;
+ }
+ }
+ s->full_update = 0;
+ if (y_start >= 0) {
+ dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start);
+ }
+ if (page_max >= page_min) {
+ memory_region_reset_dirty(&s->vram_mem,
+ page_min, page_max - page_min + TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
+ }
+ /* vsync interrupt? */
+ if (s->regs[0] & CG3_CR_ENABLE_INTS) {
+ s->regs[1] |= CG3_SR_PENDING_INT;
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void cg3_invalidate_display(void *opaque)
+{
+ CG3State *s = opaque;
+
+ memory_region_set_dirty(&s->vram_mem, 0, CG3_VRAM_SIZE);
+}
+
+static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
+{
+ CG3State *s = opaque;
+ int val;
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ case CG3_REG_BT458_COLMAP:
+ val = 0;
+ break;
+ case CG3_REG_FBC_CTRL:
+ val = s->regs[0];
+ break;
+ case CG3_REG_FBC_STATUS:
+ /* monitor ID 6, board type = 1 (color) */
+ val = s->regs[1] | CG3_SR_1152_900_76_B | CG3_SR_ID_COLOR;
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ val = s->regs[addr - 0x10];
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register read "
+ "reg 0x%" HWADDR_PRIx " size 0x%x\n",
+ addr, size);
+ val = 0;
+ break;
+ }
+ DPRINTF("read %02x from reg %" HWADDR_PRIx "\n", val, addr);
+ return val;
+}
+
+static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ CG3State *s = opaque;
+ uint8_t regval;
+ int i;
+
+ DPRINTF("write %" PRIx64 " to reg %" HWADDR_PRIx " size %d\n",
+ val, addr, size);
+
+ switch (addr) {
+ case CG3_REG_BT458_ADDR:
+ s->dac_index = val;
+ s->dac_state = 0;
+ break;
+ case CG3_REG_BT458_COLMAP:
+ /* This register can be written to as either a long word or a byte */
+ if (size == 1) {
+ val <<= 24;
+ }
+
+ for (i = 0; i < size; i++) {
+ regval = val >> 24;
+
+ switch (s->dac_state) {
+ case 0:
+ s->r[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 1:
+ s->g[s->dac_index] = regval;
+ s->dac_state++;
+ break;
+ case 2:
+ s->b[s->dac_index] = regval;
+ /* Index autoincrement */
+ s->dac_index = (s->dac_index + 1) & 0xff;
+ default:
+ s->dac_state = 0;
+ break;
+ }
+ val <<= 8;
+ }
+ s->full_update = 1;
+ break;
+ case CG3_REG_FBC_CTRL:
+ s->regs[0] = val;
+ break;
+ case CG3_REG_FBC_STATUS:
+ if (s->regs[1] & CG3_SR_PENDING_INT) {
+ /* clear interrupt */
+ s->regs[1] &= ~CG3_SR_PENDING_INT;
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case CG3_REG_FBC_CURSTART ... CG3_REG_SIZE:
+ s->regs[addr - 0x10] = val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP,
+ "cg3: Unimplemented register write "
+ "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
+ addr, size, val);
+ break;
+ }
+}
+
+static const MemoryRegionOps cg3_reg_ops = {
+ .read = cg3_reg_read,
+ .write = cg3_reg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static const GraphicHwOps cg3_ops = {
+ .invalidate = cg3_invalidate_display,
+ .gfx_update = cg3_update_display,
+};
+
+static void cg3_realizefn(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ CG3State *s = CG3(dev);
+ int ret;
+ char *fcode_filename;
+
+ /* FCode ROM */
+ memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE);
+ vmstate_register_ram_global(&s->rom);
+ memory_region_set_readonly(&s->rom, true);
+ sysbus_init_mmio(sbd, &s->rom);
+
+ fcode_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, CG3_ROM_FILE);
+ if (fcode_filename) {
+ ret = load_image_targphys(fcode_filename, s->prom_addr,
+ FCODE_MAX_ROM_SIZE);
+ if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) {
+ error_report("cg3: could not load prom '%s'", CG3_ROM_FILE);
+ }
+ }
+
+ memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
+ CG3_REG_SIZE);
+ sysbus_init_mmio(sbd, &s->reg);
+
+ memory_region_init_ram(&s->vram_mem, NULL, "cg3.vram", s->vram_size);
+ vmstate_register_ram_global(&s->vram_mem);
+ sysbus_init_mmio(sbd, &s->vram_mem);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ s->con = graphic_console_init(DEVICE(dev), &cg3_ops, s);
+ qemu_console_resize(s->con, s->width, s->height);
+}
+
+static int vmstate_cg3_post_load(void *opaque, int version_id)
+{
+ CG3State *s = opaque;
+
+ cg3_invalidate_display(s);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_cg3 = {
+ .name = "cg3",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = vmstate_cg3_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(height, CG3State),
+ VMSTATE_UINT16(width, CG3State),
+ VMSTATE_UINT16(depth, CG3State),
+ VMSTATE_BUFFER(r, CG3State),
+ VMSTATE_BUFFER(g, CG3State),
+ VMSTATE_BUFFER(b, CG3State),
+ VMSTATE_UINT8(dac_index, CG3State),
+ VMSTATE_UINT8(dac_state, CG3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void cg3_reset(DeviceState *d)
+{
+ CG3State *s = CG3(d);
+
+ /* Initialize palette */
+ memset(s->r, 0, 256);
+ memset(s->g, 0, 256);
+ memset(s->b, 0, 256);
+
+ s->dac_state = 0;
+ s->full_update = 1;
+ qemu_irq_lower(s->irq);
+}
+
+static Property cg3_properties[] = {
+ DEFINE_PROP_UINT32("vram-size", CG3State, vram_size, -1),
+ DEFINE_PROP_UINT16("width", CG3State, width, -1),
+ DEFINE_PROP_UINT16("height", CG3State, height, -1),
+ DEFINE_PROP_UINT16("depth", CG3State, depth, -1),
+ DEFINE_PROP_UINT64("prom-addr", CG3State, prom_addr, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cg3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = cg3_realizefn;
+ dc->reset = cg3_reset;
+ dc->vmsd = &vmstate_cg3;
+ dc->props = cg3_properties;
+}
+
+static const TypeInfo cg3_info = {
+ .name = TYPE_CG3,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(CG3State),
+ .class_init = cg3_class_init,
+};
+
+static void cg3_register_types(void)
+{
+ type_register_static(&cg3_info);
+}
+
+type_init(cg3_register_types)
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/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
index 968680104b..a825871d8a 100644
--- a/hw/i386/kvm/pci-assign.c
+++ b/hw/i386/kvm/pci-assign.c
@@ -743,6 +743,7 @@ static void assign_failed_examine(AssignedDevice *dev)
goto fail;
}
+ driver[r] = 0;
ns = strrchr(driver, '/');
if (!ns) {
goto fail;
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, &reg, 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, &reg, 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, &reg, true);
+
+ /* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */
+ kvm_gicd_access(s, 0x4, 0, &reg, 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, &reg, true);
+
+ /* s->priority_mask[cpu] -> GICC_PMR */
+ reg = (s->priority_mask[cpu] & 0xff);
+ kvm_gicc_access(s, 0x04, cpu, &reg, true);
+
+ /* s->bpr[cpu] -> GICC_BPR */
+ reg = (s->bpr[cpu] & 0x7);
+ kvm_gicc_access(s, 0x08, cpu, &reg, true);
+
+ /* s->abpr[cpu] -> GICC_ABPR */
+ reg = (s->abpr[cpu] & 0x7);
+ kvm_gicc_access(s, 0x1c, cpu, &reg, 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, &reg, 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, &reg, false);
+ s->enabled = reg & 1;
+
+ /* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */
+ kvm_gicd_access(s, 0x4, 0, &reg, 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, &reg, 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, &reg, 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, &reg, false);
+ s->cpu_enabled[cpu] = (reg & 1);
+
+ /* GICC_PMR -> s->priority_mask[cpu] */
+ kvm_gicc_access(s, 0x04, cpu, &reg, false);
+ s->priority_mask[cpu] = (reg & 0xff);
+
+ /* GICC_BPR -> s->bpr[cpu] */
+ kvm_gicc_access(s, 0x08, cpu, &reg, false);
+ s->bpr[cpu] = (reg & 0x7);
+
+ /* GICC_ABPR -> s->abpr[cpu] */
+ kvm_gicc_access(s, 0x1c, cpu, &reg, 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, &reg, 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/misc/vfio.c b/hw/misc/vfio.c
index 8db182fa3d..c2c688c870 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -209,6 +209,29 @@ typedef struct VFIOGroup {
QLIST_ENTRY(VFIOGroup) container_next;
} VFIOGroup;
+typedef struct VFIORomBlacklistEntry {
+ uint16_t vendor_id;
+ uint16_t device_id;
+} VFIORomBlacklistEntry;
+
+/*
+ * List of device ids/vendor ids for which to disable
+ * option rom loading. This avoids the guest hangs during rom
+ * execution as noticed with the BCM 57810 card for lack of a
+ * more better way to handle such issues.
+ * The user can still override by specifying a romfile or
+ * rombar=1.
+ * Please see https://bugs.launchpad.net/qemu/+bug/1284874
+ * for an analysis of the 57810 card hang. When adding
+ * a new vendor id/device id combination below, please also add
+ * your card/environment details and information that could
+ * help in debugging to the bug tracking this issue
+ */
+static const VFIORomBlacklistEntry romblacklist[] = {
+ /* Broadcom BCM 57810 */
+ { 0x14e4, 0x168e }
+};
+
#define MSIX_CAP_LENGTH 12
static QLIST_HEAD(, VFIOContainer)
@@ -1197,13 +1220,43 @@ static const MemoryRegionOps vfio_rom_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static bool vfio_blacklist_opt_rom(VFIODevice *vdev)
+{
+ PCIDevice *pdev = &vdev->pdev;
+ uint16_t vendor_id, device_id;
+ int count = 0;
+
+ vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
+ device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
+
+ while (count < ARRAY_SIZE(romblacklist)) {
+ if (romblacklist[count].vendor_id == vendor_id &&
+ romblacklist[count].device_id == device_id) {
+ return true;
+ }
+ count++;
+ }
+
+ return false;
+}
+
static void vfio_pci_size_rom(VFIODevice *vdev)
{
uint32_t orig, size = cpu_to_le32((uint32_t)PCI_ROM_ADDRESS_MASK);
off_t offset = vdev->config_offset + PCI_ROM_ADDRESS;
+ DeviceState *dev = DEVICE(vdev);
char name[32];
if (vdev->pdev.romfile || !vdev->pdev.rom_bar) {
+ /* Since pci handles romfile, just print a message and return */
+ if (vfio_blacklist_opt_rom(vdev) && vdev->pdev.romfile) {
+ error_printf("Warning : Device at %04x:%02x:%02x.%x "
+ "is known to cause system instability issues during "
+ "option rom execution. "
+ "Proceeding anyway since user specified romfile\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+ }
return;
}
@@ -1227,6 +1280,26 @@ static void vfio_pci_size_rom(VFIODevice *vdev)
return;
}
+ if (vfio_blacklist_opt_rom(vdev)) {
+ if (dev->opts && qemu_opt_get(dev->opts, "rombar")) {
+ error_printf("Warning : Device at %04x:%02x:%02x.%x "
+ "is known to cause system instability issues during "
+ "option rom execution. "
+ "Proceeding anyway since user specified non zero value for "
+ "rombar\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+ } else {
+ error_printf("Warning : Rom loading for device at "
+ "%04x:%02x:%02x.%x has been disabled due to "
+ "system instability issues. "
+ "Specify rombar=1 or romfile to force\n",
+ vdev->host.domain, vdev->host.bus, vdev->host.slot,
+ vdev->host.function);
+ return;
+ }
+ }
+
DPRINTF("%04x:%02x:%02x.%x ROM size 0x%x\n", vdev->host.domain,
vdev->host.bus, vdev->host.slot, vdev->host.function, size);
@@ -3681,10 +3754,10 @@ static int vfio_initfn(PCIDevice *pdev)
strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
- len = readlink(path, iommu_group_path, PATH_MAX);
- if (len <= 0) {
+ len = readlink(path, iommu_group_path, sizeof(path));
+ if (len <= 0 || len >= sizeof(path)) {
error_report("vfio: error no iommu_group for device");
- return -errno;
+ return len < 0 ? -errno : ENAMETOOLONG;
}
iommu_group_path[len] = 0;
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/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 50b89ad4aa..50a0acf1fe 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -909,7 +909,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
case VERIFY_16:
if ((buf[1] & 2) == 0) {
cmd->xfer = 0;
- } else if ((buf[1] & 4) == 1) {
+ } else if ((buf[1] & 4) != 0) {
cmd->xfer = 1;
}
cmd->xfer *= dev->blocksize;
@@ -1367,6 +1367,11 @@ const struct SCSISense sense_code_WRITE_PROTECTED = {
.key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
};
+/* Data Protection, Space Allocation Failed Write Protect */
+const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
+ .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
+};
+
/*
* scsi_build_sense
*
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index b4fadd2f24..48a28ae199 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -75,6 +75,8 @@ struct SCSIDiskState
bool media_event;
bool eject_request;
uint64_t wwn;
+ uint64_t port_wwn;
+ uint16_t port_index;
uint64_t max_unmap_size;
QEMUBH *bh;
char *version;
@@ -428,6 +430,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
case EINVAL:
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
break;
+ case ENOSPC:
+ scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
+ break;
default:
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
@@ -617,6 +622,24 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
stq_be_p(&outbuf[buflen], s->wwn);
buflen += 8;
}
+
+ if (s->port_wwn) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x93; // PIV / Target port / NAA
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 8;
+ stq_be_p(&outbuf[buflen], s->port_wwn);
+ buflen += 8;
+ }
+
+ if (s->port_index) {
+ outbuf[buflen++] = 0x61; // SAS / Binary
+ outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
+ outbuf[buflen++] = 0; // reserved
+ outbuf[buflen++] = 4;
+ stw_be_p(&outbuf[buflen + 2], s->port_index);
+ buflen += 4;
+ }
break;
}
case 0xb0: /* block limits */
@@ -2536,6 +2559,8 @@ static Property scsi_hd_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
@@ -2584,6 +2609,8 @@ static const TypeInfo scsi_hd_info = {
static Property scsi_cd_properties[] = {
DEFINE_SCSI_DISK_PROPERTIES(),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2647,6 +2674,8 @@ static Property scsi_disk_properties[] = {
DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
SCSI_DISK_F_DPOFUA, false),
DEFINE_PROP_UINT64("wwn", SCSIDiskState, wwn, 0),
+ DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, port_wwn, 0),
+ DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0),
DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
DEFAULT_MAX_UNMAP_SIZE),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index f08b64e177..8d92e0da15 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -37,8 +37,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#include <scsi/sg.h>
#include "block/scsi.h"
-#define SCSI_SENSE_BUF_SIZE 96
-
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index c0c46d7f7c..e8bca390dd 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -60,7 +60,6 @@
#define VSCSI_MAX_SECTORS 4096
#define VSCSI_REQ_LIMIT 24
-#define SCSI_SENSE_BUF_SIZE 96
#define SRP_RSP_SENSE_DATA_LEN 18
typedef union vscsi_crq {
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 2957d90177..75adb68abc 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "hw/sysbus.h"
+#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "hw/sparc/sun4m.h"
#include "hw/timer/m48t59.h"
@@ -561,6 +562,31 @@ static void tcx_init(hwaddr addr, int vram_size, int width,
}
}
+static void cg3_init(hwaddr addr, qemu_irq irq, int vram_size, int width,
+ int height, int depth)
+{
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, "cgthree");
+ qdev_prop_set_uint32(dev, "vram-size", vram_size);
+ qdev_prop_set_uint16(dev, "width", width);
+ qdev_prop_set_uint16(dev, "height", height);
+ qdev_prop_set_uint16(dev, "depth", depth);
+ qdev_prop_set_uint64(dev, "prom-addr", addr);
+ qdev_init_nofail(dev);
+ s = SYS_BUS_DEVICE(dev);
+
+ /* FCode ROM */
+ sysbus_mmio_map(s, 0, addr);
+ /* DAC */
+ sysbus_mmio_map(s, 1, addr + 0x400000ULL);
+ /* 8-bit plane */
+ sysbus_mmio_map(s, 2, addr + 0x800000ULL);
+
+ sysbus_connect_irq(s, 0, irq);
+}
+
/* NCR89C100/MACIO Internal ID register */
#define TYPE_MACIO_ID_REGISTER "macio_idreg"
@@ -914,13 +940,43 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
slavio_irq[16], iommu, &ledma_irq, 1);
if (graphic_depth != 8 && graphic_depth != 24) {
- fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+ error_report("Unsupported depth: %d", graphic_depth);
exit (1);
}
num_vsimms = 0;
if (num_vsimms == 0) {
- tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
- graphic_depth);
+ if (vga_interface_type == VGA_CG3) {
+ if (graphic_depth != 8) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768) &&
+ !(graphic_width == 1152 && graphic_height == 900)) {
+ error_report("Unsupported resolution: %d x %d", graphic_width,
+ graphic_height);
+ exit(1);
+ }
+
+ /* sbus irq 5 */
+ cg3_init(hwdef->tcx_base, slavio_irq[11], 0x00100000,
+ graphic_width, graphic_height, graphic_depth);
+ } else {
+ /* If no display specified, default to TCX */
+ if (graphic_depth != 8 && graphic_depth != 24) {
+ error_report("Unsupported depth: %d", graphic_depth);
+ exit(1);
+ }
+
+ if (!(graphic_width == 1024 && graphic_height == 768)) {
+ error_report("Unsupported resolution: %d x %d",
+ graphic_width, graphic_height);
+ exit(1);
+ }
+
+ tcx_init(hwdef->tcx_base, 0x00100000, graphic_width, graphic_height,
+ graphic_depth);
+ }
}
for (i = num_vsimms; i < MAX_VSIMMS; i++) {
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);
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index f75b914951..e4dcceaf23 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -51,7 +51,7 @@ typedef struct CPUTimerState {
ptimer_state *timer;
uint32_t count, counthigh, reached;
/* processor only */
- uint32_t running;
+ uint32_t run;
uint64_t limit;
} CPUTimerState;
@@ -177,7 +177,7 @@ static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
// only available in processor counter/timer
// read start/stop status
if (timer_index > 0) {
- ret = t->running;
+ ret = t->run;
} else {
ret = 0;
}
@@ -260,16 +260,15 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_STATUS:
if (slavio_timer_is_user(tc)) {
// start/stop user counter
- if ((val & 1) && !t->running) {
+ if (val & 1) {
trace_slavio_timer_mem_writel_status_start(timer_index);
ptimer_run(t->timer, 0);
- t->running = 1;
- } else if (!(val & 1) && t->running) {
+ } else {
trace_slavio_timer_mem_writel_status_stop(timer_index);
ptimer_stop(t->timer);
- t->running = 0;
}
}
+ t->run = val & 1;
break;
case TIMER_MODE:
if (timer_index == 0) {
@@ -284,8 +283,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
if (val & processor) { // counter -> user timer
qemu_irq_lower(curr_timer->irq);
// counters are always running
- ptimer_stop(curr_timer->timer);
- curr_timer->running = 0;
+ if (!curr_timer->run) {
+ ptimer_stop(curr_timer->timer);
+ }
// user timer limit is always the same
curr_timer->limit = TIMER_MAX_COUNT64;
ptimer_set_limit(curr_timer->timer,
@@ -296,13 +296,8 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
s->cputimer_mode |= processor;
trace_slavio_timer_mem_writel_mode_user(timer_index);
} else { // user timer -> counter
- // stop the user timer if it is running
- if (curr_timer->running) {
- ptimer_stop(curr_timer->timer);
- }
// start the counter
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
// clear this processors user timer bit in config
// register
s->cputimer_mode &= ~processor;
@@ -340,7 +335,7 @@ static const VMStateDescription vmstate_timer = {
VMSTATE_UINT32(count, CPUTimerState),
VMSTATE_UINT32(counthigh, CPUTimerState),
VMSTATE_UINT32(reached, CPUTimerState),
- VMSTATE_UINT32(running, CPUTimerState),
+ VMSTATE_UINT32(run , CPUTimerState),
VMSTATE_PTIMER(timer, CPUTimerState),
VMSTATE_END_OF_LIST()
}
@@ -373,7 +368,7 @@ static void slavio_timer_reset(DeviceState *d)
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
- curr_timer->running = 1;
+ curr_timer->run = 1;
}
}
s->cputimer_mode = 0;